diff --git a/1257-18A.sln b/1257-18A.sln new file mode 100644 index 0000000..522366a --- /dev/null +++ b/1257-18A.sln @@ -0,0 +1,141 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33530.505 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.Helper", "JinYuan.Helper\JinYuan.Helper.csproj", "{258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.VirtualDataLibrary", "JinYuan.VirtualDataLibrary\JinYuan.VirtualDataLibrary.csproj", "{2AB7E380-7795-448A-933C-0F6A081B5E7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.Models", "JinYuan.Models\JinYuan.Models.csproj", "{4C0BCB84-5CD7-4846-8363-C4C10D46E391}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.ControlCenters", "JinYuan.ControlCenter\JinYuan.ControlCenters.csproj", "{1D0FA5A4-07F0-4621-B6BB-683AEC91E658}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.DAL", "JinYuan.DAL\JinYuan.DAL.csproj", "{114AA012-29C9-418C-A2D6-3173C5341F51}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.MES", "JinYuan.MES\JinYuan.MES.csproj", "{530B6426-08E7-461C-91DC-787F876620FC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LargeSquareOne", "LargeSquareOne\LargeSquareOne.csproj", "{29E1F0D0-43DC-4077-A136-F25477E56881}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PLC", "PLC\PLC.csproj", "{486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JinYuan.ControlLib", "JinYuan.ControlLib\JinYuan.ControlLib.csproj", "{1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Language", "Language\Language.csproj", "{292A5C9C-7A82-4D25-A885-DDCEDC93F03C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOT.Services", "IOT.Services\IOT.Services.csproj", "{242400F4-9B01-4AEE-A6F7-05083757FCDD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{9FA3D6BD-1EC1-3BA5-80CB-CE02773A58D5}" + ProjectSection(SolutionItems) = preProject + 数据库\gluingmachineoftabflatteningandwelding_a.sql = 数据库\gluingmachineoftabflatteningandwelding_a.sql + 数据库\hbg_cupdataturnover.sql = 数据库\hbg_cupdataturnover.sql + TextFile1.txt = TextFile1.txt + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Debug|Any CPU.Build.0 = Debug|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Debug|x64.ActiveCfg = Debug|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Debug|x64.Build.0 = Debug|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Release|Any CPU.ActiveCfg = Release|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Release|Any CPU.Build.0 = Release|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Release|x64.ActiveCfg = Release|Any CPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}.Release|x64.Build.0 = Release|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Debug|x64.ActiveCfg = Debug|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Debug|x64.Build.0 = Debug|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Release|Any CPU.Build.0 = Release|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Release|x64.ActiveCfg = Release|Any CPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E}.Release|x64.Build.0 = Release|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Debug|x64.ActiveCfg = Debug|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Debug|x64.Build.0 = Debug|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Release|Any CPU.Build.0 = Release|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Release|x64.ActiveCfg = Release|Any CPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391}.Release|x64.Build.0 = Release|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Debug|x64.ActiveCfg = Debug|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Debug|x64.Build.0 = Debug|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Release|Any CPU.Build.0 = Release|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Release|x64.ActiveCfg = Release|Any CPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658}.Release|x64.Build.0 = Release|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Debug|x64.ActiveCfg = Debug|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Debug|x64.Build.0 = Debug|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Release|Any CPU.Build.0 = Release|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Release|x64.ActiveCfg = Release|Any CPU + {114AA012-29C9-418C-A2D6-3173C5341F51}.Release|x64.Build.0 = Release|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Debug|x64.ActiveCfg = Debug|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Debug|x64.Build.0 = Debug|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Release|Any CPU.Build.0 = Release|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Release|x64.ActiveCfg = Release|Any CPU + {530B6426-08E7-461C-91DC-787F876620FC}.Release|x64.Build.0 = Release|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Debug|x64.ActiveCfg = Debug|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Debug|x64.Build.0 = Debug|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Release|Any CPU.Build.0 = Release|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Release|x64.ActiveCfg = Release|Any CPU + {29E1F0D0-43DC-4077-A136-F25477E56881}.Release|x64.Build.0 = Release|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Debug|x64.ActiveCfg = Debug|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Debug|x64.Build.0 = Debug|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Release|Any CPU.Build.0 = Release|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Release|x64.ActiveCfg = Release|Any CPU + {486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}.Release|x64.Build.0 = Release|Any CPU + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Debug|x64.ActiveCfg = Debug|x64 + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Debug|x64.Build.0 = Debug|x64 + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Release|Any CPU.Build.0 = Release|Any CPU + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Release|x64.ActiveCfg = Release|x64 + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2}.Release|x64.Build.0 = Release|x64 + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Debug|x64.ActiveCfg = Debug|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Debug|x64.Build.0 = Debug|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Release|Any CPU.Build.0 = Release|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Release|x64.ActiveCfg = Release|Any CPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C}.Release|x64.Build.0 = Release|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Debug|x64.ActiveCfg = Debug|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Debug|x64.Build.0 = Debug|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Release|Any CPU.Build.0 = Release|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Release|x64.ActiveCfg = Release|Any CPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + RESX_AutoCreateNewLanguageFiles = False + RESX_SortFileContentOnSave = True + RESX_NeutralResourcesLanguage = zh-Hans + SolutionGuid = {E8421996-BAC4-4509-9C3E-BC424197F2D8} + EndGlobalSection +EndGlobal diff --git a/BTW/LabellingMachineA2.btw b/BTW/LabellingMachineA2.btw new file mode 100644 index 0000000..b3feb2e Binary files /dev/null and b/BTW/LabellingMachineA2.btw differ diff --git a/IOT.Services/App.config b/IOT.Services/App.config new file mode 100644 index 0000000..62f6cc9 --- /dev/null +++ b/IOT.Services/App.config @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IOT.Services/Config.xml b/IOT.Services/Config.xml new file mode 100644 index 0000000..a0fbd14 --- /dev/null +++ b/IOT.Services/Config.xml @@ -0,0 +1,3207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IOT.Services/IOT.Services.csproj b/IOT.Services/IOT.Services.csproj new file mode 100644 index 0000000..6da8971 --- /dev/null +++ b/IOT.Services/IOT.Services.csproj @@ -0,0 +1,127 @@ + + + + + Debug + AnyCPU + {242400F4-9B01-4AEE-A6F7-05083757FCDD} + WinExe + IOT.Services + IOT.Services + v4.8 + 512 + true + true + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + 10.0 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + Lib\DataConvertLib.dll + + + False + Lib\Newtonsoft.Json.dll + + + ..\packages\NLog.6.0.2\lib\net46\NLog.dll + + + False + Lib\PLCCommunication.dll + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + Service1.cs + + + + + + + + + + + + + + + + + Always + + + + + False + Microsoft .NET Framework 4.8 %28x86 和 x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + \ No newline at end of file diff --git a/IOT.Services/Lib/Newtonsoft.Json.dll b/IOT.Services/Lib/Newtonsoft.Json.dll new file mode 100644 index 0000000..7af125a Binary files /dev/null and b/IOT.Services/Lib/Newtonsoft.Json.dll differ diff --git a/IOT.Services/Lib/PLCCommunication.dll b/IOT.Services/Lib/PLCCommunication.dll new file mode 100644 index 0000000..1993b11 Binary files /dev/null and b/IOT.Services/Lib/PLCCommunication.dll differ diff --git a/IOT.Services/Logger.cs b/IOT.Services/Logger.cs new file mode 100644 index 0000000..4d6a8d7 --- /dev/null +++ b/IOT.Services/Logger.cs @@ -0,0 +1,135 @@ +using NLog; +using System; +using System.IO; +using System.Timers; + + +public class Logger +{ + + + private static readonly NLog.Logger loginfo = LogManager.GetLogger("loginfo"); + private static readonly NLog.Logger logerror = LogManager.GetLogger("logerror"); + private static readonly NLog.Logger logmqtt = LogManager.GetLogger("logmqtt"); + + private static readonly NLog.Logger logsInfo = LogManager.GetLogger("logsInfo"); + private static readonly NLog.Logger logsMEStIME = LogManager.GetLogger("logsMEStIME"); + private static readonly NLog.Logger logsSql = LogManager.GetLogger("logsSql"); + private static readonly NLog.Logger logsSysErrorLog = LogManager.GetLogger("logsSysErrorLog"); + private static readonly NLog.Logger logsSysErrorLogcn = LogManager.GetLogger("logsSysErrorLogcn"); + private static readonly Timer cleanupTimer; + private const int MAX_DAYS = 7; + private const string LOG_BASE_PATH = "Log"; + + static Logger() + { + try + { + // 创建一个每天执行一次的定时器 + cleanupTimer = new Timer(24 * 60 * 60 * 1000); // 24小时 + cleanupTimer.Elapsed += CleanupOldLogs; + cleanupTimer.Start(); + + // 启动时执行一次清理 + CleanupOldLogs(null, null); + } + catch (Exception ex) + { + WriteError("Failed to initialize logger cleanup timer", ex); + } + } + + public static void WriteInfo(string info) + { + if (loginfo.IsInfoEnabled) + { + loginfo.Info(info); + } + } + + public static void WriteMqtt(string info) + { + if (logmqtt.IsInfoEnabled) + { + logmqtt.Info(info); + } + } + + public static void WriteError(string error) + { + if (logerror.IsErrorEnabled) + { + logerror.Error(error); + } + } + + public static void WriteError(string info, Exception ex) + { + if (logerror.IsErrorEnabled) + { + logerror.Error(info, ex); + } + } + + private static void CleanupOldLogs(object sender, ElapsedEventArgs e) + { + try + { + if (!Directory.Exists(LOG_BASE_PATH)) + return; + + string[] logTypes = { "LogError", "LogInfo", "LogMqtt" }; + DateTime cutoffDate = DateTime.Now.AddDays(-MAX_DAYS); + + foreach (string logType in logTypes) + { + string logTypeDir = Path.Combine(LOG_BASE_PATH, logType); + if (!Directory.Exists(logTypeDir)) + continue; + + // 获取所有日期文件夹 + string[] dateDirs = Directory.GetDirectories(logTypeDir); + foreach (string dateDir in dateDirs) + { + string dirName = Path.GetFileName(dateDir); + if (DateTime.TryParseExact(dirName, "yyyyMMdd", null, + System.Globalization.DateTimeStyles.None, out DateTime dirDate)) + { + if (dirDate < cutoffDate) + { + try + { + Directory.Delete(dateDir, true); + WriteInfo($"Deleted old log directory: {dateDir}"); + } + catch (Exception ex) + { + WriteError($"Failed to delete log directory: {dateDir}", ex); + } + } + } + } + } + } + catch (Exception ex) + { + WriteError("Error during log cleanup", ex); + } + } + + // 提供手动清理方法 + public static void ForceCleanupOldLogs() + { + CleanupOldLogs(null, null); + } + + // 在应用程序退出时调用此方法 + public static void Shutdown() + { + if (cleanupTimer != null) + { + cleanupTimer.Stop(); + cleanupTimer.Dispose(); + } + } +} \ No newline at end of file diff --git a/IOT.Services/Models.cs b/IOT.Services/Models.cs new file mode 100644 index 0000000..97e069c --- /dev/null +++ b/IOT.Services/Models.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; + +namespace WindowsService1 +{ + #region 1、系统内部 + public enum AcquisitionType + { + PPM, + Axis, + Cylinder, + LRobot + } + + public enum PLCDataType + { + Short, + Float + } + + public class StationData + { + public string Name { get; set; } + public object MainValue { get; set; } + public DateTime Timestamp { get; set; } + } + + public class TypeConfig + { + public string Name { get; set; } + public string Address { get; set; } + public string DataType { get; set; } + } + + + + public class CollectionGroupConfig + { + public string Name { get; set; } + public string StartAddress { get; set; } + public int Length { get; set; } + public string DefaultDataType { get; set; } + public Dictionary Types { get; set; } + } + #endregion + + #region 2、PPM点位 + #endregion + + #region 3、预测性点位 + #endregion + + #region 4、机械臂 + //直角坐标机械臂 + public class LRobot + { + public string bu_id { get; set; } + public string district_id { get; set; } + public string factory_id { get; set; } + public string production_line_id { get; set; } + public string production_processes_id { get; set; } + public string work_center_id { get; set; } + public string station_id { get; set; } + public string device_name { get; set; } = "601PWM01"; + public string robot_name { get; set; } + public List taglist { get; set; } + } + public class Taglist + { + public string device_time { get; set; } + public Collection collections_items { get; set; } + + } + public class Collection + { + public string robot_status { get; set; } = "1"; + public string x_value { get; set; } + public string y_value { get; set; } + public string z_value { get; set; } + public string time_span { get; set; } = "2.5"; + public string hand_status { get; set; } = "1"; + + } + #endregion +} diff --git a/IOT.Services/MqttClientWrapper.cs b/IOT.Services/MqttClientWrapper.cs new file mode 100644 index 0000000..1e77e14 --- /dev/null +++ b/IOT.Services/MqttClientWrapper.cs @@ -0,0 +1,376 @@ +using Newtonsoft.Json.Linq; +using PLCCommunication; +using PLCCommunication.LogNet; +using PLCCommunication.MQTT; +using System; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace WindowsService1 +{ + public class MqttClientWrapper + { + private MqttClient mqttClient; + private bool mqttIsConnected; + private const int MaxReconnectAttempts = 5; + private const int ReconnectDelay = 5000; // 5 seconds + + private MqttConnectionOptions options; + public event Action OnMessageReceived; + public long ReceiveCount { get; private set; } + + public PLCCommunication.LogNet.ILogNet LogNet = new LogNetDateTime("D:\\APILog\\Logs\\MQTTLogs", GenerateMode.ByEveryDay, 20); + + public enum MessageFormat + { + Binary, + Text, + Xml, + Json + } + + + public MqttClientWrapper(string ipAddress, int port, string clientId, MqttCredential credentials) + { + InitializeMqttOptions(ipAddress, port, clientId, credentials); + } + + private void InitializeMqttOptions(string ipAddress, int port, string clientId, MqttCredential credentials) + { + options = new MqttConnectionOptions + { + IpAddress = ipAddress, + Port = port, + ClientId = clientId, + Credentials = credentials, + UseRSAProvider = false, + CleanSession = false, + UseSSL = false, + SSLSecure = false, + CertificateFile = "", + KeepAlivePeriod = TimeSpan.FromSeconds(30), + KeepAliveSendInterval = TimeSpan.FromSeconds(10), + ConnectTimeout = 5, + WillMessage = null + }; + } + + public async Task InitializeAndConnectAsync() + { + try + { + mqttClient = new MqttClient(options); + Logger.WriteMqtt("MQTT 初始化成功"); + + await ConnectMqttAsync(); + } + catch (Exception ex) + { + Logger.WriteError($"MQTT 初始化失败: {ex.Message}"); + } + } + + private async Task ConnectMqttAsync() + { + try + { + JYResult connect = await mqttClient.ConnectServerAsync(); + if (connect.IsSuccess) + { + mqttIsConnected = true; + Logger.WriteMqtt("MQTT 连接服务器成功"); + } + else + { + Logger.WriteError("MQTT 无法连接到服务器"); + } + } + catch (Exception ex) + { + Logger.WriteError($"MQTT 无法连接到服务器: {ex.Message}"); + } + } + + + public async Task SendMessageAsync(string source, string publishTopic, string type, JObject messageObj) + { + if (!mqttClient.IsConnected) + { + mqttIsConnected = false; + + Logger.WriteMqtt("客户端未连接到服务器。正在尝试重新连接..."); + + await ReconnectWithRetry(); + if (!mqttClient.IsConnected) + { + throw new InvalidOperationException("无法与 MQTT 代理建立连接."); + } + } + try + { + if (messageObj != null) + { + string json = messageObj.ToString(); + //string json = JsonConvert.SerializeObject(messageObj); + JYResult result = await mqttClient.PublishMessageAsync(new MqttApplicationMessage + { + Topic = publishTopic, + QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce, + Payload = Encoding.UTF8.GetBytes(json), + Retain = false, + }); + if (result.IsSuccess) + { + if (Service1.SwitchLog) + { + Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}]: {json}"); + } + } + else + { + Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}] 失败: {result.Message}"); + + } + } + } + catch (Exception ex) + { + Logger.WriteError($"发送消息错误: {ex.Message}"); + } + } + + + public async Task SendMessageAsync(string source, string publishTopic, string type, string messageObj) + { + if (!mqttClient.IsConnected) + { + mqttIsConnected = false; + + Logger.WriteMqtt("客户端未连接到服务器。正在尝试重新连接..."); + + + await ReconnectWithRetry(); + if (!mqttClient.IsConnected) + { + throw new InvalidOperationException("无法与 MQTT 代理建立连接."); + } + } + try + { + if (messageObj != null) + { + JYResult result = await mqttClient.PublishMessageAsync(new MqttApplicationMessage + { + Topic = publishTopic, + QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce, + Payload = Encoding.UTF8.GetBytes(messageObj), + Retain = false, + }); + + if (result.IsSuccess) + { + if (Service1.SwitchLog) + { + Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}]: {messageObj}"); + } + } + else + { + Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}] 失败: {result.Message}"); + + } + } + } + catch (Exception ex) + { + Logger.WriteError($"发送消息错误: {ex.Message}"); + } + } + + + + public void SubscribeMessage(string topic, MessageFormat format = MessageFormat.Text, bool truncateLongMessage = false) + { + if (!mqttIsConnected) + { + ConnectMqttAsync().Wait(); + } + + try + { + JYResult operateResult = mqttClient.SubscribeMessage(new string[] { topic }); + if (!operateResult.IsSuccess) + { + Logger.WriteMqtt($"订阅消息失败: {operateResult.Message}"); + return; + } + + SubscribeTopic subscribeTopic = mqttClient.GetSubscribeTopic(topic); + if (subscribeTopic != null) + { + subscribeTopic.OnMqttMessageReceived += (sender, args) => + { + HandleReceivedMessage(args.Topic, args.Payload, format, truncateLongMessage); + }; + Logger.WriteMqtt($"成功订阅主题: {topic}"); + } + else + { + Logger.WriteMqtt($"无法获取订阅主题 {topic}"); + } + } + catch (Exception ex) + { + Logger.WriteError($"订阅主题时出错 {topic}: {ex.Message}"); + } + } + + private void HandleReceivedMessage(string topic, byte[] payload, MessageFormat format, bool truncateLongMessage) + { + ReceiveCount++; + string text = string.Empty; + + try + { + switch (format) + { + case MessageFormat.Binary: + text = BitConverter.ToString(payload).Replace("-", " "); + break; + case MessageFormat.Text: + text = Encoding.UTF8.GetString(payload); + break; + case MessageFormat.Xml: + try + { + text = XElement.Parse(Encoding.UTF8.GetString(payload)).ToString(); + } + catch + { + text = Encoding.UTF8.GetString(payload); + } + break; + case MessageFormat.Json: + try + { + text = JObject.Parse(Encoding.UTF8.GetString(payload)).ToString(); + } + catch + { + text = Encoding.UTF8.GetString(payload); + } + break; + } + //if (Service1.SwitchLog) + //{ + // LogNet.WriteDebug($"收到主题 {topic}: {text}"); + //} + //if (truncateLongMessage && text.Length > 200) + //{ + // text = text.Substring(0, 200) + "..."; + //} + + string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); + OnMessageReceived?.Invoke(timestamp, topic, text); + } + catch (Exception ex) + { + Logger.WriteError($"处理收到的消息时出错: {ex.Message}"); + } + } + + public void UnsubscribeMessage(string topic) + { + try + { + JYResult operateResult = mqttClient.UnSubscribeMessage(new string[] { topic }); + if (operateResult.IsSuccess) + { + Logger.WriteMqtt($"成功取消订阅主题: {topic}"); + } + else + { + Logger.WriteMqtt($"取消订阅主题失败 {topic}: {operateResult.Message}"); + } + } + catch (Exception ex) + { + Logger.WriteError($"取消订阅主题时出错 {topic}: {ex.Message}"); + } + } + + /// + /// 重连 + /// + /// + private async Task ReconnectWithRetry() + { + int attempts = 0; + while (!mqttClient.IsConnected && attempts < MaxReconnectAttempts) + { + try + { + await mqttClient.ConnectServerAsync(); + Logger.WriteMqtt("重新连接成功."); + + return; + } + catch (Exception ex) + { + attempts++; + Logger.WriteMqtt($"重新连接尝试 {attempts} 失败的: {ex.Message}"); + await Task.Delay(ReconnectDelay); + } + } + if (!mqttClient.IsConnected) + { + Logger.WriteMqtt("尝试次数达到上限后仍无法重新连接."); + } + } + + + private async Task ReconnectAsync() + { + Logger.WriteMqtt("正在尝试重新连接..."); + mqttIsConnected = false; + int retryCount = 0; + const int maxRetries = 5; + const int retryDelayMs = 5000; + + while (!mqttIsConnected && retryCount < maxRetries) + { + try + { + await ConnectMqttAsync(); + if (mqttIsConnected) + { + Logger.WriteMqtt("重新连接成功"); + return; + } + } + catch (Exception ex) + { + Logger.WriteMqtt($"重新连接尝试 {retryCount + 1} 失败的: {ex.Message}"); + } + + retryCount++; + await Task.Delay(retryDelayMs); + } + + if (!mqttIsConnected) + { + Logger.WriteMqtt("多次尝试后仍无法重新连接"); + } + } + + + + public async Task Disconnect() + { + await mqttClient.ConnectCloseAsync(); + mqttIsConnected = false; + Logger.WriteMqtt("与 MQTT服务端断开连接!!!"); + } + } +} diff --git a/IOT.Services/MqttDataService.cs b/IOT.Services/MqttDataService.cs new file mode 100644 index 0000000..e6efb3c --- /dev/null +++ b/IOT.Services/MqttDataService.cs @@ -0,0 +1,730 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace WindowsService1 +{ + public class MqttDataService + { + + public static string BU_id; + public static string District_id; + public static string Factory_id; + public static string Production_line_id; + public static string Device_name; + public static string Topic; + public static string Work_Center_id; + public class OperationData + { + public int Item_Value { get; set; } + public string Start_Time { get; set; } + public string End_Time { get; set; } + } + + + public class MqttMessage + { + public string bu_id { get; set; } + public string district_id { get; set; } + public string factory_id { get; set; } + public string production_line_id { get; set; } + public string production_processes_id { get; set; } + public string work_center_id { get; set; } + public string station_id { get; set; } + public string device_name { get; set; } + public List taglist { get; set; } + } + + public class TagList + { + public string device_time { get; set; } + public Dictionary collection_items { get; set; } + } + + + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static MqttMessage CreateMqttMessage(string source, AcquisitionType type, List processedValues, + Dictionary> _plcAddresses, + Dictionary _collectionGroups) + { + try + { + Logger.WriteInfo($"开始创建 MQTT 消息, 类型: {type}, 数据点数量: {processedValues?.Count ?? 0}"); + + if (processedValues == null || processedValues.Count == 0) + { + Logger.WriteInfo("没有需要处理的数据,返回 null"); + return null; + } + + var addresses = _plcAddresses[type]; + var config = _collectionGroups[type]; + var collectionItems = new Dictionary(); + + // 获取当前时间作为设备时间 + var currentTime = DateTime.Now; + var deviceTimeStr = currentTime.ToString("yyyy-MM-dd HH:mm:ss.fff"); + + Logger.WriteInfo($"处理数据类型: {type}, 当前时间: {deviceTimeStr}"); + + switch (type) + { + case AcquisitionType.PPM: + ProcessPPMData(processedValues, addresses, config, collectionItems); + break; + + case AcquisitionType.Axis: + case AcquisitionType.Cylinder: + ProcessFloatData(processedValues, addresses, config, currentTime, collectionItems); + break; + + default: + Logger.WriteError($"未知的数据类型: {type}"); + return null; + } + + if (collectionItems.Count == 0) + { + Logger.WriteInfo("没有有效的采集项,返回 null"); + return null; + } + + var message = new MqttMessage + { + bu_id = BU_id, + district_id = District_id, + factory_id = Factory_id, + production_line_id = Production_line_id, + production_processes_id = string.Empty, + work_center_id = Work_Center_id, + station_id = "1", + device_name = Device_name, + taglist = new List + { + new TagList + { + device_time = deviceTimeStr, + collection_items = collectionItems + } + } + }; + + // 记录创建的消息内容 + Logger.WriteInfo($"MQTT 消息创建完成: {JsonConvert.SerializeObject(message, Formatting.None)}"); + + return message; + } + catch (Exception ex) + { + Logger.WriteError($"创建 MQTT 消息时发生错误: {ex.Message}"); + return null; + } + } + + /// + /// PPM点位数据 + /// + /// + /// + /// + /// + /// + // 添加静态字段来存储上次发送的数据 + private static Dictionary _lastSentData = new Dictionary(); + + public static void ProcessPPMData(List processedValues, Dictionary addresses, CollectionGroupConfig config, Dictionary collectionItems) + { + try + { + Logger.WriteInfo($"开始处理 PPM 数据,数据点数量: {processedValues.Count}"); + + // 创建临时字典存储当前所有数据点 + var tempItems = new Dictionary(); + + foreach (var value in processedValues) + { + var addressPair = addresses.FirstOrDefault(x => x.Key == value.Name); + if (!string.IsNullOrEmpty(addressPair.Key)) + { + int itemValue = Convert.ToInt32(ConvertToIntegerWithThreeDecimals(value.MainValue)); + + // 计算开始时间 (结束时间 - 时长) + var startTime = value.Timestamp.AddMilliseconds(-itemValue); + + var operationData = new OperationData + { + Item_Value = itemValue, + Start_Time = startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), + End_Time = value.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff") + }; + + // 检查数据是否发生变化 + bool shouldAdd = true; + + // 检查是否与上次发送的数据重复 + if (_lastSentData.TryGetValue(addressPair.Key, out var lastData)) + { + var currentEndTime = operationData.End_Time.ToString(); + var lastEndTime = lastData.End_Time.ToString(); + + if (string.Equals(lastEndTime, currentEndTime, StringComparison.OrdinalIgnoreCase)) + { + shouldAdd = false; + Logger.WriteInfo($"跳过重复数据点: {addressPair.Key}"); + continue; + } + } + + if (shouldAdd) + { + tempItems[addressPair.Key] = operationData; + Logger.WriteInfo($"处理数据点: {addressPair.Key}, 值: {itemValue}, " + + $"开始时间: {startTime:yyyy-MM-dd HH:mm:ss.fff}, " + + $"结束时间: {operationData.End_Time}"); + } + //if (shouldAdd) + //{ + // // 检查是否与当前批次的其他数据有重复的结束时间 + // var duplicateEndTimeItem = tempItems.FirstOrDefault(x => + // string.Equals(x.Value.End_Time.ToString(), operationData.End_Time.ToString(), StringComparison.OrdinalIgnoreCase)); + + // if (duplicateEndTimeItem.Key != null) + // { + // Logger.WriteError($"检测到结束时间重复: {operationData.End_Time} 对应地址: {addressPair.Key}, " + + // $"与地址 {duplicateEndTimeItem.Key} 的数据重复"); + + // // 根据地址的字母顺序决定哪个需要调整时间,确保调整的一致性 + // if (string.Compare(addressPair.Key, duplicateEndTimeItem.Key) > 0) + // { + // operationData.End_Time = value.Timestamp.AddMilliseconds(1).ToString("yyyy-MM-dd HH:mm:ss.fff"); + // Logger.WriteInfo($"调整后的结束时间: {operationData.End_Time}"); + // } + // } + + // tempItems[addressPair.Key] = operationData; + // Logger.WriteInfo($"处理数据点: {addressPair.Key}, 值: {itemValue}, " + + // $"开始时间: {startTime:yyyy-MM-dd HH:mm:ss.fff}, " + + // $"结束时间: {operationData.End_Time}"); + //} + } + else + { + Logger.WriteError($"未找到数据点 {value.Name} 对应的地址配置"); + } + } + + // 将处理后的数据添加到最终结果并更新上次发送的数据 + foreach (var item in tempItems) + { + collectionItems[item.Key] = item.Value; + _lastSentData[item.Key] = item.Value; // 更新上次发送的数据 + } + + Logger.WriteInfo($"PPM 数据处理完成,处理后的数据点数量: {collectionItems.Count}"); + } + catch (Exception ex) + { + Logger.WriteError($"处理 PPM 数据时出错: {ex.Message}"); + throw; + } + } + + private static bool IsDataEqual(OperationData data1, OperationData data2, string addressKey) + { + if (data1 == null || data2 == null) + return false; + + bool isEqual = data1.Item_Value == data2.Item_Value && + data1.Start_Time == data2.Start_Time && + data1.End_Time == data2.End_Time; + + if (isEqual) + { + Logger.WriteInfo($"检测到重复数据 - 地址: {addressKey}, " + + $"值: {data1.Item_Value}, " + + $"开始时间: {data1.Start_Time}, " + + $"结束时间: {data1.End_Time}"); + } + + return isEqual; + } + + + + /// + /// 预测性点位 + /// + /// + /// + /// + /// + /// + public static void ProcessFloatData(List processedValues, Dictionary addresses, CollectionGroupConfig config, DateTime endTime, Dictionary collectionItems) + { + for (int i = 0; i < processedValues.Count && i < config.Length; i++) + { + string address = $"D{int.Parse(config.StartAddress.Substring(1)) + i * 2}"; + if (addresses.ContainsValue(address)) + { + var key = addresses.FirstOrDefault(x => x.Value == address).Key; + int itemValue = Convert.ToInt32(ConvertToIntegerWithThreeDecimals(processedValues[i].MainValue)); + + // 计算开始时间 (结束时间 - 时长) + //var startTime = endTime.AddMilliseconds(-itemValue); + + collectionItems[key] = new OperationData + { + Item_Value = (int)itemValue, + Start_Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + End_Time = endTime.ToString("yyyy-MM-dd HH:mm:ss.fff") + }; + } + } + } + + /// + /// 机械臂数据 + /// + /// + /// + /// + /// + /// + /// + public static LRobot LRobotMessage(string source, AcquisitionType type, List processedValues, Dictionary> _plcAddresses, + Dictionary _collectionGroups) + { + if (processedValues == null || processedValues.Count == 0) + { + return null; + } + var addresses = _plcAddresses[type]; + var config = _collectionGroups[type]; + return new LRobot() + { + bu_id = BU_id, + district_id = District_id, + factory_id = Factory_id, + production_line_id = Production_line_id, + production_processes_id = "", + work_center_id = "", + station_id = "", + device_name = "601PWM01", + robot_name = "LUR01", + taglist = new List + { + new Taglist//上料动子1 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[0].MainValue.ToString(), + y_value="0", + z_value=processedValues[1].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子2 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[2].MainValue.ToString(), + y_value="0", + z_value=processedValues[3].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子3 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[4].MainValue.ToString(), + y_value="0", + z_value=processedValues[5].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子4 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[6].MainValue.ToString(), + y_value="0", + z_value=processedValues[7].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子5 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[8].MainValue.ToString(), + y_value="0", + z_value=processedValues[9].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子6 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[10].MainValue.ToString(), + y_value="0", + z_value=processedValues[11].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子7 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[13].MainValue.ToString(), + y_value="0", + z_value=processedValues[14].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子8 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[16].MainValue.ToString(), + y_value="0", + z_value=processedValues[17].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//上料动子9 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[18].MainValue.ToString(), + y_value="0", + z_value=processedValues[19].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机1 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[20].MainValue.ToString(), + y_value=processedValues[21].MainValue.ToString(), + z_value=processedValues[22].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机2 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[23].MainValue.ToString(), + y_value=processedValues[24].MainValue.ToString(), + z_value=processedValues[25].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机3 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[26].MainValue.ToString(), + y_value=processedValues[27].MainValue.ToString(), + z_value=processedValues[28].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机4 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[29].MainValue.ToString(), + y_value=processedValues[30].MainValue.ToString(), + z_value=processedValues[31].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机5 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[32].MainValue.ToString(), + y_value=processedValues[33].MainValue.ToString(), + z_value=processedValues[34].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机6 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[35].MainValue.ToString(), + y_value=processedValues[36].MainValue.ToString(), + z_value=processedValues[37].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机7 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[38].MainValue.ToString(), + y_value=processedValues[39].MainValue.ToString(), + z_value=processedValues[40].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机8 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[41].MainValue.ToString(), + y_value=processedValues[42].MainValue.ToString(), + z_value=processedValues[43].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机9 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[44].MainValue.ToString(), + y_value=processedValues[45].MainValue.ToString(), + z_value=processedValues[46].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机10 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[47].MainValue.ToString(), + y_value=processedValues[48].MainValue.ToString(), + z_value=processedValues[49].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机11 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[50].MainValue.ToString(), + y_value=processedValues[51].MainValue.ToString(), + z_value=processedValues[52].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//焊机12 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[53].MainValue.ToString(), + y_value=processedValues[54].MainValue.ToString(), + z_value=processedValues[55].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//下料动子1 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[56].MainValue.ToString(), + y_value="0", + z_value=processedValues[57].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//下料动子2 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[58].MainValue.ToString(), + y_value="0", + z_value=processedValues[59].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//下料动子3 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[61].MainValue.ToString(), + y_value="0", + z_value=processedValues[62].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//下料动子4 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[63].MainValue.ToString(), + y_value="0", + z_value=processedValues[64].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//下料动子5 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[65].MainValue.ToString(), + y_value="0", + z_value=processedValues[66].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + }, + new Taglist//下料动子6 + { + device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + collections_items=new Collection() + { + robot_status = "1", + x_value=processedValues[67].MainValue.ToString(), + y_value="0", + z_value=processedValues[68].MainValue.ToString(), + time_span="2.5", + hand_status="1", + } + } + + } + + }; + } + + + + + // 辅助方法 + private static List ConvertToShortList(object[] data) + { + return data.Select(x => Convert.ToInt16(x)).ToList(); + } + + private static List ConvertToFloatList(object[] data) + { + return data.Select(x => Convert.ToSingle(x)).ToList(); + } + + + private static object ConvertToIntegerWithThreeDecimals(object value) + { + try + { + if (value == null) return 0; + + if (value is float floatValue) + { + return (int)Math.Round(floatValue * 1000); + } + else if (value is double doubleValue) + { + return (int)Math.Round(doubleValue * 1000); + } + else if (value is decimal decimalValue) + { + return (int)Math.Round(decimalValue * 1000); + } + else + { + // 尝试转换其他类型 + float converted = Convert.ToSingle(value); + return (int)Math.Round(converted * 1000); + } + } + catch (Exception ex) + { + Logger.WriteError($"转换值到整数时出错: {ex.Message}, 值: {value}"); + return 0; + } + } + } +} diff --git a/IOT.Services/NLog.config b/IOT.Services/NLog.config new file mode 100644 index 0000000..4ca60d8 --- /dev/null +++ b/IOT.Services/NLog.config @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IOT.Services/PLCDataReader.cs b/IOT.Services/PLCDataReader.cs new file mode 100644 index 0000000..4bd584b --- /dev/null +++ b/IOT.Services/PLCDataReader.cs @@ -0,0 +1,155 @@ +using JinYuan.DataConvertLib; +using PLCCommunication.PLCType.Omron; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace WindowsService1 +{ + + + /// + /// 定义每个数据读取请求的参数。 + /// + public class PLCDataReadRequest + { + /// + /// PLC起始地址 + /// + public string StartAddress { get; set; } + /// + /// 读取长度 + /// + public ushort Length { get; set; } + /// + /// 读取区域名称 + /// + public string StorageName { get; set; } + /// + /// 读取数据类型 + /// + public PLCDataType DataType { get; set; } + } + + /// + /// 存储每次读取操作的结果。 + /// + public class PLCDataResult + { + /// + /// 读取区域名称 + /// + public string StorageName { get; set; } + /// + /// 读取数据类型 + /// + public PLCDataType DataType { get; set; } + /// + /// 数据 + /// + public byte[] Data { get; set; } + /// + /// 是否读取成功 + /// + public bool IsSuccess { get; set; } + /// + /// 读取失败的错误信息 + /// + public string ErrorMessage { get; set; } + } + + public class PLCDataReader + { + private readonly OmronFinsNet _plc; + + + public PLCDataReader(OmronFinsNet plc) + { + _plc = plc ?? throw new ArgumentNullException(nameof(plc)); + } + + public async Task ReadDataAsync(PLCDataReadRequest request) + { + try + { + var data = await _plc.ReadAsync(request.StartAddress, request.Length); + if (data.IsSuccess && data.Content.Length > 0) + { + Logger.WriteInfo($"成功读取PLC数据,起始地址:{request.StartAddress},长度:{request.Length},类型:{request.DataType}"); + return new PLCDataResult + { + StorageName = request.StorageName, + DataType = request.DataType, + Data = data.Content, + IsSuccess = true + }; + } + else + { + Logger.WriteInfo($"读取PLC数据失败,起始地址:{request.StartAddress},长度:{request.Length},类型:{request.DataType}"); + return new PLCDataResult + { + StorageName = request.StorageName, + DataType = request.DataType, + IsSuccess = false, + ErrorMessage = "读取PLC数据失败" + }; + } + } + catch (Exception ex) + { + Logger.WriteError($"读取PLC数据时发生错误:{ex.Message}"); + return new PLCDataResult + { + StorageName = request.StorageName, + DataType = request.DataType, + IsSuccess = false, + ErrorMessage = ex.Message + }; + } + } + + private object[] ParseData(byte[] content, PLCDataType dataType) + { + switch (dataType) + { + case PLCDataType.Short: + return ParseShortData(content); + case PLCDataType.Float: + return ParseFloatData(content); + default: + throw new ArgumentException($"不支持的数据类型:{dataType}"); + } + } + + private object[] ParseShortData(byte[] content) + { + int count = content.Length / 2; + return Enumerable.Range(0, count) + .Select(i => (object)ShortLib.GetShortFromByteArray(content, i * 2)) + .ToArray(); + } + + private object[] ParseFloatData(byte[] content) + { + int count = content.Length / 4; + return Enumerable.Range(0, count) + .Select(i => (object)FloatLib.GetFloatFromByteArray(content, i * 4)) + .ToArray(); + } + } + + public static class ConvertHelper + { + /// + /// 字节数组高低位转换 + /// + /// + /// + public static byte[] ByteReverse(this byte[] Arrbyte) + { + byte[] ArrByte = Arrbyte.Select((x, i) => new { x, i }).GroupBy(x => x.i / 2).SelectMany(x => new byte[] { x.Last().x, x.First().x }).ToArray(); + return ArrByte; + } + } +} diff --git a/IOT.Services/PLCWrapper.cs b/IOT.Services/PLCWrapper.cs new file mode 100644 index 0000000..f0d3889 --- /dev/null +++ b/IOT.Services/PLCWrapper.cs @@ -0,0 +1,104 @@ +using PLCCommunication.PLCType.Omron; +using System; +using System.Threading.Tasks; + +namespace WindowsService1 +{ + public class PLCWrapper + { + private OmronFinsNet _plc; + public bool _plcIsConnected; + private readonly string _ipAddress; + private readonly int _port; + private readonly int _maxReconnectAttempts; + private readonly int _reconnectDelay; + public PLCDataReader _dataReader; + public PLCWrapper(string ipAddress, int port, int maxReconnectAttempts = 3, int reconnectDelay = 5000) + { + _ipAddress = ipAddress; + _port = port; + _maxReconnectAttempts = maxReconnectAttempts; + _reconnectDelay = reconnectDelay; + } + + public async Task ConnectAsync() + { + try + { + _plc = new OmronFinsNet + { + IpAddress = _ipAddress, + Port = _port + }; + var connectResult = await Task.Run(() => _plc.ConnectServer()); + _plcIsConnected = connectResult.IsSuccess; + if (_plcIsConnected) + { + _dataReader = new PLCDataReader(GetPLCClient()); + Logger.WriteInfo("PLC连接成功"); + } + else + { + Logger.WriteInfo("PLC连接失败"); + } + return _plcIsConnected; + } + catch (Exception ex) + { + Logger.WriteError($"PLC连接失败: {ex.Message}"); + return false; + } + } + + public void Disconnect() + { + if (_plcIsConnected) + { + _plc.ConnectClose(); + _plcIsConnected = false; + Logger.WriteInfo("与PLC断开连接"); + } + } + + public OmronFinsNet GetPLCClient() + { + if (!_plcIsConnected || _plc == null) + { + throw new InvalidOperationException("PLC 未连接或未初始化。请先调用 ConnectAsync()。"); + } + return _plc; + } + + public async Task ReconnectAsync() + { + if (_plcIsConnected) + { + Logger.WriteInfo("PLC已连接,无需重连"); + return true; + } + + for (int attempt = 1; attempt <= _maxReconnectAttempts; attempt++) + { + Logger.WriteInfo($"尝试重新连接PLC,第 {attempt} 次尝试"); + if (await ConnectAsync()) + { + Logger.WriteInfo("PLC重新连接成功"); + return true; + } + + if (attempt < _maxReconnectAttempts) + { + await Task.Delay(_reconnectDelay); + } + } + + Logger.WriteError($"PLC重新连接失败,已尝试 {_maxReconnectAttempts} 次"); + return false; + } + + public bool IsConnected() + { + return _plcIsConnected; + } + } +} \ No newline at end of file diff --git a/IOT.Services/Program.cs b/IOT.Services/Program.cs new file mode 100644 index 0000000..aeeb614 --- /dev/null +++ b/IOT.Services/Program.cs @@ -0,0 +1,20 @@ +using System.ServiceProcess; + +namespace WindowsService1 +{ + internal static class Program + { + /// + /// 应用程序的主入口点。 + /// + static void Main() + { + ServiceBase[] ServicesToRun; + ServicesToRun = new ServiceBase[] + { + new Service1() + }; + ServiceBase.Run(ServicesToRun); + } + } +} diff --git a/IOT.Services/Properties/AssemblyInfo.cs b/IOT.Services/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..004aa2d --- /dev/null +++ b/IOT.Services/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("WindowsService1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WindowsService1")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("242400f4-9b01-4aee-a6f7-05083757fcdd")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/IOT.Services/Service1.Designer.cs b/IOT.Services/Service1.Designer.cs new file mode 100644 index 0000000..b7b9f85 --- /dev/null +++ b/IOT.Services/Service1.Designer.cs @@ -0,0 +1,38 @@ +namespace WindowsService1 +{ + partial class Service1 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + Logger.Shutdown(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.ServiceName = "Service1"; + } + + #endregion + } +} diff --git a/IOT.Services/Service1.cs b/IOT.Services/Service1.cs new file mode 100644 index 0000000..e347afc --- /dev/null +++ b/IOT.Services/Service1.cs @@ -0,0 +1,1179 @@ +using JinYuan.DataConvertLib; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PLCCommunication.MQTT; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.ServiceProcess; +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace WindowsService1 +{ + public partial class Service1 : ServiceBase + { + private readonly List _tasks = new List(); + private readonly CancellationTokenSource _cts = new CancellationTokenSource(); + + private PLCWrapper _plcWrapper; + private MqttClientWrapper mqttClient = null; + private System.Threading.Timer _periodicTimer; + + private Dictionary _collectionGroups; + private Dictionary> _plcAddresses; + + private AcquisitionType[] AcqTypes = null; + + private const int ReconnectionInterval = 5000; // 5 seconds + private const int MaxReconnectAttempts = 3; + + public string PlcIpAddress = "127.0.0.1"; + public int PlcPort = 9600; + + + public string MQTTServerAddress = "127.0.0.1"; + public int MQTTServerPort = 1883; + public string ClientId = "601UPW01"; + //PPM主题 + public string Topic = "EVE/60J/EQP/NEW_PPM/601UPW01"; + //PPM其他数据 + public string Topic1 = "eve/60J/EQP/601UPW01"; + //直角坐标机械臂 + public string LRobotTopic = "EVE/60J/LRobot/601PWM01_LUR01"; + //关节机械臂 + public string JRobotTopic = "EVE/60J/JRobot/601PWM01_STR01"; + + public MqttCredential credentials = null; + + public string BU_id = "EVE2BU"; + public string District_id = "QJ"; + public string Factory_id = "60J"; + public string Production_line_id = "MW-601"; + public string Device_name = "601UPW01"; + + public int ThreadInterval = 50; + public static bool SwitchLog = false; + + public Service1() + { + InitializeComponent(); + ServiceName = "TestMqttService"; + CanStop = true; // 服务可以被停止 + CanPauseAndContinue = false; + AutoLog = true; + + + } + + protected override void OnStart(string[] args) + { + Logger.WriteInfo($"OnStart:服务启动-{DateTime.Now}"); + InitializeConfig(); + _plcWrapper = new PLCWrapper(PlcIpAddress, PlcPort); + InitializeTask(); + InitializePLC(); + InitializeMQTT(); + + Task.Run(() => RunChangeDetectionTaskAsync(_cts.Token));// 启动变化检测任务 + + + Logger.WriteInfo($"OnStart:服务启动完毕-{DateTime.Now}"); + } + + protected override async void OnStop() + { + _cts.Cancel(); + _periodicTimer?.Dispose(); + // 停止 PLC 读取 + if (_plcWrapper != null) + { + _plcWrapper.Disconnect(); + Logger.WriteInfo("PLC 通讯停止."); + } + if (mqttClient != null) + { + await mqttClient.Disconnect(); + Logger.WriteInfo("MQTT 连接已关闭."); + } + Logger.WriteInfo("OnStop"); + } + + /// + /// 系统配置文件读取 + /// + private void InitializeConfig() + { + ReadConfigFromXml(); + PlcIpAddress = ConfigurationManager.AppSettings["PlcIpAddress"] ?? "127.0.0.1"; + PlcPort = int.Parse(ConfigurationManager.AppSettings["PlcPort"] ?? "9600"); + + MQTTServerAddress = ConfigurationManager.AppSettings["MQTTServerAddress"] ?? "127.0.0.1"; + MQTTServerPort = int.Parse(ConfigurationManager.AppSettings["MQTTServerPort"] ?? "1883"); + ClientId = ConfigurationManager.AppSettings["ClientId"] ?? "601UPW01"; + + Topic = ConfigurationManager.AppSettings["Topic"] ?? "EVE/60J/EQP/NEW_PPM/601UPW01"; + Topic1 = ConfigurationManager.AppSettings["Topic1"] ?? "eve/60J/EQP/601UPW01"; + LRobotTopic = ConfigurationManager.AppSettings["LRobotTopic"] ?? "EVE/60J/LRobot/601PWM01_LUR01"; + JRobotTopic = ConfigurationManager.AppSettings["JRobotTopic"] ?? "EVE/60J/JRobot/601PWM01_STR01"; + + BU_id = ConfigurationManager.AppSettings["BU_id"] ?? "601UPW01"; + District_id = ConfigurationManager.AppSettings["District_id"] ?? "QJ"; + Factory_id = ConfigurationManager.AppSettings["Factory_id"] ?? "60J"; + Production_line_id = ConfigurationManager.AppSettings["Production_line_id"] ?? "MW-601"; + Device_name = ConfigurationManager.AppSettings["Device_name"] ?? "601UPW01"; + ThreadInterval = int.Parse(ConfigurationManager.AppSettings["ThreadInterval"] ?? "50"); + SwitchLog = bool.Parse(ConfigurationManager.AppSettings["SwitchLog"] ?? "True"); + MqttDataService.BU_id = BU_id; + MqttDataService.District_id = District_id; + MqttDataService.Factory_id = Factory_id; + MqttDataService.Production_line_id = Production_line_id; + MqttDataService.Device_name = Device_name; + MqttDataService.Work_Center_id = "601FGE02"; + + Logger.WriteInfo("读取系统配置文件成功!"); + + + } + + private void ReadConfigFromXml() + { + try + { + var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.xml"); + var doc = XDocument.Load(configPath); + string deviceName = ""; + _plcAddresses = new Dictionary>(); + _collectionGroups = new Dictionary(); + + foreach (var deviceElement in doc.Descendants("Device")) + { + var isEnabled = bool.Parse(deviceElement.Attribute("isEnable")?.Value ?? "false"); + + if (isEnabled) + { + deviceName = deviceElement.Attribute("name")?.Value; + + foreach (var groupElement in deviceElement.Elements("CollectionGroup")) + { + var groupName = groupElement.Attribute("name").Value; + Logger.WriteInfo($"添加寄存器组类型: {groupName}"); + + var acquisitionType = (AcquisitionType)Enum.Parse(typeof(AcquisitionType), groupName); + var groupConfig = new CollectionGroupConfig + { + Name = groupName, + StartAddress = groupElement.Attribute("StartAddress").Value, + Length = int.Parse(groupElement.Attribute("length").Value), + DefaultDataType = groupElement.Attribute("DataType")?.Value ?? "Short", + Types = new Dictionary() + }; + + var groupAddresses = new Dictionary(); + + foreach (var typeElement in groupElement.Elements("Type")) + { + var typeName = typeElement.Attribute("name").Value; + var typeAddress = typeElement.Attribute("address")?.Value ?? typeElement.Value; + var dataType = typeElement.Attribute("DataType")?.Value ?? groupConfig.DefaultDataType; + + // 创建TypeConfig对象 + var typeConfig = new TypeConfig + { + Name = typeName, + Address = typeAddress, + DataType = dataType + }; + + groupConfig.Types[typeName] = typeConfig; + groupAddresses[typeName] = typeAddress; + + Logger.WriteInfo($"添加类型: {typeName}, 地址: {typeAddress}, 数据类型: {dataType}"); + } + + _collectionGroups[acquisitionType] = groupConfig; + _plcAddresses[acquisitionType] = groupAddresses; + } + break; // 只处理第一个启用的Device + } + } + + Logger.WriteInfo($"读取 【{deviceName}】地址文件成功!!!"); + } + catch (Exception ex) + { + Logger.WriteError($"读取配置文件错误: {ex.Message}"); + } + } + + + + + private static PLCDataType DetermineDataType(string groupName, string dataTypeAttribute) + { + if (!string.IsNullOrEmpty(dataTypeAttribute)) + { + return (PLCDataType)Enum.Parse(typeof(PLCDataType), dataTypeAttribute); + } + if (!string.IsNullOrEmpty(groupName)) + { + AcquisitionType type = (AcquisitionType)Enum.Parse(typeof(AcquisitionType), groupName); + // 如果 DataType 属性为空,根据组名推断类型 + switch (type) + { + case AcquisitionType.PPM: + return PLCDataType.Short; + case AcquisitionType.Axis: + case AcquisitionType.Cylinder: + return PLCDataType.Float; + default: + throw new ArgumentException($"未知的组名: {groupName}"); + } + + } + else + { + throw new ArgumentException($"未知的组名: {groupName}"); + } + } + + + #region 初始化Task线程,PLC,MQTT + private void InitializeTask() + { + if (_collectionGroups != null && _collectionGroups.Count > 0) + { + List typesList = new List(); + foreach (var kvp in _collectionGroups) + { + switch (kvp.Key) + { + case AcquisitionType.Axis: + case AcquisitionType.Cylinder: + StartPeriodicTask(); // 启动定时读取任务 + break; + case AcquisitionType.PPM: + typesList.Add(kvp.Key); + break; + default: + break; + } + } + + // 将 List 转换为数组 + AcqTypes = typesList.ToArray(); + + // 如果需要,你可以在这里使用 types 数组 + if (AcqTypes.Length > 0) + { + Logger.WriteInfo("添加类型: " + string.Join(", ", AcqTypes)); + // 这里可以添加其他使用 types 数组的逻辑 + } + } + } + + + + + private async void InitializePLC() + { + try + { + bool connected = await _plcWrapper.ConnectAsync(); + if (connected) + { + Logger.WriteInfo("PLC初始化并连接成功."); + } + else + { + Logger.WriteInfo("无法连接 PLC."); + throw new Exception("PLC 连接失败"); + } + } + catch (Exception ex) + { + Logger.WriteError($"初始化 PLC 错误: {ex.Message}"); + } + } + + private async void InitializeMQTT() + { + try + { + mqttClient = new MqttClientWrapper(MQTTServerAddress, MQTTServerPort, ClientId, credentials); //初始化 + await mqttClient.InitializeAndConnectAsync();//连接MQTT + SubscribeTopic(Topic);//订阅主题 + SubscribeTopic(Topic1);//订阅主题1 + SubscribeTopic(LRobotTopic);//订阅直角坐标机械臂 + SubscribeTopic(JRobotTopic);//订阅关机机械臂 + } + catch (Exception ex) + { + Logger.WriteError($"连接 MQTT 代理时出错: {ex.Message}"); + } + } + + /// + /// 订阅主题 + /// + /// + private void SubscribeTopic(string topicToSubscribe) + { + mqttClient.OnMessageReceived += (timestamp, topic, message) => + { + //Console.WriteLine($"{timestamp} Topic[{topic}]: {message}"); + //Logger.WriteMqtt($"{timestamp} Topic[{topic}]"); + // 在这里更新你的 UI + }; + mqttClient.SubscribeMessage(topicToSubscribe, MqttClientWrapper.MessageFormat.Json, true); + } + + + /// + /// 类发布消息 + /// + /// + /// + /// + private async Task SendMqttAsync(string source, string publishTopic, string type, JObject messageObj) + { + try + { + if (publishTopic != null) + { + + await mqttClient.SendMessageAsync(source, publishTopic, type, messageObj); + } + } + catch (Exception ex) + { + + Console.WriteLine($"发布信息: {ex.Message}"); + } + + } + + + /// + /// 字符串发布消息 + /// + /// + /// + /// + /// + /// + private async Task SendMqttAsync(string source, string publishTopic, string type, string messageObj) + { + try + { + if (publishTopic != null) + { + + + await mqttClient.SendMessageAsync(source, publishTopic, type, messageObj); + } + } + catch (Exception ex) + { + + Console.WriteLine($"发布信息: {ex.Message}"); + } + + } + #endregion + + + #region 创建定时线程 + /// + /// 轴扭矩定时器采集线程 + /// + private void StartPeriodicTask() + { + Logger.WriteInfo("启动定期数据收集任务"); + _periodicTimer = new System.Threading.Timer(async _ => + { + try + { + Logger.WriteInfo($"定期触发任务: {DateTime.Now}"); + await CollectAndPublishData("AxisTask", new[] { AcquisitionType.Axis }); + await CollectAndPublishData("AxisTask", new[] { AcquisitionType.Cylinder }); + await CollectAndPublishData("LRobotTask", new[] { AcquisitionType.LRobot }); + Logger.WriteInfo($"定期任务完成: {DateTime.Now}"); + } + catch (Exception ex) + { + Logger.WriteError($"周期性任务执行错误: {ex.Message}"); + } + }, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); // 每秒执行一次 + } + + /// + /// 有变化数据采集线程 + /// + /// + /// + /// + + private async Task RunChangeDetectionTaskAsync(CancellationToken ct) + { + while (!ct.IsCancellationRequested) + { + if (_plcWrapper._plcIsConnected) + { + try + { + await CollectAndPublishData("ChangeTask", AcqTypes); + await Task.Delay(500, ct); + } + catch (OperationCanceledException) + { + // 正常取消,无需额外处理 + } + catch (Exception ex) + { + Logger.WriteError($"变更检测任务错误: {ex.Message}"); + await Task.Delay(1000, ct); + } + } + } + } + #endregion + + /// + /// 读取数据 + /// + /// + /// + /// + private async Task CollectAndPublishData(string source, AcquisitionType[] types) + { + const int maxRetries = 3; + for (int retry = 0; retry < maxRetries; retry++) + { + try + { + var requests = new List(); + foreach (var type in types) + { + var config = _collectionGroups[type]; + requests.Add(new PLCDataReadRequest + { + StartAddress = config.StartAddress, + Length = (ushort)config.Length, + StorageName = config.Name + }); + } + + foreach (var request in requests) + { + var result = await _plcWrapper._dataReader.ReadDataAsync(request); + if (result.IsSuccess) + { + await ProcessPLCData(source, request.StorageName, result.Data); + } + else + { + Logger.WriteInfo($"错误读取 {result.StorageName}: {result.ErrorMessage}"); + throw new Exception($"读取 PLC 数据失败: {result.ErrorMessage}"); + } + } + break; // 如果成功,退出重试循环 + } + catch (Exception ex) + { + Logger.WriteError($"Error {source}: {ex.Message}"); + if (retry < maxRetries - 1) + { + Logger.WriteInfo($"尝试重新连接到 PLC,尝试 {retry + 1}"); + bool reconnected = await AttemptReconnection(_cts.Token); + if (!reconnected) + { + Logger.WriteError("无法重新连接 PLC,放弃进一步尝试"); + break; + } + } + else + { + Logger.WriteError($"最大重试次数 ({maxRetries}) 已到达,放弃操作"); + } + } + } + } + + /// + /// 重连PLC + /// + /// + /// + private async Task AttemptReconnection(CancellationToken ct) + { + const int MaxReconnectAttempts = 3; + const int ReconnectionInterval = 5000; // 5 seconds + + for (int attempt = 1; attempt <= MaxReconnectAttempts; attempt++) + { + if (ct.IsCancellationRequested) + { + return false; + } + + Logger.WriteInfo($"尝试重新连接PLC,第 {attempt} 次尝试"); + bool reconnected = await _plcWrapper.ReconnectAsync(); + if (reconnected) + { + Logger.WriteInfo("PLC重新连接成功"); + return true; + } + + if (attempt < MaxReconnectAttempts) + { + await Task.Delay(ReconnectionInterval, ct); + } + } + Logger.WriteError($"PLC重新连接失败,已尝试 {MaxReconnectAttempts} 次"); + return false; + } + + + /// + /// 读取PLC数据 + /// + /// + /// + /// + /// + private async Task ProcessPLCData(string source, string acquisitionTypeName, byte[] data) + { + try + { + AcquisitionType type = (AcquisitionType)Enum.Parse(typeof(AcquisitionType), acquisitionTypeName); + var typeConfigs = GetTypeConfigs(type).ToList(); + bool hasChanges = false; + List processedValues = null; + + switch (type) + { + case AcquisitionType.PPM: + var ppmResult = ProcessShortData(type, data, typeConfigs); + hasChanges = ppmResult.hasChanges; + processedValues = ppmResult.values; + break; + + case AcquisitionType.Axis: + case AcquisitionType.Cylinder: + case AcquisitionType.LRobot: + var floatResult = ProcessFloatData(type, data, typeConfigs); + hasChanges = floatResult.hasChanges; + processedValues = floatResult.values; + break; + + default: + Logger.WriteError($"未知的采集类型: {type}"); + return; + } + + if (hasChanges && processedValues != null) + { + + // 上传到MQTT服务器 + await UpMQTTServerDataNew(source, type, processedValues); + } + else + { + Logger.WriteInfo($"{type} 数据未改变,未上传"); + } + } + catch (Exception ex) + { + Logger.WriteError($"处理 PLC 数据时出错(源: {source}, 类型: {acquisitionTypeName}): {ex.Message}"); + } + } + + // 相应地,ProcessFloatData方法也需要修改返回类型 + + private List _lastFloatStationData = new List(); + private (bool hasChanges, List values) ProcessFloatData(AcquisitionType type, byte[] rawData, List typeConfigs) + { + bool hasChanges = false; + var currentValues = new DataValue[typeConfigs.Count]; + + // 记录实际需要处理的数据点数量 + Logger.WriteInfo($"开始处理数据: typeConfigs.Count={typeConfigs.Count}, rawData.Length={rawData.Length}"); + var sw = new Stopwatch(); + sw.Restart(); + // 初始化数组为完整的大小 + currentValues = new DataValue[typeConfigs.Count]; + var stationDataList = new List(); + + try + { + // 第一步:处理所有Float类型数据(主数据) + var floatConfigs = typeConfigs.Where(t => t.DataType.Equals("Float", StringComparison.OrdinalIgnoreCase)).ToList(); + foreach (var config in floatConfigs) + { + // 从地址中提取偏移量 + if (int.TryParse(config.Address.Substring(1), out int address)) + { + int startAddress = int.Parse(typeConfigs[0].Address.Substring(1)); + int offset = (address - startAddress) * 2; + + if (offset >= 0 && offset + 4 <= rawData.Length) + { + byte[] valueBytes = new byte[4]; + for (int j = 0; j < 4; j++) + { + valueBytes[j] = (byte)(Convert.ToInt32(rawData[offset + j]) & 0xFF); + } + + object convertedValue = ConvertFromBytes(valueBytes, "Float"); + int index = typeConfigs.IndexOf(config); + currentValues[index] = new DataValue + { + Name = config.Name, + Value = convertedValue, + DataType = config.DataType + }; + } + } + } + + // 第二步:处理所有Short类型数据 + var shortConfigs = typeConfigs.Where(t => t.DataType.Equals("Short", StringComparison.OrdinalIgnoreCase)).ToList(); + foreach (var config in shortConfigs) + { + if (int.TryParse(config.Address.Substring(1), out int address)) + { + int startAddress = int.Parse(typeConfigs[0].Address.Substring(1)); + int offset = (address - startAddress) * 2; + + if (offset >= 0 && offset + 2 <= rawData.Length) + { + byte[] valueBytes = new byte[2]; + for (int j = 0; j < 2; j++) + { + valueBytes[j] = (byte)(Convert.ToInt32(rawData[offset + j]) & 0xFF); + } + + object convertedValue = ConvertFromBytes(valueBytes, "Short"); + int index = typeConfigs.IndexOf(config); + currentValues[index] = new DataValue + { + Name = config.Name, + Value = convertedValue, + DataType = config.DataType + }; + } + } + } + + // 第三步:组织StationData列表 + + foreach (var floatConfig in floatConfigs) + { + string baseName = floatConfig.Name; // 例如 "S_MagLev" + var mainValue = currentValues[typeConfigs.IndexOf(floatConfig)]?.Value; + // 先获取MainValue,如果为0则跳过这个工位,暂时不过滤 + //if (mainValue == null || Convert.ToDouble(mainValue) == 0) + //{ + // Logger.WriteInfo($"跳过工位 {baseName}: MainValue为0或null"); + // continue; + //} + + // 只检查MainValue是否与上一次的值相同,暂时不检查 + //var lastData = _lastStationData.FirstOrDefault(x => x.Name == baseName); + //if (lastData != null) + //{ + // bool valueEqual = Convert.ToDouble(lastData.MainValue) == Convert.ToDouble(mainValue); + + // if (valueEqual) + // { + // Logger.WriteInfo($"跳过工位 {baseName}: 值未变化 当前值:{mainValue}"); + // continue; + // } + + // Logger.WriteInfo($"工位 {baseName} 数值发生变化: {lastData.MainValue} -> {mainValue}"); + //} + + // 创建StationData对象 + var stationData = new StationData + { + Name = baseName, + MainValue = mainValue, + Timestamp = DateTime.Now, + }; + + stationDataList.Add(stationData); + Logger.WriteInfo($"添加工位数据: {stationData.Name}, 值: {stationData.MainValue}, 时间戳: {stationData.Timestamp:HH:mm:ss.fff}"); + } + + // 检查是否有新数据需要更新 + if (stationDataList.Any()) + { + hasChanges = true; // 如果有数据通过过滤,就表示有变化 + + // 创建深拷贝以避免引用问题 + _lastFloatStationData = stationDataList.Select(s => new StationData + { + Name = s.Name, + MainValue = s.MainValue, + Timestamp = s.Timestamp + }).ToList(); + + _lastFloatStationData = stationDataList;//把当前的新数据赋值到旧的集合中 + + + //// 记录变化信息 + //foreach (var newData in stationDataList) + //{ + // Logger.WriteInfo($"工位 {newData.Name} 更新: 时间戳: {newData.Timestamp:HH:mm:ss.fff}, 值: {newData.MainValue}"); + //} + } + else + { + Logger.WriteInfo("没有发现时间戳变化的数据"); + hasChanges = false; + } + + + sw.Stop(); + Logger.WriteInfo($"处理结束耗时:{sw.ElapsedMilliseconds}ms"); + return (hasChanges, stationDataList); + } + catch (Exception ex) + { + Logger.WriteError($"处理数据时出错: {ex.Message}"); + return (false, stationDataList); + } + + } + + + + + /// + /// 检测PPM数据是否有变化 + /// + /// + /// + private List _lastStationData = new List(); + + private readonly StationDataComparer2 _comparer = new StationDataComparer2(); + + private (bool hasChanges, List values) ProcessShortData(AcquisitionType type, byte[] rawData, List typeConfigs) + { + var sw = new Stopwatch(); + sw.Start(); + Logger.WriteInfo($"开始新一轮数据处理"); + + try + { + var currentStationData = new Dictionary(); + bool hasNewData = false; + + // 1. 获取所有主值配置(Float类型) + var mainValueConfigs = typeConfigs + .Where(t => string.Equals(t.DataType, "Float", StringComparison.OrdinalIgnoreCase)) + .OrderBy(t => int.Parse(t.Address.Substring(1))) + .ToList(); + + Logger.WriteInfo($"找到 {mainValueConfigs.Count} 个Float类型配置"); + foreach (var config in mainValueConfigs) + { + Logger.WriteInfo($"Float配置: {config.Name}, 地址: {config.Address}"); + } + + // 2. 获取所有时间配置(Short类型) + var timeConfigs = typeConfigs + .Where(t => string.Equals(t.DataType, "Short", StringComparison.OrdinalIgnoreCase)) + .ToList(); + + // 3. 首先读取所有工位的当前值和时间戳 + foreach (var mainConfig in mainValueConfigs) + { + string stationName = mainConfig.Name; + + // 读取主值 + double? mainValue = ReadFloatValue(mainConfig, rawData, typeConfigs[0].Address); + if (mainValue == null || mainValue <= 0) + { + Logger.WriteInfo($"工位 {stationName} 主值无效: {mainValue}"); + continue; + } + + // 读取时间组件 + DateTime timestamp = ReadTimestamp(stationName, timeConfigs, rawData, typeConfigs[0].Address); + + // 添加到当前数据集合 + currentStationData[stationName] = new StationData + { + Name = stationName, + MainValue = mainValue, + Timestamp = timestamp + }; + + Logger.WriteInfo($"读取工位数据: {stationName}, 值: {mainValue}, 时间: {timestamp:HH:mm:ss.fff}"); + } + + // 4. 比较新旧数据,确定是否有变化 + if (currentStationData.Any()) + { + if (_lastStationData == null || !_lastStationData.Any()) + { + hasNewData = true; + Logger.WriteInfo("首次数据采集,记录所有数据"); + } + else + { + // 检查每个工位的数据是否有变化 + foreach (var current in currentStationData.Values) + { + var lastData = _lastStationData.FirstOrDefault(x => x.Name == current.Name); + if (lastData == null) + { + hasNewData = true; + Logger.WriteInfo($"发现新工位数据: {current.Name}"); + break; + } + + // 检查值和时间戳是否都有变化 + bool valueChanged = Math.Abs(Convert.ToDouble(lastData.MainValue) - Convert.ToDouble(current.MainValue)) > 0.001; + bool timeChanged = Math.Abs((current.Timestamp - lastData.Timestamp).TotalMilliseconds) >= 500; + + if (valueChanged || timeChanged) + { + hasNewData = true; + Logger.WriteInfo($"工位 {current.Name} 数据发生变化 - 值变化: {valueChanged}, 时间变化: {timeChanged}"); + break; + } + } + } + } + + // 5. 如果有新数据,更新最后处理的数据 + var resultList = currentStationData.Values.ToList(); + if (hasNewData) + { + _lastStationData = new List(resultList); + Logger.WriteInfo($"更新状态数据,数量: {resultList.Count}"); + } + + sw.Stop(); + Logger.WriteInfo($"处理完成,耗时: {sw.ElapsedMilliseconds}ms, 数据点数量: {resultList.Count}, 有变化: {hasNewData}"); + + return (hasNewData, resultList); + } + catch (Exception ex) + { + Logger.WriteError($"数据处理错误: {ex.Message}\n{ex.StackTrace}"); + return (false, new List()); + } + } + + private double? ReadFloatValue(TypeConfig config, byte[] rawData, string baseAddress) + { + try + { + if (!int.TryParse(config.Address.Substring(1), out int address) || + !int.TryParse(baseAddress.Substring(1), out int startAddress)) + { + return null; + } + + int offset = (address - startAddress) * 2; + if (offset < 0 || offset + 4 > rawData.Length) + { + return null; + } + + byte[] valueBytes = new byte[4]; + Array.Copy(rawData, offset, valueBytes, 0, 4); + var value = ConvertFromBytes(valueBytes, "Float"); + return value != null ? Convert.ToDouble(value) : null; + } + catch + { + return null; + } + } + + private DateTime ReadTimestamp(string stationName, List timeConfigs, byte[] rawData, string baseAddress) + { + // 获取时间组件配置 + var hourConfig = timeConfigs.FirstOrDefault(t => t.Name == $"{stationName}_Hour"); + var minConfig = timeConfigs.FirstOrDefault(t => t.Name == $"{stationName}_Min"); + var secConfig = timeConfigs.FirstOrDefault(t => t.Name == $"{stationName}_Sec"); + var msecConfig = timeConfigs.FirstOrDefault(t => t.Name == $"{stationName}_MSec"); + + // 读取时间值 + int hour = ReadShortValue(hourConfig, rawData, baseAddress); + int minute = ReadShortValue(minConfig, rawData, baseAddress); + int second = ReadShortValue(secConfig, rawData, baseAddress); + int millisecond = ReadShortValue(msecConfig, rawData, baseAddress); + + // 验证时间值 + hour = Math.Min(Math.Max(hour, 0), 23); + minute = Math.Min(Math.Max(minute, 0), 59); + second = Math.Min(Math.Max(second, 0), 59); + millisecond = Math.Min(Math.Max(millisecond, 0), 999); + + // 获取当前时间 + var now = DateTime.Now; + + // 构建读取的时间 + var readTime = new DateTime( + now.Year, + now.Month, + now.Day, + hour, + minute, + second, + millisecond + ); + + // 如果读取的时间比当前时间大,说明应该是前一天的数据 + if (readTime > now) + { + readTime = readTime.AddDays(-1); + Logger.WriteInfo($"检测到跨天数据,调整日期为前一天: {readTime:yyyy-MM-dd HH:mm:ss.fff}"); + } + + return readTime; + } + + private int ReadShortValue(TypeConfig config, byte[] rawData, string baseAddress) + { + try + { + if (config == null || !int.TryParse(config.Address.Substring(1), out int address) || + !int.TryParse(baseAddress.Substring(1), out int startAddress)) + { + return 0; + } + + int offset = (address - startAddress) * 2; + if (offset < 0 || offset + 2 > rawData.Length) + { + return 0; + } + + byte[] valueBytes = new byte[2]; + Array.Copy(rawData, offset, valueBytes, 0, 2); + var value = ConvertFromBytes(valueBytes, "Short"); + return Convert.ToInt32(value); + } + catch + { + return 0; + } + } + + + + private object ConvertFromBytes(byte[] bytes, string dataType) + { + try + { + if (bytes == null || bytes.Length == 0) + return null; + + switch (dataType.ToLower()) + { + case "bool": + return BitConverter.ToInt16(bytes, 0) != 0; + case "short": + return ShortLib.GetShortFromByteArray(bytes, 0, DataFormat.CDAB); + case "int": + return IntLib.GetIntFromByteArray(bytes, 0, DataFormat.CDAB); + case "float": + return FloatLib.GetFloatFromByteArray(bytes, 0, DataFormat.CDAB); + default: + return ShortLib.GetShortFromByteArray(bytes, 0, DataFormat.CDAB); + } + } + catch (Exception ex) + { + Logger.WriteError($"转换数据类型失败: {BitConverter.ToString(bytes)} to {dataType}, {ex.Message}"); + return null; + } + } + + + + /// + /// 上传MQTT + /// + /// + /// + /// + /// + public async Task UpMQTTServerDataNew(string source, AcquisitionType type, List processedValues) + { + try + { + if (processedValues == null || processedValues.Count == 0) + { + return; + } + + //var addresses = _plcAddresses[type]; + //var config = _collectionGroups[type]; + + var message = MqttDataService.CreateMqttMessage(source, type, processedValues, _plcAddresses, _collectionGroups); + + if (message != null) + { + var messageJson = JsonConvert.SerializeObject(message, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + if (type.ToString() == "PPM") + { + await SendMqttAsync(source, Topic, type.ToString(), messageJson); + } + else if (type.ToString() == "Axis" || type.ToString() == "Cylinder") + { + await SendMqttAsync(source, Topic1, type.ToString(), messageJson); + } + } + if (type.ToString() == "LRobot") + { + var message1 = MqttDataService.LRobotMessage(source, type, processedValues, _plcAddresses, _collectionGroups); + if (message1 != null) + { + var messageJson1 = JsonConvert.SerializeObject(message1, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + if (type.ToString() == "LRobot") + { + await SendMqttAsync(source, LRobotTopic, type.ToString(), messageJson1); + } + } + } + + } + catch (Exception ex) + { + Logger.WriteError($"方法:上传MQTTServer数据,上传失败: {ex.Message}", ex); + } + } + + + + + private List ConvertToShortList(object[] data) + { + return data.Select(d => Convert.ToInt16(d)).ToList(); + } + + private List ConvertToFloatList(object[] data) + { + return data.Select(d => Convert.ToSingle(d)).ToList(); + } + + // 获取特定类型的数据类型 + public string GetDataType(AcquisitionType acquisitionType, string typeName) + { + if (_collectionGroups.TryGetValue(acquisitionType, out var groupConfig)) + { + if (groupConfig.Types.TryGetValue(typeName, out var typeConfig)) + { + return typeConfig.DataType; + } + } + return "Short"; // 默认返回Short类型 + } + + // 获取数据类型的字节大小 + public int GetTypeSize(string dataType) + { + switch (dataType.ToLower()) + { + case "bool": + return 2; // 在PLC中通常用2字节表示 + case "short": + return 2; // 2字节 + case "int": + return 4; // 4字节 + case "float": + return 4; // 4字节 + default: + return 2; // 默认2字节 + } + } + + // 获取组内所有类型配置 + public IEnumerable GetTypeConfigs(AcquisitionType acquisitionType) + { + if (_collectionGroups.TryGetValue(acquisitionType, out var groupConfig)) + { + return groupConfig.Types.Values; + } + return Enumerable.Empty(); + } + + + } + + + /// + /// 时间转化 + /// + + public static class DateTimeExtensions + { + public static long ToUnixTimeMilliseconds(this DateTime dateTime) + { + return (long)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; + } + + public static long GetUnixTimestamp() + { + return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000; + } + } + + // 辅助类 + public class DataValue + { + public string Name { get; set; } + public object Value { get; set; } + public string DataType { get; set; } + + public override bool Equals(object obj) + { + if (obj is DataValue other) + { + if (Value == null && other.Value == null) return true; + if (Value == null || other.Value == null) return false; + + switch (DataType.ToLower()) + { + case "float": + if (Value is float f1 && other.Value is float f2) + return Math.Abs(f1 - f2) < 0.000001f; + break; + case "bool": + if (Value is bool b1 && other.Value is bool b2) + return b1 == b2; + break; + } + + return Value.Equals(other.Value); + } + return false; + } + + public override int GetHashCode() + { + return Value?.GetHashCode() ?? 0; + } + } +} diff --git a/IOT.Services/StationDataComparer.cs b/IOT.Services/StationDataComparer.cs new file mode 100644 index 0000000..0963233 --- /dev/null +++ b/IOT.Services/StationDataComparer.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; + +namespace WindowsService1 +{ + /// + /// 判断工位耗时变化 + /// + public class StationDataComparer : IEqualityComparer + { + private const float FloatEpsilon = 0.000001f; // 可以调整精度 + + public bool Equals(StationData x, StationData y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + + // 比较名称 + if (x.Name != y.Name) return false; + + // 比较主值 + if (x.MainValue is float xFloat && y.MainValue is float yFloat) + { + if (Math.Abs(xFloat - yFloat) > FloatEpsilon) return false; + } + else if (x.MainValue is double xDouble && y.MainValue is double yDouble) + { + if (Math.Abs(xDouble - yDouble) > FloatEpsilon) return false; + } + else if (!Equals(x.MainValue, y.MainValue)) + { + return false; + } + + // 比较时间戳(可以选择是否忽略毫秒) + return Math.Abs((x.Timestamp - y.Timestamp).TotalMilliseconds) < 1; + } + + public int GetHashCode(StationData obj) + { + if (obj is null) return 0; + + unchecked + { + int hash = 17; + hash = hash * 23 + (obj.Name?.GetHashCode() ?? 0); + + // 对于浮点数,可以先转换为整数再计算哈希 + if (obj.MainValue is float f) + { + hash = hash * 23 + ((int)(f * 1000000)).GetHashCode(); + } + else + { + hash = hash * 23 + (obj.MainValue?.GetHashCode() ?? 0); + } + + hash = hash * 23 + obj.Timestamp.GetHashCode(); + return hash; + } + } + } + + /// + /// 判断时间戳变化 + /// + public class StationDataComparer2 : IEqualityComparer + { + public bool Equals(StationData x, StationData y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + + // 只比较名称和时间戳 + if (x.Name != y.Name) return false; + + // 比较时间戳,检查是否完全相同 + return x.Timestamp == y.Timestamp; + } + + public int GetHashCode(StationData obj) + { + if (obj is null) return 0; + + unchecked + { + int hash = 17; + hash = hash * 23 + (obj.Name?.GetHashCode() ?? 0); + hash = hash * 23 + obj.Timestamp.GetHashCode(); + return hash; + } + } + } +} diff --git a/IOT.Services/XmlConfigReader.cs b/IOT.Services/XmlConfigReader.cs new file mode 100644 index 0000000..4a95ee2 --- /dev/null +++ b/IOT.Services/XmlConfigReader.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; + +namespace WindowsService1 +{ + public class XmlConfigReader + { + private Dictionary>> deviceData; + + public XmlConfigReader(string xmlContent) + { + XDocument doc = XDocument.Parse(xmlContent); + deviceData = ReadXmlToNestedDictionary(doc); + } + + public XmlConfigReader(XDocument doc) + { + deviceData = ReadXmlToNestedDictionary(doc); + } + + private Dictionary>> ReadXmlToNestedDictionary(XDocument doc) + { + var result = new Dictionary>>(); + var mainDevice = doc.Root.Element("Device"); + string mainDeviceName = mainDevice.Attribute("name").Value; + result[mainDeviceName] = new Dictionary>(); + + foreach (var subDevice in mainDevice.Elements("Device")) + { + string subDeviceName = subDevice.Attribute("name").Value; + result[mainDeviceName][subDeviceName] = new Dictionary(); + + foreach (var type in subDevice.Elements("Type")) + { + string typeName = type.Attribute("name").Value; + string typeValue = type.Value; + result[mainDeviceName][subDeviceName][typeName] = typeValue; + } + } + + return result; + } + + public void PrintStructure() + { + foreach (var mainDevice in deviceData) + { + Console.WriteLine($"Main Device: {mainDevice.Key}"); + foreach (var subDevice in mainDevice.Value) + { + Console.WriteLine($" Sub Device: {subDevice.Key}"); + foreach (var type in subDevice.Value) + { + Console.WriteLine($" Type: {type.Key}, Value: {type.Value}"); + } + } + } + } + + public bool TryGetValue(string mainDeviceName, string subDeviceName, string typeName, out string value) + { + value = null; + return deviceData.TryGetValue(mainDeviceName, out var mainDevice) && + mainDevice.TryGetValue(subDeviceName, out var subDevice) && + subDevice.TryGetValue(typeName, out value); + } + + public Dictionary>> GetAllData() + { + return deviceData; + } + } +} diff --git a/IOT.Services/log4net.config b/IOT.Services/log4net.config new file mode 100644 index 0000000..b177cf0 --- /dev/null +++ b/IOT.Services/log4net.config @@ -0,0 +1,62 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IOT.Services/packages.config b/IOT.Services/packages.config new file mode 100644 index 0000000..92e2b4b --- /dev/null +++ b/IOT.Services/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/JinYuan.ControlCenter/ControlCenter.cs b/JinYuan.ControlCenter/ControlCenter.cs new file mode 100644 index 0000000..f6bdf5b --- /dev/null +++ b/JinYuan.ControlCenter/ControlCenter.cs @@ -0,0 +1,2838 @@ +using JinYuan.Helper; +using JinYuan.MES.Models; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using Language; +using MiniExcelLibs; +using PLC; +using PLC.PLCAlarm; +using PLCCommunication; +using PLCCommunication.Common; +using PLCCommunication.Common.DataConvert; +using SqlSugar; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using static System.Runtime.CompilerServices.RuntimeHelpers; +using AlarmData = JinYuan.Models.AlarmData; +using DataType = PLC.DataType; + +namespace JinYuan.ControlCenters +{ + public partial class ControlCenter : IDisposable + { + #region 单例 + private static readonly object uiLock = new object(); + private static ControlCenter _instance; + public static ControlCenter Instance + { + get + { + lock (uiLock) + { + if (_instance == null) + _instance = new ControlCenter(); + return _instance; + } + } + } + #endregion + + #region 变量 + private Dictionary, PlcGroup, Task>> _stationFunctions; + private Dictionary _groupThreads; + private readonly Dictionary> _plcDeviceMapping = new Dictionary>(); + private readonly Dictionary _plcAlarmReaders = new Dictionary(); + + private CancellationTokenSource _cts; + private Task _heartbeatTask; + private const int HeartbeatInterval = 1000; + + private readonly object _statusLock = new object(); + private Dictionary _groupStatus = new Dictionary(); + + /// + /// 定时器-定时刷新状态和数据 + /// + private System.Timers.Timer _timerRefreshData; + + #region 独立任务队列 + private readonly ConcurrentQueue _taskQueue = new ConcurrentQueue(); + private Thread _workerThread; + private readonly ManualResetEvent _taskEvent = new ManualResetEvent(false); + private bool _isWorkerRunning = true; + + // 队列监控 + private int _maxQueueSize = 1000; + private DateTime _lastQueueWarningTime = DateTime.MinValue; + private int _totalProcessedCount = 0; + private int _totalRejectedCount = 0; + + // 线程健康监控 + private DateTime _lastHeartbeat = DateTime.Now; + private int _stuckDetectCount = 0; + #endregion + + #region 资源管理 + //private readonly SemaphoreSlim _dbSemaphore = new SemaphoreSlim(10); // 限制数据库并发 + private readonly SemaphoreSlim _plcWriteSemaphore = new SemaphoreSlim(5); // 限制PLC写入并发 + private bool _isDisposed = false; + private System.Timers.Timer _healthMonitorTimer; + #endregion + + #endregion + + #region 2、初始化函数 + private ControlCenter() + { + _groupThreads = new Dictionary(); + _cts = new CancellationTokenSource(); + + if (CommonMethods.plcDevices == null) + { + CommonMethods.plcDevices = new List(); + } + + // 启动独立任务处理线程 + StartWorkerThread(); + InitializeDevicesFromExcel(); + GetAlarmData(); + InitFunc(); + + _timerRefreshData = new System.Timers.Timer(1000); + _timerRefreshData.Elapsed += Timer_RefreshData_Elapsed; + _timerRefreshData.Start(); + + Thread thread = new Thread(ShowStateEven_Run); + thread.IsBackground = true; + thread.Start(); + + string[] clrPath = new[] { CommonMethods.strAlarmLogspath, CommonMethods.strMesLogspath, CommonMethods.strWattrMeterpath, @"D:\APILog\Logs\" }; + short[] seltWay = new[] { (short)0, (short)0, (short)0, (short)1 }; + DeleteLog.Start(clrPath, seltWay); + + if (!CommonMethods.IsRun) + { + CommonMethods.ResetEventRecv.Reset(); + } + + // 启动健康监控 + StartHealthMonitor(); + } + + /// + /// 开始健康监控 + /// + private void StartHealthMonitor() + { + _healthMonitorTimer = new System.Timers.Timer(30000); // 每30秒检查一次 + _healthMonitorTimer.Elapsed += HealthMonitorCallback; + _healthMonitorTimer.AutoReset = true; + _healthMonitorTimer.Start(); + } + + private void HealthMonitorCallback(object sender, System.Timers.ElapsedEventArgs e) + { + try + { + var now = DateTime.Now; + var timeSinceLastHeartbeat = now - _lastHeartbeat; + + // 检查工作线程是否卡死 + if (timeSinceLastHeartbeat.TotalSeconds > 60) + { + _stuckDetectCount++; + LogHelper.Instance.WriteError($"健康监控:工作线程可能卡死,最后心跳:{_lastHeartbeat}, 卡死计数:{_stuckDetectCount}"); + + if (_stuckDetectCount >= 3) + { + LogHelper.Instance.WriteError($"健康监控:工作线程已卡死,尝试恢复..."); + RecoverWorkerThread(); + _stuckDetectCount = 0; + } + } + else + { + _stuckDetectCount = 0; + } + + // 记录系统状态 + int queueSize = _taskQueue.Count; + if (queueSize > _maxQueueSize * 0.8) + { + LogHelper.Instance.WriteError($"健康监控:任务队列接近溢出,当前大小:{queueSize}/{_maxQueueSize}, 已处理:{_totalProcessedCount}, 已拒绝:{_totalRejectedCount}"); + } + + // 记录线程状态 + int activeThreads = Process.GetCurrentProcess().Threads.Count; + LogHelper.Instance.WriteLog($"健康监控 - 队列:{queueSize}, 线程数:{activeThreads}, 内存:{GC.GetTotalMemory(false) / 1024 / 1024}MB"); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"健康监控异常:{ex.Message}"); + } + } + + /// + /// 恢复工作线程 + /// + private void RecoverWorkerThread() + { + try + { + _isWorkerRunning = false; + _taskEvent.Set(); + + if (_workerThread != null && _workerThread.IsAlive) + { + _workerThread.Join(5000); + } + + // 清空队列 + while (_taskQueue.TryDequeue(out _)) { } + + // 重新启动 + _isWorkerRunning = true; + StartWorkerThread(); + + LogHelper.Instance.WriteLog("健康监控:工作线程已恢复"); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"恢复工作线程失败:{ex.Message}"); + } + } + + /// + /// 独立工作线程 + /// + private void StartWorkerThread() + { + _workerThread = new Thread(delegate () + { + var lastProgressLog = DateTime.Now; + + while (_isWorkerRunning && !(_cts?.IsCancellationRequested ?? true)) + { + try + { + // 更新心跳 + _lastHeartbeat = DateTime.Now; + + // 等待事件,添加超时防止永久阻塞 + bool hasEvent = _taskEvent.WaitOne(1000); + + if (!hasEvent) + { + // 超时继续循环,保持心跳 + continue; + } + + // 批量处理任务,提高效率 + int batchSize = Math.Min(10, _taskQueue.Count); + for (int i = 0; i < batchSize; i++) + { + if (_taskQueue.TryDequeue(out Action task)) + { + try + { + // 添加超时控制 + var taskWithTimeout = Task.Run(() => task()); + if (!taskWithTimeout.Wait(30000)) // 30秒超时 + { + LogHelper.Instance.WriteError($"任务执行超时(30秒),已跳过"); + } + _totalProcessedCount++; + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"业务执行异常:{ex.Message}"); + } + } + } + + // 定期记录处理统计 + if ((DateTime.Now - lastProgressLog).TotalMinutes >= 5) + { + LogHelper.Instance.WriteLog($"任务处理统计 - 已处理:{_totalProcessedCount}, 已拒绝:{_totalRejectedCount}, 当前队列:{_taskQueue.Count}"); + lastProgressLog = DateTime.Now; + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"工作线程异常:{ex.Message}"); + Thread.Sleep(1000); + } + } + }); + + _workerThread.IsBackground = true; + _workerThread.Priority = ThreadPriority.AboveNormal; + _workerThread.Name = "ControlCenterWorker"; + _workerThread.Start(); + } + + /// + /// 安全添加任务到队列 + /// + private bool EnqueueTask(Action task, string taskName = "") + { + try + { + // 检查队列是否已满 + if (_taskQueue.Count >= _maxQueueSize) + { + _totalRejectedCount++; + + // 限制日志频率,避免日志风暴 + if ((DateTime.Now - _lastQueueWarningTime).TotalSeconds > 30) + { + LogHelper.Instance.WriteError($"任务队列已满({_taskQueue.Count}/{_maxQueueSize}),拒绝任务:{taskName}"); + _lastQueueWarningTime = DateTime.Now; + } + return false; + } + + _taskQueue.Enqueue(task); + _taskEvent.Set(); + return true; + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"入队失败:{ex.Message}"); + return false; + } + } + + /// + /// 初始化工位方法 + /// + private void InitFunc() + { + _stationFunctions = new Dictionary, PlcGroup, Task>>(); + _stationFunctions.Add("物流线料盘来料", TrayFeedingStation); + _stationFunctions.Add("物流线料盘进站", CheckTrayStation); + _stationFunctions.Add("电池进站", FeedingStation); + _stationFunctions.Add("电池与拖盘绑定", PackStation); + _stationFunctions.Add("强制放行", ForceOutStation); + _stationFunctions.Add("料框码解绑", UnBindTrayStation); + } + + /// + /// 启动心跳及工位读取线程 + /// + public async Task StartAsync() + { + // 先清理旧的线程 + StopAndCleanOldThreads(); + + // 创建新线程 + CreatePLCThreads(); + _heartbeatTask = StartHeartbeatCheck(_cts.Token); + await Task.CompletedTask; + } + + /// + /// 停止并清理旧线程 + /// + private void StopAndCleanOldThreads() + { + try + { + foreach (var kvp in _groupThreads) + { + var thread = kvp.Value; + if (thread != null && thread.IsAlive) + { + try + { + thread.Join(1000); + } + catch (ThreadInterruptedException) { } + catch { } + } + } + _groupThreads.Clear(); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"清理旧线程异常:{ex.Message}"); + } + } + + /// + /// 加载配置文件 + /// + private void InitializeDevicesFromExcel() + { + string gongwei = CommonMethods.sysConfig.StationNo; + CommonMethods.AddDataMonitorLog(1, "开始加载配置参数……".Translated()); + string deviceConfigPath = CommonMethods.deviceConfigPath;//Path.Combine(configFolderPath, "Device.xlsx"); + string groupConfigPath = CommonMethods.groupConfigPath;//Path.Combine(configFolderPath, $"Group_{gongwei}.xlsx"); + string variableConfigPath = CommonMethods.variableConfigPath;//Path.Combine(configFolderPath, $"Variable_{gongwei}.xlsx"); + //string plcVariableConfigPath = Path.Combine(configFolderPath, "PLCVariable.xlsx"); + + if (!File.Exists(deviceConfigPath) || !File.Exists(groupConfigPath) || !File.Exists(variableConfigPath)) + { + LogHelper.Instance.WriteError("配置文件不存在"); + return; + } + + try + { + var deviceConfigs = MiniExcel.Query(deviceConfigPath).ToList(); + var groupConfigs = MiniExcel.Query(groupConfigPath).ToList(); + var variableConfigs = MiniExcel.Query(variableConfigPath).ToList(); + + foreach (var deviceConfig in deviceConfigs.Where(d => d.IsActive)) + { + IPEndPoint iep = new IPEndPoint(IPAddress.Parse(deviceConfig.IPAddress), deviceConfig.Port); + PlcReadWriteBase plc = PLCFactory.CreatePLC(GetPLCTypeEnum(deviceConfig.PLCType), deviceConfig.PlcNum, $"PLC_{deviceConfig.PlcNum}", iep); + + string GongWei = CommonMethods.sysConfig.GongWei; + var stationNo = CommonMethods.sysConfig.StationNo; + deviceConfig.Cts = new CancellationTokenSource(); + deviceConfig.GroupList = groupConfigs + .Where(g => g.IsActive && g.PlcNum == deviceConfig.PlcNum && ((g.PlcNum == 1 && g.StationName == stationNo) || (g.PlcNum == 2 && g.StationName == GongWei)) || g.GroupName == "MES心跳") + .ToList(); + + foreach (var group in deviceConfig.GroupList) + { + group.VarList = variableConfigs + .Where(v => v.GroupName == group.GroupName && v.PlcNum == deviceConfig.PlcNum && v.StationName == group.StationName) + .ToList(); + + lock (_statusLock) + { + _groupStatus[group.GroupName] = 0; + } + } + + _plcDeviceMapping[plc] = new List { deviceConfig }; + CommonMethods.plcDevices.Add(plc); + + // 初始化 PLCAlarm Reader报警读取 + var alarmReader = new PLCAlarmReader( + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmConfig.csv"), + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmRecords"), + RecordType.RecordWhenFinish, + false + ); + + //alarmReader.PLCAlarm_New += AlrmReader_PLCAlarm_New; + //alarmReader.PLCAlarm_Remove += AlrmReader_PLCAlarm_Remove; + _plcAlarmReaders[plc] = alarmReader; + + CommonMethods.plcStatuses[plc] = new Dictionary + { + ["OldStatus"] = (short)0, + ["StatusCount"] = 0, + ["GuidAlarm"] = string.Empty, + ["Status"] = new List { false, false, false, false } + }; + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"加载配置失败:{ex.Message}"); + } + CommonMethods.AddDataMonitorLog(1, "配置文件加载完成".Translated()); + } + + #endregion + + #region 3、PLC读写 + + #region 创建PLC线程 几个工位就几个线程 + /// + /// 按工位读取线程 + /// + private void CreatePLCThreads() + { + for (int i = 0; i < CommonMethods.plcDevices.Count; i++) + { + PlcReadWriteBase plc = CommonMethods.plcDevices[i]; + int plcIndex = i; // 捕获索引 + + if (_plcDeviceMapping.TryGetValue(plc, out var devList)) + { + foreach (PlcDevice dev in devList) + { + foreach (PlcGroup group in dev.GroupList) + { + if (group.IsActive) + { + string key = dev.PlcNum + "-" + group.GroupName; + + // 如果已存在同名线程,先停止 + if (_groupThreads.ContainsKey(key)) + { + var oldThread = _groupThreads[key]; + if (oldThread != null && oldThread.IsAlive) + { + try { oldThread.Join(500); } catch { } + } + } + + Thread t = new Thread(ReadPLCWorkModel); + t.IsBackground = true; + t.Priority = ThreadPriority.Highest; + t.Name = $"PLC_{key}"; + _groupThreads[key] = t; + + var param = new Tuple(group, plcIndex); + t.Start(param); + } + } + } + } + } + + LogHelper.Instance.WriteLog($"PLC线程创建完成,共{_groupThreads.Count}个线程"); + } + #endregion + + #region 循环读取PLC工位状态 + /// + /// 读取PLC循环工位 + /// + /// + private void ReadPLCWorkModel(object parameter) + { + Tuple param = parameter as Tuple; + if (param == null) return; + + PlcGroup group = param.Item1; + int plcIndex = param.Item2; + + // 添加重连计数器 + int consecutiveErrorCount = 0; + const int maxConsecutiveErrors = 10; + int lastLogSecond = 0; // 用于限制日志频率 + + while (_cts != null && !_cts.Token.IsCancellationRequested) + { + try + { + // 检查系统运行状态 + if (!CommonMethods.IsRun) + { + Thread.Sleep(100); + consecutiveErrorCount = 0; + continue; + } + + PlcReadWriteBase plc = CommonMethods.plcDevices[plcIndex]; + if (plc == null || !plc.IsConnected) + { + consecutiveErrorCount++; + if (consecutiveErrorCount > maxConsecutiveErrors && lastLogSecond != DateTime.Now.Second) + { + lastLogSecond = DateTime.Now.Second; + LogHelper.Instance.WriteError($"【诊断-PLC状态】{group.GroupName} | PLC未连接 | 连续失败次数={consecutiveErrorCount}"); + } + + Thread.Sleep(100); + continue; + } + + consecutiveErrorCount = 0; + if (!CommonMethods.sysConfig.WuLiu && group.GroupName == "物流线料盘来料") + { + Thread.Sleep(100); + continue; + } + + // 重点监视物流线料盘进站 + bool isCriticalStation = group.GroupName == "物流线料盘进站" || group.GroupName == "物流线料盘来料"; + + // 读取触发信号 + var trigResult = ReadWithTimeout(plc, group, 2000); + if (trigResult == null || !trigResult.IsSuccess) + { + if (isCriticalStation && lastLogSecond != DateTime.Now.Second) + { + lastLogSecond = DateTime.Now.Second; + LogHelper.Instance.WriteError($"【诊断-读取失败】{group.GroupName} | 读取触发信号失败"); + } + + Thread.Sleep(50); + continue; + } + + short trig = trigResult.Content; + int status = 0; + + lock (_statusLock) + { + if (_groupStatus.ContainsKey(group.GroupName)) + status = _groupStatus[group.GroupName]; + } + + // 记录触发信号(仅对关键工站) + if (isCriticalStation && trig != 0) + { + StationDiagnostics.LogTrigger(group.GroupName, trig, status); + } + + if (trig == 1 && status == 0) + { + if (isCriticalStation) + { + LogHelper.Instance.WriteLog($"【诊断-信号触发】{group.GroupName} | 检测到触发信号 | 开始处理..."); + } + + JYResult data = plc.ReadValue>( + group.VarList[1].VarAddress, + DataType.ArrByte, + Convert.ToUInt16(group.VarList[1].OffsetOrLength) + ); + + if (data != null && _stationFunctions.ContainsKey(group.GroupName)) + { + Func, PlcGroup, Task> func = _stationFunctions[group.GroupName]; + + lock (_statusLock) + { + _groupStatus[group.GroupName] = 1; + } + + // 使用安全的入队方法 + string groupName = group.GroupName; + DateTime triggerTime = DateTime.Now; + + bool enqueued = EnqueueTask(() => + { + try + { + StationDiagnostics.LogTaskStart(groupName); + // 记录入队到开始执行的延迟 + var queueDelay = DateTime.Now - triggerTime; + if (queueDelay.TotalMilliseconds > 500) + { + LogHelper.Instance.WriteError($"【诊断-队列延迟】{groupName} | 入队到执行延迟={queueDelay.TotalMilliseconds:F0}ms"); + } + + // 添加超时控制 + var task = func(data, group); + if (!task.Wait(30000)) + { + StationDiagnostics.LogTimeout(groupName, 30); + LogHelper.Instance.WriteError($"【诊断-业务超时】{groupName} | 执行超过30秒"); + + // 超时后强制完成,避免状态卡死 + lock (_statusLock) + { + if (_groupStatus.ContainsKey(groupName) && _groupStatus[groupName] == 1) + { + WriteFinishToPLC(group, plcIndex); + _groupStatus[groupName] = 0; + LogHelper.Instance.WriteError($"【诊断-强制恢复】{groupName} | 超时后强制重置状态"); + } + } + return; + } + + + StationDiagnostics.LogTaskComplete(groupName, true); + LogHelper.Instance.WriteLog($"【业务完成】{groupName} | 总耗时={(DateTime.Now - triggerTime).TotalMilliseconds:F0}ms"); + } + catch (Exception ex) + { + StationDiagnostics.LogTaskComplete(groupName, false, ex.Message); + LogHelper.Instance.WriteError($"【诊断-异常】{groupName} | {ex.Message}"); + + // 异常时也要重置状态 + lock (_statusLock) + { + if (_groupStatus.ContainsKey(groupName) && _groupStatus[groupName] == 1) + { + _groupStatus[groupName] = 0; + } + } + } + }, groupName); + + if (!enqueued) + { + LogHelper.Instance.WriteError($"【诊断-入队失败】{groupName} | 队列已满,任务被拒绝"); + lock (_statusLock) + { + _groupStatus[group.GroupName] = 0; + } + } + else + { + StationDiagnostics.LogTaskEnqueued(groupName, _taskQueue.Count); + } + } + } + else if (trig == 0 && status == 1) + { + if (isCriticalStation) + { + LogHelper.Instance.WriteLog($"【诊断-信号下降】{group.GroupName} | 触发信号已复位 | 清理状态"); + } + + lock (_statusLock) + { + _groupStatus[group.GroupName] = 0; + } + + ClearFinishFlags(group, plcIndex); + } + + Thread.Sleep(50); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"PLC读取异常:{ex.Message}"); + Thread.Sleep(100); + } + } + } + + /// + /// 带超时的PLC读取(新增) + /// + private JYResult ReadWithTimeout(PlcReadWriteBase plc, PlcGroup group, int timeoutMs) + { + try + { + var task = Task.Run(() => plc.ReadValue>(group.VarList[0].VarAddress, DataType.Short)); + if (task.Wait(timeoutMs)) + { + return task.Result; + } + else + { + LogHelper.Instance.WriteError($"PLC读取超时:{group.GroupName}"); + return null; + } + } + catch + { + return null; + } + } + + private void WriteFinishToPLC(PlcGroup group, int plcIndex) + { + try + { + PlcReadWriteBase plc = CommonMethods.plcDevices[plcIndex]; + if (plc == null || !plc.IsConnected) return; + + // 使用信号量限制并发写入 + if (_plcWriteSemaphore.Wait(1000)) + { + try + { + switch (group.GroupName) + { + case "物流线料盘来料": + case "物流线料盘进站": + plc.WriteInt16(group.VarList[5].VarAddress, 1); + plc.WriteInt16(group.VarList[4].VarAddress, 1); + break; + case "电池进站": + plc.WriteInt16(group.VarList[5].VarAddress, 1); + break; + case "电池与拖盘绑定": + plc.WriteInt16(group.VarList[8].VarAddress, 1); + plc.WriteInt16(group.VarList[7].VarAddress, 1); + break; + case "料框码解绑": + plc.WriteInt16(group.VarList[2].VarAddress, 1); + break; + case "强制放行": + plc.WriteInt16(group.VarList[2].VarAddress, 1); + break; + } + } + finally + { + _plcWriteSemaphore.Release(); + } + } + else + { + LogHelper.Instance.WriteError($"获取PLC写入信号量超时:{group.GroupName}"); + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"写入PLC失败:{ex.Message}"); + } + } + + /// + /// 清空PLC响应标志 + /// + private void ClearFinishFlags(PlcGroup group, int plcIndex) + { + try + { + PlcReadWriteBase plc = CommonMethods.plcDevices[plcIndex]; + if (plc == null || !plc.IsConnected) return; + + if (_plcWriteSemaphore.Wait(500)) + { + try + { + switch (group.GroupName) + { + case "电池与拖盘绑定": + plc.WriteInt16(group.VarList[8].VarAddress, 0); + plc.WriteInt16(group.VarList[7].VarAddress, 0); + break; + case "电池进站": + plc.WriteInt16(group.VarList[5].VarAddress, 0); + break; + case "物流线料盘来料": + case "物流线料盘进站": + //plc.WriteInt16(group.VarList[4].VarAddress, 0); + plc.WriteInt16(group.VarList[5].VarAddress, 0); + break; + case "料框码解绑": + plc.WriteInt16(group.VarList[2].VarAddress, 0); + break; + } + } + finally + { + _plcWriteSemaphore.Release(); + } + } + } + catch { } + } + + #endregion + + #region 开始停止联机事件 + /// + /// 开始联机 + /// + /// + + public async Task ConnectAllPlcsAsync() + { + bool allConnected = true; + if (CommonMethods.plcDevices.Count <= 0) + { + CommonMethods.AddDataMonitorLog(1, "无PLC配置信息".Translated() + "," + "请检查配置文件".Translated()); + return false; + } + + foreach (var plc in CommonMethods.plcDevices) + { + if (_plcDeviceMapping.TryGetValue(plc, out var plcDevices)) + { + foreach (var deviceConfig in plcDevices) + { + string msg = ""; + try + { + // 使用 Task.Run 来在后台线程执行连接操作 + bool isConnected = await Task.Run(delegate () + { + // 设置一个连接超时 + //using var cts = new CancellationTokenSource(10000); + + try + { + return plc.Connect(ref msg); + } + catch + { + msg = "连接超时"; + return false; + } + }); + + deviceConfig.IsConnected = isConnected; + plc.IsConnected = isConnected; + + if (!isConnected) + { + allConnected = false; + LogHelper.Instance.WriteLog($"连接PLC失败: {deviceConfig.PlcNum}, 错误: {msg}"); + CommonMethods.AddDataMonitorLog(1, "连接PLC失败".Translated() + $": {deviceConfig.PlcNum}, " + "错误".Translated() + $": {msg}"); + } + else + { + await SendConfigToPLCAsync(plc); + await SendUserRightToPLCAsync(plc); + CommonMethods.AddDataMonitorLog(0, "成功连接PLC".Translated() + $": {deviceConfig.PlcNum}"); + } + } + catch (Exception ex) + { + allConnected = false; + LogHelper.Instance.WriteLog($"连接PLC时发生异常: {deviceConfig.PlcNum}, 错误: {ex.Message}"); + CommonMethods.AddDataMonitorLog(2, "连接PLC时发生异常".Translated() + $": {deviceConfig.PlcNum}" + "错误".Translated() + $": {ex.Message}"); + } + } + } + } + return allConnected; + } + + /// + /// 断开链接 + /// + public void DisconnectAllPlcs() + { + try + { + if (_cts != null && !_cts.IsCancellationRequested) + { + _cts.Cancel(); + } + + foreach (var plc in CommonMethods.plcDevices) + { + try + { + if (plc.IsConnected) + { + plc.Disconnect(); + plc.IsConnected = false; + CommonMethods.AddDataMonitorLog(0, "已断开与PLC".Translated() + $"[{plc.PlcID}]" + "的链接".Translated()); + } + } + catch (Exception ex) + { + Debug.WriteLine($"断开PLC {plc.PlcID} 异常:{ex.Message}"); + } + } + } + catch (Exception ex) + { + Debug.WriteLine($"断开连接异常: {ex.Message}"); + } + + } + + + #endregion + + #endregion + + #region MES + /// + /// Mes心跳 + /// + private void UpdateMesHeartBeat() + { + Thread.Sleep(100); + while (!_cts.Token.IsCancellationRequested) + { + try + { + if (CommonMethods.IsRun)//CommonMethods.mesConfig.isUpMes && CommonMethods.mesConfig.IsLoginMesOK && + { + bool isOnline = FastPing(); + CommonMethods.mesConfig.isConnected = isOnline; + + if (!isOnline) + { + foreach (var plc in CommonMethods.plcDevices) + { + if (plc.IsConnected && plc.Name == "PLC_1") + { + plc.WriteInt16("D80", 1); + } + } + } + + //if (Ping() == true) + //{ + // CommonMethods.mesConfig.isConnected = true; + // string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping成功,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort}"; + // TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr); + //} + //else//Ping失败,提示检查线路。 + //{ + // int count = 0; + // bool mesOnLine = false; + // do//重复3次 + // { + // Thread.Sleep(1000); + // if (Ping() == true) { mesOnLine = true; break; } + // count++; + // } + // while (count < 3); + + // if (!mesOnLine) + // { + // CommonMethods.mesConfig.isConnected = false; + // if (CommonMethods.plcDevices.Count() > 0) + // { + // for (int i = 0; i < CommonMethods.plcDevices.Count(); i++) + // { + // if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1") + // { + // CommonMethods.plcDevices[i].WriteInt16("D80", (short)1); + + // string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping失败,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort}"; + // TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr); + // } + // } + // } + // } + //} + } + } + catch (Exception ex) + { + string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr); + } + Thread.Sleep(1000); + } + } + + /// + /// Ping 检查网络线路问题 + /// + /// + public bool FastPing() + { + try + { + string ip = CommonMethods.mesConfig.MESURLAddressIP; + using var _ping = new Ping(); + int timeout = 500; + var reply = _ping.Send(ip, timeout); + return reply.Status == IPStatus.Success; + } + catch (Exception ex) + { + string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr); + return false; + } + + } + #endregion + + #region 4、心跳和状态检查 + /// + /// 心跳检测 + /// + /// + /// + private async Task StartHeartbeatCheck(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + if (CommonMethods.IsRun) + { + foreach (var plc in CommonMethods.plcDevices) + { + if (_plcDeviceMapping.TryGetValue(plc, out var plcDevices)) + { + foreach (var plcDevice in plcDevices) + { + if (plcDevice.IsActive && plcDevice.IsHeartBeat) + { + await CheckHeartbeatForDevice(plc, plcDevice); + } + } + } + } + } + await Task.Delay(HeartbeatInterval, cancellationToken); + } + } + + /// + /// + /// + /// + /// + /// + private async Task CheckHeartbeatForDevice(PlcReadWriteBase plc, PlcDevice plcDevice) + { + if (plcDevice.IsConnected) + { + try + { + JYResult result = await Task.Run(() => plc.ReadValue>(plcDevice.HeartBeat, DataType.Short)); + if (result.IsSuccess) + { + plcDevice.ErrorTimes = 0; + await Task.Run(() => plc.WriteValue(plcDevice.HeartBeat, (short)1, DataType.Short)); + plcDevice.IsConnected = true; + plc.IsConnected = true; + return; + } + } + catch { } + + plcDevice.ErrorTimes++; + if (plcDevice.ErrorTimes >= plcDevice.AllowErrorTimes) + { + plcDevice.IsConnected = false; + plc.IsConnected = false; + LogHelper.Instance.WriteLog($"编号:[{plcDevice.PlcNum}]的PLC链接断开:{plcDevice.ErrorTimes}"); + } + } + else + { + await ReconnectDevice(plc, plcDevice); + } + } + + + + private async Task ReconnectDevice(PlcReadWriteBase plc, PlcDevice plcDevice) + { + if (!plcDevice.IsFirstConnect) + { + await Task.Delay(plcDevice.ReConnectTime); + plc.Disconnect(); + } + + string msg = ""; + var connectResult = await Task.Run(() => plc.Connect(ref msg)); + plcDevice.IsConnected = connectResult; + LogHelper.Instance.WriteLog(connectResult + ? $"PLC编号:{plcDevice.PlcNum}{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接成功{msg}!" + : $"[{plcDevice.PlcNum}]#PLC{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接失败{msg}!"); + + plcDevice.IsFirstConnect = false; + } + + #endregion + + #region 定时刷新数据 + + private int TotalNum = 0; + private int TotalNum1 = 0; + private int Regular = 0; + private bool _isUploadingEnergy = false; + private bool _isGettingEnergy = false; + + private void Timer_RefreshData_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + try + { + // 防止定时器重入 + if (Regular >= 300 && !_isUploadingEnergy) + { + _isUploadingEnergy = true; + Task.Run(() => + { + try + { + UploadEquEnergy(); + } + finally + { + _isUploadingEnergy = false; + } + }); + Regular = 0; + } + + if (TotalNum > 4) + { + if (CommonMethods.sysConfig.StationNo == "1" && !_isGettingEnergy) + { + _isGettingEnergy = true; + Task.Run(() => + { + try + { + GetEnergyData(); + } + finally + { + _isGettingEnergy = false; + } + }); + } + else if (!_isGettingEnergy) + { + _isGettingEnergy = true; + Task.Run(() => + { + try + { + GetEnergyDataFormPlc(); + } + finally + { + _isGettingEnergy = false; + } + }); + } + + Task.Run(() => Refresh12HourProdQty()); + GetDefectTypeQty(); + ReadPLCComm(); + + Task.Run(() => GetASqlAlarmData(DateTime.Today, CommonMethods.strClass)); + TotalNum = 0; + } + else if (TotalNum == 2)//设备状态读取 + { + SetClass(); //变更班次 + } + + if (TotalNum1 >= 3600 * 24) + { + Task.Run(() => DeleteFileOfLocal()); + TotalNum1 = 0; + } + + TotalNum++; + TotalNum1++; + Regular++; + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"定时器异常:{ex.Message}"); + } + } + + #endregion + + #region 设备综合信息 + /// + /// 读取PLC通用信息 + /// + internal void ReadPLCComm() + { + try + { + foreach (var plc in CommonMethods.plcDevices) + { + if (plc.IsConnected && plc.Name == "PLC_1") + { + _ = UpTotalCount(null); + + CommonMethods.TotalQty = plc.ReadFloat("D15");//生产总数 + CommonMethods.ProOKQty = plc.ReadFloat("D17");//良品总数 + CommonMethods.Ppm = plc.ReadFloat("D13"); + CommonMethods.JiaDL = Convert.ToDouble(plc.ReadFloat("D11").ToString("F2")); + + #region 开机时间/运行时间 + CommonMethods.PlcOpenAndRunTime = GetList(6, 0); + JYResult resByte = plc.ReadValue>($"D50", DataType.ArrByte, 12); + if (resByte.IsSuccess && resByte.Content.Length >= 24) + { + for (int j = 0; j < CommonMethods.PlcOpenAndRunTimeAdress.Count; j++) + { + CommonMethods.PlcOpenAndRunTime[j] = IntLib.GetIntFromByteArray(resByte.Content, j * 4, DataFormat.CDAB); + } + } + #endregion + } + } + } + catch { } + } + #endregion + + #region 保存12小时产能数据 + public int totalNum = 0; // 总数 + public int okNum = 0; // 良品数 + + /// + /// 储存数据到数据库 + /// + /// + public async Task UpTotalCount(int[] DataCount) + { + try + { + DateTime now = DateTime.Now; + string date = now.ToString("yyyy-MM-dd"); + int hour = now.Minute < 30 ? (now.Hour + 23) % 24 : now.Hour; + + if (now.Hour == 0 && now.Minute < 30) + date = now.AddDays(-1).ToString("yyyy-MM-dd"); + + int inQty = GetToDayHourQty(hour, true); + int outQty = GetToDayHourQty(hour, false); + + Hourprod prod = new Hourprod + { + FDate = date, + FHour = hour, + ProdIn = inQty, + ProdOut = outQty, + TestTime = now, + Ppm = (int)CommonMethods.Ppm, + JiaDL = Convert.ToDecimal(CommonMethods.JiaDL) + }; + + int update = CommonMethods.db.UpdateSingle(prod, + it => new Hourprod { ProdIn = prod.ProdIn, ProdOut = prod.ProdOut, TestTime = prod.TestTime }, + it => it.FDate == date && it.FHour == hour); + + if (update <= 0) + await CommonMethods.db.AddReturnBoolAsync(prod); + } + catch { } + + //try + //{ + // DateTime dateTime = DateTime.Now; + // string strDate = dateTime.ToString("yyyy-MM-dd"); + + // // 获取当前时间的小时和分钟 + // int currentHour = dateTime.Hour; + // int currentMinute = dateTime.Minute; + + // // 根据当前分钟确定统计小时 + // // 如果当前时间在 X:30 之前,则统计的是前一个小时的数据(从前一个小时的30分到这个小时的29分) + // // 如果当前时间在 X:30 之后,则统计的是当前小时的数据(从当前小时的30分到下个小时的29分) + // int statisticalHour; + // if (currentMinute < 30) + // { + // statisticalHour = (currentHour + 23) % 24; // 前一个小时,处理跨天的情况 + // // 如果是凌晨0点前的数据,需要使用前一天的日期 + // if (currentHour == 0) + // { + // strDate = dateTime.AddDays(-1).ToString("yyyy-MM-dd"); + // } + // } + // else + // { + // statisticalHour = currentHour; + // } + + // // 数据有效性验证 + // if (statisticalHour < 0 || statisticalHour > 23) + // { + // throw new ArgumentException($"无效的小时值: {statisticalHour}"); + // } + + // //读取统计小时的PLC投入总数和产出数 + // int ProdCurrAllQty = GetToDayHourQty(statisticalHour, true); + // int ProdCurrOKQty = GetToDayHourQty(statisticalHour, false); + + // // 确保数量为非负数 + // if (ProdCurrAllQty < 0 || ProdCurrOKQty < 0) + // { + // LogHelper.Instance.WriteError($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}"); + // //throw new ArgumentException($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}"); + // } + + // Hourprod mh = new Hourprod + // { + // FDate = strDate, + // FHour = statisticalHour, + // ProdIn = ProdCurrAllQty, + // ProdOut = ProdCurrOKQty, + // TestTime = dateTime, + // Ppm = (int)CommonMethods.Ppm, + // JiaDL = Convert.ToDecimal(CommonMethods.JiaDL) + // }; + + // // 尝试更新记录 + // int res = CommonMethods.db.UpdateSingle( + // mh, + // it => new Hourprod + // { + // ProdIn = mh.ProdIn, + // ProdOut = mh.ProdOut, + // TestTime = mh.TestTime, + // Ppm = mh.Ppm, + // JiaDL = mh.JiaDL + // }, + // it => it.FDate == mh.FDate && it.FHour == mh.FHour + // ); + + // // 如果更新失败(记录不存在),则新增记录 + // if (res <= 0) + // { + // bool addResult = await CommonMethods.db.AddReturnBoolAsync(mh).ConfigureAwait(false); + // if (!addResult) + // { + // LogHelper.Instance.WriteError($"保存小时产能新增记录失败"); + // } + // } + + // // 可以添加日志记录成功信息 + // // Logger.Log($"成功更新/新增产能数据: 日期={strDate}, 小时={statisticalHour}, 时段={statisticalHour}:30~{(statisticalHour + 1) % 24}:29"); + //} + //catch (Exception ex) + //{ + // // 这里应该添加错误日志记录 + // LogHelper.Instance.WriteEX($"保存小时产能数据失败: ", ex); + //} + } + + /// + /// 每小时产能读取处理 + /// + /// + /// + /// + private int GetToDayHourQty(int hour, bool flag) + { + try + { + string strAddr = flag ? $"D{1040 + hour}" : $"D{1070 + hour}"; + + foreach (var plc in CommonMethods.plcDevices) + { + if (plc.IsConnected && plc.Name == "PLC_1") + { + int ProdNGQty = plc.ReadInt16(strAddr); + return ProdNGQty; + } + + } + + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "系统异常", MessageBoxButtons.OK, MessageBoxIcon.Hand); + } + return 0; + } + + #endregion + + #region 5、设备状态 + /// + /// 定时获取设备状态 + /// + /// + /// + int OldStatues = int.TryParse(IniConfigHelper.ReadIniData("上一次设备状态", "DeviceStatus", "1", CommonMethods.strDeviceStatusPath), out var result) ? result : 0; //退出程序前设备状态 + string strGuidAlarm = IniConfigHelper.ReadIniData("上一次Guid", "DeviceGuid", Guid.NewGuid().ToString(), CommonMethods.strDeviceStatusPath);//退出程序前Guid + DateTime StatuesBeginTime = DateTime.Now; // DateTime.Now.AddMinutes(-6); + bool run_AlarmMark = false;//特殊情况1标志(运行状态) + bool run_IdleMark = false;//特殊情况2标志(闲置状态) + bool isUpIdleAlarm = false;//闲置状态报警信息上传标志 + List idleAlarmData = new List();//闲置状态的报警信息 + + private async void ShowStateEven_Run() + { + while (!_cts.Token.IsCancellationRequested) + { + + try + { + foreach (var plc in CommonMethods.plcDevices) + { + + if (plc.IsConnected && plc.Name == "PLC_1") + { + DateTime Date = DateTime.Now; + bool isUpload = false; + string deviceStatus = string.Empty; + string deviceStatusDesc = string.Empty; + short NewStatus = plc.ReadInt16("D10"); + + if (NewStatus != 100) + { + //特殊情况1:运行->报警->……->运行 + if (NewStatus == 3 && OldStatues == 1) { run_AlarmMark = true; }//第一次进入报警状态 + if (NewStatus == 1) { run_AlarmMark = false; }//下一次运行状态,置位 + if (run_AlarmMark) { NewStatus = 3; }//报警状态后下一次运行状态期间一直是报警状态 + //特殊情况2:运行->闲置->……->运行 + if (NewStatus == 4 && OldStatues == 1) { run_IdleMark = true; }//第一次进入闲置状态 + if (NewStatus == 1) { run_IdleMark = false; }//下一次闲置状态,置位 + if (run_IdleMark) { NewStatus = 4; }//闲置状态后下一次运行状态期间一直是闲置状态 + + //闲置状态结束报警信息上传 + if (OldStatues == 4 && NewStatus != 4 && isUpIdleAlarm) + { + _ = UpIdleDataAsync(idleAlarmData, strGuidAlarm); + } + + //设备状态信号灯变量 + CommonMethods.Statues = new List { NewStatus == 1, NewStatus == 2, NewStatus == 3, NewStatus == 4 }; + + // 状态切换时生成新的 GUID + if (NewStatus != OldStatues) + { + // 从 Alert 切换到非 Alert 状态时,上传报警信息 + if (OldStatues == 3 && NewStatus != 3) + { + ShowAlarmEven_Run(strGuidAlarm, NewStatus); + } + + // 只要状态变更,就生成新的 GUID + strGuidAlarm = Guid.NewGuid().ToString(); // 强制生成新的 GUID + + isUpload = true; + OldStatues = NewStatus; + StatuesBeginTime = Convert.ToDateTime(Date); + + IniConfigHelper.WriteIniData("上一次设备状态", "DeviceStatus", NewStatus.ToString(), CommonMethods.strDeviceStatusPath); + IniConfigHelper.WriteIniData("上一次Guid", "DeviceGuid", strGuidAlarm, CommonMethods.strDeviceStatusPath); + } + else + { + if (Date.Subtract(StatuesBeginTime).TotalSeconds < 5 * 60 && Date.Subtract(StatuesBeginTime).TotalSeconds >= 4 * 60) + { + isUpload = true; + StatuesBeginTime = DateTime.Now; + } + } + + // 根据状态设置设备状态和描述 + switch (NewStatus) + { + case 1: + deviceStatus = "Run"; + deviceStatusDesc = "正常运行"; + break; + case 2://取消 + deviceStatus = "Maintain"; + deviceStatusDesc = "停止运行"; + break; + case 3: + deviceStatus = "Alert"; + deviceStatusDesc = "故障调试"; + // Alert 状态时上传报警信息 + ShowAlarmEven_Run(strGuidAlarm, NewStatus); + break; + case 4: + deviceStatus = "Idle"; + deviceStatusDesc = "闲置待机"; + ShowStuesEven_Run(strGuidAlarm); + break; + } + + // 上传设备状态信息 + if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected && isUpload && (NewStatus == 1 || NewStatus == 3 || NewStatus == 4)) + { + var (success, message) = await CommonMethods.hbgMes.UploadEquStatusAsync( + CommonMethods.mesConfig.DeviceStatus, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + CommonMethods.mesConfig.MaterialCode, + CommonMethods.mesConfig.mesUserName, + strGuidAlarm, // RUN 状态时传空 + deviceStatus, + null + ).ConfigureAwait(false); + + if (success) + { + //StatuesCount = 0; + } + } + } + } + + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + } + Thread.Sleep(100); + //Task.Delay(100).CountinueWith(); + } + } + + + #region 触摸屏弹窗 + private async void ShowStuesEven_Run(string strGuid) + { + if (CommonMethods.plcDevices.Count() > 0) + { + for (int i = 0; i < CommonMethods.plcDevices.Count(); i++) + { + if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1") + { + + string strCode = ""; + string alarmName = ""; + short HMIStatus = CommonMethods.plcDevices[i].ReadInt16("D40"); + if (HMIStatus != 0) + { + CommonMethods.AddDataMonitorLog(0, "触发了手动HMI弹窗功能".Translated()); + switch (HMIStatus) //注意:B1-D12都为闲置代码,上传代码是只需上传闲置代码 + { + case 5: + strCode = "D1"; + alarmName = "设备故障".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 6: + strCode = "D2"; + alarmName = "设备转型".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 7: + strCode = "D3"; + alarmName = "工程变更".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 8: + strCode = "D4"; + alarmName = "MES停机".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 9: + strCode = "D5"; + alarmName = "品质异常".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 10: + strCode = "D6"; + alarmName = "配件,物料更换".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 11: + strCode = "D7"; + alarmName = "来料不良".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 12: + strCode = "D8"; + alarmName = "待料".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 13: + strCode = "D9"; + alarmName = "品质检查".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 14: + strCode = "D10"; + alarmName = "清洁点检".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 15: + strCode = "D11"; + alarmName = "环境不满足".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + case 16: + strCode = "D12"; + alarmName = "其它非计划停机".Translated(); + CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}"); + break; + default: + break; + } + + if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected) + { + List alarmObj = new List(); + AlarmData alarmData = new AlarmData(); + alarmData.AlarmCode = strCode; + alarmData.StartTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + alarmData.EndTime = ""; + alarmData.AlarmType = "非计划损失"; + alarmData.AlarmContent = alarmName; + alarmObj.Add(alarmData); + + //闲置报警上传标志 + isUpIdleAlarm = true; + idleAlarmData.Add(alarmData); + + //上传报警 + var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, alarmObj, strGuid).ConfigureAwait(false); + if (success) + CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗状态已上传成功,代码".Translated() + $":{strCode}"); + } + bool IsSuccess = CommonMethods.plcDevices[i].WriteInt16("D40", 0); + if (IsSuccess) + CommonMethods.AddDataMonitorLog(0, $"D40已复位0".Translated()); + + } + } + } + } + } + + #endregion + + /// + /// HMI手动弹窗结束状态上传 + /// + /// + /// + /// + private async Task UpIdleDataAsync(List idleAlarmDate, string strGuidAlarm) + { + if (idleAlarmDate.Count == 0) { return; } + string strCode = ""; + foreach (var item in idleAlarmDate) + { + item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + strCode = item.AlarmCode + ","; + } + if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected) + { + //上传报警 + var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, idleAlarmDate, strGuidAlarm).ConfigureAwait(false); + if (success) + CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗结束状态已上传成功,代码".Translated() + $":{strCode.TrimEnd(',')}"); + } + idleAlarmData.Clear(); + isUpIdleAlarm = false; + } + + #endregion + + #region 6、设备报警 + //报警表单数据 + List listAlarmForm = null; + public void GetAlarmData() + { + //加载PLC报警文件 + try + { + string strFileName = Path.Combine(Environment.CurrentDirectory, "欧姆龙报警寄存器对应表.csv"); + listAlarmForm = CSVHelper.ReadCSV(strFileName); + } + catch (Exception ex) + { + MessageBox.Show("加载报警文件失败!"); + } + + } + + /// + /// 报警信息读取 + /// + /// + /// + List listOld = new List(); + List listNew = new List(); + private void ShowAlarmEven_Run(string strGuidAlarm,int MachineState) + { + //if (!CommonMethods.IsRun || !CommonMethods.plcDevices[0].IsConnected) + //{ + // return; + //} + bool boolIsConnected = false; + if (CommonMethods.plcDevices.Count() > 0) + { + for (int i = 0; i < CommonMethods.plcDevices.Count(); i++) + { + if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1") + { + boolIsConnected = true; + break; + } + } + } + if (!CommonMethods.IsRun || !boolIsConnected) + { + return; + } + + try + { + // 1. 读取 PLC 报警信息 + List alarmStatusList = ReadAlarmStatusFromPLC(); + if (alarmStatusList == null || listAlarmForm == null)//true + { + return; + } + + // 2. 解析报警信息并生成新的报警列表 + List newAlarms = ParseAlarmStatus(alarmStatusList, strGuidAlarm); + if (newAlarms.Count > 0) + { + // 3. 检测新报警并添加到旧报警列表,上传第一次报警信息 + DetectNewAlarmsAsync(newAlarms); + + // 4. 文字显示新报警信息 + DisplayAlarmInfo(newAlarms); + } + + // 5. 检测已取消的报警并处理 + List canceledAlarms = DetectCanceledAlarms(newAlarms); + if (canceledAlarms.Count > 0) + { + // 6. 记录已取消的报警信息(保存本地) + LogCanceledAlarms(canceledAlarms); + + // 7. 上传已取消的报警信息(报警结束上传一次) + UploadCanceledAlarmsAsync(canceledAlarms, strGuidAlarm); + } + + if (MachineState != 3 && listOld.Count > 0) //设备状态变为非报警并旧报警仍有报警。旧报警上传并清空 + { + List tempOldAlarmList = new List(); + foreach (var item in listOld) + { + item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); //所有报警全部结束时间赋值 + tempOldAlarmList.Add(item); + } + + // 6. 记录已取消的报警信息(保存本地) + LogCanceledAlarms(tempOldAlarmList); + + // 7. 上传已取消的报警信息(报警结束上传一次) + UploadCanceledAlarmsAsync(tempOldAlarmList, strGuidAlarm); + + listOld.Clear(); + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + } + } + + + /// + /// 从 PLC 读取报警状态 + /// + private List ReadAlarmStatusFromPLC() + { + string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + // 读取足够的字节覆盖所有可能的报警地址 + int startAddr = 10010; + int endAddr = 10519; // 根据实际最大地址调整 + int wordCount = endAddr - startAddr + 1; + int byteCount = wordCount * 2; // 每个字2字节 + + if (CommonMethods.plcDevices.Count() > 0) + { + for (int i = 0; i < CommonMethods.plcDevices.Count(); i++) + { + if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1") + { + + JYResult resByte = CommonMethods.plcDevices[i].ReadValue>($"D{startAddr}", DataType.ArrByte, (ushort)byteCount); + + if (resByte.IsSuccess && resByte.Content != null) + { + return PLCAlarmParseHelper.OmronFinsByte2Status(startAddr, resByte.Content); + } + } + } + } + + return null; + } + + /// + /// 解析报警状态并生成新的报警列表 + /// + private List ParseAlarmStatus(List alarmStatusList, string strGuidAlarm) + { + string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + + var alarmTypeMap = new Dictionary // 定义报警类型映射字典 + { + {'1', "停机报警"}, + {'2', "非停机报警"}, + }; + switch (LanguageManager.LanguageCode) + { + case "en"://英语报警信息 + return alarmStatusList + .Where(status => status.Status) + .Join( + listAlarmForm, + status => status.PLCAdress, + form => form.PLCAdress, + (status, form) => + { + var alarmContent = string.IsNullOrEmpty(form.EnAlarmContent) + ? status.PLCAdress + : form.EnAlarmContent; + string alarmType = "停机报警"; // 默认值 + if (form.AlarmCode?.Length >= 3) + { + char thirdChar = form.AlarmCode[2]; + // 尝试从字典获取对应的值 + if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType)) + { + alarmType = mappedType; + } + } + return new AlarmData + { + AlarmGuid = strGuidAlarm, + PLCAdress = status.PLCAdress, + AlarmCode = form.AlarmCode, + AlarmContent = alarmContent, + AlarmType = alarmType, + AlarmDesc = alarmContent, + AlarmState = "1", + StartTime = Date, + EndTime = "", + Flag = 0 + }; + }) + .ToList(); + case "hu"://匈牙利语报警信息 + return alarmStatusList + .Where(status => status.Status) + .Join( + listAlarmForm, + status => status.PLCAdress, + form => form.PLCAdress, + (status, form) => + { + var alarmContent = string.IsNullOrEmpty(form.HuAlarmContent) + ? status.PLCAdress + : form.HuAlarmContent; + string alarmType = "停机报警"; // 默认值 + if (form.AlarmCode?.Length >= 3) + { + char thirdChar = form.AlarmCode[2]; + // 尝试从字典获取对应的值 + if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType)) + { + alarmType = mappedType; + } + } + return new AlarmData + { + AlarmGuid = strGuidAlarm, + PLCAdress = status.PLCAdress, + AlarmCode = form.AlarmCode, + AlarmContent = alarmContent, + AlarmType = alarmType, + AlarmDesc = alarmContent, + AlarmState = "1", + StartTime = Date, + EndTime = "", + Flag = 0 + }; + }) + .ToList(); + case "ms"://马来语报警信息 + return alarmStatusList + .Where(status => status.Status) + .Join( + listAlarmForm, + status => status.PLCAdress, + form => form.PLCAdress, + (status, form) => + { + var alarmContent = string.IsNullOrEmpty(form.MsAlarmContent) + ? status.PLCAdress + : form.MsAlarmContent; + string alarmType = "停机报警"; // 默认值 + if (form.AlarmCode?.Length >= 3) + { + char thirdChar = form.AlarmCode[2]; + // 尝试从字典获取对应的值 + if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType)) + { + alarmType = mappedType; + } + } + return new AlarmData + { + AlarmGuid = strGuidAlarm, + PLCAdress = status.PLCAdress, + AlarmCode = form.AlarmCode, + AlarmContent = alarmContent, + AlarmType = alarmType, + AlarmDesc = alarmContent, + AlarmState = "1", + StartTime = Date, + EndTime = "", + Flag = 0 + }; + }) + .ToList(); + case "zh": + default: + return alarmStatusList + .Where(status => status.Status) + .Join( + listAlarmForm, + status => status.PLCAdress, + form => form.PLCAdress, + (status, form) => + { + var alarmContent = string.IsNullOrEmpty(form.AlarmContent) + ? status.PLCAdress + : form.AlarmContent; + string alarmType = "停机报警"; // 默认值 + if (form.AlarmCode?.Length >= 3) + { + char thirdChar = form.AlarmCode[2]; + // 尝试从字典获取对应的值 + if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType)) + { + alarmType = mappedType; + } + } + return new AlarmData + { + AlarmGuid = strGuidAlarm, + PLCAdress = status.PLCAdress, + AlarmCode = form.AlarmCode, + AlarmContent = alarmContent, + AlarmType = alarmType, + AlarmDesc = alarmContent, + AlarmState = "1", + StartTime = Date, + EndTime = "", + Flag = 0 + }; + }) + .ToList(); + } + } + + private HashSet _allUploadedAlarmContents = new HashSet(); + private void DetectNewAlarmsAsync(List newAlarms) + { + List tempAlarmList = new List(); + foreach (var alarm in newAlarms) + { + if (!listOld.Any(o => o.PLCAdress == alarm.PLCAdress)) + { + listOld.Add(alarm); + tempAlarmList.Add(alarm); //把新报警保存到临时表中 + } + } + if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected) + { + CommonMethods.hbgMes.UploadEquAlarmAsync( + CommonMethods.mesConfig.DeviceAlarm, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + CommonMethods.mesConfig.MaterialCode, + CommonMethods.mesConfig.mesUserName, + tempAlarmList, + strGuidAlarm + ); + } + } + + /// + /// 显示报警信息 + /// + private void DisplayAlarmInfo(List newAlarms) + { + StringBuilder sb = new StringBuilder(); + newAlarms.ForEach(r => sb.Append($"{r.AlarmContent} ")); + + if (sb.Length > 0) + { + CommonMethods.SlideAlarmText = sb.ToString().Substring(0, sb.Length - 10); + } + } + + /// + /// 检测已取消的报警 + /// + private List DetectCanceledAlarms(List newAlarms) + { + var canceledAlarms = new List(); + var listOldAlarm = new List(listOld); + + foreach (var item in listOldAlarm) + { + if (!newAlarms.Any(n => n.PLCAdress == item.PLCAdress)) + { + item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + canceledAlarms.Add(item); + listOld.Remove(item); + } + } + + return canceledAlarms; + } + + /// + /// 记录已取消的报警信息 + /// + private void LogCanceledAlarms(List canceledAlarms) + { + var nowDate = DateTime.Now; + string basePath = $@"{CommonMethods.strAlarmLogspath}\{nowDate.Year}\{nowDate.Month}"; + string fileName = $@"{nowDate.Day}.csv"; + string title = "GUID,报警地址,故障代码,报警内容,开始时间,结束时间,是否停机"; + string alarmContent = string.Join("\n", canceledAlarms.Select(m1 => + $"{m1.AlarmGuid},{m1.PLCAdress},{m1.AlarmCode},{m1.AlarmContent},{m1.StartTime},{m1.EndTime},{m1.AlarmType}")); + + CSVHelper.WriterCSV(basePath, fileName, title, alarmContent); + + foreach (var m1 in canceledAlarms) + { + var alarm = new SysLog + { + InsertTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + LogType = "报警日志", + Note = m1.AlarmContent == "" ? m1.PLCAdress : m1.AlarmContent, + AlarmType = "错误", + Operater = CommonMethods.currentAdmin.LoginName, + VarName = m1.PLCAdress, + AlarmSet = "", + AlarmValue = "1", + }; + // 显示报警信息 + CommonMethods.AddAlarmLog(alarm);//存报警信息 + // 报警top10保存 + SaveAlarmCount(canceledAlarms); + + } + } + + + /// + /// 报警结束上传 + /// + /// + /// + private void UploadCanceledAlarmsAsync(List canceledAlarms, string strGuidAlarm) + { + if (CommonMethods.sysConfig.MesModeSwitching) + { + CommonMethods.hbgMes.UploadEquAlarmAsync( + CommonMethods.mesConfig.DeviceAlarm, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + CommonMethods.mesConfig.MaterialCode, + CommonMethods.mesConfig.mesUserName, + canceledAlarms, + strGuidAlarm + ); + } + } + + + /// + /// 报警Top10保存 + /// + private async Task SaveAlarmCount(List alarmDatas) + { + bool ISAdd = false; + var recordToUpdate = new AlarmCountEntry(); + + DateTime today = DateTime.Today; + DateTime upTime = DateTime.Now; + var listAlarmStatistics = CommonMethods.db.QueryWhereList(it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today); + List fd = new List(); + if (listAlarmStatistics != null) + { + alarmDatas.ForEach(async r => + { + recordToUpdate = listAlarmStatistics.FirstOrDefault(x => x.PLCAdress.Trim() == r.PLCAdress); + if (recordToUpdate != null) + { + await CommonMethods.db.UpdateAsync(it => it.AlarmCount == it.AlarmCount + 1, it => it.PLCAdress == r.PLCAdress && Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today).ConfigureAwait(false); + } + else + { + ISAdd = true; + AlarmCountEntry alarm = new AlarmCountEntry(); + alarm.PLCAdress = r.PLCAdress; + alarm.AlarmContent = r.AlarmContent; + alarm.AlarmCount = 1; + alarm.Class = CommonMethods.strClass; + alarm.AlarmTime = upTime; + fd.Add(alarm); + } + }); + if (ISAdd) + { + bool res = await CommonMethods.db.AddReturnBoolAsync(fd).ConfigureAwait(false); + ISAdd = false; + } + } + // 显示报警信息方法已存数据库,报警TOP10就插入新增了 + //else + //{ + // foreach (var m in listNew) + // { + // AlarmCountEntry alarm = new AlarmCountEntry(); + // alarm.PLCAdress = m.PLCAdress; + // alarm.AlarmContent = m.AlarmContent; + // alarm.AlarmCount = 1; + // alarm.Class = CommonMethods.strClass; + // alarm.AlarmTime = today; + // fd.Add(alarm); + // } + // await CommonMethods.db.AddReturnBoolAsync(fd); + //} + await GetASqlAlarmData(DateTime.Today, CommonMethods.strClass).ConfigureAwait(false); + } + + + /// + /// 读取数据库报警信息 + /// + /// + /// + public async Task GetASqlAlarmData(DateTime today, string strClass) + { + try + { + List chartAlarms = new List(); + List AlarmDatas = null; + List List_X = new List(); + List List_Y = new List(); + + DateTime baiClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 8:30:00")); + DateTime baiClassEnd = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:29:59")); + + DateTime yeClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:30:00")); + DateTime yeClassEnd = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 8:29:59")); + + + if (strClass == "全天".Translated()) + { + AlarmDatas = await CommonMethods.db.QueryListAsync("AlarmCount", 10, it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today).ConfigureAwait(false); + } + else if (strClass == "白班".Translated()) + { + AlarmDatas = await CommonMethods.db.QueryListAsync("AlarmCount", 10, it => it.AlarmTime >= baiClassStart && it.AlarmTime <= baiClassEnd && it.Class == strClass).ConfigureAwait(false); + } + else + { + AlarmDatas = await CommonMethods.db.QueryListAsync("AlarmCount", 10, it => it.AlarmTime >= yeClassStart && it.AlarmTime <= yeClassEnd && it.Class == strClass).ConfigureAwait(false); + } + + if (AlarmDatas != null && AlarmDatas.Count > 0) + { + + for (int i = 0; i < AlarmDatas.Count; i++) + { + chartAlarms.Add(new ChartDataType() + { + DataType = AlarmDatas[i].AlarmContent, + DataCount = (int)AlarmDatas[i].AlarmCount + }); + } + CommonMethods.Lst_AlarmTop10_Qty = chartAlarms; + } + else + { + CommonMethods.Lst_AlarmTop10_Qty = null; + } + } + catch (Exception) + { + + } + } + + #endregion + + #region 配置下发给PLC + public async Task SendConfigToPLCAsync(PlcReadWriteBase plc) + { + try + { + // 给物流线PLC下发 生产型号 和 本机架各垛位的档位 + if (plc.IsConnected && plc.Name == "PLC_2") + { + await SendConfigToWuliuPLCAsync(plc); + } + else if (plc.IsConnected && plc.Name == "PLC_1") + { + await SendConfigToZuPanPLCAsync(plc); + } + + } + catch (Exception ex) + { + CommonMethods.AddLog(true, "PC写入PLC配置异常".Translated() + ":" + ex.Message); + LogHelper.Instance.WriteEX(ex); + } + } + + private async Task SendConfigToWuliuPLCAsync(PlcReadWriteBase plc) + { + string plc_addr = CommonMethods.mesConfig.GetWuliuModelAddr(); + if (plc_addr == null || String.IsNullOrEmpty(plc_addr)) + { + CommonMethods.AddDataMonitorLog(2, $"机架号不识别,无对应机架号的PLC生产型号地址({plc_addr})"); + return; + } + + int model = CommonMethods.mesConfig.GetModel(CommonMethods.mesConfig.ModelName); + JYResult result = await Task.Run(() => plc.WriteValue(plc_addr, (short)model, DataType.Short)).ConfigureAwait(false); + if (result.IsSuccess) + { + CommonMethods.AddDataMonitorLog(1, $"Write_WuLiu_PLC_model({plc_addr})_{model}_Successful"); + } + else + { + CommonMethods.AddDataMonitorLog(2, $"Write_Wuliu_PLC_model({plc_addr})_{model}_Failed"); + } + + Dictionary plc_addrDict = CommonMethods.mesConfig.GetWuliuGradeAddr(); + if (plc_addrDict == null || plc_addrDict.Count == 0) + { + CommonMethods.AddDataMonitorLog(2, $"机架号不识别或者垛位号错误,无对应的PLC分档地址({plc_addr})"); + return; + } + + foreach (var kvp in plc_addrDict) + { + if (kvp.Value == null || String.IsNullOrEmpty(kvp.Value)) + { + continue; + } + + int stationNo = kvp.Key; + string plcAddress = kvp.Value; + string strGrade = MesConfig.GetLocGrade(stationNo, CommonMethods.curFdConfig); + int grade = CommonMethods.GetGradeNo(strGrade); + + result = await Task.Run(() => plc.WriteValue(plcAddress, (short)grade, DataType.Short)).ConfigureAwait(false); + if (result.IsSuccess) + { + CommonMethods.AddDataMonitorLog(1, $"Write_PLC_grade({plcAddress})_{strGrade}({grade})_Successful"); + } + else + { + CommonMethods.AddDataMonitorLog(2, $"Write_PLC_grade({plcAddress})_{strGrade}({grade})_Failed"); + } + } + } + + private async Task SendConfigToZuPanPLCAsync(PlcReadWriteBase plc) + { + var writeTasks = new List(); + Dictionary loc_plcAddr = CommonMethods.mesConfig.gw_loc_plcAddr[Convert.ToInt16(CommonMethods.sysConfig.StationNo)]; + + FDConfig fdconfig = CommonMethods.curFdConfig; + foreach (KeyValuePair locKvp in loc_plcAddr) + { + int stationNo = locKvp.Key; + string plcAddr = locKvp.Value; + + string gradeStr = MesConfig.GetLocGrade(stationNo, fdconfig); + try + { + // 转换等级 + int gradeValue = CommonMethods.GetGradeNo(gradeStr); + string logBase = $"LOC{stationNo} Write_Zupan_PLC({plcAddr}:等级{gradeStr},转换PLC值{gradeValue})"; + JYResult result = await Task.Run(() => plc.WriteValue(plcAddr, (short)gradeValue, DataType.Short)).ConfigureAwait(false); + if (result.IsSuccess) + { + CommonMethods.AddDataMonitorLog(1, $"{logBase} 成功"); + CommonMethods.AddOPLog(true, $"{logBase} 成功"); + } + else + { + string failMsg = $"{logBase} 失败,错误:{result.Message ?? "无详细信息"}"; + CommonMethods.AddDataMonitorLog(2, failMsg); + CommonMethods.AddOPLog(false, failMsg); + } + } + catch (Exception ex) + { + string exMsg = $"LOC{stationNo} Write_Zupan_PLC({plcAddr}) 异常:{ex.Message},堆栈:{ex.StackTrace}"; + CommonMethods.AddDataMonitorLog(3, exMsg); + CommonMethods.AddOPLog(false, exMsg); + } + } + } + #endregion + + #region 下发权限给PLC + /// + /// 下发权限到PLC + /// + public async Task SendUserRightToPLCAsync(PlcReadWriteBase plc) + { + + if (!plc.IsConnected || plc.Name != "PLC_1") + { + if(plc.Name == "PLC_1") + CommonMethods.AddDataMonitorLog(2, $"组盘PLC连接中断,无法给PLC下发用户名和权限"); + return; + } + + ushort quanxian = 1; + switch (CommonMethods.currentAdmin.LoginLevel) + { + case "操作员": + quanxian = 1; + break; + case "工程师": + quanxian = 2; + break; + case "管理员": + quanxian = 3; + break; + default: + break; + } + + Dictionary plc_addrs = CommonMethods.mesConfig.GetHMIUserRightAddr(); + if (!string.IsNullOrEmpty(plc_addrs["right"])) + { + JYResult result = await Task.Run(() => plc.WriteValue(plc_addrs["right"], (short)quanxian, DataType.Short)); + if (result.IsSuccess) + { + CommonMethods.AddDataMonitorLog(1, $"Write_PLC_permission_{quanxian}({plc_addrs["right"]})_Successful"); + } + else + { + CommonMethods.AddDataMonitorLog(2, $"Write_PLC_permission_{quanxian}({plc_addrs["right"]})_Failed"); + } + } + + if (!string.IsNullOrEmpty(plc_addrs["user"])) + { + const int BARCODE_SIZE = 40; + string loginName = string.Concat(CommonMethods.currentAdmin.LoginName + GetString_0(BARCODE_SIZE - CommonMethods.currentAdmin.LoginName.Length)); + byte[] codeBytes = Encoding.Default.GetBytes(loginName).ByteReverse(); + JYResult result2 = await Task.Run(() => plc.WriteValue(plc_addrs["user"], codeBytes, DataType.ArrByte)); + if (result2.IsSuccess) + { + CommonMethods.AddDataMonitorLog(1, $"Write_PLC_username_{loginName}({plc_addrs["user"]})_Successful\n"); + } + else + { + CommonMethods.AddDataMonitorLog(2, $"Write_PLC_username_{loginName}({plc_addrs["user"]})_Failed"); + } + } + } + + #endregion + + #region 获取白夜班次 + bool qiehuan = false; + private void SetClass() + { + try + { + var nowDate = DateTime.Now; + string strClass = ""; + DateTime time1 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {CommonMethods.ChangeClassTime}"); + DateTime time2 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {Convert.ToDateTime(CommonMethods.ChangeClassTime).AddHours(12).ToString("HH:mm:ss")}"); + if (nowDate <= time1 && nowDate >= time2) + { + foreach (var plc in CommonMethods.plcDevices) + { + if (_plcDeviceMapping.TryGetValue(plc, out var plcDevices)) + { + foreach (var plcDevice in plcDevices) + { + if (plcDevice.IsConnected) + { + if (!qiehuan) + { + if (!SetPlcTime(plc)) + { + CommonMethods.AddLog(true, $"PC写入PLC时间失败".Translated()); + } + else + { + qiehuan = true; + CommonMethods.AddLog(false, "PC写入PLC时间成功".Translated()); + } + } + } + } + strClass = "白班".Translated(); + } + } + } + else + { + qiehuan = false; + strClass = "夜班".Translated(); + } + CommonMethods.strClass = strClass; + } + catch (Exception ex) + { + CommonMethods.AddLog(true, "PC写入PLC时间异常".Translated() + ":" + ex.Message); + LogHelper.Instance.WriteEX(ex); + } + } + #endregion + + #region 写入PLC时间 + /// + /// 写当前时间给PLC + /// + private bool SetPlcTime(PlcReadWriteBase plcDevice) + { + var nowDate = DateTime.Now; + string yearStr = nowDate.Year.ToString(); + + + bool IsSuccess = false; + + // 为防止PLC时间出现偏差,每次自动运行的时候写PLC系统时间 + short[] writeArr = new short[] + { + Convert.ToInt16(nowDate.Year),//D70 + Convert.ToInt16(nowDate.Month),//D71 + Convert.ToInt16(nowDate.Day),//D72 + Convert.ToInt16(nowDate.Hour),//D73 + Convert.ToInt16(nowDate.Minute),//D74 + Convert.ToInt16(nowDate.Second),//D75 + (short)1 //D76 + }; + if (plcDevice.IsConnected) + { + JYResult result = plcDevice.WriteValue("D70", writeArr, DataType.ArrShort); + if (result.IsSuccess) + { + IsSuccess = true; + } + } + return IsSuccess; + + } + #endregion + + #region 9、IDisposable 实现 + + + // 如果需要在StopAsync中也显示进度,可以添加一个进度回调 + + //private Task processTask; + + public async Task StopAsync(IProgress progress = null) + { + progress?.Report("正在停止控制中心..."); + + // 停止健康监控 + if (_healthMonitorTimer != null) + { + _healthMonitorTimer.Stop(); + _healthMonitorTimer.Dispose(); + } + + // 取消所有操作 + if (_cts != null) + { + _cts.Cancel(); + } + _isWorkerRunning = false; + _taskEvent.Set(); + + // 等待心跳任务完成 + if (_heartbeatTask != null) + { + progress?.Report("停止心跳任务..."); + try + { + // 使用Wait带超时 + _heartbeatTask.Wait(5000); + } + catch (AggregateException) { } + catch { } + } + + // 停止所有PLC读取线程 + progress?.Report("停止PLC读取线程..."); + StopAndCleanOldThreads(); + + // 等待工作线程完成 + if (_workerThread != null && _workerThread.IsAlive) + { + progress?.Report("停止工作线程..."); + _workerThread.Join(5000); + } + + // 清理队列 + int remainingTasks = _taskQueue.Count; + if (remainingTasks > 0) + { + progress?.Report($"清理剩余{remainingTasks}个任务..."); + while (_taskQueue.TryDequeue(out _)) { } + } + + progress?.Report("控制中心已停止"); + } + + public void Dispose() + { + if (_isDisposed) return; + _isDisposed = true; + + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _isWorkerRunning = false; + _taskEvent.Set(); + _taskEvent.Dispose(); + + if (_cts != null) + { + _cts.Cancel(); + _cts.Dispose(); + } + + if (_healthMonitorTimer != null) + { + _healthMonitorTimer.Stop(); + _healthMonitorTimer.Dispose(); + } + + _dbSemaphore?.Dispose(); + _plcWriteSemaphore?.Dispose(); + + if (_timerRefreshData != null) + { + _timerRefreshData.Stop(); + _timerRefreshData.Dispose(); + } + + foreach (var plc in CommonMethods.plcDevices) + { + try + { + plc.Disconnect(); + } + catch { } + } + + CommonMethods.plcDevices?.Clear(); + _plcDeviceMapping?.Clear(); + _plcAlarmReaders?.Clear(); + CommonMethods.plcStatuses?.Clear(); + + _groupStatus?.Clear(); + _stationFunctions?.Clear(); + } + } + + #endregion + + #region 7、辅助方法 + + private static PLCType GetPLCTypeEnum(string plcTypeString) + { + if (Enum.TryParse(plcTypeString, out PLCType plcType)) + { + return plcType; + } + throw new ArgumentException($"PLC 类型无效: {plcTypeString}"); + } + + #endregion + + #region 诊断日志 + + private void StartDiagnosticMonitor() + { + Thread monitorThread = new Thread(() => + { + while (!_cts.Token.IsCancellationRequested) + { + try + { + Thread.Sleep(60000); // 每分钟输出一次报告 + + // 检查关键工站是否卡死 + CheckStuckStation("物流线料盘进站"); + CheckStuckStation("物流线料盘来料"); + CheckStuckStation("电池进站"); + + // 输出诊断报告 + var report = StationDiagnostics.GetDiagnosticReport(); + LogHelper.Instance.WriteLog(report); + + // 输出系统状态 + LogHelper.Instance.WriteLog($"【系统状态】队列大小={_taskQueue.Count} | 工作线程运行={_isWorkerRunning} | 总处理={_totalProcessedCount} | 总拒绝={_totalRejectedCount}"); + + // 检查PLC连接状态 + foreach (var plc in CommonMethods.plcDevices) + { + if (plc != null) + { + LogHelper.Instance.WriteLog($"【PLC状态】{plc.Name} | IsConnected={plc.IsConnected}"); + } + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"监控线程异常:{ex.Message}"); + } + } + }); + monitorThread.IsBackground = true; + monitorThread.Name = "DiagnosticMonitor"; + monitorThread.Start(); + } + + public string GetStationStatus(string stationName) + { + lock (_statusLock) + { + var status = _groupStatus.ContainsKey(stationName) ? _groupStatus[stationName] : -1; + var queueSize = _taskQueue.Count; + var workerAlive = _workerThread?.IsAlive ?? false; + + return $"工站:{stationName} 状态:{status} 队列:{queueSize} 工作线程存活:{workerAlive}"; + } + } + + // 手动重置卡死的工站 + public void ResetStation(string stationName) + { + lock (_statusLock) + { + if (_groupStatus.ContainsKey(stationName)) + { + _groupStatus[stationName] = 0; + LogHelper.Instance.WriteLog($"手动重置工站: {stationName}"); + } + } + } + + private void CheckStuckStation(string stationName) + { + // 检查是否有工站卡在处理中状态超过30秒 + lock (_statusLock) + { + if (_groupStatus.ContainsKey(stationName) && _groupStatus[stationName] == 1) + { + LogHelper.Instance.WriteError($"【诊断-卡死检测】{stationName} | 状态为1(处理中)已超过30秒,可能已卡死"); + } + } + } + public class StationDiagnostics + { + private static readonly object _lock = new object(); + private static Dictionary> _triggerHistory = new Dictionary>(); + private static Dictionary _timeoutCount = new Dictionary(); + private static Dictionary _lastTriggerTime = new Dictionary(); + private static Dictionary _lastCompleteTime = new Dictionary(); + + /// + /// 记录触发信号 + /// + public static void LogTrigger(string stationName, short trigValue, int status) + { + lock (_lock) + { + if (!_triggerHistory.ContainsKey(stationName)) + _triggerHistory[stationName] = new Queue(); + + _triggerHistory[stationName].Enqueue(DateTime.Now); + + // 只保留最近100条记录 + while (_triggerHistory[stationName].Count > 100) + _triggerHistory[stationName].Dequeue(); + + _lastTriggerTime[stationName] = DateTime.Now; + + LogHelper.Instance.WriteLog($"【诊断-触发】{stationName} | Trig={trigValue} | Status={status} | 队列长度={_triggerHistory[stationName].Count}"); + } + } + + /// + /// 记录任务入队 + /// + public static void LogTaskEnqueued(string stationName, int queueSize) + { + lock (_lock) + { + LogHelper.Instance.WriteLog($"【诊断-入队】{stationName} | 当前队列大小={queueSize}"); + } + } + + /// + /// 记录任务开始执行 + /// + public static void LogTaskStart(string stationName) + { + lock (_lock) + { + var now = DateTime.Now; + if (_lastTriggerTime.ContainsKey(stationName)) + { + var waitTime = (now - _lastTriggerTime[stationName]).TotalMilliseconds; + LogHelper.Instance.WriteLog($"【诊断-执行开始】{stationName} | 等待时间={waitTime:F0}ms"); + } + else + { + LogHelper.Instance.WriteLog($"【诊断-执行开始】{stationName}"); + } + } + } + + /// + /// 记录任务完成 + /// + public static void LogTaskComplete(string stationName, bool success, string errorMsg = "") + { + lock (_lock) + { + _lastCompleteTime[stationName] = DateTime.Now; + LogHelper.Instance.WriteLog($"【诊断-执行完成】{stationName} | 成功={success} | 错误={errorMsg}"); + } + } + + /// + /// 记录超时 + /// + public static void LogTimeout(string stationName, int timeoutSeconds) + { + lock (_lock) + { + if (!_timeoutCount.ContainsKey(stationName)) + _timeoutCount[stationName] = 0; + + _timeoutCount[stationName]++; + + LogHelper.Instance.WriteError($"【诊断-超时】{stationName} | 超时时间={timeoutSeconds}秒 | 累计超时次数={_timeoutCount[stationName]}"); + } + } + + /// + /// 获取诊断报告 + /// + public static string GetDiagnosticReport() + { + lock (_lock) + { + var sb = new StringBuilder(); + sb.AppendLine("=== 工站诊断报告 ==="); + + foreach (var station in _triggerHistory.Keys) + { + sb.AppendLine($"工站: {station}"); + sb.AppendLine($" 最近触发时间: {(_lastTriggerTime.ContainsKey(station) ? _lastTriggerTime[station].ToString() : "无")}"); + sb.AppendLine($" 最近完成时间: {(_lastCompleteTime.ContainsKey(station) ? _lastCompleteTime[station].ToString() : "无")}"); + sb.AppendLine($" 触发次数(最近100): {_triggerHistory[station].Count}"); + sb.AppendLine($" 超时次数: {(_timeoutCount.ContainsKey(station) ? _timeoutCount[station] : 0)}"); + + if (_lastTriggerTime.ContainsKey(station) && _lastCompleteTime.ContainsKey(station)) + { + var processingTime = _lastCompleteTime[station] - _lastTriggerTime[station]; + sb.AppendLine($" 最近处理耗时: {processingTime.TotalMilliseconds:F0}ms"); + } + sb.AppendLine(); + } + + return sb.ToString(); + } + } + } + #endregion + } +} \ No newline at end of file diff --git a/JinYuan.ControlCenter/ControlCenter_Ext.cs b/JinYuan.ControlCenter/ControlCenter_Ext.cs new file mode 100644 index 0000000..bd636f1 --- /dev/null +++ b/JinYuan.ControlCenter/ControlCenter_Ext.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JinYuan.Helper; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using PLCCommunication.Common; +using PLCCommunication.Common.DataConvert; + +namespace JinYuan.ControlCenters +{ + public partial class ControlCenter + { + public static string GetValueFromByteArray(byte[] bArray, string PLCGroupVariablekey, int offset = 0, Group pf = null) + { + return GetValueFromByteArray(bArray, getPLCVariable(PLCGroupVariablekey), offset, pf); + } + + public static PLCGroupVariable getPLCVariable(string key) + { + PLCGroupVariable pLCGroupVariable = new PLCGroupVariable(); + CommonMethods.PLCVariable.TryGetValue(key, out pLCGroupVariable); + return pLCGroupVariable; + } + + /// + /// 获取MES返回结果 + /// + /// + /// + /// + /// + /// + public static string GetValueFromByteArray(byte[] bArray, PLCGroupVariable var, int offset = 0, Group pf = null) + { + string value = "0"; + try + { + switch (var.DataType) + { + case "Float": + value = FloatLib.GetFloatFromByteArray(bArray, var.ArrayStart * 2 + offset, DataFormat.CDAB).ToString("0.###"); + break; + case "Short": + value = ShortLib.GetShortFromByteArray(bArray, var.ArrayStart * 2 + offset).ToString(); + break; + case "Int": + value = IntLib.GetIntFromByteArray(bArray, var.ArrayStart * 2 + offset).ToString(); + break; + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"数据解析异常, 原因: {ex}", "SysErrorLog"); + } + return value; + } + } +} diff --git a/JinYuan.ControlCenter/ControlCenter_Plc.cs b/JinYuan.ControlCenter/ControlCenter_Plc.cs new file mode 100644 index 0000000..85cdc82 --- /dev/null +++ b/JinYuan.ControlCenter/ControlCenter_Plc.cs @@ -0,0 +1,2244 @@ + +using JinYuan.Helper; +using JinYuan.MES.Enums; +using JinYuan.MES.Models; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using JinYuan.VirtualDataLibrary.Utlis; +using Language; +using PLC; +using PLCCommunication; +using PLCCommunication.Common; +using PLCCommunication.Common.DataConvert; +using SqlSugar; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Diagnostics.Eventing.Reader; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.Policy; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using static System.Runtime.CompilerServices.RuntimeHelpers; +using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; + + +namespace JinYuan.ControlCenters +{ + public partial class ControlCenter + { + private static readonly SemaphoreSlim _plcSemaphore = new SemaphoreSlim(5, 10); // PLC操作并发限制 + private static readonly SemaphoreSlim _dbSemaphore = new SemaphoreSlim(10, 20); // 数据库操作并发限制 + private static readonly object _fileLock = new object(); // 文件锁 + //private static readonly TimeSpan _plcTimeout = TimeSpan.FromSeconds(1); // PLC操作超时 + //private static readonly TimeSpan _mesTimeout = TimeSpan.FromSeconds(2); // MES请求超时 + + // UI同步上下文:避免跨线程阻塞UI + private readonly SynchronizationContext _uiSyncContext = SynchronizationContext.Current; + + #region 保留2位小数 + private float SaveTwoNum(float TNum) + { + return (float)Math.Round(TNum, 2, MidpointRounding.AwayFromZero); + } + #endregion + + #region PLC设备安全访问 + /// + /// 安全获取PLC设备 + /// + /// PLC编号(从1开始) + /// PLC设备实例,若不存在或未连接则返回null + private PlcReadWriteBase GetPlcDevice(int plcNum) + { + try + { + if (CommonMethods.plcDevices != null && plcNum > 0) + { + // 根据PLC编号查找设备,而不是依赖列表索引 + var plcDevice = CommonMethods.plcDevices.FirstOrDefault(p => + p != null && + p.Name == $"PLC_{plcNum}" && + p.IsConnected); + + if (plcDevice != null) + { + return plcDevice; + } + } + } + catch { } + return null; + } + #endregion + + + #region 物流线料盘来料 + /// + /// 物流线料盘来料 + /// + private async Task TrayFeedingStation(JYResult bArrays, object plcModel) + { + LogHelper.Instance.WriteLog($"Step 1: 进入 TrayFeedingStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + PlcGroup pf = plcModel as PlcGroup; + if (pf == null) + { + LogHelper.Instance.WriteError("PLC模型转换失败", "WuLiuLog"); + + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 2); //反馈结果 1OK 2NG + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); //反馈处理完成 + return; + } + + using (var timer = new TimedOperation("物流线料盘来料", (elapsedMs, operationName) => + { + CommonMethods.AddDataMonitorLog(0, $"物流线料盘来料共耗时:{operationName} 执行耗时:{elapsedMs}ms"); + })) + { + if (!bArrays.IsSuccess || bArrays.Content == null) + { + await HandleFeedingError(pf, "PLC读地址无料框码数据", null); + return; + } + + try + { + LogHelper.Instance.WriteLog($"Step 2: ClearPLCRegistersBatch - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + + // 1. 批量清空PLC寄存器 + await ClearPLCRegistersBatch(pf, new[] { 2, 3, 4 }, 0).ConfigureAwait(false); + + #region 数据解析 + const int BARCODE_SIZE = 40; + byte[] bytes = bArrays.Content.ByteReverse();//高低位转换 + string trayID = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding(bytes, 0, BARCODE_SIZE, Encoding.ASCII)); + + #endregion + + LogHelper.Instance.WriteLog($"Step 3: 数据解析: 料盘码【{trayID}】", "WuLiuLog"); + + if (!IsValidTrayID(trayID)) + { + await HandleFeedingError(pf, $"料框码无效:{trayID}", trayID); + return; + } + + var mesResult = await GetTrayInfoWithTimeout(pf, trayID, 500); + LogHelper.Instance.WriteLog($"Step 4: GetTrayInfoWithTimeout: 料盘码【{trayID}】", "WuLiuLog"); + + if (!mesResult.Success || mesResult.TrayInfo == null) + { + await HandleFeedingError(pf, mesResult.ErrorMessage, trayID); + + return; + } + + //获取电池型号 + var modelType = mesResult.TrayInfo.productCode; + + // 获取电池档位信息 + var gradeResult = await GetBatteryGradesWithTimeout(mesResult.TrayInfo, 500); + LogHelper.Instance.WriteLog($"Step 5: 获取电池档位: 料盘码【{trayID}】", "WuLiuLog"); + + string finalGrade = gradeResult.Grade; + string gradeRemark = gradeResult.IsConsistent ? "" : gradeResult.ErrorMessage; + + LogHelper.Instance.WriteLog($"Step 6:物流线料盘来料: 获取电池型号【{modelType}】,电池档位:【{gradeResult}】{gradeRemark}", "WuLiuLog"); + + // 构建并保存实体 + var mesTrayEntity = BuildTrayEntity(mesResult.TrayInfo, finalGrade, gradeRemark); + await SaveTrayDataBatchAsync(new List { mesTrayEntity }).ConfigureAwait(false); + LogHelper.Instance.WriteLog($"Step 7: 保存数据: 料盘码【{trayID}】", "WuLiuLog"); + + // 反馈PLC + await FeedBackToPLC(pf, mesResult.TrayInfo, finalGrade); + LogHelper.Instance.WriteLog($"Step 8: 写PLC: 料盘码【{trayID}】", "WuLiuLog"); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"物流线料盘来料异常: {ex}", "WuLiuLog"); + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 2); //反馈结果 1 OK 2 NG + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); //反馈处理完成 + } + } + } + + + /// + /// 带超时的MES料盘信息获取 + /// + private async Task<(bool Success, TrayInfo TrayInfo, string ErrorMessage)> GetTrayInfoWithTimeout(PlcGroup pf, string trayID, int timeoutMs) + { + var task = QueryMesTrayInfos(pf, trayID, CancellationToken.None); + + if (await Task.WhenAny(task, Task.Delay(timeoutMs)) != task) + { + return (false, null, "MES请求超时"); + } + + var result = await task; + return (result.success, result.trayinfo, result.mesMessage); + } + + /// + /// 等级查询结果 + /// + private class GradeQueryResult + { + public string Grade { get; set; } + public bool IsConsistent { get; set; } + public string ErrorMessage { get; set; } + } + + + /// + /// 带超时的电池等级查询 + /// + private async Task GetBatteryGradesWithTimeout(TrayInfo trayInfo, int timeoutMs) + { + var result = new GradeQueryResult { Grade = "", IsConsistent = true, ErrorMessage = "" }; + + // 构建电池条码列表 + var listCode = BuildMaterialLotList(trayInfo); + + if (listCode.Count == 0) + { + result.ErrorMessage = "料盘中无电池条码"; + CommonMethods.AddDataMonitorLog(0, result.ErrorMessage); + return result; + } + + var gradeTask = QueryGrades(listCode, CancellationToken.None); + + if (await Task.WhenAny(gradeTask, Task.Delay(timeoutMs)) != gradeTask) + { + result.ErrorMessage = "电池等级查询超时"; + result.IsConsistent = false; + CommonMethods.AddDataMonitorLog(0, result.ErrorMessage); + return result; + } + + var gradeResult = await gradeTask; + + if (!gradeResult.success || gradeResult.batteryInfo == null || gradeResult.batteryInfo.Count == 0) + { + result.ErrorMessage = "电池等级查询失败或无数据"; + result.IsConsistent = false; + CommonMethods.AddDataMonitorLog(0, result.ErrorMessage); + return result; + } + + // 检查等级一致性 + var grades = gradeResult.batteryInfo.Where(g => !string.IsNullOrEmpty(g?.grade)).Select(g => g.grade).Distinct().ToList(); + + if (grades.Count == 0) + { + result.ErrorMessage = "未获取到有效的电池等级"; + result.IsConsistent = false; + CommonMethods.AddDataMonitorLog(0, result.ErrorMessage); + return result; + } + + if (grades.Count == 1) + { + result.Grade = grades[0]; + result.IsConsistent = true; + CommonMethods.AddDataMonitorLog(0, $"电池等级查询成功,所有电池等级一致: {result.Grade}"); + } + else + { + result.ErrorMessage = $"电池等级不一致!检测到多个等级: {string.Join(",", grades)}"; + result.IsConsistent = false; + LogHelper.Instance.WriteError(result.ErrorMessage, "WuLiuLog"); + CommonMethods.AddDataMonitorLog(0, result.ErrorMessage); + } + + return result; + } + + /// + /// 构建MaterialLot列表 + /// + private List BuildMaterialLotList(TrayInfo trayInfo) + { + var listCode = new List(); + + if (trayInfo?.cellList == null) return listCode; + + foreach (var cell in trayInfo.cellList) + { + if (!string.IsNullOrEmpty(cell.cellNo)) + { + listCode.Add(new MaterialLot + { + identification = cell.cellNo, + locationBat = cell.channel.ToString() + }); + } + } + + return listCode; + } + + /// + /// 构建TrayEntity实体 + /// + private TrayEntity BuildTrayEntity(TrayInfo trayInfo, string grade, string gradeRemark) + { + return new TrayEntity + { + trayID = trayInfo?.trayNo ?? "", + model = trayInfo?.productCode ?? CommonMethods.mesConfig.ModelName, + grade = grade, + moreGrade = "", + Count = trayInfo?.cellList?.Count ?? 0, + GongWei = CommonMethods.sysConfig.GongWei, + Time = DateTime.Now, + Result = string.IsNullOrEmpty(gradeRemark) ? "OK" : "NG", + Remark = string.IsNullOrEmpty(gradeRemark) + ? $"本机架电池型号{CommonMethods.mesConfig.ModelName}, 处理档位{string.Join("|", CommonMethods.GetValidGrades())}" + : gradeRemark + }; + } + + /// + /// 反馈结果到PLC + /// + private async Task FeedBackToPLC(PlcGroup pf, TrayInfo trayInfo, string grade) + { + short model = (short)CommonMethods.mesConfig.GetModel(trayInfo?.productCode ?? CommonMethods.mesConfig.ModelName); + if (model == 0) model = 1; + + short gradeCode = 99; + if (!string.IsNullOrEmpty(grade)) + gradeCode = (short)CommonMethods.GetGradeNo(grade); + + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, model); + await WritePLCInt16Sync(pf, pf.VarList[3].VarAddress, gradeCode); + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 1); + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); + + CommonMethods.AddDataMonitorLog(0, $"物流线料盘来料[{trayInfo.trayNo}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号{model}(mes获取的原型号:{trayInfo?.productCode}); [{pf.VarList[3].VarAddress}]写挡位{gradeCode}({grade})"); + LogHelper.Instance.WriteLog($"物流线料盘来料[{trayInfo.trayNo}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号{model}(mes获取的原型号:{trayInfo?.productCode}); [{pf.VarList[3].VarAddress}]写挡位{gradeCode}({grade})", "WuLiuLog"); + } + + + /// + /// 处理错误并反馈PLC + /// + private async Task HandleFeedingError(PlcGroup pf, string errorMessage, string trayID) + { + var mesTrayEntity = new TrayEntity + { + trayID = trayID ?? "", + model = "", + grade = "", + moreGrade = "", + Count = 0, + GongWei = CommonMethods.sysConfig.GongWei, + Time = DateTime.Now, + Result = "NG", + Remark = errorMessage + }; + + await SaveTrayDataBatchAsync(new List { mesTrayEntity }); + + + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 2); //反馈结果 1OK 2NG + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); //反馈处理完成 + + CommonMethods.AddDataMonitorLog(0, $"料盘码[{trayID}]:" + errorMessage); + LogHelper.Instance.WriteLog($"料盘码[{trayID}]:" + errorMessage, "WuLiuLog"); + } + + // MES查询方法 + private async Task<(bool success, string mesMessage, MesResType mesResType, TrayInfo trayinfo)> QueryMesTrayInfos(PlcGroup plcGroup, string trayID, CancellationToken token) + { + token.ThrowIfCancellationRequested(); + + try + { + var (success, mesMessage, mesResType, trayinfo) = await CommonMethods.hbgMes.QueryMesTrayInfosAsync( + CommonMethods.mesConfig.queryTrayUrl, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + trayID, + CommonMethods.mesConfig.MaterialCode, + CommonMethods.mesConfig.mesUserName + ); + return (success, mesMessage, mesResType, trayinfo); + } + catch (OperationCanceledException) + { + // 超时, 快速返回,不等待 + return (false, "MES查询超时", MesResType.B, null); + } + catch (Exception ex) + { + // 其他错误 + LogHelper.Instance.WriteEX(ex); + return (false, "MES查询失败", MesResType.B, null); + } + } + + + private async Task<(bool success, List batteryInfo)> QueryGrades(List listCode, CancellationToken token) + { + token.ThrowIfCancellationRequested(); + + if (listCode == null || listCode.Count == 0) + { + return (false, null); + } + + try + { + var (success, batteryInfo) = await CommonMethods.hbgMes.QueryGradeAsync( + CommonMethods.mesConfig.queryGradeUrl, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + listCode.Count.ToString(), + CommonMethods.mesConfig.MaterialCode, + CommonMethods.mesConfig.mesUserName, + listCode + ); + return (success, batteryInfo); + } + catch (OperationCanceledException) + { + // 超时, 快速返回,不等待 + LogHelper.Instance.WriteError($"查询电池等级超时", "WuLiuLog"); + return (false, null); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"查询电池等级异常: {ex.Message}", "WuLiuLog"); + return (false, null); + } + } + + + #endregion + + + #region 物流线料盘进站 + /// + /// 物流线料盘进站 + /// + private async Task CheckTrayStation(JYResult bArrays, object plcModel) + { + LogHelper.Instance.WriteLog($"Step 1: 进入 CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + PlcGroup pf = plcModel as PlcGroup; + if (pf == null) + { + LogHelper.Instance.WriteError("PLC模型转换失败", "WuLiuLog"); + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 2); //反馈结果 1OK 2NG + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); //反馈处理完成 + return; + } + + using (var timer = new TimedOperation("物流线料盘进站", (elapsedMs, operationName) => + { + CommonMethods.AddDataMonitorLog(0, $"物流线料盘进站共耗时:{operationName} 执行耗时:{elapsedMs}ms"); + })) + { + LogHelper.Instance.WriteLog($"Step 2: 判断bArrays CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + + if (!bArrays.IsSuccess || bArrays.Content == null) + { + await HandleCheckError(pf, "PLC读地址无料框码数据", null); + return; + } + + try + { + LogHelper.Instance.WriteLog($"Step 3: ClearPLCRegistersBatch CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + // 批量清空寄存器 + await ClearPLCRegistersBatch(pf, new[] { 2, 3, 4 }, 0).ConfigureAwait(false); + + #region 数据解析 + const int BARCODE_SIZE = 40; + LogHelper.Instance.WriteLog($"Step 4: 数据解析 CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + byte[] bytes = bArrays.Content.ByteReverse();//高低位转换 + // 读取料盘码 + string trayID = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding(bytes, 0, BARCODE_SIZE, Encoding.ASCII)); + + #endregion + + LogHelper.Instance.WriteLog($"Step 5: 验证料框码ID CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + // 验证卡板ID + if (!IsValidTrayID(trayID)) + { + await HandleCheckError(pf, $"料框码无效:{trayID}", trayID); + return; + } + + // 获取MES料盘信息 + var mesResult = await GetTrayInfoWithTimeout(pf, trayID, 500); + + if (!mesResult.Success || mesResult.TrayInfo == null) + { + await HandleCheckError(pf, mesResult.ErrorMessage, trayID); + return; + } + + LogHelper.Instance.WriteLog($"Step 8: 组合TrayEntity CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + + // 获取电池等级信息 + var gradeResult = await GetBatteryGradesWithTimeout(mesResult.TrayInfo, 500); + string finalGrade = gradeResult.IsConsistent ? gradeResult.Grade : CommonMethods.curFdConfig.Grade1; + string add = (gradeResult.Grade == null || string.IsNullOrEmpty(gradeResult.Grade)) ? ",临时使用本机架1垛位的挡位" : ""; + string gradeRemark = gradeResult.IsConsistent ? "" : gradeResult.ErrorMessage + add; + + // 反馈电池条码到PLC + //await WriteBatteryBarcodesToPLC(pf, mesResult.TrayInfo); + + + // 构建并保存实体 + var mesTrayEntity = BuildTrayEntity(mesResult.TrayInfo, finalGrade, gradeRemark); + await SaveTrayDataBatchAsync(new List { mesTrayEntity }).ConfigureAwait(false); + + // 反馈PLC + await FeedBackToPLCCheck(pf, mesResult.TrayInfo, finalGrade); + LogHelper.Instance.WriteLog($"物流线料盘进站:料框码:{trayID},往PLC地址[{pf.VarList[4].VarAddress}]写1(OK)", "WuLiuLog"); + LogHelper.Instance.WriteLog($"Step 11: 结束 CheckTrayStation - {DateTime.Now:HH:mm:ss.fff}", "WuLiuLog"); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"物流线料盘进站异常: {ex}", "WuLiuLog"); + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 2); //反馈结果 1OK 2NG + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); //反馈处理完成 + } + } + } + + /// + /// 进站反馈结果到PLC + /// + private async Task FeedBackToPLCCheck(PlcGroup pf, TrayInfo trayInfo, string grade) + { + short model = (short)CommonMethods.mesConfig.GetModel(trayInfo?.productCode ?? CommonMethods.mesConfig.ModelName); + if (model == 0) model = 1; + + short gradeCode = 99; // 默认NG档位 + if (!string.IsNullOrEmpty(grade)) + gradeCode = (short)CommonMethods.GetGradeNo(grade); + + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, model); + await WritePLCInt16Sync(pf, pf.VarList[3].VarAddress, gradeCode); + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 1); + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); + + CommonMethods.AddDataMonitorLog(0, $"物流线料盘进站[{trayInfo.trayNo}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号{model}(mes获取的原型号:{trayInfo?.productCode}); [{pf.VarList[3].VarAddress}]写挡位{gradeCode}({grade})"); + LogHelper.Instance.WriteError($"物流线料盘进站[{trayInfo.trayNo}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号{model}(mes获取的原型号:{trayInfo?.productCode}); [{pf.VarList[3].VarAddress}]写挡位{gradeCode}({grade})", "WuLiuLog"); + LogHelper.Instance.WriteLog($"物流线料盘进站完成", "WuLiuLog"); + } + + /// + /// 处理进站错误 + /// + private async Task HandleCheckError(PlcGroup pf, string errorMessage, string trayID) + { + var mesTrayEntity = new TrayEntity + { + trayID = trayID ?? "", + model = "", + grade = "", + moreGrade = "", + Count = 0, + GongWei = CommonMethods.sysConfig.GongWei, + Time = DateTime.Now, + Result = "NG", + Remark = errorMessage + }; + + await SaveTrayDataBatchAsync(new List { mesTrayEntity }); + + short model = (short)CommonMethods.mesConfig.GetModel(CommonMethods.mesConfig.ModelName); + if (model == 0) model = 1; + + short gradeCode = 99; // 默认NG档位 + + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, model); + await WritePLCInt16Sync(pf, pf.VarList[3].VarAddress, gradeCode);//档位NG 99 + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, 2); + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); + + CommonMethods.AddDataMonitorLog(0, $"物流线料盘进站[{trayID}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号1(mes获取的原型号:无); [{pf.VarList[3].VarAddress}]写挡位99(NG)"); + LogHelper.Instance.WriteError($"物流线料盘进站[{trayID}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号1(mes获取的原型号:无); [{pf.VarList[3].VarAddress}]写挡位99(NG)", "WuLiuLog"); + + CommonMethods.AddDataMonitorLog(0, errorMessage); + } + + /// + /// 保存料盘数据 + /// + /// + /// + private async Task SaveTrayDataBatchAsync(List list) + { + if (list == null || list.Count == 0) + return; + + try + { + foreach (var m in list) + { + if (string.IsNullOrEmpty(m.trayID)) + { + m.Remark += " 料盘ID为空,跳过"; + continue; + } + try + { + int updateCount = await CommonMethods.db.UpdateSingleAsync(m, null, it => it.trayID == m.trayID); + + if (updateCount > 0) + { + m.Remark += " 更新Yes"; + } + else + { + // 新增时直接调用底层,减少封装开销 + bool addSuccess = await Task.Run(() => + CommonMethods.db.AddReturnBoolAsync(m) + ); + m.Remark += addSuccess ? " 新增Yes" : " 新增No"; + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"物流线进站保存{m.trayID}处理异常:{ex}", "WuLiuLog"); + continue; + } + + } + + _uiSyncContext.Post(_ => CommonMethods.ShowTrayDataDelegate?.Invoke(list), null); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"物流线进站保存处理异常:{ex}", "WuLiuLog"); + throw; + } + finally + { + // _dbSemaphore.Release(); + } + } + + + + private bool IsValidTrayID(string trayID) + { + return !string.IsNullOrWhiteSpace(trayID) && + !trayID.ToUpper().Trim().Equals("ERROR", StringComparison.OrdinalIgnoreCase) && + trayID.Length >= 3; // 增加字母数字校验,提前过滤无效数据 + } + + #endregion + + + #region 电池进站 + + /// + /// 电池进站 + /// + private async Task FeedingStation(JYResult bArrays, object plcModel) + { + LogHelper.Instance.WriteLog($"Step 1: 进入 FeedingStation - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + PlcGroup pf = plcModel as PlcGroup; + if (pf == null) + { + LogHelper.Instance.WriteLog("PLC模型转换失败", "ZuPanLog"); + + WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 2); + + return; + } + + Stopwatch sw = Stopwatch.StartNew(); + try + { + LogHelper.Instance.WriteLog($"Step 2: 判断bArrays FeedingStation - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + + if (!bArrays.IsSuccess || bArrays.Content == null) + { + await HandleFeedingStationError(pf, "PLC读地址无料框码数据,不存库", null, null); + return; + } + + LogHelper.Instance.WriteLog($"Step 3.1: ClearPLCRegistersBatch FeedingStation - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + + #region 清空上一次寄存器数据 + // 批量清空寄存器 + await ClearPLCRegistersBatch(pf, new[] { 3, 4, 5 }, 0); + + LogHelper.Instance.WriteLog($"Step 3.2: Clear电池条码 FeedingStation - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + // 清空电池条码区域 + await ClearBatteryBarcodeArea(pf); + #endregion + + #region 数据解析 + const int BARCODE_SIZE = 40; + byte[] bytes = bArrays.Content.ByteReverse(); + string trayID = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding(bytes, 0, BARCODE_SIZE, Encoding.ASCII)); + #endregion + + if (!IsValidTrayID(trayID)) + { + await HandleFeedingStationError(pf, "料框码无效,不存库", trayID, null); + return; + } + + CommonMethods.AddDataMonitorLog(0, $"PLC读地址料框码数据,PLC地址[{pf.VarList[1].VarAddress}]:料框码{trayID}"); + + // 获取MES料盘信息 + var mesResult = await GetTrayInfoWithTimeout(pf, trayID, 500); + if (!mesResult.Success || mesResult.TrayInfo == null) + { + await HandleFeedingStationError(pf, mesResult.ErrorMessage, trayID, mesResult.TrayInfo); + return; + } + + // 获取电池等级信息 + var gradeResult = await GetBatteryGradesWithTimeout(mesResult.TrayInfo, 500); + string finalGrade = gradeResult.IsConsistent ? gradeResult.Grade : CommonMethods.curFdConfig.Grade1; + string add = (gradeResult.Grade == null || string.IsNullOrEmpty(gradeResult.Grade) )? ",临时使用本机架1垛位的挡位" : ""; + string gradeRemark = gradeResult.IsConsistent ? "" : gradeResult.ErrorMessage + add; + + // 反馈电池条码到PLC + await WriteBatteryBarcodesToPLC(pf, mesResult.TrayInfo); + + // 构建保存数据 + var feedingList = BuildFeedingEntityList(mesResult.TrayInfo, finalGrade, gradeRemark); + await SaveFeedingDataBatchAsync(feedingList); + + // 反馈结果到PLC + await FeedBackToPLCLayer(pf, mesResult.TrayInfo, finalGrade); + + LogHelper.Instance.WriteLog($"Step 12: 结束 FeedingStation - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + } + catch (Exception ex) + { + LogHelper.Instance.WriteLog($"电池上料组盘线程处理异常:{ex}", "ZuPanLog"); + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 2); + } + finally + { + sw.Stop(); + CommonMethods.AddDataMonitorLog(0, "组盘上料共耗时".Translated() + $":{sw.Elapsed.TotalMilliseconds}ms"); + } + } + + /// + /// 清空电池条码区域 + /// + private async Task ClearBatteryBarcodeArea(PlcGroup pf) + { + const int BARCODE_SIZE = 40; + int trayCapacity = 40; + string strBatteryIDBar = ""; + for (int i = 0; i < trayCapacity; i++) + { + strBatteryIDBar += GetString_0(BARCODE_SIZE); + } + + byte[] codeBytes = Encoding.Default.GetBytes(strBatteryIDBar).ByteReverse(); + var plcDevice = GetPlcDevice(pf.PlcNum); + if (plcDevice != null) + { + plcDevice.WriteValue(pf.VarList[2].VarAddress, codeBytes, PLC.DataType.ArrByte); + } + } + + /// + /// 写入电池条码到PLC + /// + private async Task WriteBatteryBarcodesToPLC(PlcGroup pf, TrayInfo trayInfo) + { + const int BARCODE_SIZE = 40; + string batteryIDBar = string.Concat(trayInfo.cellList.Select(cell => + cell.cellNo + GetString_0(BARCODE_SIZE - cell.cellNo.Length))); + byte[] codeBytes = Encoding.Default.GetBytes(batteryIDBar).ByteReverse(); + await WritePLCByteArray(pf, pf.VarList[2].VarAddress, codeBytes); + } + + /// + /// 构建上料实体列表 + /// + private List BuildFeedingEntityList(TrayInfo trayInfo, string grade, string gradeRemark) + { + return trayInfo.cellList.Select((cell, i) => new AGearEntity + { + Location = cell.channel.ToString(), + Time = DateTime.Now, + BarCode = cell.cellNo, + TrayID = trayInfo.trayNo, + Result = string.IsNullOrEmpty(gradeRemark) ? "OK" : "NG", + Remark = gradeRemark, + Grade = grade, + Model = trayInfo.productCode ?? CommonMethods.mesConfig.ModelName, + GongWei = CommonMethods.sysConfig.GongWei, + }).ToList(); + } + + /// + /// 反馈上料结果到PLC + /// + private async Task FeedBackToPLCLayer(PlcGroup pf, TrayInfo trayInfo, string grade) + { + short model = (short)CommonMethods.mesConfig.GetModel(trayInfo?.productCode ?? CommonMethods.mesConfig.ModelName); + if (model == 0) model = 1; + + short gradeCode = 99; + if (!string.IsNullOrEmpty(grade)) + gradeCode = (short)CommonMethods.GetGradeNo(grade); + + await WritePLCInt16Sync(pf, pf.VarList[3].VarAddress, model); + await WritePLCInt16Sync(pf, pf.VarList[4].VarAddress, gradeCode); + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 1); + + CommonMethods.AddDataMonitorLog(0, $"电池进站[{trayInfo.trayNo}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号{model}(mes获取的原型号:{trayInfo?.productCode}); [{pf.VarList[3].VarAddress}]写挡位{gradeCode}({grade})"); + LogHelper.Instance.WriteError($"电池进站[{trayInfo.trayNo}]:反馈PLC:[{pf.VarList[2].VarAddress}]写型号{model}(mes获取的原型号:{trayInfo?.productCode}); [{pf.VarList[3].VarAddress}]写挡位{gradeCode}({grade})", "ZuPanLog"); + } + + /// + /// 处理上料错误 + /// + private async Task HandleFeedingStationError(PlcGroup pf, string errorMessage, string trayID, TrayInfo trayInfo) + { + var entity = new AGearEntity + { + Time = DateTime.Now, + BarCode = "", + TrayID = trayID ?? "", + Result = "NG", + Remark = errorMessage, + Grade = "", + Model = trayInfo?.productCode ?? "", + GongWei = CommonMethods.sysConfig.GongWei, + }; + + _uiSyncContext.Post(_ => CommonMethods.ShowFeedingDelegate?.Invoke(new List { entity }), null); + await WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, 2); + } + + #region 保存上料数据 + /// + /// 保存上料数据 + /// + /// + private async Task SaveFeedingDataBatchAsync(List list) + { + if (list == null || list.Count == 0) + return; + + try + { + var barcodes = list.Select(x => x.BarCode).ToList(); + + var existing = CommonMethods.db.QueryWhereList() + .Where(x => barcodes.Contains(x.BarCode)) + .Select(x => x.BarCode) + .ToList(); + + var toUpdate = list.Where(x => existing.Contains(x.BarCode)).ToList(); + var toInsert = list.Where(x => !existing.Contains(x.BarCode)).ToList(); + + + // 批量更新、批量插入 + if (toUpdate.Any()) + await CommonMethods.db.UpdateAsync(toUpdate); + if (toInsert.Any()) + await CommonMethods.db.AddReturnBoolAsync(toInsert); + + // UI更新(主线程) + _uiSyncContext.Post(_ => CommonMethods.ShowFeedingDelegate?.Invoke(list), null); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"组盘工位保存处理异常:{ex}", "SysErrorLog"); + throw; // 重新抛出异常,让上层知道保存失败 + } + finally + { + //_dbSemaphore.Release(); + } + } + #endregion + + #endregion + + #region 满箱上传 + /// + /// 组盘 + /// + /// + /// + /// + private async Task PackStation(JYResult bArrays, object plcModel) + { + LogHelper.Instance.WriteLog($"Step 1: 进入 PackStation - {DateTime.Now:HH:mm:ss.fff}"); + PlcGroup pf = plcModel as PlcGroup; + if (pf == null) + { + LogHelper.Instance.WriteError("PLC模型转换失败", "ZuPanLog"); + + UpdatePLCStatus(pf, 999, 2, 2, 2, 999); + return; + } + + using (var timer = new TimedOperation("电池满层绑定", (elapsedMs, operationName) => + { + LogHelper.Instance.WriteLog($"电池满层绑定共耗时:{elapsedMs}ms", "ZuPanLog"); + CommonMethods.AddDataMonitorLog(0, $"电池满层绑定共耗时:{operationName} 执行耗时:{elapsedMs}ms"); + })) + { + if (bArrays.IsSuccess && bArrays.Content != null) + { + await ProcessPackStation(bArrays, pf).ConfigureAwait(false); + } + } + } + + private async Task ProcessPackStation(JYResult bArrays, PlcGroup pf) + { + try + { + LogHelper.Instance.WriteLog($"Step 2: PackStation ParseAndValidateData - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + + var parseTask = ParseAndValidateData(bArrays, pf); + int timeout = 200; + if (await Task.WhenAny(parseTask, Task.Delay(timeout)) == parseTask) + { + LogHelper.Instance.WriteLog($"Step 3: PackStation ParseAndValidateData完成 - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + // 正常返回 + var parsedData = await parseTask; + if (!parsedData.IsValid) + { + LogHelper.Instance.WriteLog($"Step 4: PackStation HandleInvalidData - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + await HandleInvalidData(parsedData, pf); + return; + } + + LogHelper.Instance.WriteLog($"Step 4: PackStation ProcessBinding - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + // 处理绑定逻辑 + await ProcessBinding(parsedData, pf); + } + else + { + LogHelper.Instance.WriteLog($"Step 3: PackStation ParseAndValidateData超时 - {DateTime.Now:HH:mm:ss.fff}", "ZuPanLog"); + // 超时,直接返回, + LogHelper.Instance.WriteError($"PLC解析超时({timeout}ms)", "ZuPanLog"); + UpdatePLCStatus(pf, 999, 2, 2, 2, 999); + return; + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"电池满层绑定线程处理异常:{ex}", "ZuPanLog"); + // 异常时反馈NG状态 + UpdatePLCStatus(pf, 999, 2, 2, 2, 999); + } + } + #endregion + + #region 保存叠盘数据 + /// + /// 保存叠盘工位数据 + /// + /// + private async Task SaveBlankingDataBatchAsync(List list) + { + if (list == null || list.Count == 0) return; + + await _dbSemaphore.WaitAsync().ConfigureAwait(false); + //数据的保存 + try + { + if (list != null && list.Count > 0) + { + //数据显示 + foreach (BGearEntity m in list) + { + string strRes = ""; + if (m.VassoioID != "NG") + { + bool b = await CommonMethods.db.AddReturnBoolAsync(m); + + } + else + { + strRes = ",不存储"; + } + m.Remark = m.Remark + strRes; + } + + //数据显示 + //CommonMethods.ShowBlankingDelegate.Invoke(list); + // UI更新 + _uiSyncContext.Post(_ => CommonMethods.ShowBlankingDelegate?.Invoke(list), null); + } + else + { + LogHelper.Instance.WriteError($"组盘工位数据List为空", "SysErrorLog"); + } + + //// 过滤有效数据 + //var validList = list.Where(m => m.VassoioID != "NG").ToList(); + //if (validList.Any()) + //{ + // await CommonMethods.db.Insertable(validList).ExecuteCommandAsync().ConfigureAwait(false); + //} + + + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"组盘数据保存异常:{ex}", "SysErrorLog"); + } + finally + { + //_dbSemaphore.Release(); + } + } + #endregion + + #region 初始化方法 + // 初始化PLC状态 + private void InitializePLCStatus(PlcGroup pf) + { + ////电池条码读取结果 + //CommonMethods.plcDevices[pf.PlcNum - 1].WriteInt16(pf.VarList[4].VarAddress, 0); + ////卡板码读取结果反馈 + //CommonMethods.plcDevices[pf.PlcNum - 1].WriteInt16(pf.VarList[5].VarAddress, 0); + ////绑定结果反馈 + //CommonMethods.plcDevices[pf.PlcNum - 1].WriteInt16(pf.VarList[6].VarAddress, 0); + ////绑定处理完成反馈 + //CommonMethods.plcDevices[pf.PlcNum - 1].WriteInt16(pf.VarList[7].VarAddress, 0); + _ = ClearPLCRegistersBatch(pf, new[] { 4, 5, 6, 7 }, 0); + } + #endregion + + #region 数据解析和验证 + private async Task ParseAndValidateData(JYResult bArrays, PlcGroup pf) + { + var parsedData = new ParsedData(); + + const int BARCODE_SIZE = 40; + string containerCode = ""; + var plcDevice = GetPlcDevice(pf.PlcNum); + + // 读取跺号 + int stationNo = 0; + if (plcDevice != null) + { + stationNo = plcDevice.ReadInt16(pf.VarList[4].VarAddress); + } + + if (stationNo != 0 ) + { + JYResult kbArrays = plcDevice.ReadValue>( + $"{pf.VarList[3].VarAddress}", + PLC.DataType.ArrByte, + Convert.ToUInt16(pf.VarList[3].OffsetOrLength)); + + // 从3个可能的地址读取卡板码 + //for (int i = 0; i < 3; i++) + { + string code = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding( + kbArrays.Content.ByteReverse(), + (stationNo - 1) * BARCODE_SIZE, + BARCODE_SIZE, + Encoding.ASCII)); + + if (!string.IsNullOrEmpty(code) && code.ToUpper() != "ERROR" && code.Length >= 8) + { + containerCode = code; + //stationNo = i + 1; + //break; + } + } + } + + // 读取层数 + short layerNum = 0; + if (plcDevice != null) + { + layerNum = plcDevice.ReadInt16(pf.VarList[2].VarAddress); + } + + parsedData.ContainerCode = (string)containerCode; + parsedData.StationNo = stationNo; + parsedData.LayerNum = layerNum; + // 验证基础数据 + var (ret, errType, errMessage) = ValidateBasicData(containerCode, stationNo, layerNum); + if (!ret) + { + parsedData.ErrorType = errType; + parsedData.ErrorMessage = errMessage; + parsedData.IsValid = ret; + return parsedData; + } + + // 解析电池条码 + var batteryInfos = ParseBatteryBarcodes(bArrays, layerNum); + var validBarcodeCount = batteryInfos.Count(b => !string.IsNullOrEmpty(b.identification) && b.identification.ToUpper() != "ERROR"); + parsedData.BatteryInfos = batteryInfos; + parsedData.ValidBarcodeCount = validBarcodeCount; + // 验证电池数据 + var (batteryRet, batErrType, batErrMessage) = ValidateBatteryData(validBarcodeCount); + if (!batteryRet) + { + parsedData.ErrorType = batErrType; + parsedData.ErrorMessage = batErrMessage; + parsedData.IsValid = batteryRet; + return parsedData; + } + string grade = ""; + + // 读取电池等级(从第一个有效条码获取) + if (validBarcodeCount > 0) + { + grade = await GetBatteryGrade(batteryInfos.First(b => !string.IsNullOrEmpty(b.identification) && b.identification.ToUpper() != "ERROR").identification).ConfigureAwait(false); + parsedData.Grade = grade; + } + if(parsedData.Grade == "") + { + parsedData.Grade = MesConfig.GetLocGrade(stationNo, CommonMethods.curFdConfig);//CommonMethods.mesConfig.GetGradeNo("A").ToString(); + } + parsedData.IsValid = true; + + return parsedData; + } + + private async Task<(string, int)> ParseContainerCode(PlcGroup pf) + { + //await _plcSemaphore.WaitAsync().ConfigureAwait(false); + try + { + // 将PLC读取和解析放到后台线程执行 + //var cts = new CancellationTokenSource(_plcTimeout); + return await Task.Run(() => + { + const int BARCODE_SIZE = 40; + const int BARCODE_ACTUAL_LENGTH = 39; + + string containerCode = ""; + int stationNo = 0; + + var plcDevice = GetPlcDevice(pf.PlcNum); + if (plcDevice != null) + { + stationNo = plcDevice.ReadInt16(pf.VarList[4].VarAddress); + JYResult kbArrays = plcDevice.ReadValue>( + $"{pf.VarList[3].VarAddress}", + PLC.DataType.ArrByte, + Convert.ToUInt16(pf.VarList[3].OffsetOrLength)); + + // 从3个可能的地址读取卡板码 + if(stationNo != 0) + { + string code = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding( + kbArrays.Content.ByteReverse(), + (stationNo - 1) * BARCODE_SIZE, + BARCODE_ACTUAL_LENGTH, + Encoding.ASCII)); + + if (!string.IsNullOrEmpty(code) && code.ToUpper() != "ERROR" && code.Length >= 8) + { + containerCode = code; + //stationNo = i + 1; + //break; + } + } + } + + return (containerCode, stationNo); + }); + } + catch (TaskCanceledException) + { + LogHelper.Instance.WriteError($"PLC读取容器码超时", "SysErrorLog"); + return ("", 0); + } + finally + { + _plcSemaphore.Release(); + } + } + + private List ParseBatteryBarcodes(JYResult bArrays, short layerNum) + { + const int BARCODE_SIZE = 40; + + int maxBatteryNum = CommonMethods.mesConfig.rowsPerLayer * CommonMethods.mesConfig.colsPerLayer; + var batteryInfos = new List(maxBatteryNum); + + for (int i = 0; i < maxBatteryNum; i++) + { + string location = ParseLocation(layerNum, i); + string barcode = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding( + bArrays.Content.ByteReverse(), + i * BARCODE_SIZE, + BARCODE_SIZE, + Encoding.ASCII)); + + LogHelper.Instance.WriteLog($"PLC读取绑盘条码{i}-{barcode}-{location}", "绑盘条码"); + + if (string.IsNullOrEmpty(barcode) || barcode.Length < 8) + { + LogHelper.Instance.WriteLog($"PLC读取绑盘条码{i}-{barcode}-{location}异常!!!", "绑盘条码"); + continue; + } + + batteryInfos.Add(new BatteryInfo + { + identification = barcode, + locationRow = location + }); + + if (!string.IsNullOrEmpty(barcode) && barcode.ToUpper() != "ERROR") + { + LogHelper.Instance.WriteLog($"电池条码:{barcode},序号:{i + 1}, 位置:{location},层数:{layerNum}"); + } + } + + return batteryInfos; + } + + private (bool, ErrorType, string) ValidateBasicData(string containerCode, int stationNo, int layerNum) + { + string errorMessage = ""; + ErrorType errorType = ErrorType.None; + // 验证卡板码 + if (string.IsNullOrEmpty(containerCode) || + containerCode.ToUpper().Trim() == "ERROR" || + containerCode.ToUpper().Trim() == "NG" || containerCode.Length < 8) + { + errorType = ErrorType.ContainerCodeEmpty; + errorMessage = "箱唛码NG"; + return (false, errorType, errorMessage); + } + + // 验证 机架号 + if (stationNo < 1 || stationNo > 3) + { + errorType = ErrorType.InvalidStation; + errorMessage = $"机架号NG{stationNo}"; + return (false, errorType, errorMessage); + } + + // 验证层数范围 + if (layerNum < 1 || layerNum > CommonMethods.mesConfig.packLayers) + { + errorType = ErrorType.InvalidLayer; + errorMessage = $"层数NG{layerNum}"; + return (false, errorType, errorMessage); + } + + return (true, errorType, errorMessage); + } + + private (bool, ErrorType, string) ValidateBatteryData(int validBarcodeCount) + { + string errMessage = ""; + ErrorType errorType = ErrorType.None; + int maxBatteryNum = CommonMethods.mesConfig.rowsPerLayer * CommonMethods.mesConfig.colsPerLayer; + + // 验证是否有有效条码 + if (validBarcodeCount == 0) + { + errorType = ErrorType.NoValidBarcodes; + errMessage = "电池信息列表为空"; + return (false, errorType, errMessage); + } + + // 验证是否满盘 + if (validBarcodeCount != maxBatteryNum) + { + errorType = ErrorType.NotFullPack; + errMessage = $"电池未满盘,有效条码:{validBarcodeCount},应满盘:{maxBatteryNum}"; + return (false, errorType, errMessage); + } + + return (true, errorType, errMessage); + } + + private async Task GetBatteryGrade(string barcode) + { + try + { + await _dbSemaphore.WaitAsync(); + var entities = await Task.Run(() => CommonMethods.db.QueryWhereList(it => it.BarCode == barcode)).ConfigureAwait(false); + if (entities == null || entities.Count == 0) + { + LogHelper.Instance.WriteError($"本地数据库无该电池条码{barcode}", "SysErrorLog"); + return string.Empty; + } + + return entities[0].Grade; + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"本地数据库无该电池条码{barcode}:{ex}", "SysErrorLog"); + return string.Empty; + } + finally + { + _dbSemaphore.Release(); + } + } + + #endregion + + #region 数据处理方法 + private async Task HandleInvalidData(ParsedData data, PlcGroup pf) + { + // 创建基础实体 + var bGearEntity = CreateBaseBGearEntity(data); + short batteryReadResult = 0; + short containerReadResult = 0; + short bindingResult = 0; + short processCompleteLayer = 999; + + switch (data.ErrorType) + { + case ErrorType.ContainerCodeEmpty: + bGearEntity.Result = "NG"; + bGearEntity.Remark = data.ErrorMessage; + batteryReadResult = 2; + containerReadResult = 2; + bindingResult = 2; + processCompleteLayer = data.LayerNum; + break; + + case ErrorType.InvalidLayer: + bGearEntity.Result = "NG"; + bGearEntity.Remark = data.ErrorMessage; + batteryReadResult = 2; + containerReadResult = 2; + bindingResult = 2; + processCompleteLayer = data.LayerNum; + break; + + case ErrorType.NoValidBarcodes: + bGearEntity.Result = "NG"; + bGearEntity.Remark = data.ErrorMessage; + batteryReadResult = 2; + containerReadResult = 1; + bindingResult = 2; + processCompleteLayer = data.LayerNum; + break; + + case ErrorType.NotFullPack: + bGearEntity.Result = "NG"; + bGearEntity.Remark = data.ErrorMessage ?? "电池未满盘,不绑定"; + batteryReadResult = 1; + containerReadResult = 1; + bindingResult = 2; + processCompleteLayer = data.LayerNum; + break; + } + + // 显示结果 + var bGearlist = new List { bGearEntity }; + CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + + UpdatePLCStatus(pf, (short)(data.LayerNum == 0? 999: data.LayerNum), + batteryReadResult, + containerReadResult, + bindingResult, + processCompleteLayer); + + // 记录日志 + CommonMethods.AddDataMonitorLog(1, data.ErrorMessage); + } + + private async Task ProcessBinding(ParsedData data, PlcGroup pf) + { + // 创建基础实体 + var bGearEntity = CreateBaseBGearEntity(data); + bGearEntity.Total = data.ValidBarcodeCount; + bGearEntity.Qty = data.Grade; + + LogHelper.Instance.WriteLog($"Step 5: PackStation ProcessMESBinding - {DateTime.Now:HH:mm:ss.fff}"); + await ProcessMESBinding(data, pf, bGearEntity); + } + + private async Task ProcessMESBinding(ParsedData data, PlcGroup pf, BGearEntity bGearEntity) + { + try + { + // 合并电池信息 + var totalBatteryInfos = new List(); + totalBatteryInfos.AddRange(data.BatteryInfos); + + if (data.LayerNum == CommonMethods.mesConfig.packLayers) + { + LogHelper.Instance.WriteLog($"Step 6: PackStation QueryWhereList - {DateTime.Now:HH:mm:ss.fff}"); + + // 查询数据库中已存在的绑定记录 + var existingBatteries = CommonMethods.db.QueryWhereList( + it => it.containerCode == data.ContainerCode) + .Select(a => new BatteryInfo + { + identification = a.identification, + locationRow = a.location //(a.location).Replace("-", "") + }) + .GroupBy(b => new { b.identification, b.locationRow }) + .Select(g => g.First()) // 保留每组的第一条记录 + .ToList(); + + totalBatteryInfos.AddRange(existingBatteries); + + totalBatteryInfos = totalBatteryInfos + .GroupBy(b => new { b.identification, b.locationRow }) + .Select(g => g.First()) + .ToList(); + + bGearEntity.Total = totalBatteryInfos.Count; + + LogHelper.Instance.WriteLog($"Step 7: PackStation CallMESPackLoadAsync - {DateTime.Now:HH:mm:ss.fff}"); + + // 调用MES接口 + var mesResult = await CallMESPackLoadAsync(data, totalBatteryInfos); + + if (!mesResult.Success) + { + bGearEntity.OutSuccTotal = 0; + LogHelper.Instance.WriteLog($"Step 8: PackStation HandleMESRequestFailed - {DateTime.Now:HH:mm:ss.fff}"); + await HandleMESRequestFailed(data, pf, bGearEntity, mesResult.ErrorMessage); + return; + } + + LogHelper.Instance.WriteLog($"Step 8: PackStation ProcessMESResult - {DateTime.Now:HH:mm:ss.fff}"); + // 处理MES返回结果 + await ProcessMESResult(data, pf, bGearEntity, mesResult).ConfigureAwait(false); + + //string palletId = ""; + //var upParamResult = await CallMESUpResultParamAsync(data.ContainerCode, palletId, totalBatteryInfos); + } + else + { + LogHelper.Instance.WriteLog($"Step 6: PackStation ProcessTempResult - {DateTime.Now:HH:mm:ss.fff}"); + // 处理MES返回结果 + await ProcessTempResult(data, pf, bGearEntity).ConfigureAwait(false); + } + + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"MES绑定处理异常:{ex}", "SysErrorLog"); + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + } + } + + private async Task CallMESPackLoadAsync(ParsedData data, List totalBatteryInfos) + { + if (!CommonMethods.sysConfig.FinishSwitching) + { + var result = await CommonMethods.hbgMes.PackLoadAsync( + CommonMethods.mesConfig.packLoadUrl, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + data.ContainerCode, + totalBatteryInfos.Count, + data.Grade, + CommonMethods.mesConfig.MaterialCode, + totalBatteryInfos + ); + return new MESPackLoadResult + { + Success = result.Item1, + ErrorMessage = result.Item2, + ResType = (short)result.Item3, + MaterialPackInfos = result.Item4 + }; + + } + else + { + var result = await CommonMethods.hbgMes.PackLoadFinishAsync( + CommonMethods.mesConfig.finishedPackUrl, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + data.ContainerCode, + totalBatteryInfos.Count, + data.Grade, + CommonMethods.mesConfig.MaterialCode, + totalBatteryInfos + ); + + return new MESPackLoadResult + { + Success = result.Item1, + ErrorMessage = result.Item2, + ResType = (short)result.Item3, + MaterialPackInfos = result.Item4 + }; + } + } + + private async Task ProcessMESResult(ParsedData data, PlcGroup pf, BGearEntity bGearEntity, MESPackLoadResult mesResult) + { + var batteryEntities = new List(); + bool allSuccess = true; + + LogHelper.Instance.WriteLog($"Step 9: PackStation 整合 - {DateTime.Now:HH:mm:ss.fff}"); + // 处理每个电池的绑定结果 + var matpackDict = mesResult.MaterialPackInfos.ToDictionary(m => m.identification, StringComparer.OrdinalIgnoreCase); + + foreach (var batteryInfo in data.BatteryInfos) + { + if (matpackDict.TryGetValue(batteryInfo.identification, out var matpackInfo)) + { + batteryEntities.Add(new BatteryEntity + { + identification = matpackInfo.identification, + location = $"{matpackInfo.locationRow[0]}-{matpackInfo.locationRow[1]}-{matpackInfo.locationRow.Substring(2)}", + packResult = mesResult.Success, + packFalseReason = mesResult.ErrorMessage, + containerCode = data.ContainerCode, + grade = data.Grade, + outStationType = 1 + }); + + if (!matpackInfo.packResult) + { + allSuccess = false; + } + } + } + + LogHelper.Instance.WriteLog($"Step 10: PackStation SaveBatteryEntitiesBatchAsync 开始 - {DateTime.Now:HH:mm:ss.fff}"); + // 保存到数据库 + await SaveBatteryEntitiesBatchAsync(batteryEntities); + + LogHelper.Instance.WriteLog($"Step 11: PackStation SaveBatteryEntitiesBatchAsync 结束 - {DateTime.Now:HH:mm:ss.fff}"); + + // 更新UI + //CommonMethods.ShowBatteryNGRsnDelegate?.Invoke(batteryEntities); + //CommonMethods.ShowBatteryStatusDelegate?.Invoke(data.StationNo, batteryEntities); + //CommonMethods.ShowBatteryQRCoderDelegate?.Invoke(batteryEntities); + + // 设置结果 + if (allSuccess) + { + bGearEntity.Result = "OK"; + bGearEntity.Remark = "电芯绑定成功"; + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 1, data.LayerNum); + } + else + { + bGearEntity.Result = "绑定_NG"; + bGearEntity.Remark = "部分电芯绑定失败"; + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + } + + bGearEntity.OutSuccTotal = batteryEntities.Where(m => m.packResult).Count(); + + LogHelper.Instance.WriteLog($"Step 12: PackStation ShowBlankingDelegate 开始 - {DateTime.Now:HH:mm:ss.fff}"); + + // 显示结果 + var bGearlist = new List { bGearEntity }; + CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + LogHelper.Instance.WriteLog($"Step 13: PackStation ShowBlankingDelegate 结束 - {DateTime.Now:HH:mm:ss.fff}"); + + // 保存到本地数据库 + if (bGearEntity.Result == "OK") + { + LogHelper.Instance.WriteLog($"Step 14: PackStation AddReturnBoolAsync 开始 - {DateTime.Now:HH:mm:ss.fff}"); + bool saveSuccess = await CommonMethods.db.AddReturnBoolAsync(bGearlist); + CommonMethods.AddDataMonitorLog(1, $"电池满层绑定本地存储{(saveSuccess ? "成功" : "失败")}"); + + LogHelper.Instance.WriteLog($"Step 15: PackStation AddReturnBoolAsync 结束 - {DateTime.Now:HH:mm:ss.fff}"); + } + else + { + LogHelper.Instance.WriteLog($"Step 14: PackStation ng 结果不存库 - {DateTime.Now:HH:mm:ss.fff}"); + } + } + + private async Task CallMESUpResultParamAsync(string containerCode, string palletId, List totalBatteryInfos) + { + var result = await CommonMethods.hbgMes.ProducResultParamAsync( + CommonMethods.mesConfig.upResultParamUrl, + CommonMethods.mesConfig.siteCode, + CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.equipNum, + CommonMethods.mesConfig.MaterialCode, + CommonMethods.mesConfig.mesUserName, + containerCode, + palletId, + totalBatteryInfos, + MesUploadType.DZ + ); + + return result; + + } + + private async Task ProcessTempResult(ParsedData data, PlcGroup pf, BGearEntity bGearEntity) + { + var batteryEntities = new List(); + bool allSuccess = true; + + foreach (var batteryInfo in data.BatteryInfos) + { + batteryEntities.Add(new BatteryEntity + { + identification = batteryInfo.identification, + location = batteryInfo.locationRow, //$"{batteryInfo.locationRow[0]}-{batteryInfo.locationRow[1]}-{batteryInfo.locationRow.Substring(2)}", + packResult = true, + packFalseReason = "", + containerCode = data.ContainerCode, + grade = data.Grade, + outStationType = 1 + }); + } + + LogHelper.Instance.WriteLog($"Step 7: PackStation SaveBatteryEntitiesBatchAsync 开始 - {DateTime.Now:HH:mm:ss.fff}"); + // 保存到数据库 + await SaveBatteryEntitiesBatchAsync(batteryEntities); + + // 更新UI + //CommonMethods.ShowBatteryNGRsnDelegate?.Invoke(batteryEntities); + //CommonMethods.ShowBatteryStatusDelegate?.Invoke(data.StationNo, batteryEntities); + //CommonMethods.ShowBatteryQRCoderDelegate?.Invoke(batteryEntities); + + LogHelper.Instance.WriteLog($"Step 8: PackStation SaveBatteryEntitiesBatchAsync 完成 - {DateTime.Now:HH:mm:ss.fff}"); + + // 设置结果 + //if (allSuccess) + { + bGearEntity.Result = "OK"; + bGearEntity.Remark = "待整垛电芯一起绑定"; + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 1, data.LayerNum); + } + //else + //{ + // bGearEntity.Result = "绑定_NG"; + // bGearEntity.Remark = "待整垛电芯绑定"; + // UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + //} + + bGearEntity.OutSuccTotal = batteryEntities.Where(m => !m.packResult).Count(); + + LogHelper.Instance.WriteLog($"Step 9: PackStation ShowBlankingDelegate - {DateTime.Now:HH:mm:ss.fff}"); + + // 显示结果 + var bGearlist = new List { bGearEntity }; + CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + + // 保存到本地数据库 + if (bGearEntity.Result == "OK") + { + LogHelper.Instance.WriteLog($"Step 10: PackStation AddReturnBoolAsync 开始 - {DateTime.Now:HH:mm:ss.fff}"); + bool saveSuccess = await CommonMethods.db.AddReturnBoolAsync(bGearlist).ConfigureAwait(false); + CommonMethods.AddDataMonitorLog(1, $"电池满层绑定本地存储{(saveSuccess ? "成功" : "失败")}"); + LogHelper.Instance.WriteLog($"Step 11: PackStation AddReturnBoolAsync 结束 - {DateTime.Now:HH:mm:ss.fff}"); + } + else + { + LogHelper.Instance.WriteLog($"Step 10: PackStation ng结果不保存 - {DateTime.Now:HH:mm:ss.fff}"); + } + } + + private async Task ProcessDebugBinding(ParsedData data, PlcGroup pf, BGearEntity bGearEntity) + { + // 创建模拟的绑定结果 + var batteryEntities = new List(); + + for (int i = 0; i < data.BatteryInfos.Count; i++) + { + var batteryInfo = data.BatteryInfos[i]; + bool packResult = true; //(i % 3) != 1; // 模拟部分失败 + string packFalseReason = packResult ? null : "模拟失败原因"; + + batteryEntities.Add(new BatteryEntity + { + identification = string.IsNullOrEmpty(batteryInfo.identification) ? $"DC_{i}" : batteryInfo.identification, + location = batteryInfo.locationRow, + packResult = packResult, + packFalseReason = packFalseReason, + containerCode = data.ContainerCode, + grade = data.Grade, + outStationType = 1 + }); + } + + // 保存到数据库 + await SaveBatteryEntitiesBatchAsync(batteryEntities).ConfigureAwait(false); + + // 更新UI + //CommonMethods.ShowBatteryNGRsnDelegate?.Invoke(batteryEntities); + //CommonMethods.ShowBatteryStatusDelegate?.Invoke(data.StationNo, batteryEntities); + //CommonMethods.ShowBatteryQRCoderDelegate?.Invoke(batteryEntities); + + // 设置结果 + bGearEntity.Result = "OK"; + bGearEntity.Remark = "调试模式绑定成功"; + bGearEntity.OutSuccTotal = batteryEntities.Count; + + UpdatePLCStatus(pf, data.LayerNum, 0, 0, 1, data.LayerNum); + + // 显示结果 + var bGearlist = new List { bGearEntity }; + CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + } + + private async Task ProcessDebugMode(ParsedData data, PlcGroup pf, BGearEntity bGearEntity) + { + // 调试模式模拟数据 + data.StationNo = data.StationNo == 0 ? 1 : data.StationNo; + data.LayerNum = data.LayerNum == (short)0 ? (short)1 : data.LayerNum; + data.Grade = data.Grade ?? MesConfig.GetLocGrade(data.StationNo, CommonMethods.curFdConfig); + + // 生成模拟电池信息 + int maxBatteryNum = CommonMethods.mesConfig.rowsPerLayer * CommonMethods.mesConfig.colsPerLayer; + var batteryEntities = new List(maxBatteryNum); + + for (int i = 0; i < maxBatteryNum; i++) + { + bool packResult = (i % 5) != 1; // 模拟部分失败 + string packFalseReason = packResult ? null : $"错误NG{(i % 5)}"; + + batteryEntities.Add(new BatteryEntity + { + identification = $"DC_{i}", + location = ParseLocation(data.LayerNum, i), + packResult = packResult, + packFalseReason = packFalseReason, + containerCode = "DEBUG_XM_CODE123", + grade = data.Grade, + outStationType = 1 + }); + } + + // 保存到数据库 + await SaveBatteryEntitiesBatchAsync(batteryEntities).ConfigureAwait(false); + + // 更新UI + //CommonMethods.ShowBatteryNGRsnDelegate?.Invoke(batteryEntities); + //CommonMethods.ShowBatteryStatusDelegate?.Invoke(data.StationNo, batteryEntities); + + //CommonMethods.ShowBatteryQRCoderDelegate?.Invoke(batteryEntities); + + // 设置结果 + bGearEntity.Result = "NG"; + bGearEntity.Remark = "电芯绑定失败(调试模式)"; + bGearEntity.OutSuccTotal = batteryEntities.Where(x => x.packResult == true).Count(); + bGearEntity.Qty = data.Grade; + bGearEntity.Total = batteryEntities.Count; + + // 显示结果 + var bGearlist = new List { bGearEntity }; + CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + + UpdatePLCStatus(pf, data.LayerNum, 0, 0, 2, data.LayerNum); + } + + #endregion + + #region 辅助方法 + + private BGearEntity CreateBaseBGearEntity(ParsedData data) + { + return new BGearEntity + { + TestTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + VassoioID = data.ContainerCode ?? string.Empty, + GongWei = CommonMethods.sysConfig.GongWei, + StackingLayer = data.LayerNum + }; + } + + private async Task SaveBatteryEntitiesBatchAsync(List batteryEntities) + { + if (batteryEntities == null || !batteryEntities.Any()) return; + + try + { + var containerCodes = batteryEntities.Select(m => m.containerCode).Distinct().ToList(); + bool b = await CommonMethods.db.AddReturnBoolAsync(batteryEntities); + CommonMethods.AddDataMonitorLog(0, $"电池绑定数据批量保存成功"); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"电池绑定保存异常:{ex}", "SysErrorLog"); + } + finally + { + } + } + + private void UpdatePLCStatus(PlcGroup pf, short layerNum, + short batteryReadResult, short containerReadResult, + short bindingResult, short processCompleteLayer) + { + + var dict = new Dictionary(); + if (batteryReadResult != 0) dict[pf.VarList[5].VarAddress] = batteryReadResult; // 电池条码读取结果反馈 + if (containerReadResult != 0) dict[pf.VarList[6].VarAddress] = containerReadResult; // 卡板码读取结果反馈 + if (bindingResult != 0) dict[pf.VarList[7].VarAddress] = bindingResult; // 绑定结果反馈 + if (processCompleteLayer != 0) dict[pf.VarList[8].VarAddress] = processCompleteLayer; // 绑定处理完成反馈 + + WritePLCInt16Sync(pf, pf.VarList[5].VarAddress, batteryReadResult); + WritePLCInt16Sync(pf, pf.VarList[6].VarAddress, containerReadResult); + WritePLCInt16Sync(pf, pf.VarList[7].VarAddress, bindingResult); + WritePLCInt16Sync(pf, pf.VarList[8].VarAddress, processCompleteLayer); + } + + private async Task HandleMESDisconnected(ParsedData data, PlcGroup pf, BGearEntity bGearEntity) + { + await Task.Run(() => + { + bGearEntity.Result = "MES_NG"; + bGearEntity.Remark = "MES连接中断"; + + //var bGearlist = new List { bGearEntity }; + //CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + + //CommonMethods.AddDataMonitorLog(1, "MES连接中断,停止上传"); + //CommonMethods.plcDevices[pf.PlcNum - 1].WriteInt16("D80", 1); + + //UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + + var bGearlist = new List { bGearEntity }; + _uiSyncContext.Post(_ => CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist), null); + + CommonMethods.AddDataMonitorLog(1, "MES连接中断,停止上传"); + _ = WritePLCInt16Sync(pf, "D80", 1); + + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + }); + } + + private async Task HandleMESRequestFailed(ParsedData data, PlcGroup pf, BGearEntity bGearEntity, string errorMessage) + { + await Task.Run(() => + { + bGearEntity.Result = "MES_NG"; + bGearEntity.Remark = $"MES请求失败:{errorMessage}"; + + var bGearlist = new List { bGearEntity }; + + _uiSyncContext.Post(_ => CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist), null); + + CommonMethods.AddDataMonitorLog(1, $"MES请求失败:{errorMessage}"); + _ = WritePLCInt16Sync(pf, "D80", 1); + + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + }); + } + + private async Task HandleMESDataMismatch(ParsedData data, PlcGroup pf, BGearEntity bGearEntity, MESPackLoadResult mesResult) + { + await Task.Run(() => + { + CommonMethods.AddDataMonitorLog(1, + $"返回数据数量不匹配({mesResult.MaterialPackInfos?.Count ?? 0} != {data.BatteryInfos.Count})"); + + bGearEntity.Result = "绑定_NG"; + bGearEntity.Remark = "部分电芯没有返回绑定结果"; + bGearEntity.OutSuccTotal = mesResult.MaterialPackInfos?.Where(x => x.packResult == true).Count() ?? 0; + + //var bGearlist = new List { bGearEntity }; + //CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist); + + //UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + var bGearlist = new List { bGearEntity }; + _uiSyncContext.Post(_ => CommonMethods.ShowBlankingDelegate?.Invoke(bGearlist), null); + + UpdatePLCStatus(pf, data.LayerNum, 1, 1, 2, data.LayerNum); + }); + } + + #endregion + + #region 数据模型 + + private class ParsedData + { + public bool IsValid { get; set; } + public string ContainerCode { get; set; } + public short LayerNum { get; set; } + public List BatteryInfos { get; set; } + public int ValidBarcodeCount { get; set; } + public string Grade { get; set; } + public string ErrorMessage { get; set; } + public ErrorType ErrorType { get; set; } + public int StationNo { get; set; } + } + + private class MESPackLoadResult + { + public bool Success { get; set; } + public string ErrorMessage { get; set; } + public short ResType { get; set; } + public List MaterialPackInfos { get; set; } + } + + private enum ErrorType + { + None, + ContainerCodeEmpty, + InvalidStation, + InvalidLayer, + NoValidBarcodes, + NotFullPack + } + + #endregion + + #region 强制出站 + private Task ForceOutStation(JYResult bArrays, object plcModel) + { + + PlcGroup pf = plcModel as PlcGroup; + if (pf == null) + { + LogHelper.Instance.WriteError("PLC模型转换失败", "SysErrorLog"); + return Task.CompletedTask; + } + + using (var timer = new TimedOperation("强制出站", (elapsedMs, operationName) => + { + CommonMethods.AddDataMonitorLog(0, $"强制出站共耗时:{operationName} 执行耗时:{elapsedMs}ms"); + })) + { + // 空方法直接返回已完成任务,避免异步开销 + return Task.CompletedTask; + } + } + + /// + /// 解析位置编码 + /// + /// 位置编码(0-99999) + /// 包含层号和位置信息的元组 + public string ParseLocation(int layerNum, int number) + { + if (CommonMethods.mesConfig.colsPerLayer <= 0) + throw new InvalidOperationException("列数配置无效"); + + Dictionary dictRow = new Dictionary() { { 1, "A" }, { 2, "B" }, { 3, "C" }, { 4, "D" }, { 5, "E" }, }; + if (CommonMethods.mesConfig.ModelName == "LF350S") + { + int row = number / CommonMethods.mesConfig.colsPerLayer + 1; + string rowStr = dictRow[row]; + int col = (number % CommonMethods.mesConfig.colsPerLayer) + 1; + return $"{rowStr}{col}"; + } + else + { + int row = number / CommonMethods.mesConfig.colsPerLayer + 1; + int col = (number % CommonMethods.mesConfig.colsPerLayer) + 1; + return $"{layerNum}{row}{col}"; + } + } + + #endregion + + + #region 料框码解绑 + /// + /// 料框码解绑 + /// + /// + /// + /// + private async Task UnBindTrayStation(JYResult bArrays, object plcModel) + { + PlcGroup pf = plcModel as PlcGroup; + if (pf == null) + { + LogHelper.Instance.WriteError("PLC模型转换失败", "SysErrorLog"); + return; + } + + CommonMethods.AddDataMonitorLog(0, $"料框码解绑开始"); + int _mesTimeout = 1000; + using (var cts = new CancellationTokenSource(_mesTimeout)) + { + if (bArrays.IsSuccess && bArrays.Content != null) + { + + byte[] bytes = bArrays.Content.ByteReverse(); + + //料框码 + string trayCode = FormatBarcode(StringLib.GetStringFromByteArrayByEncoding(bytes, 0, 40, System.Text.Encoding.ASCII)); + CommonMethods.AddDataMonitorLog(0, $"料框码解绑料况码{trayCode}"); + if (string.IsNullOrEmpty(trayCode) || trayCode.ToUpper().Contains("ERROR") || trayCode.ToUpper().Contains("NG")) + { + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, 2); + return; + } + + + try + { + var (success, mesMessage) = await UnbindTrayInfo(trayCode); + + { + + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, success ? (short)1 : (short)2); + LogHelper.Instance.WriteError($"料框码解绑完成:{trayCode},解绑结果:{success},{mesMessage}", "ZuPanLog"); + CommonMethods.AddDataMonitorLog(0, $"料框码解绑完成,料框码:{trayCode},解绑结果:{success},{mesMessage}"); + } + + } + catch (OperationCanceledException) + { + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, 2); + LogHelper.Instance.WriteError($"料框码解绑被取消(超时):{trayCode}", "ZuPanLog"); + CommonMethods.AddDataMonitorLog(0, $"料框码解绑被取消(超时):{trayCode}"); + } + catch (Exception ex) + { + await WritePLCInt16Sync(pf, pf.VarList[2].VarAddress, 2); + LogHelper.Instance.WriteError($"料框码解绑异常:{ex.Message},料框码:{trayCode}", "ZuPanLog"); + CommonMethods.AddDataMonitorLog(0, $"料框码解绑异常:{ex.Message},料框码:{trayCode}"); + } + } + } + } + + // MES查询方法 + private async Task<(bool success, string mesMessage)> UnbindTrayInfo(string trayID) + { + //if (!CommonMethods.mesConfig.isConnected) + //{ + // //CommonMethods.AddDataMonitorLog(1, "MES连接中断,停止上传"); + + // return (false, "MES连接中断", MesResType.B, null); + //} + try + { + var (success, mesMessage) = await CommonMethods.hbgMes.UnbindTrayInfosAsync( + CommonMethods.mesConfig.unbindTrayUrl, + CommonMethods.mesConfig.equipNum, + trayID + ).ConfigureAwait(false); + + return (success, mesMessage); + } + catch (Exception ex) + { + return (false, $"MES解绑失败{ex.Message}"); + } + } + #endregion + + + + + + #region 创建空的数组List + + private List GetList(int count, T defaultValue) + { + if (count <= 0) + { + return new List(); + } + // Enumerable.Repeat比循环Add更高效,尤其是大数据量 + return Enumerable.Repeat(defaultValue, count).ToList(); + } + + public List GetMesType(int Num) + { + List mesResTypes = new List(); + for (int i = 0; i < Num; i++) + { + mesResTypes.Add(MesResType.UnKnow); + } + return mesResTypes; + } + + /// + /// PLC内批量写\0 + /// + /// + /// + public string GetString_0(int Num) + { + string ff = ""; + for (int i = 0; i < Num; i++) + { + ff = ff.Insert(ff.Length, "\0"); + } + return ff; + } + + + #endregion + + + #region 辅助方法 + + /// + /// 批量清空PLC寄存器 + /// + private async Task ClearPLCRegistersBatch(PlcGroup pf, int[] varIndexes, short value) + { + var dict = varIndexes.ToDictionary(i => pf.VarList[i].VarAddress, _ => value); + await WritePLCInt16Batch(pf, dict); + } + + private async Task WritePLCInt16BatchWithTimeout(PlcGroup pf, Dictionary addressValues) + { + try + { + // 给PLC写入加超时,避免卡慢 + var writeTask = WritePLCInt16Batch(pf, addressValues); + //var timeoutTask = Task.Delay(_plcTimeout); + + //var completedTask = await Task.WhenAny(writeTask, timeoutTask).ConfigureAwait(false); + //if (completedTask == timeoutTask) + //{ + // //LogHelper.Instance.WriteError($"PLC批量写入超时({_plcTimeout.TotalSeconds}s)", "WuLiuLog"); + // throw new TimeoutException("PLC写入超时"); + //} + + //await writeTask.ConfigureAwait(false); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"PLC批量写入异常:{ex.Message}", "WuLiuLog"); + // 可考虑重试1次(可选) + // await Task.Delay(100); + // await WritePLCInt16Batch(pf, addressValues).ConfigureAwait(false); + } + } + + /// + /// 批量写入Int16到PLC + /// + private async Task WritePLCInt16Batch(PlcGroup pf, Dictionary addressValueDict) + { + //if (addressValueDict.Count == 0) return; + + //var tasks = addressValueDict.Select(kv => WritePLCInt16Sync(pf, kv.Key, kv.Value)); + //await Task.WhenAll(tasks); + + if (addressValueDict == null || addressValueDict.Count == 0) return; + + var plc = GetPlcDevice(pf.PlcNum); + if (plc == null) return; + + //await _plcSemaphore.WaitAsync().ConfigureAwait(false); + try + { + // 【关键优化】批量写入,一次通讯完成 + foreach (var kv in addressValueDict) + { + plc.WriteInt16(kv.Key, kv.Value); + } + } + finally + { + //_plcSemaphore.Release(); + } + } + + /// + /// 写入Int16到PLC + /// + private async Task WritePLCInt16Sync(PlcGroup pf, string address, short value) + { + + try + { + var plc = GetPlcDevice(pf.PlcNum); + if (plc == null) return; + + //// 加信号量 + 超时保护 + //await _plcSemaphore.WaitAsync(100); + //try + { + plc.WriteInt16(address, value); + } + //finally + //{ + // _plcSemaphore.Release(); + //} + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"PLC写入失败(地址:{address}):{ex.Message}", "SysErrorLog"); + } + } + + + /// + /// 写入字节数组到PLC(带超时) + /// + private async Task WritePLCByteArray(PlcGroup pf, string address, byte[] data) + { + await _plcSemaphore.WaitAsync(); + try + { + //var cts = new CancellationTokenSource(_plcTimeout); + //await Task.Run(() => + // CommonMethods.plcDevices[pf.PlcNum - 1].WriteValue(address.ToString(), data, PLC.DataType.ArrByte), cts.Token); + await Task.Run(() => GetPlcDevice(pf.PlcNum).WriteValue(address.ToString(), data, PLC.DataType.ArrByte)); + } + finally + { + _plcSemaphore.Release(); + } + } + + + + /// + /// 检测数据是否只包含字母加数字 + /// + /// + /// + private static readonly Regex _alphaNumericRegex = new Regex("^[a-zA-Z0-9]+$", RegexOptions.Compiled); + public bool IsAlphaNumeric(string input) + { + return !string.IsNullOrEmpty(input) && _alphaNumericRegex.IsMatch(input); + } + + /// + /// 格式化条码 + /// + private string FormatBarcode(string barcode) + { + if (string.IsNullOrEmpty(barcode)) return string.Empty; + int index = barcode.IndexOf('\0'); + if (index >= 0) + barcode = barcode.Substring(0, index); + return barcode.Replace("\0", "").Replace("\r", "").Replace(" ", "").Trim(); + } + + + #endregion + + } +} + +//http://10.22.160.3/core/api/public/product/process/param/new/result + +//{ +// "equipNum": "60PLR03", +// "type": "DZ", +// "payload": "{\"siteCode\":\"60J\",\"lineCode\":\"KW-602\",\"userName\":\"admin\",\"materialCode\":\"81044802\",\"carCode\":\"\",\"recordDate\":\"2026/06/24 12:01:00\",\"qty\":2,\"containerCode\":\"ETE\",\"identificationList\":[{\"identification\":\"ML-10085826-001\",\"qualityStatus\":\"\",\"tagDataVOList\":[{\"tagCode\":\"TRAY_NUMBER_DBJJG\",\"tagValue\":\"\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"托盘号\"},{\"tagCode\":\"PALLET_NUMBER_DBJJG\",\"tagValue\":\"\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"栈板号\"},{\"tagCode\":\"BATTERY_LOCATION_DBJJG\",\"tagValue\":\"111\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"电池位置\"},{\"tagCode\":\"TOP_COVER_CODE_DBJJG\",\"tagValue\":\"\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"电芯顶盖码\"}]},{\"identification\":\"ML-10085826-002\",\"qualityStatus\":\"\",\"tagDataVOList\":[{\"tagCode\":\"TRAY_NUMBER_DBJJG\",\"tagValue\":\"\",\"tagTime\":\"2026/06/2412:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"托盘号\"},{\"tagCode\":\"PALLET_NUMBER_DBJJG\",\"tagValue\":\"\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"栈板号\"},{\"tagCode\":\"BATTERY_LOCATION_DBJJG\",\"tagValue\":\"4512\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"电池位置\"},{\"tagCode\":\"TOP_COVER_CODE_DBJJG\",\"tagValue\":\"\",\"tagTime\":\"2026/06/24 12:01:00\",\"tagCalculateResult\":\"\",\"tagRemark\":\"电芯顶盖码\"}]}]}" +//} \ No newline at end of file diff --git a/JinYuan.ControlCenter/ControlCenter_Total.cs b/JinYuan.ControlCenter/ControlCenter_Total.cs new file mode 100644 index 0000000..4f34ae1 --- /dev/null +++ b/JinYuan.ControlCenter/ControlCenter_Total.cs @@ -0,0 +1,744 @@ + +using JinYuan.Helper; +using JinYuan.MES.Models; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using Language; +using PLCCommunication; +using PLCCommunication.Common; +using PLCCommunication.Modbus; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using static System.Windows.Forms.LinkLabel; + + +namespace JinYuan.ControlCenters +{ + public partial class ControlCenter + { + #region 刷新12小时产能 + + public int GetHour() + { + DateTime now = DateTime.Now; + int nowHour = Convert.ToInt32($"{now.Hour}30"); + int hour = 0; + if (CommonMethods.LastHour != nowHour) + { + hour = Convert.ToInt32($"{now.Hour - 1}30"); + if (now.Hour == 0) + { + hour = 2330; + } + } + else + { + hour = Convert.ToInt32($"{now.Hour}30"); + } + return hour; + } + + + public void Refresh12HourProdQty() + { + List chart12Hours = new List(); + DateTime dtTime = DateTime.Now; + string strDate = dtTime.ToString("yyyy-MM-dd"); + string nextDate = dtTime.AddDays(1).ToString("yyyy-MM-dd"); + int Hour = GetHour(); + + var listTotal = CommonMethods.db.QueryWhereList(t => + t.FDate == strDate || t.FDate == nextDate);// 查询两天的数据 + + if (listTotal != null && listTotal.Count > 0) + { + for (int i = 0; i < 24; i++) // 改为24小时 + { + int currentHour = (i + 8) % 24; // 从8点开始 + int nextHour = (currentHour + 1) % 24; + string currentDate = currentHour >= 8 ? strDate : nextDate; + + var hour1 = listTotal.Where(p => + p.FDate == currentDate && + p.FHour == currentHour).FirstOrDefault(); + + int ProdALLQty = 0; + int ProdOKQty = 0; + int ProdNGQty = 0; + string strOkRatio = "0.00"; + if (hour1 != null) + { + ProdALLQty = hour1.ProdIn; + ProdOKQty = hour1.ProdOut; + } + ProdNGQty = ProdALLQty - ProdOKQty; + if (ProdOKQty >= 0 && ProdALLQty > 0) + { + strOkRatio = (Math.Round(decimal.Parse(ProdOKQty.ToString()) / decimal.Parse(ProdALLQty.ToString()), 4)).ToString(); + } + string displayTime = $"{currentHour:D2}:30~{nextHour:D2}:29"; + + chart12Hours.Add(new Chart12HourData() + { + DisplayTime = displayTime, + ProdIn = ProdALLQty, + ProdOut = ProdOKQty, + ProdNg = ProdNGQty, + OKRatio = strOkRatio + }); + } + } + else + { + for (int i = 0; i < 24; i++) + { + int currentHour = (i + 8) % 24; + int nextHour = (currentHour + 1) % 24; + + Random rand = new Random(); + int ranOK = rand.Next(1000, 3000); + int ranNG = rand.Next(400, 1200); + int total = ranOK + ranNG; + string displayTime = $"{currentHour:D2}:30~{nextHour:D2}:29"; + string strOkRatio = (Math.Round(decimal.Parse(ranOK.ToString()) / decimal.Parse(total.ToString()), 4)).ToString(); + chart12Hours.Add(new Chart12HourData() + { + DisplayTime = displayTime, + ProdIn = ranOK + ranNG, + ProdOut = ranOK, + ProdNg = ranNG, + OKRatio = strOkRatio // 保留2位小数,添加% + }); + } + } + if (chart12Hours != null) + { + CommonMethods.Lst_Prod12HourData = chart12Hours; + } + } + #endregion + + #region 检测项不良 + /// + /// 读取检测项不良 + /// + private void GetDefectTypeQty() + { + + try + { + if (CommonMethods.Lst_DefectTypeQty.Count <= 0) + { + + //CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "极性检测不良".Translated(), DataCount = 0 }); + //CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "称重不良".Translated(), DataCount = 0 }); + //CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "铜极耳剪切不良".Translated(), DataCount = 0 }); + //CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "铝极耳剪切不良".Translated(), DataCount = 0 }); + //CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "厚度不良", DataCount = 0 }); + //CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "焊前CCD正极耳顶面不良", DataCount = 0 }); + CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "扫码不良".Translated(), DataCount = 0 }); + CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "MES不良".Translated(), DataCount = 0 }); + CommonMethods.Lst_DefectTypeQty.Add(new ChartDataType { DataType = "其他不良".Translated(), DataCount = 0 }); + } + else //读取PLC数据 + { + var plcDevicesCopy = CommonMethods.plcDevices.ToList(); + if (plcDevicesCopy.Count() > 0) + { + for (int i = 0; i < plcDevicesCopy.Count(); i++) + { + var plcDevice = plcDevicesCopy[i]; + if (plcDevice != null && plcDevice.IsConnected && plcDevice.Name == "PLC_1") + { + + Task.Run(() => + { + try + { + int ProdDRFIDNgQty = plcDevice.ReadInt16("D1000");//扫码不良 + int ProdDXNgQty = plcDevice.ReadInt16("D1001");//MES不良 + int ProdGRFIDNgQty = plcDevice.ReadInt16("D1002");//其他不良 + + CommonMethods.Lst_DefectTypeQty.Where(p => p.DataType == "扫码不良".Translated()).FirstOrDefault().DataCount = ProdDRFIDNgQty; + CommonMethods.Lst_DefectTypeQty.Where(p => p.DataType == "MES不良".Translated()).FirstOrDefault().DataCount = ProdDXNgQty; + CommonMethods.Lst_DefectTypeQty.Where(p => p.DataType == "其他不良".Translated()).FirstOrDefault().DataCount = ProdGRFIDNgQty; + //CommonMethods.Lst_DefectTypeQty.Where(p => p.DataType == "铝极耳剪切不良".Translated()).FirstOrDefault().DataCount = ProdYLZNgQty; + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + } + }); + } + } + + } + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + } + } + #endregion + + #region 智能电表 ---默认D1300开始 + public void GetEnergyData() + { + ModbusRtu busRtuClient = new ModbusRtu(); + if (CommonMethods.plcDevices.Count() > 0) + { + for (int i = 0; i < CommonMethods.plcDevices.Count(); i++) + { + if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1") + { + List listM = new List(); + List ListF = new List(); + List listAddre = new List() + { + "D1100","D1102","D1104","D1106","D1108","D1110","D1112","D1114","D1116","D1118","D1120","D1122","D1124","D1126" + }; + try + { + + ElectricEnergy m = new ElectricEnergy(); + //for (int i = 0; i < listAddre.Count; i++) + //{ + // ListF.Add(CommonMethods.plcDevices[0].ReadFloat(listAddre[i])); + //} + + //m.AccumulatedElectricity = (Decimal)ListF[0]; //有功电能(累计电能)D1100 + //m.PhaseVoltageA = (Decimal)ListF[1]; ; //A相电压 D1102 + //m.PhaseVoltageB = (Decimal)ListF[2]; ;//B相电压 D1104 + //m.PhaseVoltageC = (Decimal)ListF[3]; ;//C相电压 D1106 + //m.PhaseCurrentA = (Decimal)ListF[4]; ; //电流IA D1108 + //m.PhaseCurrentB = (Decimal)ListF[5]; ;//电流IB D1110 + //m.PhaseCurrentC = (Decimal)ListF[6]; ;//电流IC D1112 + //m.PhasePowerA = (Decimal)ListF[7]; ; //A相有功功率 D1114 + //m.PhasePowerB = (Decimal)ListF[8]; ; //B相有功功率 D1116 + //m.PhasePowerC = (Decimal)ListF[9]; ;//C相有功功率 D1118 + //m.ActivePower = (Decimal)ListF[10]; ; //总有功功率 D1120 + //m.PowerFactor = (Decimal)ListF[11]; ; //总功率因数 D1122 + //m.pt = (Decimal)ListF[12]; ; //电压变比 D1124 + //m.ct = (Decimal)ListF[13]; ; //电流变比 D1126 + + //listM.Add(m); + //CommonMethods.listElectricEnergy = listM; + //return; + + busRtuClient.SerialPortInni(sp => + { + sp.PortName = "COM1"; + sp.BaudRate = 9600; + sp.DataBits = 8; + sp.StopBits = System.IO.Ports.StopBits.One; + sp.Parity = System.IO.Ports.Parity.None; + }); + busRtuClient.DataFormat = (PLCCommunication.Common.DataFormat)DataFormat.CDAB; + busRtuClient.Open(); // 打开 + if (busRtuClient.IsOpen()) + { + // 读取数据 + JYResult readResult = busRtuClient.Read("35", 30); + JYResult readResult1 = busRtuClient.Read("3", 2); + if (readResult.IsSuccess && readResult1.IsSuccess) + { + //DPT + Byte DptH = busRtuClient.ByteTransform.TransByte(readResult.Content, 0);//高8位 + Byte DptL = busRtuClient.ByteTransform.TransByte(readResult.Content, 1);//低8位 + //DPQ + Byte DpqH = busRtuClient.ByteTransform.TransByte(readResult.Content, 2);//高8位 + Byte DpqL = busRtuClient.ByteTransform.TransByte(readResult.Content, 3);//低8位 + + //m = new ElectricEnergy(); + Decimal q = busRtuClient.ByteTransform.TransUInt16(readResult.Content, 56); + Decimal w = busRtuClient.ByteTransform.TransUInt16(readResult.Content, 58); + + m.pt = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult1.Content, 0)); //电压变比 D1124 + m.ct = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult1.Content, 2)); //电流变比 D1126 + Decimal Power = (q * 65536 + w) / 1000; + m.AccumulatedElectricity = Convert.ToDecimal(Power * m.pt * m.ct); //有功电能(累计电能)D1100 + ListF.Add((float)m.AccumulatedElectricity.Value); + //电压 + m.PhaseVoltageA = Convert.ToDecimal(busRtuClient.ByteTransform.TransUInt16(readResult.Content, 4) * Math.Pow(10, DptH - 4)); //A相电压 D1102 + m.PhaseVoltageB = Convert.ToDecimal(busRtuClient.ByteTransform.TransUInt16(readResult.Content, 6) * Math.Pow(10, DptH - 4));//B相电压 D1104 + m.PhaseVoltageC = Convert.ToDecimal(busRtuClient.ByteTransform.TransUInt16(readResult.Content, 8) * Math.Pow(10, DptH - 4));//C相电压 D1106 + ListF.Add((float)m.PhaseVoltageA.Value); + ListF.Add((float)m.PhaseVoltageB.Value); + ListF.Add((float)m.PhaseVoltageC.Value); + + //电流 + m.PhaseCurrentA = Convert.ToDecimal(busRtuClient.ByteTransform.TransUInt16(readResult.Content, 16) * Math.Pow(10, DptL - 4)); //电流IA D1108 + m.PhaseCurrentB = Convert.ToDecimal(busRtuClient.ByteTransform.TransUInt16(readResult.Content, 18) * Math.Pow(10, DptL - 4));//电流IB D1110 + m.PhaseCurrentC = Convert.ToDecimal(busRtuClient.ByteTransform.TransUInt16(readResult.Content, 20) * Math.Pow(10, DptL - 4));//电流IC D1112 + ListF.Add((float)m.PhaseCurrentA.Value); + ListF.Add((float)m.PhaseCurrentB.Value); + ListF.Add((float)m.PhaseCurrentC.Value); + + //有功功率 + m.PhasePowerA = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult.Content, 22) * Math.Pow(10, DpqH - 4)); //A相有功功率 D1114 + m.PhasePowerB = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult.Content, 24) * Math.Pow(10, DpqH - 4)); //B相有功功率 D1116 + m.PhasePowerC = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult.Content, 26) * Math.Pow(10, DpqH - 4));//C相有功功率 D1118 + m.ActivePower = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult.Content, 28) * Math.Pow(10, DpqH - 4)); //总有功功率 D1120 + ListF.Add((float)m.PhasePowerA.Value); + ListF.Add((float)m.PhasePowerB.Value); + ListF.Add((float)m.PhasePowerC.Value); + ListF.Add((float)m.ActivePower.Value); + m.PowerFactor = Convert.ToDecimal(busRtuClient.ByteTransform.TransInt16(readResult.Content, 44)) / 1000; //总功率因数 D1122 + ListF.Add((float)m.PowerFactor.Value); + ListF.Add((float)m.pt.Value); + ListF.Add((float)m.ct.Value); + + for (int j = 0; j < ListF.Count; j++) + { + CommonMethods.plcDevices[i].WriteFloat(listAddre[j], ListF[j]); + } + listM.Add(m); + CommonMethods.listElectricEnergy = listM; + + } + else + { + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "智能电表:读取数据失败"); + } + } + else + { + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "智能电表:串口打开失败"); + } + } + catch (Exception ex) + { + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"智能电表:{ex}"); + } + finally + { + if (busRtuClient.IsOpen()) + { + busRtuClient.Close(); + } + } + } + } + } + } + + public void GetEnergyDataFormPlc() + { + ModbusRtu busRtuClient = new ModbusRtu(); + if (CommonMethods.plcDevices.Count() > 0) + { + for (int i = 0; i < CommonMethods.plcDevices.Count(); i++) + { + if (CommonMethods.plcDevices[i].IsConnected && CommonMethods.plcDevices[i].Name == "PLC_1") + { + + List listM = new List(); + List ListF = new List(); + List listAddre = new List() + { + "D1100","D1102","D1104","D1106","D1108","D1110","D1112","D1114","D1116","D1118","D1120","D1122","D1124","D1126" + }; + try + { + + ElectricEnergy m = new ElectricEnergy(); + for (int j = 0; j < listAddre.Count; j++) + { + ListF.Add(CommonMethods.plcDevices[i].ReadFloat(listAddre[j])); + } + + m.AccumulatedElectricity = (Decimal)ListF[0]; //有功电能(累计电能)D1100 + m.PhaseVoltageA = (Decimal)ListF[1]; //A相电压 D1102 + m.PhaseVoltageB = (Decimal)ListF[2]; //B相电压 D1104 + m.PhaseVoltageC = (Decimal)ListF[3]; //C相电压 D1106 + m.PhaseCurrentA = (Decimal)ListF[4]; //电流IA D1108 + m.PhaseCurrentB = (Decimal)ListF[5]; //电流IB D1110 + m.PhaseCurrentC = (Decimal)ListF[6]; //电流IC D1112 + m.PhasePowerA = (Decimal)ListF[7]; //A相有功功率 D1114 + m.PhasePowerB = (Decimal)ListF[8]; //B相有功功率 D1116 + m.PhasePowerC = (Decimal)ListF[9]; //C相有功功率 D1118 + m.ActivePower = (Decimal)ListF[10]; //总有功功率 D1120 + m.PowerFactor = (Decimal)ListF[11]; //总功率因数 D1122 + m.pt = (Decimal)ListF[12]; //电压变比 D1124 + m.ct = (Decimal)ListF[13]; //电流变比 D1126 + + listM.Add(m); + CommonMethods.listElectricEnergy = listM; + return; + } + catch (Exception ex) + { + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"智能电表:{ex}"); + } + finally + { + if (busRtuClient.IsOpen()) + { + busRtuClient.Close(); + } + } + //if (CommonMethods.plcDevices.Count <= 0) { return; } + //if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected && CommonMethods.energyMeter != null && CommonMethods.energyMeter.Connected) + //{ + + // List listM = new List(); + // List ListF = new List(); + // List listAddre = new List() + // { + // //"D1100","D1102","D1104","D1106","D1108","D1110","D1112","D1114","D1116","D1118","D1120","D1122","D1124","D1126" + // "D1300","D1302","D1304","D1306","D1308","D1310","D1312","D1314","D1316","D1318","D1320","D1322","D1324","D1326" + // }; + // //00 00 00 00 00 06 报文头 + // //01 04 00 00 00 3E 不需要校验位 + // byte[] bytes = new byte[12]; + // bytes[0] = Convert.ToByte(01 >> 8); // Slave id high byte//事务元标识符,高字节在前,低字节在后 + // bytes[1] = Convert.ToByte(01);// Slave id low byte + // bytes[2] = 0x00;//协议标识符,高字节在前,低字节在后 (TCP 00) + // bytes[3] = 0x00; + // bytes[4] = 0x00;//后续字节长度,高字节在前,低字节在后 + // bytes[5] = 0x06; // Message size + // bytes[6] = 0x01; // Slave address + // bytes[7] = 0x04;//功能码04H // Function code + // bytes[8] = Convert.ToByte((00 >> 8) & 0xFF); // Start address//寄存器起始地址高字节m_unBeginWord + // bytes[9] = Convert.ToByte(00 & 0xFF); // Start address//寄存器起始地址低字节m_unBeginWord + // bytes[10] = Convert.ToByte((88 >> 8) & 0xFF); // Number of data to read//寄存器数量高字节m_unWordsCount + // bytes[11] = Convert.ToByte(88 & 0xFF); // Number of data to read//寄存器数量低字节m_unWordsCount 0x58 + + // try + // { + // CommonMethods.energyMeter.SendAndGetRes(bytes, ref listM); + // #region 读取× + // //for (int i = 0; i < listAddre.Count; i++) + // //{ + // // float val = CommonMethods.plcDevices[0].ReadFloat(listAddre[i]); + // // ListF.Add(val); + // //} + + // //ElectricEnergy m = new ElectricEnergy(); + // //m.AccumulatedElectricity = Convert.ToDecimal(ListF[0]); + // //m.PhaseVoltageA = Convert.ToDecimal(ListF[1]); + // //m.PhaseVoltageB = Convert.ToDecimal(ListF[2]); + // //m.PhaseVoltageC = Convert.ToDecimal(ListF[3]); + // //m.PhaseCurrentA = Convert.ToDecimal(ListF[4]); + // //m.PhaseCurrentB = Convert.ToDecimal(ListF[5]); + // //m.PhaseCurrentC = Convert.ToDecimal(ListF[6]); + // //m.PhasePowerA = Convert.ToDecimal(ListF[7]); + // //m.PhasePowerB = Convert.ToDecimal(ListF[8]); + // //m.PhasePowerC = Convert.ToDecimal(ListF[9]); + // //m.ActivePower = Convert.ToDecimal(ListF[10]); + // //m.PowerFactor = Convert.ToDecimal(ListF[11]); + // //m.pt = Convert.ToDecimal(ListF[12]); + // //m.ct = Convert.ToDecimal(ListF[13]); + + // //listM.Add(m); + // #endregion + // foreach (ElectricEnergy energy in listM) + // { + // CommonMethods.plcDevices[0].WriteFloat(listAddre[0], (float)energy.AccumulatedElectricity); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[1], (float)energy.PhaseVoltageA); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[2], (float)energy.PhaseVoltageB); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[3], (float)energy.PhaseVoltageC); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[4], (float)energy.PhaseCurrentA); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[5], (float)energy.PhaseCurrentB); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[6], (float)energy.PhaseCurrentC); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[7], (float)energy.PhasePowerA); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[8], (float)energy.PhasePowerB); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[9], (float)energy.PhasePowerC); + + // CommonMethods.plcDevices[0].WriteFloat(listAddre[10], (float)energy.ActivePower); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[11], (float)energy.PowerFactor); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[12], (float)energy.pt); + // CommonMethods.plcDevices[0].WriteFloat(listAddre[13], (float)energy.ct); + // } + // CommonMethods.listElectricEnergy = listM; + // } + // catch (Exception ex) + // { + // TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"智能电表:{ex}"); + // } + //} + } + } + + } + } + + /// + /// 能耗上传MES + /// + public async void UploadEquEnergy() + { + if (CommonMethods.listElectricEnergy.Count > 0) + { + if (CommonMethods.mesConfig.isUpMes) + { + string msg = string.Empty; + DateTime nowDate = DateTime.Now; + string filePath = string.Empty; + string fileName = string.Empty; + string fileTitle = string.Empty; + string fileContent = string.Empty; + List listP = new List(); + int i = 0; + foreach (ElectricEnergy m in CommonMethods.listElectricEnergy) + { + WattrMeter param = new WattrMeter(); + param.siteCode = CommonMethods.mesConfig.siteCode; + param.lineCode = CommonMethods.mesConfig.lineCode; + param.equipNum = CommonMethods.mesConfig.equipNum; + param.userName = CommonMethods.mesConfig.mesUserName; + param.electricMeterNum = CommonMethods.mesConfig.electricMeterNum[i]; + param.recordDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"); + param.accumulatedElectricity = (decimal)m.AccumulatedElectricity; + param.phaseVoltageA = (decimal)m.PhaseVoltageA; + param.phaseVoltageB = (decimal)m.PhaseVoltageB; + param.phaseVoltageC = (decimal)m.PhaseVoltageC; + param.phaseCurrentA = (decimal)m.PhaseCurrentA; + param.phaseCurrentB = (decimal)m.PhaseCurrentB; + param.phaseCurrentC = (decimal)m.PhaseCurrentC; + param.phasePowerA = (decimal)m.PhasePowerA; + param.phasePowerB = (decimal)m.PhasePowerB; + param.phasePowerC = (decimal)m.PhasePowerC; + param.activePower = (decimal)m.ActivePower; + param.powerFactor = (decimal)m.PowerFactor; + param.pt = (decimal)m.pt; + param.ct = (decimal)m.ct; + + listP.Add(param); + i++; + + // 写csv文件 + string productName = string.Empty; + + filePath = $@"{CommonMethods.strWattrMeterpath}\{nowDate.Year}\{nowDate.Month}"; + fileName = $@"{nowDate.Day}.csv"; + fileTitle = "工序名称,生产机台编号,拉线,型号,物料编号,操作人员,班次,电表编号,采集时间,有功电能(累计电能)KwH,A相电压 V,B相电压 V,C相电压 V,A相电流 A,B相电流 A,C相电流 A,A相功率 Kw,B相功率 Kw,C相功率 Kw,总有功功率 Kw,总功率因数 %,电压变比,电流变比"; + fileContent = $"组盘工序,{CommonMethods.mesConfig.equipNum},{CommonMethods.mesConfig.lineCode},{productName},{CommonMethods.mesConfig.MaterialCode},{CommonMethods.mesConfig.mesUserName},{CommonMethods.strClass},{param.electricMeterNum},{nowDate.ToString("yyyy-MM-dd HH:mm:ss")}," + + $"{param.accumulatedElectricity},{param.phaseVoltageA},{param.phaseVoltageB},{param.phaseVoltageC},{param.phaseCurrentA},{param.phaseCurrentB},{param.phaseCurrentC}," + + $"{param.phasePowerA},{param.phasePowerB},{param.phasePowerC},{param.activePower},{param.powerFactor},{param.pt},{param.ct}"; + CSVHelper.WriterCSV(filePath, fileName, fileTitle, fileContent); + } + //上传MES + var (success, mesg) = await CommonMethods.hbgMes.UploadEquEnergyAsync(CommonMethods.mesConfig.EnergyConsumption, CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode, + CommonMethods.mesConfig.mesUserName, CommonMethods.mesConfig.electricMeterNum, listP).ConfigureAwait(false); + } + } + } + + public static byte[] CalculateCRCTemp(ref byte[] messageArray, int dataLength) + { + byte usCRCHi = 0xFF; + byte usCRCLo = 0xFF; + byte[] returnResult = { 0x00, 0x00 }; + int index = 0; + int messageIndex = 0; + while (dataLength > 0) + { + index = usCRCLo ^ messageArray[messageIndex]; + usCRCLo = Convert.ToByte(usCRCHi ^ crcHi[index]); + usCRCHi = crcLo[index]; + messageIndex++; + dataLength--; + } + //0th item is crcLo + returnResult[0] = usCRCLo; + //1st item is crcHi + returnResult[1] = usCRCHi; + //2nd item is the total CRC16. + //returnResult[2] = Convert.ToByte((usCRCHi << 8 | usCRCLo)); + return returnResult; + } + + static byte[] crcHi = + { + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, + 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, + 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, + 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, + 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, + 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40 + }; + + static byte[] crcLo = + { + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, + 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, + 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, + 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, + 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, + 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, + 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, + 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, + 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, + 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, + 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, + 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, + 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, + 0x40 + }; + #endregion + + #region 定期清理本地保存下料数据 + /// + /// 定期清理本地保存下料数据 + /// + public void DeleteFileOfLocal() + { + try + { + //string filePath = string.Format(@"{0}\Data\{1}", Application.StartupPath, DateTime.Now.AddDays(-365).Year); + string filePath = string.Format(@"{0}\{1}", @"D:\LocalData", DateTime.Now.AddYears(-1).Year); + if (Directory.Exists(filePath)) + { + //判断是否有子文件夹,循环删除 + for (int i = 1; i <= DateTime.Now.Month; i++) + { + string tempPath = string.Format(@"{0}\{1}", filePath, i); + if (Directory.Exists(tempPath)) + { + LogCLear_DirOrFile("下料本地文件", DateTime.Now, tempPath, 365); + } + } + //没有子文件夹,删除目录 + DirectoryInfo[] DirList = GetSubcatalog(filePath);//获取文件路径 + if (DirList != null)//目录存在 + { + if (DirList.Length == 0) + { + Directory.Delete(filePath, true); + Thread.Sleep(10); + } + } + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteLog($"定期清理本地保存下料数据异常:{ex.ToString()}", "Info"); + } + + } + + /// 清理指定目录下的文件夹或文件 + /// 清理文件注释 + /// 当前时间 + /// 文件目录 + /// 保留天数 + public void LogCLear_DirOrFile(string strName, DateTime CurrentTime, string FilePath, uint RtnDayNums) + { + long time = 0; + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + bool b_OK = true; + LogHelper.Instance.WriteLog($"清理{strName}开始", "Info"); + try + { + DirectoryInfo[] DirList = GetSubcatalog(FilePath);//获取文件路径 + if (DirList != null)//目录不存在 + { + if (DirList.Length != 0)//目录是否有子文件夹:如 文件夹“2021-10-31” + { + #region 删文件夹 + foreach (var dirInfo in DirList)//循环删除文件夹 + { + DateTime itemDateTime = dirInfo.CreationTime;//获取文件夹创建日期 + if (CurrentTime.AddDays(-RtnDayNums) > itemDateTime) + { + if (dirInfo.Exists) + { + dirInfo.Delete(true); + Thread.Sleep(10); + } + } + } + #endregion + } + else//目录下无子文件夹存在时,判断是否有文件 + { + string[] fileList = null; + if (Directory.Exists(FilePath)) + { + //获取文件列表 + fileList = Directory.GetFiles(FilePath); + if (fileList != null)//目录不存在 + { + if (fileList.Length != 0)//目录下是否存在文件 + { + #region 删除文件 + foreach (var filePath in fileList)//循环删除文件 + { + DateTime itemDateTime = new FileInfo(filePath).LastWriteTime;//获取文件修改日期 + if (CurrentTime.AddDays(-RtnDayNums) > itemDateTime) + { + if (File.Exists(filePath)) + { + File.Delete(filePath); + Thread.Sleep(2); + } + } + } + #endregion + } + else + { + #region 删除文件夹 + Directory.Delete(FilePath, true); + #endregion + } + } + } + } + } + b_OK = true; + } + catch (Exception) + { + b_OK = false; + } + stopWatch.Stop(); + time = stopWatch.ElapsedMilliseconds; + LogHelper.Instance.WriteLog($"{FilePath},清理结束,结果;{b_OK},耗时:{time}", "Info"); + } + + /// + /// 获取指定目录中所有文件列表 + /// + /// 指定目录的绝对路径 + public DirectoryInfo[] GetSubcatalog(string directoryPath) + { + DirectoryInfo dir = new DirectoryInfo(directoryPath); + //如果目录存在 + if (dir.Exists) + { + //获取文件列表 + DirectoryInfo[] dirs = dir.GetDirectories(); + return dirs; + } + else + return null; + } + + #endregion + } +} diff --git a/JinYuan.ControlCenter/JinYuan.ControlCenters.csproj b/JinYuan.ControlCenter/JinYuan.ControlCenters.csproj new file mode 100644 index 0000000..bb805e2 --- /dev/null +++ b/JinYuan.ControlCenter/JinYuan.ControlCenters.csproj @@ -0,0 +1,101 @@ + + + + + Debug + AnyCPU + {1D0FA5A4-07F0-4621-B6BB-683AEC91E658} + Library + Properties + JinYuan.ControlCenters + JinYuan.ControlCenters + v4.8 + 512 + true + 8.0 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MiniExcel.1.36.1\lib\net45\MiniExcel.dll + + + False + ..\LargeSquareOne\Lib\PLCCommunication.dll + + + ..\Libs\SqlSugar.dll + + + + + + + + + + + + + + + + + + + + + + + + {114aa012-29c9-418c-a2d6-3173c5341f51} + JinYuan.DAL + + + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360} + JinYuan.Helper + + + {530B6426-08E7-461C-91DC-787F876620FC} + JinYuan.MES + + + {4c0bcb84-5cd7-4846-8363-c4c10d46e391} + JinYuan.Models + + + {2ab7e380-7795-448a-933c-0f6a081b5e7e} + JinYuan.VirtualDataLibrary + + + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C} + Language + + + {486aecd0-c2bf-43c5-b7d7-88e565ade4b7} + PLC + + + + + + + + \ No newline at end of file diff --git a/JinYuan.ControlCenter/Properties/AssemblyInfo.cs b/JinYuan.ControlCenter/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a45bd93 --- /dev/null +++ b/JinYuan.ControlCenter/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.ControlCenters")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.ControlCenters")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("1d0fa5a4-07f0-4621-b6bb-683aec91e658")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.ControlCenter/app.config b/JinYuan.ControlCenter/app.config new file mode 100644 index 0000000..875387a --- /dev/null +++ b/JinYuan.ControlCenter/app.config @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JinYuan.ControlCenter/iniConfigHelper/CreateIniFile.cs b/JinYuan.ControlCenter/iniConfigHelper/CreateIniFile.cs new file mode 100644 index 0000000..5440afa --- /dev/null +++ b/JinYuan.ControlCenter/iniConfigHelper/CreateIniFile.cs @@ -0,0 +1,6 @@ +namespace iniConfigHelper +{ + internal class CreateIniFile + { + } +} \ No newline at end of file diff --git a/JinYuan.ControlCenter/packages.config b/JinYuan.ControlCenter/packages.config new file mode 100644 index 0000000..906dcfd --- /dev/null +++ b/JinYuan.ControlCenter/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/AlertManager.cs b/JinYuan.ControlLib/AlertManager.cs new file mode 100644 index 0000000..d5e0aaa --- /dev/null +++ b/JinYuan.ControlLib/AlertManager.cs @@ -0,0 +1,63 @@ +using AntdUI; +using System; +using System.Collections.Generic; + +namespace Controls +{ + public class AlertManager + { + private readonly Alert alert; + private readonly Queue<(string message, TType type)> messageQueue = new Queue<(string, TType)>(); + private readonly System.Windows.Forms.Timer throttleTimer; + private const int ThrottleInterval = 100; // 毫秒 + + public AlertManager(Alert alertControl) + { + alert = alertControl ?? throw new ArgumentNullException(nameof(alertControl)); + + throttleTimer = new System.Windows.Forms.Timer(); + throttleTimer.Interval = ThrottleInterval; + throttleTimer.Tick += ThrottleTimer_Tick; + } + + public void ShowAlert(string message, TType type = TType.Info) + { + messageQueue.Enqueue((message, type)); + if (!throttleTimer.Enabled) + { + throttleTimer.Start(); + } + } + + private void ThrottleTimer_Tick(object sender, EventArgs e) + { + if (messageQueue.Count > 0) + { + var (message, type) = messageQueue.Dequeue(); + UpdateAlertUI(message, type); + } + else + { + throttleTimer.Stop(); + } + } + + private void UpdateAlertUI(string message, TType type) + { + if (alert.InvokeRequired) + { + alert.BeginInvoke(new Action(() => UpdateAlertUI(message, type))); + return; + } + + alert.Text = message; + alert.Icon = type; + alert.Invalidate(); + } + + public void Dispose() + { + throttleTimer?.Dispose(); + } + } +} diff --git a/JinYuan.ControlLib/ArrTotalQty.Designer.cs b/JinYuan.ControlLib/ArrTotalQty.Designer.cs new file mode 100644 index 0000000..e77ad7b --- /dev/null +++ b/JinYuan.ControlLib/ArrTotalQty.Designer.cs @@ -0,0 +1,173 @@ +namespace JinYuan.ControlLib +{ + partial class ArrTotalQty + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ArrTotalQty)); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lbl_Title6 = new JinYuan.ControlLib.TotalQty(); + this.lbl_Title5 = new JinYuan.ControlLib.TotalQty(); + this.lbl_Title4 = new JinYuan.ControlLib.TotalQty(); + this.lbl_Title3 = new JinYuan.ControlLib.TotalQty(); + this.lbl_Title2 = new JinYuan.ControlLib.TotalQty(); + this.lbl_Title1 = new JinYuan.ControlLib.TotalQty(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 6; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title6, 5, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title5, 4, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title4, 3, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title3, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title2, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title1, 0, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(300, 79); + this.tableLayoutPanel1.TabIndex = 1; + // + // lbl_Title6 + // + this.lbl_Title6.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title6.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("lbl_Title6.BackgroundImage"))); + this.lbl_Title6.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.lbl_Title6.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title6.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title6.Location = new System.Drawing.Point(254, 5); + this.lbl_Title6.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title6.Name = "lbl_Title6"; + this.lbl_Title6.Size = new System.Drawing.Size(42, 69); + this.lbl_Title6.TabIndex = 5; + this.lbl_Title6.TitleName = "0"; + // + // lbl_Title5 + // + this.lbl_Title5.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title5.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("lbl_Title5.BackgroundImage"))); + this.lbl_Title5.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.lbl_Title5.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title5.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title5.Location = new System.Drawing.Point(204, 5); + this.lbl_Title5.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title5.Name = "lbl_Title5"; + this.lbl_Title5.Size = new System.Drawing.Size(42, 69); + this.lbl_Title5.TabIndex = 4; + this.lbl_Title5.TitleName = "0"; + // + // lbl_Title4 + // + this.lbl_Title4.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title4.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("lbl_Title4.BackgroundImage"))); + this.lbl_Title4.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.lbl_Title4.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title4.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title4.Location = new System.Drawing.Point(154, 5); + this.lbl_Title4.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title4.Name = "lbl_Title4"; + this.lbl_Title4.Size = new System.Drawing.Size(42, 69); + this.lbl_Title4.TabIndex = 3; + this.lbl_Title4.TitleName = "0"; + // + // lbl_Title3 + // + this.lbl_Title3.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title3.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("lbl_Title3.BackgroundImage"))); + this.lbl_Title3.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.lbl_Title3.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title3.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title3.Location = new System.Drawing.Point(104, 5); + this.lbl_Title3.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title3.Name = "lbl_Title3"; + this.lbl_Title3.Size = new System.Drawing.Size(42, 69); + this.lbl_Title3.TabIndex = 2; + this.lbl_Title3.TitleName = "0"; + // + // lbl_Title2 + // + this.lbl_Title2.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title2.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("lbl_Title2.BackgroundImage"))); + this.lbl_Title2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.lbl_Title2.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title2.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title2.Location = new System.Drawing.Point(54, 5); + this.lbl_Title2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title2.Name = "lbl_Title2"; + this.lbl_Title2.Size = new System.Drawing.Size(42, 69); + this.lbl_Title2.TabIndex = 1; + this.lbl_Title2.TitleName = "0"; + // + // lbl_Title1 + // + this.lbl_Title1.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("lbl_Title1.BackgroundImage"))); + this.lbl_Title1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.lbl_Title1.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title1.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title1.ForeColor = System.Drawing.Color.White; + this.lbl_Title1.Location = new System.Drawing.Point(4, 5); + this.lbl_Title1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title1.Name = "lbl_Title1"; + this.lbl_Title1.Size = new System.Drawing.Size(42, 69); + this.lbl_Title1.TabIndex = 0; + this.lbl_Title1.TitleName = "0"; + // + // ArrTotalQty + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ArrTotalQty"; + this.Size = new System.Drawing.Size(300, 79); + this.tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private TotalQty lbl_Title1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private TotalQty lbl_Title6; + private TotalQty lbl_Title5; + private TotalQty lbl_Title4; + private TotalQty lbl_Title3; + private TotalQty lbl_Title2; + } +} diff --git a/JinYuan.ControlLib/ArrTotalQty.cs b/JinYuan.ControlLib/ArrTotalQty.cs new file mode 100644 index 0000000..c8ff3fc --- /dev/null +++ b/JinYuan.ControlLib/ArrTotalQty.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class ArrTotalQty : UserControl + { + public ArrTotalQty() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + // UpData(); + } + + + //#region 减少闪烁 + //protected override CreateParams CreateParams + //{ + // get + // { + // CreateParams cp = base.CreateParams; + // cp.ExStyle |= 0x02000000; + // return cp; + // } + //} + //#endregion + + private int _MaxValue = 999999; + + + private int totalValue = 0; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示数字值:(最大值999999)")] + + + public int TotalValue + { + get { return totalValue; } + set + { + if (value > _MaxValue) return; + totalValue = value; + SetElectricEnergy(totalValue); + } + } + + + private void SetElectricEnergy(int value) + { + if (totalValue.ToString().Length < 7) + { + bool isNumeric = Regex.IsMatch(totalValue.ToString(), @"^\d+$"); + if (isNumeric) + { + List numbers = new List(); + + foreach (char c in totalValue.ToString()) + { + if (char.IsDigit(c)) + { + int number = int.Parse(c.ToString()); + numbers.Add(number); + } + } + + for (int i = 1; i < numbers.Count + 1; i++) + { + switch (numbers.Count) + { + case 1: + this.lbl_Title1.TitleName = 0.ToString(); + this.lbl_Title2.TitleName = 0.ToString(); + this.lbl_Title3.TitleName = 0.ToString(); + this.lbl_Title4.TitleName = 0.ToString(); + this.lbl_Title5.TitleName = 0.ToString(); + this.lbl_Title6.TitleName = numbers[0].ToString(); + break; + case 2: + this.lbl_Title1.TitleName = 0.ToString(); + this.lbl_Title2.TitleName = 0.ToString(); + this.lbl_Title3.TitleName = 0.ToString(); + this.lbl_Title4.TitleName = 0.ToString(); + this.lbl_Title5.TitleName = numbers[0].ToString(); + this.lbl_Title6.TitleName = numbers[1].ToString(); + break; + case 3: + this.lbl_Title1.TitleName = 0.ToString(); + this.lbl_Title2.TitleName = 0.ToString(); + this.lbl_Title3.TitleName = 0.ToString(); + this.lbl_Title4.TitleName = numbers[0].ToString(); + this.lbl_Title5.TitleName = numbers[1].ToString(); + this.lbl_Title6.TitleName = numbers[2].ToString(); + break; + case 4: + this.lbl_Title1.TitleName = 0.ToString(); + this.lbl_Title2.TitleName = 0.ToString(); + this.lbl_Title3.TitleName = numbers[0].ToString(); + this.lbl_Title4.TitleName = numbers[1].ToString(); + this.lbl_Title5.TitleName = numbers[2].ToString(); + this.lbl_Title6.TitleName = numbers[3].ToString(); + break; + case 5: + this.lbl_Title1.TitleName = 0.ToString(); + this.lbl_Title2.TitleName = numbers[0].ToString(); + this.lbl_Title3.TitleName = numbers[1].ToString(); + this.lbl_Title4.TitleName = numbers[2].ToString(); + this.lbl_Title5.TitleName = numbers[3].ToString(); + this.lbl_Title6.TitleName = numbers[4].ToString(); + break; + case 6: + this.lbl_Title1.TitleName = numbers[0].ToString(); + this.lbl_Title2.TitleName = numbers[1].ToString(); + this.lbl_Title3.TitleName = numbers[2].ToString(); + this.lbl_Title4.TitleName = numbers[3].ToString(); + this.lbl_Title5.TitleName = numbers[4].ToString(); + this.lbl_Title6.TitleName = numbers[5].ToString(); + break; + default: + break; + } + } + } + } + } + } +} diff --git a/JinYuan.ControlLib/ArrTotalQty.resx b/JinYuan.ControlLib/ArrTotalQty.resx new file mode 100644 index 0000000..d4d689f --- /dev/null +++ b/JinYuan.ControlLib/ArrTotalQty.resx @@ -0,0 +1,877 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + BD5r4T4h7uvLAAAAAElFTkSuQmCC + + + + + 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 + BD5r4T4h7uvLAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAADEAAABFCAYAAADjLw7LAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH + DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKNWlDQ1BzUkdCIElFQzYxOTY2LTIuMQAA + SMedlndUVNcWh8+9d3qhzTDSGXqTLjCA9C4gHQRRGGYGGMoAwwxNbIioQEQREQFFkKCAAaOhSKyIYiEo + qGAPSBBQYjCKqKhkRtZKfHl57+Xl98e939pn73P32XuftS4AJE8fLi8FlgIgmSfgB3o401eFR9Cx/QAG + eIABpgAwWempvkHuwUAkLzcXerrICfyL3gwBSPy+ZejpT6eD/0/SrFS+AADIX8TmbE46S8T5Ik7KFKSK + 7TMipsYkihlGiZkvSlDEcmKOW+Sln30W2VHM7GQeW8TinFPZyWwx94h4e4aQI2LER8QFGVxOpohvi1gz + SZjMFfFbcWwyh5kOAIoktgs4rHgRm4iYxA8OdBHxcgBwpLgvOOYLFnCyBOJDuaSkZvO5cfECui5Lj25q + bc2ge3IykzgCgaE/k5XI5LPpLinJqUxeNgCLZ/4sGXFt6aIiW5paW1oamhmZflGo/7r4NyXu7SK9Cvjc + M4jW94ftr/xS6gBgzIpqs+sPW8x+ADq2AiB3/w+b5iEAJEV9a7/xxXlo4nmJFwhSbYyNMzMzjbgclpG4 + oL/rfzr8DX3xPSPxdr+Xh+7KiWUKkwR0cd1YKUkpQj49PZXJ4tAN/zzE/zjwr/NYGsiJ5fA5PFFEqGjK + uLw4Ubt5bK6Am8Kjc3n/qYn/MOxPWpxrkSj1nwA1yghI3aAC5Oc+gKIQARJ5UNz13/vmgw8F4psXpjqx + OPefBf37rnCJ+JHOjfsc5xIYTGcJ+RmLa+JrCdCAACQBFcgDFaABdIEhMANWwBY4AjewAviBYBAO1gIW + iAfJgA8yQS7YDApAEdgF9oJKUAPqQSNoASdABzgNLoDL4Dq4Ce6AB2AEjIPnYAa8AfMQBGEhMkSB5CFV + SAsygMwgBmQPuUE+UCAUDkVDcRAPEkK50BaoCCqFKqFaqBH6FjoFXYCuQgPQPWgUmoJ+hd7DCEyCqbAy + rA0bwwzYCfaGg+E1cBycBufA+fBOuAKug4/B7fAF+Dp8Bx6Bn8OzCECICA1RQwwRBuKC+CERSCzCRzYg + hUg5Uoe0IF1IL3ILGUGmkXcoDIqCoqMMUbYoT1QIioVKQ21AFaMqUUdR7age1C3UKGoG9QlNRiuhDdA2 + aC/0KnQcOhNdgC5HN6Db0JfQd9Dj6DcYDIaG0cFYYTwx4ZgEzDpMMeYAphVzHjOAGcPMYrFYeawB1g7r + h2ViBdgC7H7sMew57CB2HPsWR8Sp4sxw7rgIHA+XhyvHNeHO4gZxE7h5vBReC2+D98Oz8dn4Enw9vgt/ + Az+OnydIE3QIdoRgQgJhM6GC0EK4RHhIeEUkEtWJ1sQAIpe4iVhBPE68QhwlviPJkPRJLqRIkpC0k3SE + dJ50j/SKTCZrkx3JEWQBeSe5kXyR/Jj8VoIiYSThJcGW2ChRJdEuMSjxQhIvqSXpJLlWMkeyXPKk5A3J + aSm8lLaUixRTaoNUldQpqWGpWWmKtKm0n3SydLF0k/RV6UkZrIy2jJsMWyZf5rDMRZkxCkLRoLhQWJQt + lHrKJco4FUPVoXpRE6hF1G+o/dQZWRnZZbKhslmyVbJnZEdoCE2b5kVLopXQTtCGaO+XKC9xWsJZsmNJ + y5LBJXNyinKOchy5QrlWuTty7+Xp8m7yifK75TvkHymgFPQVAhQyFQ4qXFKYVqQq2iqyFAsVTyjeV4KV + 9JUCldYpHVbqU5pVVlH2UE5V3q98UXlahabiqJKgUqZyVmVKlaJqr8pVLVM9p/qMLkt3oifRK+g99Bk1 + JTVPNaFarVq/2ry6jnqIep56q/ojDYIGQyNWo0yjW2NGU1XTVzNXs1nzvhZei6EVr7VPq1drTltHO0x7 + m3aH9qSOnI6XTo5Os85DXbKug26abp3ubT2MHkMvUe+A3k19WN9CP16/Sv+GAWxgacA1OGAwsBS91Hop + b2nd0mFDkqGTYYZhs+GoEc3IxyjPqMPohbGmcYTxbuNe408mFiZJJvUmD0xlTFeY5pl2mf5qpm/GMqsy + u21ONnc332jeaf5ymcEyzrKDy+5aUCx8LbZZdFt8tLSy5Fu2WE5ZaVpFW1VbDTOoDH9GMeOKNdra2Xqj + 9WnrdzaWNgKbEza/2BraJto22U4u11nOWV6/fMxO3Y5pV2s3Yk+3j7Y/ZD/ioObAdKhzeOKo4ch2bHCc + cNJzSnA65vTC2cSZ79zmPOdi47Le5bwr4urhWuja7ybjFuJW6fbYXd09zr3ZfcbDwmOdx3lPtKe3527P + YS9lL5ZXo9fMCqsV61f0eJO8g7wrvZ/46Pvwfbp8Yd8Vvnt8H67UWslb2eEH/Lz89vg98tfxT/P/PgAT + 4B9QFfA00DQwN7A3iBIUFdQU9CbYObgk+EGIbogwpDtUMjQytDF0Lsw1rDRsZJXxqvWrrocrhHPDOyOw + EaERDRGzq91W7109HmkRWRA5tEZnTdaaq2sV1iatPRMlGcWMOhmNjg6Lbor+wPRj1jFnY7xiqmNmWC6s + faznbEd2GXuKY8cp5UzE2sWWxk7G2cXtiZuKd4gvj5/munAruS8TPBNqEuYS/RKPJC4khSW1JuOSo5NP + 8WR4ibyeFJWUrJSBVIPUgtSRNJu0vWkzfG9+QzqUvia9U0AV/Uz1CXWFW4WjGfYZVRlvM0MzT2ZJZ/Gy + +rL1s3dkT+S453y9DrWOta47Vy13c+7oeqf1tRugDTEbujdqbMzfOL7JY9PRzYTNiZt/yDPJK817vSVs + S1e+cv6m/LGtHlubCyQK+AXD22y31WxHbedu799hvmP/jk+F7MJrRSZF5UUfilnF174y/ariq4WdsTv7 + SyxLDu7C7OLtGtrtsPtoqXRpTunYHt897WX0ssKy13uj9l4tX1Zes4+wT7hvpMKnonO/5v5d+z9Uxlfe + qXKuaq1Wqt5RPXeAfWDwoOPBlhrlmqKa94e4h+7WetS212nXlR/GHM44/LQ+tL73a8bXjQ0KDUUNH4/w + jowcDTza02jV2Nik1FTSDDcLm6eORR67+Y3rN50thi21rbTWouPguPD4s2+jvx064X2i+yTjZMt3Wt9V + t1HaCtuh9uz2mY74jpHO8M6BUytOdXfZdrV9b/T9kdNqp6vOyJ4pOUs4m3924VzOudnzqeenL8RdGOuO + 6n5wcdXF2z0BPf2XvC9duex++WKvU++5K3ZXTl+1uXrqGuNax3XL6+19Fn1tP1j80NZv2d9+w+pG503r + m10DywfODjoMXrjleuvyba/b1++svDMwFDJ0dzhyeOQu++7kvaR7L+9n3J9/sOkh+mHhI6lH5Y+VHtf9 + qPdj64jlyJlR19G+J0FPHoyxxp7/lP7Th/H8p+Sn5ROqE42TZpOnp9ynbj5b/Wz8eerz+emCn6V/rn6h + ++K7Xxx/6ZtZNTP+kv9y4dfiV/Kvjrxe9rp71n/28ZvkN/NzhW/l3x59x3jX+z7s/cR85gfsh4qPeh+7 + Pnl/eriQvLDwG/eE8/s6uL5TAAAACXBIWXMAAAsMAAALDAE/QCLIAAARpklEQVRoQ9WaeVwT19rHh50k + bAmEBEjC5lp7l89t6y4ighu07rsgLiwuJIQAIYEEENms4tbba93aWtu6L9W64FK1ouLWuoIrgrWiVq2t + du/M/T2TRKPX9733837e2+AfXyfJzHme5ztzZs45g4ys8MIrYAwYCAZZwef6gTJz/Rtyc93rjgQ1vI5a + 3viX+oouDA801cdKDec9SKIPMIJpFuqnys3n0+WmcylBpjOTwUTHcnYSSJGbzqdBaIq1zumQyIZEIiQE + TGDRpShZ4UXakSQ314+Vm86MDC44PTSk4ItBIfnH31DkH3vdkYTknxhItQQXnBoCqRE4waMhkygrupgq + NV8YGmCsFzDS4ss9ITFdZq4bG1RwZkRwwReDFcZjryuNtQOUxkP9Qg01fUMNB/s4ChVqUBqPDFAYjyaE + 5J+EzOmh6CWjUXOKtPDSsICCCwImoPhKL3ShabhkI2A8WJF/NF5lQPF5n8eG5u2LCdfv7RWu3xPtGPZG + h+n39Q7NOxCLmvoq8mvjcWUG4WQPlxfWT4LE8AATSZRAwlw3lQzpCpBAmP5AbHjunugIfXVUq9zt3R3H + ju6ROdVREbm7e4bp9/cONR7sozQehcgXg4LM55MDii4N9zddhMTMht50I2PHQOpCuAJxJBCZs6NH6+yt + XdvoNndpo9vU2TFs7tI6e0uXVjnbu5NIaN7+3krj4f4K3KtB5rOJkBjhb74kZPwhga6USjvoHghDF4rI + rY7iBbI2dW6bta5ju6y1DqOtbkMniHSlk0pdm+5R9JiEIPOZxIDiSyPEhZeFjKS0MVZuPptCNw4O6BOB + ftgqZ0f3NrpPurSDQHvtqlfba1c7iFWvkghdlVbZ27pFoIeo0FOoSwWbTo/1n3FlpF/xVUiUNcZBIpWX + yDsIiT2Q2A6JTZ0R4DUK9FLmR684inba1a+1zaKrsbVbeO7uaOru9LQKNp0aA4lRfsUNXoy4vKkvJNIg + Ef9iSXw5RlJydYzvjEZvRlxxvb/cfC79xZM4NVZS0jDWd0aTN+NXeWPACylhPjVWPLMhyWdGkw9JJLyo + V0I881qSTwkkfN+8iZnquSkvmER/SIzzK2tK9i694cP4zG4eKC88N/WFkjBAwgyJ8qZJXmU3fBmfObeG + QGIaJDBa20tsxjixlh8nnhf8j4KX0G20SWDUtkmcHudb8VWKV/lNP8Z77u1h8sLz05WGZ69Ey5SwDHa1 + A4LMpxMhkcpLeFV9MwISGZAYQFNfy4jdEiQ+fIVyt8ta81ob3UaM2J9CAiO2wSphIokb6V4VzZCYd2ck + JNQKwzFMwWv6hus/64VpRw+rhEPvCZp60InkJXIggV6iQm/BtAOP2DNJPpVfTxVVNIsZ0by7YyCRqTAe + T8AMEdPwz3pF5uyExCddaPLnWAnb3OmJBLp8HN2/8sKzyd6zvs4QVtySMKL598fJCuu0kIinaW6ofn9M + RIuT2GyZjlsk+tCTlJd4s1kjnHVHwggXfDs5sLBOpzCeiFdZJHpHYCHSWrela1vd+k4tSYKm4tTlMRWP + x3pivPfsW7mQ8GcE8+4PkZQ1FCqNJ7CuPtKfloIRubt64mnAS7TLWv1a+0zHiJAE9QbqFdTFqatTlyeJ + wOJ6tWju3SxRxS13RlR620dU9Y1eXnQ2Gc9frK1JYndP9MGubbM2YsBb4xCJ9pkf8esJOpHUK6h3UC/B + wq1/SMHJIT6zbxYLK+/81avoJsMIFtxlPOd9G+1f3pCv0h+KDTUciLNIbOuG57MDJagr0RjBj9ZdqXdg + eRqryjvURzbj/GSvkjtqz8X3GOfzvzAMc4V71WPRgxH+xQ05Kv3hOIwVkNgDie3dHS+xxjblsEocgMTh + PuhKU4Rv3h3puu/ndsx9rj3DXOM2ub/zfZVkxrV0Vd6RPrhx+tANZB3wLPOnzI8dJ2F9vFpeFPASfQML + 6tI9lz2IZr7m5jBXuTcZ/LPU/Z3vKiQl1zJIghbi1gEPV6KlSND6GhLo6ioDJEwXpnou/q4v08CZQD51 + p6Vui7+fJS65lqnKq40NMx37W0R+TYc2hj1t2us/De+Qs1H5sm6N4s+61cF/JC/r1io65KxXvqTfEtbW + sDOytfFAuwjz0b+oCk50DjTVZXgu+a7/E4mr3BL3dx7OlpRez1DqjyRIpm7cK05bV+OfvubzgLRVBwLS + Pt4vTf1wn0NI+2gf5fdPX33AP33dQb/UNTXS6Z+ukBVdTvJY+n3CUxJuix/NkVQ0T1Fm7R8iaBXLuSk7 + c+7h0ZxbeAznFtGbc42IcwCxPHwNqMU9vCfnGtCB8+2YfE9ecWsYJN54SsJ1yQ9V4rIbmaqcmgHSweXL + A+NN78sTCpbL4w1LgwfkLgnpr1sM3vljyV4cPCBncXC8finVIksofFfaz7BCPurtysCSxskeSx8OflZi + vl9Jo15lOBobWlr3l8iSU23bFB0Jb2/er+hgqg76k3Gr7M/GLYF/JH8ybpO9bNoh72DeG9K2qCa0dfHJ + yIiyupfCis+9KjXVa92XPRoCAbOdxI8L/GY26fF0iqW5CYb3GHpt+HgS2JKeThgnpOaLavelj4Y9kbjC + LXZZ+tNCv7LrBkj0bnmP2A2dLOOEbbA7FBdQeFHjtuyHEfYSmyCxDBK4EodjWtxg98yIHQoJuhJu7/04 + hLnJzUNPms0wzdx41+U/5/uVXJ+BaQckDvahZaBFwvrGw2ESNHfCBNBu7hSqP9g7oPiixn3hw8lOJ3/r + j2lHAuO26hHj+o+fBvlU3lgYqq+JfjIB3O7gCeDHllnsU1Px/TGheTWx0pl1ae5zHy11n/uAcVv3kGE8 + Sr91c/37D/P9Sy/rcKlwuR5PxR0qQTwrQfcqdXel4dgA77m3Frks+NHoWXjPhXF9+6dkr6rb7ysMtDyl + vxTZLYqyaFHkWAl0Z0hswsoOTyjr8lRpONovOP/UUOGCe1udF/8Sx7gs/bVKOuNiKdbYff/n5enHz03y + 38ZOwu6VDdbY+UcTlPrj0eLypuXMCm48SVTIiuqKbRJh+n0YI6qjHo8RvMTzk/y3sUjwY4X15Rnd3Px7 + p3hl3vFefhXX32Pe48aSxCxZUX2J0nisb0t7ZUPYvYvFE6o6KgzdnSRU+qPR4oqm9yGRyDgv+202Vkol + yryjWBAdwkBHY0TLeHlGWCRsj1lI8OvsI/1V+tqe4kpIvM8lMc7Lf5tjkajFguOgVaJFvYtFl1rXsXX2 + J10jc+kxu4//MzAkoiCxAvdEMq7E73MhMVNpqI1roS+UrRJbeAk8ZjEgH+oHiR6Q+ABXYgJJzLdIHMEY + 8SJJHOkOiQ8hMQndiV0IiVIlTf6ekmg5f2Sxdqcukbn0B3ka8GwS1z9Cd0phnJazb0Gi7AWU6OZXeX0V + JFJJ4u3/H4kP/w88L87T/BuJ1TaJRZAo/88knpeYZriYrGWuopmnDXxf/RyeOuZx26fjPS34byTWQCKN + JBZDouL5Epg3QQIzSiQFGhSrwY2mWfNaO826jm3V68GGTm3VGzu1UW/q3Dpjs5VPuljY0vUJ9N2yv43a + gqXteqJjO81axEQ+jV0+AvnpAdM6e/PzJNZCYgpJLHkswf8HFZvEZozYGzq2y0Sxmes7tdFg6Nds7tJa + jaeE+tNukRnbu0dm7OgRkVEdZWFXz/Dpu+3YE/00T/ZFZBDVRBTFQCyieyv11m4Uv40GkshHedtpkT+L + ph2WcQISMfS/0SDRFRLrIDGVcXqXWwaJWZgZxvJzp7x9mADu7hmp29GjVSYCa7Z1j9Rs7xGh3hUVod4d + HZaxt1dYxmcxoRn7eodm7AdYbWXsj8OWwOfP40KnA9raY/mtj+U7HUtteKg94uyLCc/YG0PxI9R7elK+ + SM021LCteyvtju6Rup1RNAHE3AnTjiMD+Csx6/oGZiU3jXFayS2XFl2crTCcoL/AJKj0h/qGZh+MC81C + osz9vcPUSKLG2lZ9ME6VUdPXwqF+yozD4Eh/OwZYwOSMUD+D7Xce27H27Q/3o7h8fHVN31A1ZNUH4sI0 + yK890Bv1xFJdSj3/9wnMYo9F+VV+tYlZx01nnBax70pLL80NNnwZH5x3cnBIzolBCt2JgQrt8QRF5tF4 + heZogkJzDNtj2B5/3cKJN0I0JwaGaE5iexLbLwaBwRa+HByceWpIyDPwv2GfBf5YagP4GHw8imuJT7l4 + LPkz8VmL31FXSO6Jgah1iEJ/Msa36sYW5i1IOJey70tmX3lLrj83RK4/Pzoo5+xIue7syCDt6WFgaFDm + l3wBwZrT2J4eZmV4kPbsCIDjzo0K0qKd9vwYC3Vj5Vn1jwnKevx9HO0DluMy0YbQnkMMinNmOMW1xh8a + rCFxS25LLWeGy7NxXM7ZUfK8ujHBuWf6eb91c4dTNpfBOFewKySV1xYF6i+OluZeniDNvpQcqKtPlPHJ + 60bLUKAcyeRILEMRMm09kSjTXiCSZFkXxwfqLiXLdJcmyLKvTJRlX50sy25Ikeoa03y1jWlCTWOaBNtA + 3bU0/J4q012dJNNdnkjHB2YhF9pb4lC8unGW+JSLh8+PWsaAcYHZF5ICcy5NkOovT5Tn1A30nt+8y8nA + aRincm6lpLRpEYInynSNU6TaxvQAzbVUWWZDilxzNUWqaUgJwGf8lu6f2TjVP7Npur/2ukasvZ4lzvoq + R5L9dZ44p7lAom+eITHerpAWfjM/qOz+YtWCBx+9+u7DLTErH+7ssOT7jcFV364ILLv3j4Cib6ok+bfL + JcbmIrHhZr4k54ZeovsqG/G0Em2TWpzZNM1fc20qSPfXNKSCFH/U4Z95LRWk+Wc1TvHPvjZFpr002Lvq + djVj4LIYpzncLp95zYclhTf+LjY3f+BruvWBX/7tD3zzb62krbfxzseinLsbvPLvrhUZ724UGO9t9jR9 + u83T/KBaaP5ur6Dw4UHBjEfHBaU/nhOU/Xzdq+rX++Klv/+q/JTlhp/hOFMDx0Uf57jA9Sznu+j3H0VV + v9wRVP50VVj6wxnhzEe1gqLvDyDOHqHpwQ5hwf0tovx7m5BrvSj/mzVe+XdWeeXf/tCb6iAKbq30Nt1a + 6VPYvEJiapolfOfuDaaAMzEu+Vyu81x2i3P57584lbFbcY9sA9sfM5Pd6TyDq3YpZXcSHqXsLlEZR+x2 + L+P2uJVze90quM/cKrkDHpXcQY83uRrPOdxh4Tyu1nchVyteyB3xXsDVCudytZ6zucO0H8d+jjb70fYz + 1zJurwvigN0uFWy1SyW7C1s+F9jhMhOgDpcyvh6qbZsz1Vn++2bUvdUlg41l3EexjPsIjnEbyeEztqM4 + J7fRnCtwA+4eYzgPj0QwjhN4JLJCryRW5Dee9fabwPqIJrJ+whRWIkpl/UXprNRrGiv3nsYG+6hZhbea + VXllcCqhmlN5qVklviu9prMKHBMsmsLKRGmslNoJJ7FiAeJ4JrM+nojrkcR6IZ+QzzeO83RHfnfUAdyA + M9XI10n1DgdjOIZxT2SdgAsKRLGsCPgikARIPZK4QCDzGM/JCc/xXDC2IW7JrMJ9IqvwnMQqBSmsCoQK + UtkwYRpIZ8NBBAGxCBQcSVvrb5Z9dGwq2lC7yWg/mVUilgIiITzj2SCP8Syf01oDYAOwFaM+HzqZwB11 + O1P9DL7YIBE34IkGIkAyYkBCAZ6Q8kQwiBByJJN7TmDlgglcEM5ksGASZ08ICgsRTuaAZUvf+d9tx0wk + 0G4CYiEOHy+Zk1nis4GUj/Ja81Md3qiNTjKdbFfgDOgiMPYSjCesgDNwAx5AgGAi4AN8gRhIgD8IQDJC + yicFguTHyAQo6F+h3y3H2kHt6SQRFJugPJSP8or4OnDmgSvgi7fxPAkbNhkX4IZAHsCTD4g+C2xShB+w + ydlDos9iv5/aENTeFotiE3TyKB8VTieU6qCa+Prsa/7fJOyxCTkjqCsgKXdrEkJoxSZoj7cdz+6j46md + rWBL0RTfUrQlp13xNuxr/k8lnkKAoHY4Axc7XAVJnBX6zLrhM6Ct3T467kkbikE8jvu8vPbY1+yeyDL/ + BD5r4T4h7uvLAAAAAElFTkSuQmCC + + + + + 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 + BD5r4T4h7uvLAAAAAElFTkSuQmCC + + + + + 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 + BD5r4T4h7uvLAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAADEAAABFCAYAAADjLw7LAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH + DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKNWlDQ1BzUkdCIElFQzYxOTY2LTIuMQAA + SMedlndUVNcWh8+9d3qhzTDSGXqTLjCA9C4gHQRRGGYGGMoAwwxNbIioQEQREQFFkKCAAaOhSKyIYiEo + qGAPSBBQYjCKqKhkRtZKfHl57+Xl98e939pn73P32XuftS4AJE8fLi8FlgIgmSfgB3o401eFR9Cx/QAG + eIABpgAwWempvkHuwUAkLzcXerrICfyL3gwBSPy+ZejpT6eD/0/SrFS+AADIX8TmbE46S8T5Ik7KFKSK + 7TMipsYkihlGiZkvSlDEcmKOW+Sln30W2VHM7GQeW8TinFPZyWwx94h4e4aQI2LER8QFGVxOpohvi1gz + SZjMFfFbcWwyh5kOAIoktgs4rHgRm4iYxA8OdBHxcgBwpLgvOOYLFnCyBOJDuaSkZvO5cfECui5Lj25q + bc2ge3IykzgCgaE/k5XI5LPpLinJqUxeNgCLZ/4sGXFt6aIiW5paW1oamhmZflGo/7r4NyXu7SK9Cvjc + M4jW94ftr/xS6gBgzIpqs+sPW8x+ADq2AiB3/w+b5iEAJEV9a7/xxXlo4nmJFwhSbYyNMzMzjbgclpG4 + oL/rfzr8DX3xPSPxdr+Xh+7KiWUKkwR0cd1YKUkpQj49PZXJ4tAN/zzE/zjwr/NYGsiJ5fA5PFFEqGjK + uLw4Ubt5bK6Am8Kjc3n/qYn/MOxPWpxrkSj1nwA1yghI3aAC5Oc+gKIQARJ5UNz13/vmgw8F4psXpjqx + OPefBf37rnCJ+JHOjfsc5xIYTGcJ+RmLa+JrCdCAACQBFcgDFaABdIEhMANWwBY4AjewAviBYBAO1gIW + iAfJgA8yQS7YDApAEdgF9oJKUAPqQSNoASdABzgNLoDL4Dq4Ce6AB2AEjIPnYAa8AfMQBGEhMkSB5CFV + SAsygMwgBmQPuUE+UCAUDkVDcRAPEkK50BaoCCqFKqFaqBH6FjoFXYCuQgPQPWgUmoJ+hd7DCEyCqbAy + rA0bwwzYCfaGg+E1cBycBufA+fBOuAKug4/B7fAF+Dp8Bx6Bn8OzCECICA1RQwwRBuKC+CERSCzCRzYg + hUg5Uoe0IF1IL3ILGUGmkXcoDIqCoqMMUbYoT1QIioVKQ21AFaMqUUdR7age1C3UKGoG9QlNRiuhDdA2 + aC/0KnQcOhNdgC5HN6Db0JfQd9Dj6DcYDIaG0cFYYTwx4ZgEzDpMMeYAphVzHjOAGcPMYrFYeawB1g7r + h2ViBdgC7H7sMew57CB2HPsWR8Sp4sxw7rgIHA+XhyvHNeHO4gZxE7h5vBReC2+D98Oz8dn4Enw9vgt/ + Az+OnydIE3QIdoRgQgJhM6GC0EK4RHhIeEUkEtWJ1sQAIpe4iVhBPE68QhwlviPJkPRJLqRIkpC0k3SE + dJ50j/SKTCZrkx3JEWQBeSe5kXyR/Jj8VoIiYSThJcGW2ChRJdEuMSjxQhIvqSXpJLlWMkeyXPKk5A3J + aSm8lLaUixRTaoNUldQpqWGpWWmKtKm0n3SydLF0k/RV6UkZrIy2jJsMWyZf5rDMRZkxCkLRoLhQWJQt + lHrKJco4FUPVoXpRE6hF1G+o/dQZWRnZZbKhslmyVbJnZEdoCE2b5kVLopXQTtCGaO+XKC9xWsJZsmNJ + y5LBJXNyinKOchy5QrlWuTty7+Xp8m7yifK75TvkHymgFPQVAhQyFQ4qXFKYVqQq2iqyFAsVTyjeV4KV + 9JUCldYpHVbqU5pVVlH2UE5V3q98UXlahabiqJKgUqZyVmVKlaJqr8pVLVM9p/qMLkt3oifRK+g99Bk1 + JTVPNaFarVq/2ry6jnqIep56q/ojDYIGQyNWo0yjW2NGU1XTVzNXs1nzvhZei6EVr7VPq1drTltHO0x7 + m3aH9qSOnI6XTo5Os85DXbKug26abp3ubT2MHkMvUe+A3k19WN9CP16/Sv+GAWxgacA1OGAwsBS91Hop + b2nd0mFDkqGTYYZhs+GoEc3IxyjPqMPohbGmcYTxbuNe408mFiZJJvUmD0xlTFeY5pl2mf5qpm/GMqsy + u21ONnc332jeaf5ymcEyzrKDy+5aUCx8LbZZdFt8tLSy5Fu2WE5ZaVpFW1VbDTOoDH9GMeOKNdra2Xqj + 9WnrdzaWNgKbEza/2BraJto22U4u11nOWV6/fMxO3Y5pV2s3Yk+3j7Y/ZD/ioObAdKhzeOKo4ch2bHCc + cNJzSnA65vTC2cSZ79zmPOdi47Le5bwr4urhWuja7ybjFuJW6fbYXd09zr3ZfcbDwmOdx3lPtKe3527P + YS9lL5ZXo9fMCqsV61f0eJO8g7wrvZ/46Pvwfbp8Yd8Vvnt8H67UWslb2eEH/Lz89vg98tfxT/P/PgAT + 4B9QFfA00DQwN7A3iBIUFdQU9CbYObgk+EGIbogwpDtUMjQytDF0Lsw1rDRsZJXxqvWrrocrhHPDOyOw + EaERDRGzq91W7109HmkRWRA5tEZnTdaaq2sV1iatPRMlGcWMOhmNjg6Lbor+wPRj1jFnY7xiqmNmWC6s + faznbEd2GXuKY8cp5UzE2sWWxk7G2cXtiZuKd4gvj5/munAruS8TPBNqEuYS/RKPJC4khSW1JuOSo5NP + 8WR4ibyeFJWUrJSBVIPUgtSRNJu0vWkzfG9+QzqUvia9U0AV/Uz1CXWFW4WjGfYZVRlvM0MzT2ZJZ/Gy + +rL1s3dkT+S453y9DrWOta47Vy13c+7oeqf1tRugDTEbujdqbMzfOL7JY9PRzYTNiZt/yDPJK817vSVs + S1e+cv6m/LGtHlubCyQK+AXD22y31WxHbedu799hvmP/jk+F7MJrRSZF5UUfilnF174y/ariq4WdsTv7 + SyxLDu7C7OLtGtrtsPtoqXRpTunYHt897WX0ssKy13uj9l4tX1Zes4+wT7hvpMKnonO/5v5d+z9Uxlfe + qXKuaq1Wqt5RPXeAfWDwoOPBlhrlmqKa94e4h+7WetS212nXlR/GHM44/LQ+tL73a8bXjQ0KDUUNH4/w + jowcDTza02jV2Nik1FTSDDcLm6eORR67+Y3rN50thi21rbTWouPguPD4s2+jvx064X2i+yTjZMt3Wt9V + t1HaCtuh9uz2mY74jpHO8M6BUytOdXfZdrV9b/T9kdNqp6vOyJ4pOUs4m3924VzOudnzqeenL8RdGOuO + 6n5wcdXF2z0BPf2XvC9duex++WKvU++5K3ZXTl+1uXrqGuNax3XL6+19Fn1tP1j80NZv2d9+w+pG503r + m10DywfODjoMXrjleuvyba/b1++svDMwFDJ0dzhyeOQu++7kvaR7L+9n3J9/sOkh+mHhI6lH5Y+VHtf9 + qPdj64jlyJlR19G+J0FPHoyxxp7/lP7Th/H8p+Sn5ROqE42TZpOnp9ynbj5b/Wz8eerz+emCn6V/rn6h + ++K7Xxx/6ZtZNTP+kv9y4dfiV/Kvjrxe9rp71n/28ZvkN/NzhW/l3x59x3jX+z7s/cR85gfsh4qPeh+7 + Pnl/eriQvLDwG/eE8/s6uL5TAAAACXBIWXMAAAsMAAALDAE/QCLIAAARpklEQVRoQ9WaeVwT19rHh50k + bAmEBEjC5lp7l89t6y4ighu07rsgLiwuJIQAIYEEENms4tbba93aWtu6L9W64FK1ouLWuoIrgrWiVq2t + du/M/T2TRKPX9733837e2+AfXyfJzHme5ztzZs45g4ys8MIrYAwYCAZZwef6gTJz/Rtyc93rjgQ1vI5a + 3viX+oouDA801cdKDec9SKIPMIJpFuqnys3n0+WmcylBpjOTwUTHcnYSSJGbzqdBaIq1zumQyIZEIiQE + TGDRpShZ4UXakSQ314+Vm86MDC44PTSk4ItBIfnH31DkH3vdkYTknxhItQQXnBoCqRE4waMhkygrupgq + NV8YGmCsFzDS4ss9ITFdZq4bG1RwZkRwwReDFcZjryuNtQOUxkP9Qg01fUMNB/s4ChVqUBqPDFAYjyaE + 5J+EzOmh6CWjUXOKtPDSsICCCwImoPhKL3ShabhkI2A8WJF/NF5lQPF5n8eG5u2LCdfv7RWu3xPtGPZG + h+n39Q7NOxCLmvoq8mvjcWUG4WQPlxfWT4LE8AATSZRAwlw3lQzpCpBAmP5AbHjunugIfXVUq9zt3R3H + ju6ROdVREbm7e4bp9/cONR7sozQehcgXg4LM55MDii4N9zddhMTMht50I2PHQOpCuAJxJBCZs6NH6+yt + XdvoNndpo9vU2TFs7tI6e0uXVjnbu5NIaN7+3krj4f4K3KtB5rOJkBjhb74kZPwhga6USjvoHghDF4rI + rY7iBbI2dW6bta5ju6y1DqOtbkMniHSlk0pdm+5R9JiEIPOZxIDiSyPEhZeFjKS0MVZuPptCNw4O6BOB + ftgqZ0f3NrpPurSDQHvtqlfba1c7iFWvkghdlVbZ27pFoIeo0FOoSwWbTo/1n3FlpF/xVUiUNcZBIpWX + yDsIiT2Q2A6JTZ0R4DUK9FLmR684inba1a+1zaKrsbVbeO7uaOru9LQKNp0aA4lRfsUNXoy4vKkvJNIg + Ef9iSXw5RlJydYzvjEZvRlxxvb/cfC79xZM4NVZS0jDWd0aTN+NXeWPACylhPjVWPLMhyWdGkw9JJLyo + V0I881qSTwkkfN+8iZnquSkvmER/SIzzK2tK9i694cP4zG4eKC88N/WFkjBAwgyJ8qZJXmU3fBmfObeG + QGIaJDBa20tsxjixlh8nnhf8j4KX0G20SWDUtkmcHudb8VWKV/lNP8Z77u1h8sLz05WGZ69Ey5SwDHa1 + A4LMpxMhkcpLeFV9MwISGZAYQFNfy4jdEiQ+fIVyt8ta81ob3UaM2J9CAiO2wSphIokb6V4VzZCYd2ck + JNQKwzFMwWv6hus/64VpRw+rhEPvCZp60InkJXIggV6iQm/BtAOP2DNJPpVfTxVVNIsZ0by7YyCRqTAe + T8AMEdPwz3pF5uyExCddaPLnWAnb3OmJBLp8HN2/8sKzyd6zvs4QVtySMKL598fJCuu0kIinaW6ofn9M + RIuT2GyZjlsk+tCTlJd4s1kjnHVHwggXfDs5sLBOpzCeiFdZJHpHYCHSWrela1vd+k4tSYKm4tTlMRWP + x3pivPfsW7mQ8GcE8+4PkZQ1FCqNJ7CuPtKfloIRubt64mnAS7TLWv1a+0zHiJAE9QbqFdTFqatTlyeJ + wOJ6tWju3SxRxS13RlR620dU9Y1eXnQ2Gc9frK1JYndP9MGubbM2YsBb4xCJ9pkf8esJOpHUK6h3UC/B + wq1/SMHJIT6zbxYLK+/81avoJsMIFtxlPOd9G+1f3pCv0h+KDTUciLNIbOuG57MDJagr0RjBj9ZdqXdg + eRqryjvURzbj/GSvkjtqz8X3GOfzvzAMc4V71WPRgxH+xQ05Kv3hOIwVkNgDie3dHS+xxjblsEocgMTh + PuhKU4Rv3h3puu/ndsx9rj3DXOM2ub/zfZVkxrV0Vd6RPrhx+tANZB3wLPOnzI8dJ2F9vFpeFPASfQML + 6tI9lz2IZr7m5jBXuTcZ/LPU/Z3vKiQl1zJIghbi1gEPV6KlSND6GhLo6ioDJEwXpnou/q4v08CZQD51 + p6Vui7+fJS65lqnKq40NMx37W0R+TYc2hj1t2us/De+Qs1H5sm6N4s+61cF/JC/r1io65KxXvqTfEtbW + sDOytfFAuwjz0b+oCk50DjTVZXgu+a7/E4mr3BL3dx7OlpRez1DqjyRIpm7cK05bV+OfvubzgLRVBwLS + Pt4vTf1wn0NI+2gf5fdPX33AP33dQb/UNTXS6Z+ukBVdTvJY+n3CUxJuix/NkVQ0T1Fm7R8iaBXLuSk7 + c+7h0ZxbeAznFtGbc42IcwCxPHwNqMU9vCfnGtCB8+2YfE9ecWsYJN54SsJ1yQ9V4rIbmaqcmgHSweXL + A+NN78sTCpbL4w1LgwfkLgnpr1sM3vljyV4cPCBncXC8finVIksofFfaz7BCPurtysCSxskeSx8OflZi + vl9Jo15lOBobWlr3l8iSU23bFB0Jb2/er+hgqg76k3Gr7M/GLYF/JH8ybpO9bNoh72DeG9K2qCa0dfHJ + yIiyupfCis+9KjXVa92XPRoCAbOdxI8L/GY26fF0iqW5CYb3GHpt+HgS2JKeThgnpOaLavelj4Y9kbjC + LXZZ+tNCv7LrBkj0bnmP2A2dLOOEbbA7FBdQeFHjtuyHEfYSmyCxDBK4EodjWtxg98yIHQoJuhJu7/04 + hLnJzUNPms0wzdx41+U/5/uVXJ+BaQckDvahZaBFwvrGw2ESNHfCBNBu7hSqP9g7oPiixn3hw8lOJ3/r + j2lHAuO26hHj+o+fBvlU3lgYqq+JfjIB3O7gCeDHllnsU1Px/TGheTWx0pl1ae5zHy11n/uAcVv3kGE8 + Sr91c/37D/P9Sy/rcKlwuR5PxR0qQTwrQfcqdXel4dgA77m3Frks+NHoWXjPhXF9+6dkr6rb7ysMtDyl + vxTZLYqyaFHkWAl0Z0hswsoOTyjr8lRpONovOP/UUOGCe1udF/8Sx7gs/bVKOuNiKdbYff/n5enHz03y + 38ZOwu6VDdbY+UcTlPrj0eLypuXMCm48SVTIiuqKbRJh+n0YI6qjHo8RvMTzk/y3sUjwY4X15Rnd3Px7 + p3hl3vFefhXX32Pe48aSxCxZUX2J0nisb0t7ZUPYvYvFE6o6KgzdnSRU+qPR4oqm9yGRyDgv+202Vkol + yryjWBAdwkBHY0TLeHlGWCRsj1lI8OvsI/1V+tqe4kpIvM8lMc7Lf5tjkajFguOgVaJFvYtFl1rXsXX2 + J10jc+kxu4//MzAkoiCxAvdEMq7E73MhMVNpqI1roS+UrRJbeAk8ZjEgH+oHiR6Q+ABXYgJJzLdIHMEY + 8SJJHOkOiQ8hMQndiV0IiVIlTf6ekmg5f2Sxdqcukbn0B3ka8GwS1z9Cd0phnJazb0Gi7AWU6OZXeX0V + JFJJ4u3/H4kP/w88L87T/BuJ1TaJRZAo/88knpeYZriYrGWuopmnDXxf/RyeOuZx26fjPS34byTWQCKN + JBZDouL5Epg3QQIzSiQFGhSrwY2mWfNaO826jm3V68GGTm3VGzu1UW/q3Dpjs5VPuljY0vUJ9N2yv43a + gqXteqJjO81axEQ+jV0+AvnpAdM6e/PzJNZCYgpJLHkswf8HFZvEZozYGzq2y0Sxmes7tdFg6Nds7tJa + jaeE+tNukRnbu0dm7OgRkVEdZWFXz/Dpu+3YE/00T/ZFZBDVRBTFQCyieyv11m4Uv40GkshHedtpkT+L + ph2WcQISMfS/0SDRFRLrIDGVcXqXWwaJWZgZxvJzp7x9mADu7hmp29GjVSYCa7Z1j9Rs7xGh3hUVod4d + HZaxt1dYxmcxoRn7eodm7AdYbWXsj8OWwOfP40KnA9raY/mtj+U7HUtteKg94uyLCc/YG0PxI9R7elK+ + SM021LCteyvtju6Rup1RNAHE3AnTjiMD+Csx6/oGZiU3jXFayS2XFl2crTCcoL/AJKj0h/qGZh+MC81C + osz9vcPUSKLG2lZ9ME6VUdPXwqF+yozD4Eh/OwZYwOSMUD+D7Xce27H27Q/3o7h8fHVN31A1ZNUH4sI0 + yK890Bv1xFJdSj3/9wnMYo9F+VV+tYlZx01nnBax70pLL80NNnwZH5x3cnBIzolBCt2JgQrt8QRF5tF4 + heZogkJzDNtj2B5/3cKJN0I0JwaGaE5iexLbLwaBwRa+HByceWpIyDPwv2GfBf5YagP4GHw8imuJT7l4 + LPkz8VmL31FXSO6Jgah1iEJ/Msa36sYW5i1IOJey70tmX3lLrj83RK4/Pzoo5+xIue7syCDt6WFgaFDm + l3wBwZrT2J4eZmV4kPbsCIDjzo0K0qKd9vwYC3Vj5Vn1jwnKevx9HO0DluMy0YbQnkMMinNmOMW1xh8a + rCFxS25LLWeGy7NxXM7ZUfK8ujHBuWf6eb91c4dTNpfBOFewKySV1xYF6i+OluZeniDNvpQcqKtPlPHJ + 60bLUKAcyeRILEMRMm09kSjTXiCSZFkXxwfqLiXLdJcmyLKvTJRlX50sy25Ikeoa03y1jWlCTWOaBNtA + 3bU0/J4q012dJNNdnkjHB2YhF9pb4lC8unGW+JSLh8+PWsaAcYHZF5ICcy5NkOovT5Tn1A30nt+8y8nA + aRincm6lpLRpEYInynSNU6TaxvQAzbVUWWZDilxzNUWqaUgJwGf8lu6f2TjVP7Npur/2ukasvZ4lzvoq + R5L9dZ44p7lAom+eITHerpAWfjM/qOz+YtWCBx+9+u7DLTErH+7ssOT7jcFV364ILLv3j4Cib6ok+bfL + JcbmIrHhZr4k54ZeovsqG/G0Em2TWpzZNM1fc20qSPfXNKSCFH/U4Z95LRWk+Wc1TvHPvjZFpr002Lvq + djVj4LIYpzncLp95zYclhTf+LjY3f+BruvWBX/7tD3zzb62krbfxzseinLsbvPLvrhUZ724UGO9t9jR9 + u83T/KBaaP5ur6Dw4UHBjEfHBaU/nhOU/Xzdq+rX++Klv/+q/JTlhp/hOFMDx0Uf57jA9Sznu+j3H0VV + v9wRVP50VVj6wxnhzEe1gqLvDyDOHqHpwQ5hwf0tovx7m5BrvSj/mzVe+XdWeeXf/tCb6iAKbq30Nt1a + 6VPYvEJiapolfOfuDaaAMzEu+Vyu81x2i3P57584lbFbcY9sA9sfM5Pd6TyDq3YpZXcSHqXsLlEZR+x2 + L+P2uJVze90quM/cKrkDHpXcQY83uRrPOdxh4Tyu1nchVyteyB3xXsDVCudytZ6zucO0H8d+jjb70fYz + 1zJurwvigN0uFWy1SyW7C1s+F9jhMhOgDpcyvh6qbZsz1Vn++2bUvdUlg41l3EexjPsIjnEbyeEztqM4 + J7fRnCtwA+4eYzgPj0QwjhN4JLJCryRW5Dee9fabwPqIJrJ+whRWIkpl/UXprNRrGiv3nsYG+6hZhbea + VXllcCqhmlN5qVklviu9prMKHBMsmsLKRGmslNoJJ7FiAeJ4JrM+nojrkcR6IZ+QzzeO83RHfnfUAdyA + M9XI10n1DgdjOIZxT2SdgAsKRLGsCPgikARIPZK4QCDzGM/JCc/xXDC2IW7JrMJ9IqvwnMQqBSmsCoQK + UtkwYRpIZ8NBBAGxCBQcSVvrb5Z9dGwq2lC7yWg/mVUilgIiITzj2SCP8Syf01oDYAOwFaM+HzqZwB11 + O1P9DL7YIBE34IkGIkAyYkBCAZ6Q8kQwiBByJJN7TmDlgglcEM5ksGASZ08ICgsRTuaAZUvf+d9tx0wk + 0G4CYiEOHy+Zk1nis4GUj/Ja81Md3qiNTjKdbFfgDOgiMPYSjCesgDNwAx5AgGAi4AN8gRhIgD8IQDJC + yicFguTHyAQo6F+h3y3H2kHt6SQRFJugPJSP8or4OnDmgSvgi7fxPAkbNhkX4IZAHsCTD4g+C2xShB+w + ydlDos9iv5/aENTeFotiE3TyKB8VTieU6qCa+Prsa/7fJOyxCTkjqCsgKXdrEkJoxSZoj7cdz+6j46md + rWBL0RTfUrQlp13xNuxr/k8lnkKAoHY4Axc7XAVJnBX6zLrhM6Ct3T467kkbikE8jvu8vPbY1+yeyDL/ + BD5r4T4h7uvLAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/CPK.Designer.cs b/JinYuan.ControlLib/CPK.Designer.cs new file mode 100644 index 0000000..3509c37 --- /dev/null +++ b/JinYuan.ControlLib/CPK.Designer.cs @@ -0,0 +1,263 @@ +namespace JinYuan.ControlLib +{ + partial class CPK + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.listView1 = new System.Windows.Forms.ListView(); + this.项目1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.数值1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.项目2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.数值2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.项目3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.数值3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.lbl_Ca = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.listView2 = new System.Windows.Forms.ListView(); + this.tableLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.SuspendLayout(); + // + // listView1 + // + this.listView1.Activation = System.Windows.Forms.ItemActivation.OneClick; + this.listView1.AutoArrange = false; + this.listView1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(30)))), ((int)(((byte)(78))))); + this.listView1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.项目1, + this.数值1, + this.项目2, + this.数值2, + this.项目3, + this.数值3}); + this.listView1.ForeColor = System.Drawing.Color.White; + this.listView1.GridLines = true; + this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.listView1.HideSelection = false; + this.listView1.LabelWrap = false; + this.listView1.Location = new System.Drawing.Point(4, 5); + this.listView1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.listView1.Name = "listView1"; + this.listView1.ShowItemToolTips = true; + this.listView1.Size = new System.Drawing.Size(518, 99); + this.listView1.TabIndex = 3; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // 项目1 + // + this.项目1.Text = "项目1"; + this.项目1.Width = 90; + // + // 数值1 + // + this.数值1.Text = "数值"; + this.数值1.Width = 80; + // + // 项目2 + // + this.项目2.Text = "项目2"; + this.项目2.Width = 90; + // + // 数值2 + // + this.数值2.Text = "数值"; + this.数值2.Width = 75; + // + // 项目3 + // + this.项目3.Text = "项目3"; + this.项目3.Width = 100; + // + // 数值3 + // + this.数值3.Text = "数值3"; + this.数值3.Width = 80; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.listView1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.listView2, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 109F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 229F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 364F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(526, 415); + this.tableLayoutPanel1.TabIndex = 5; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single; + this.tableLayoutPanel2.ColumnCount = 3; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 53.63881F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 46.36119F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 195F)); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel5, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel4, 1, 0); + this.tableLayoutPanel2.Location = new System.Drawing.Point(4, 343); + this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 2; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(518, 67); + this.tableLayoutPanel2.TabIndex = 5; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single; + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.Location = new System.Drawing.Point(325, 6); + this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 1; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(185, 22); + this.tableLayoutPanel5.TabIndex = 2; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single; + this.tableLayoutPanel3.ColumnCount = 2; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel3.Controls.Add(this.lbl_Ca, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.label2, 0, 0); + this.tableLayoutPanel3.Location = new System.Drawing.Point(5, 6); + this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 1; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(163, 22); + this.tableLayoutPanel3.TabIndex = 0; + // + // lbl_Ca + // + this.lbl_Ca.AutoSize = true; + this.lbl_Ca.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Ca.ForeColor = System.Drawing.Color.White; + this.lbl_Ca.Location = new System.Drawing.Point(86, 1); + this.lbl_Ca.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lbl_Ca.Name = "lbl_Ca"; + this.lbl_Ca.Size = new System.Drawing.Size(72, 20); + this.lbl_Ca.TabIndex = 0; + this.lbl_Ca.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Fill; + this.label2.ForeColor = System.Drawing.Color.White; + this.label2.Location = new System.Drawing.Point(4, 1); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(74, 20); + this.label2.TabIndex = 1; + this.label2.Text = "CA"; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single; + this.tableLayoutPanel4.ColumnCount = 2; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel4.Location = new System.Drawing.Point(177, 6); + this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 1; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(139, 22); + this.tableLayoutPanel4.TabIndex = 1; + // + // listView2 + // + this.listView2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(30)))), ((int)(((byte)(78))))); + this.listView2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.listView2.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView2.ForeColor = System.Drawing.Color.White; + this.listView2.GridLines = true; + this.listView2.HideSelection = false; + this.listView2.Location = new System.Drawing.Point(3, 112); + this.listView2.Name = "listView2"; + this.listView2.Size = new System.Drawing.Size(520, 223); + this.listView2.TabIndex = 6; + this.listView2.UseCompatibleStateImageBehavior = false; + this.listView2.View = System.Windows.Forms.View.Details; + // + // trw + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.Controls.Add(this.tableLayoutPanel1); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "trw"; + this.Size = new System.Drawing.Size(526, 415); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader 项目1; + private System.Windows.Forms.ColumnHeader 数值1; + private System.Windows.Forms.ColumnHeader 项目2; + private System.Windows.Forms.ColumnHeader 数值2; + private System.Windows.Forms.ColumnHeader 项目3; + private System.Windows.Forms.ColumnHeader 数值3; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Label lbl_Ca; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.ListView listView2; + } +} diff --git a/JinYuan.ControlLib/CPK.cs b/JinYuan.ControlLib/CPK.cs new file mode 100644 index 0000000..86c8037 --- /dev/null +++ b/JinYuan.ControlLib/CPK.cs @@ -0,0 +1,285 @@ +using JinYuan.ControlLib.Models; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class CPK : UserControl + { + public CPK() + { + InitializeComponent(); + IntValue(); + } + + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + + private int subgroupSize = 5; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取子组大小值")] + public int SubgroupSize + { + get { return subgroupSize; } + set + { + subgroupSize = value; + listView1.Items[0].SubItems[3].Text = value.ToString(); + this.Invalidate(); + } + } + + private double _uSLs = 0; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取上规格值")] + public double USLs + { + get { return _uSLs; } + set + { + _uSLs = value; + listView1.Items[2].SubItems[1].Text = value.ToString(); + this.Invalidate(); + } + } + + private double _lSLs = 0; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取下规格值")] + public double LSLs + { + get { return _lSLs; } + set + { + _lSLs = value; + listView1.Items[2].SubItems[5].Text = value.ToString(); + this.Invalidate(); + } + } + + private double _cpkPpkAcceptanceValue = 0; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取目标值")] + public double CpkPpkAcceptanceValue + { + get { return _cpkPpkAcceptanceValue; } + set + { + _cpkPpkAcceptanceValue = value; + listView1.Items[2].SubItems[3].Text = value.ToString(); + this.Invalidate(); + } + } + + + private CPKModel _cPKData = new CPKModel(); + [Browsable(true)] + [Category("自定义属性")] + [Description("获取目标值")] + public CPKModel CPKData + { + get { return _cPKData; } + set + { + if (value != null) + { + _cPKData = value; + //总样本数 + listView1.Items[0].SubItems[1].Text = _cPKData.TotalNumber.ToString(); + //平均值 + listView1.Items[1].SubItems[1].Text = _cPKData.MeanVlaue.ToString(); + //最大值 + listView1.Items[1].SubItems[3].Text = _cPKData.MaxValue.ToString(); + //最小值 + listView1.Items[1].SubItems[5].Text = _cPKData.MinValue.ToString(); + // 正的3倍标准差线 + listView1.Items[3].SubItems[1].Text = _cPKData.Pos3Sigma.ToString(); + // 负的3倍标准差线 + listView1.Items[3].SubItems[3].Text = _cPKData.Neg3Sigma.ToString(); + + // 组内标准差值 + listView2.Items[0].SubItems[1].Text = _cPKData.GroupSTDEV.ToString(); + // 整体标准差值 + listView2.Items[0].SubItems[2].Text = _cPKData.WholeSTDEV.ToString(); + + // 组内CPK值 + listView2.Items[1].SubItems[1].Text = _cPKData.GroupCPK.ToString(); + // 整体CPK值 + listView2.Items[1].SubItems[2].Text = _cPKData.WholeCPK.ToString(); + // 组内CP值 + listView2.Items[2].SubItems[1].Text = _cPKData.GroupCP.ToString(); + // 整体CP值 + listView2.Items[2].SubItems[2].Text = _cPKData.WholeCP.ToString(); + + // 组内CPL值 + listView2.Items[3].SubItems[1].Text = _cPKData.GroupCPL.ToString(); + // 整体CPL值 + listView2.Items[3].SubItems[2].Text = _cPKData.WholeCPL.ToString(); + // 组内CPU值 + listView2.Items[4].SubItems[1].Text = _cPKData.GroupCPU.ToString(); + // 整体CPU值 + listView2.Items[4].SubItems[2].Text = _cPKData.WholeCPU.ToString(); + + // 组内PPMUSL值 + listView2.Items[6].SubItems[1].Text = _cPKData.GroupPPM_USL.ToString(); + // 整体PPM>USL值 + listView2.Items[6].SubItems[2].Text = _cPKData.WholePPM_USL.ToString(); + + // 组内PPM Total值 + listView2.Items[7].SubItems[1].Text = _cPKData.GroupPPM_Total.ToString(); + // 整体PPMN Total值 + listView2.Items[7].SubItems[2].Text = _cPKData.WholePPM_Total.ToString(); + + lbl_Ca.Text = _cPKData.CA.ToString(); + this.Invalidate(); + } + + } + } + + + + #region 初始化 + private void IntValue() + { + + //listView2.OwnerDraw = true; + //listView2.DrawColumnHeader += ListView2_DrawColumnHeader; + + listView1.Columns.Clear(); + listView2.Columns.Clear(); + + // 假设ListView控件的名称为listView1 + // 添加列头 + listView1.Columns.Add("项目1", 80); + listView1.Columns.Add("数值1", 90); + listView1.Columns.Add("项目2", 80); + listView1.Columns.Add("数值2", 90); + listView1.Columns.Add("项目3", 80); + listView1.Columns.Add("数值3", 95); + + // 创建一个ListViewItem对象,并将数据添加到指定单元格 0 + ListViewItem item1_1 = new ListViewItem("总样本数"); + item1_1.SubItems.Add("0"); + item1_1.SubItems.Add("子组大小"); + item1_1.SubItems.Add("0"); + item1_1.SubItems.Add("图标类型"); + item1_1.SubItems.Add("XR"); + listView1.Items.Add(item1_1); // 添加完整的ListViewItem对象到ListView控件中的指定行索引 + + + // 如果需要添加多行数据,可以类似地重复上述步骤 + ListViewItem item1_2 = new ListViewItem("平均值"); //1 + item1_2.SubItems.Add("0"); + item1_2.SubItems.Add("最大值"); + item1_2.SubItems.Add("0"); + item1_2.SubItems.Add("最小值"); + item1_2.SubItems.Add("0"); + listView1.Items.Add(item1_2); + + ListViewItem item1_3 = new ListViewItem("上规格"); //2 + item1_3.SubItems.Add("0"); + item1_3.SubItems.Add("目标值"); + item1_3.SubItems.Add("0"); + item1_3.SubItems.Add("下规格"); + item1_3.SubItems.Add("0"); + listView1.Items.Add(item1_3); + + ListViewItem item1_4 = new ListViewItem("+3Sigma"); //3 + item1_4.SubItems.Add("0"); + item1_4.SubItems.Add("-3Sigma"); + item1_4.SubItems.Add("0"); + listView1.Items.Add(item1_4); + + + + + // 假设ListView控件的名称为listView1 + // 添加列头 + listView2.Columns.Add("", 150); + listView2.Columns.Add("组内", 120); + listView2.Columns.Add("整体", 120); + listView2.Columns.Add("实测", 128); + + // 创建一个ListViewItem对象,并将数据添加到指定单元格 + ListViewItem item2_1 = new ListViewItem("STDEV"); //0 + item2_1.SubItems.Add("0"); + item2_1.SubItems.Add("0"); + item2_1.SubItems.Add(""); + listView2.Items.Add(item2_1); // 添加完整的ListViewItem对象到ListView控件中的指定行索引 + + ListViewItem item2_2 = new ListViewItem("CPK"); //1 + item2_2.SubItems.Add("0"); + item2_2.SubItems.Add("0"); + item2_2.SubItems.Add(""); + listView2.Items.Add(item2_2); + ListViewItem item2_3 = new ListViewItem("CP");//2 + item2_3.SubItems.Add("0"); + item2_3.SubItems.Add("0"); + item2_3.SubItems.Add(""); + listView2.Items.Add(item2_3); + ListViewItem item2_4 = new ListViewItem("CPL");//3 + item2_4.SubItems.Add("0"); + item2_4.SubItems.Add("0"); + item2_4.SubItems.Add(""); + listView2.Items.Add(item2_4); + ListViewItem item2_5 = new ListViewItem("CPU");//4 + item2_5.SubItems.Add("0"); + item2_5.SubItems.Add("0"); + item2_5.SubItems.Add(""); + listView2.Items.Add(item2_5); + ListViewItem item2_6 = new ListViewItem("PPMUSL");//6 + item2_7.SubItems.Add("0"); + item2_7.SubItems.Add("0"); + item2_7.SubItems.Add("0"); + listView2.Items.Add(item2_7); + ListViewItem item2_8 = new ListViewItem("PPM Total");//7 + item2_8.SubItems.Add("0"); + item2_8.SubItems.Add("0"); + item2_8.SubItems.Add("0"); + listView2.Items.Add(item2_8); + + lbl_Ca.Text = "0"; + } + + #endregion + + public void ListView2_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) + { + e.DrawBackground(); + + // 设置自定义的列标题栏背景颜色 + e.Graphics.FillRectangle(Brushes.AliceBlue, e.Bounds); + + // 绘制列标题栏的文本 + e.DrawText(); + } + } + +} diff --git a/JinYuan.ControlLib/CPK.resx b/JinYuan.ControlLib/CPK.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/CPK.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/CheckBoxExt.Designer.cs b/JinYuan.ControlLib/CheckBoxExt.Designer.cs new file mode 100644 index 0000000..875b6d4 --- /dev/null +++ b/JinYuan.ControlLib/CheckBoxExt.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class CheckBoxExt + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/CheckBoxExt.cs b/JinYuan.ControlLib/CheckBoxExt.cs new file mode 100644 index 0000000..84f6fae --- /dev/null +++ b/JinYuan.ControlLib/CheckBoxExt.cs @@ -0,0 +1,132 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class CheckBoxExt : CheckBox + { + public CheckBoxExt() + { + InitializeComponent(); + + _format.LineAlignment = StringAlignment.Center; + _format.Alignment = StringAlignment.Center; + + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private StringFormat _format = new StringFormat(); + + + + private int defultCheckButtonWidth = 20; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示标题名称")] + public int DefultCheckButtonWidth + { + get { return defultCheckButtonWidth; } + set { defultCheckButtonWidth = value; } + } + + private Color checkColor = Color.FromArgb(3, 25, 66); + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示选中颜色")] + public Color CheckColor + { + get { return checkColor; } + set + { + checkColor = value; + this.Invalidate(); + } + } + + private Color checkBackColor = Color.White; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示选中框背景颜色")] + public Color CheckBackColor + { + get { return checkBackColor; } + set + { + checkBackColor = value; + this.Invalidate(); + } + } + + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + base.OnPaintBackground(e); + + Graphics g = e.Graphics; + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + Rectangle checkRec; + Rectangle textRec; + + CalculatorRec(out checkRec, out textRec); + + SolidBrush solidBrush = new SolidBrush(CheckBackColor); + g.FillRectangle(solidBrush, checkRec); + + Pen pen = new Pen(Color.LightGray); + g.DrawRectangle(pen, checkRec); + + if (this.CheckState == CheckState.Checked) + { + //画勾选 + DrawCheckFlag(g, checkRec, checkColor); + } + + //绘制文本 + g.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), textRec, this._format); + } + + + /// + /// 计算矩形 + /// + /// + /// + private void CalculatorRec(out Rectangle checkRec, out Rectangle textRec) + { + checkRec = new Rectangle(3, (this.Height - defultCheckButtonWidth) / 2, defultCheckButtonWidth, + defultCheckButtonWidth); + + textRec = new Rectangle(checkRec.Right + 3, 0, Width - checkRec.Right - 6, this.Height); + } + + + /// + /// 画勾选 + /// + /// + /// + /// + private void DrawCheckFlag(Graphics g, Rectangle rectangle, Color color) + { + PointF[] pointFs = new PointF[3]; + + pointFs[0] = new PointF(rectangle.X + rectangle.Width / 4.5f, rectangle.Y + rectangle.Height / 2.5f); + pointFs[1] = new PointF(rectangle.X + rectangle.Width / 2.5F, rectangle.Bottom - rectangle.Height / 3.0f); + pointFs[2] = new PointF(rectangle.Right - rectangle.Width / 4.0f, rectangle.Y + rectangle.Height / 4.5f); + + Pen pen = new Pen(color, 2.0f); + g.DrawLines(pen, pointFs); + + } + } +} diff --git a/JinYuan.ControlLib/CircleProgramBar.Designer.cs b/JinYuan.ControlLib/CircleProgramBar.Designer.cs new file mode 100644 index 0000000..f86b951 --- /dev/null +++ b/JinYuan.ControlLib/CircleProgramBar.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class CircleProgramBar + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/CircleProgramBar.cs b/JinYuan.ControlLib/CircleProgramBar.cs new file mode 100644 index 0000000..2944890 --- /dev/null +++ b/JinYuan.ControlLib/CircleProgramBar.cs @@ -0,0 +1,220 @@ +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class CircleProgramBar : Control + { + public CircleProgramBar() + { + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + InitControl(); + this.SizeChanged += delegate + { + this.Invalidate(); //重绘控件 + }; + + + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + /// + /// 初始化控件参数 + /// + private void InitControl() + { + this.Width = 200; + this.Height = 200; + } + + private Color bgColor = Color.FromArgb(224, 224, 224); + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示背景边框颜色")] + public Color BgColor + { + get { return this.bgColor; } + set + { + this.bgColor = value; + this.Invalidate(); + } + } + + private Color sectorColor = Color.FromArgb(109, 179, 63); + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示扇形颜色")] + public Color SectorColor + { + get { return this.sectorColor; } + set + { + this.sectorColor = value; + this.Invalidate(); + } + } + + private int borderWidth = 5; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示边框宽度")] + public int BorderWidth + { + get { return this.borderWidth; } + set + { + this.borderWidth = value; + this.Invalidate(); + } + } + + private int maxValue = 100; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示进度最大值")] + public int MaxValue + { + get { return this.maxValue; } + set + { + this.maxValue = value; + this.Invalidate(); + } + } + + + private bool isShowDataType = false; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置显示数值是小数还是整数")] + public bool IsShowDataType + { + get { return this.isShowDataType; } + set + { + this.isShowDataType = value; + this.Invalidate(); + } + } + + + private int intValue = 0; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示整数进度值")] + public int IntValue + { + get { return this.intValue; } + set + { + if (value > this.maxValue) + { + return; + } + this.intValue = value; + this.Invalidate(); + } + } + + private int floatValue = 0; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示小数进度值")] + public int FloatValue + { + get { return this.floatValue; } + set + { + if (value > this.maxValue) + { + return; + } + this.floatValue = value; + this.Invalidate(); + } + } + + + private bool setShowsign = false; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示百分号,显示百分号需要设置MaxValue值为100")] + public bool SetShowsign + { + get { return this.setShowsign; } + set + { + if (this.maxValue > 100) + { + this.maxValue = 100; + } + this.setShowsign = value; + this.Invalidate(); + } + } + + //对Control进行绘制 + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (this.Width < borderWidth * 4 || this.Height < borderWidth * 4) + { + return; + } + var g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias;//消除锯齿,也就是抗锯齿什么鬼东西 + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.CompositingQuality = CompositingQuality.HighQuality; + + + RectangleF bg_rectangle = new RectangleF(0 + borderWidth, 0 + borderWidth, Width - borderWidth * 2, Height - borderWidth * 2); //控件整体坐标 + + g.DrawEllipse(new Pen(bgColor, borderWidth), bg_rectangle); //画背景圆 + + + + Rectangle rl = new Rectangle(0 + borderWidth * 2, 0 + borderWidth * 2, this.Width - borderWidth * 4, this.Height - borderWidth * 4); + + decimal topAngle = (isShowDataType ? this.floatValue : this.intValue * 1.0M / this.maxValue) * 360M;//计算进度条划过的度数 + g.FillPie(new SolidBrush(sectorColor), rl, 0, (float)topAngle); //填充扇形 + + if (this.setShowsign) + { + SizeF proValSize = g.MeasureString(isShowDataType ? this.floatValue.ToString() : this.intValue.ToString() + "%", this.Font);//计算文字的范围 + + g.DrawString(isShowDataType ? this.floatValue.ToString() : this.intValue.ToString() + "%", this.Font, new SolidBrush(this.ForeColor), + + bg_rectangle.X + bg_rectangle.Width / 2 - proValSize.Width / 2, bg_rectangle.Y + bg_rectangle.Height / 2 - proValSize.Height / 2); + } + else + { + SizeF proValSize = g.MeasureString(isShowDataType ? this.floatValue.ToString() : this.intValue.ToString(), this.Font);//计算文字的范围 + + g.DrawString(isShowDataType ? this.floatValue.ToString() : this.intValue.ToString(), this.Font, new SolidBrush(this.ForeColor), + bg_rectangle.X + bg_rectangle.Width / 2 - proValSize.Width / 2, bg_rectangle.Y + bg_rectangle.Height / 2 - proValSize.Height / 2); + } + } + } +} diff --git a/JinYuan.ControlLib/ControlBase.Designer.cs b/JinYuan.ControlLib/ControlBase.Designer.cs new file mode 100644 index 0000000..85599ac --- /dev/null +++ b/JinYuan.ControlLib/ControlBase.Designer.cs @@ -0,0 +1,37 @@ +namespace JinYuan.ControlLib +{ + partial class ControlBase + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + //protected override void Dispose(bool disposing) + //{ + // if (disposing && (components != null)) + // { + // components.Dispose(); + // } + // base.Dispose(disposing); + //} + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/ControlBase.cs b/JinYuan.ControlLib/ControlBase.cs new file mode 100644 index 0000000..3694802 --- /dev/null +++ b/JinYuan.ControlLib/ControlBase.cs @@ -0,0 +1,306 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class ControlBase : UserControl + { + /// + /// The is radius + /// + private bool _isRadius = false; + + /// + /// The corner radius + /// + private int _cornerRadius = 24; + + + /// + /// The is show rect + /// + private bool _isShowRect = false; + + /// + /// The rect color + /// + private Color _rectColor = Color.FromArgb(220, 220, 220); + + /// + /// The rect width + /// + private int _rectWidth = 1; + + /// + /// The fill color + /// + private Color _fillColor = Color.Transparent; + + // 缓存绘图对象,避免重复创建(线程安全:UI线程单例) + private SolidBrush _fillBrush; + private Pen _rectPen; + private bool _isRegionDirty = true; // 标记区域是否需要重新计算 + + #region 公共属性(替换Refresh为Invalidate) + [Description("是否圆角"), Category("自定义")] + public virtual bool IsRadius + { + get => _isRadius; + set + { + if (_isRadius == value) return; + _isRadius = value; + _isRegionDirty = true; + Invalidate(); + } + } + /// + /// 圆角角度 + /// + /// The coner radius. + [Description("圆角角度"), Category("自定义")] + public virtual int ConerRadius + { + get => _cornerRadius; + set + { + value = Math.Max(value, 1); + if (_cornerRadius == value) return; + _cornerRadius = value; + _isRegionDirty = true; + Invalidate(); + } + } + + /// + /// 是否显示边框 + /// + /// true if this instance is show rect; otherwise, false. + [Description("是否显示边框"), Category("自定义")] + public virtual bool IsShowRect + { + get => _isShowRect; + set + { + if (_isShowRect == value) return; + _isShowRect = value; + Invalidate(); + } + } + /// + /// 边框颜色 + /// + /// The color of the rect. + [Description("边框颜色"), Category("自定义")] + public virtual Color RectColor + { + get => _rectColor; + set + { + if (_rectColor == value) return; + _rectColor = value; + // 重置画笔,下次使用时创建 + _rectPen?.Dispose(); + _rectPen = null; + Invalidate(); + } + } + + /// + /// 边框宽度 + /// + /// The width of the rect. + [Description("边框宽度"), Category("自定义")] + public virtual int RectWidth + { + get => _rectWidth; + set + { + if (_rectWidth == value) return; + _rectWidth = value; + // 重置画笔,下次使用时创建 + _rectPen?.Dispose(); + _rectPen = null; + Invalidate(); + } + } + /// + /// 当使用边框时填充颜色,当值为背景色或透明色或空值则不填充 + /// + /// The color of the fill. + [Description("当使用边框时填充颜色,当值为背景色或透明色或空值则不填充"), Category("自定义")] + public virtual Color FillColor + { + get => _fillColor; + set + { + if (_fillColor == value) return; + _fillColor = value; + // 重置画刷,下次使用时创建 + _fillBrush?.Dispose(); + _fillBrush = null; + Invalidate(); + } + } + #endregion + + /// + /// Initializes a new instance of the class. + /// + public ControlBase() + { + InitializeComponent(); + // 优化双缓冲设置 + SetStyle(ControlStyles.AllPaintingInWmPaint | + ControlStyles.DoubleBuffer | + ControlStyles.ResizeRedraw | + ControlStyles.Selectable | + ControlStyles.SupportsTransparentBackColor | + ControlStyles.UserPaint | + ControlStyles.OptimizedDoubleBuffer, true); + UpdateStyles(); // 应用样式设置 + } + + #region 核心优化:重写OnPaint + protected override void OnPaint(PaintEventArgs e) + { + if (!Visible) return; + + // 1. 仅在区域脏时更新Region + if (_isRegionDirty) + { + UpdateWindowRegion(); + _isRegionDirty = false; + } + + // 2. 优化绘图质量 + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + e.Graphics.CompositingQuality = CompositingQuality.HighQuality; + e.Graphics.Clear(BackColor); // 统一背景清除,避免闪烁 + + // 3. 绘制逻辑:仅在需要时创建GraphicsPath + if (_isShowRect || (_fillColor != Color.Empty && _fillColor != Color.Transparent && _fillColor != BackColor)) + { + using (var graphicsPath = CreateRoundedRectPath(ClientRectangle)) + { + // 绘制填充 + if (_fillColor != Color.Empty && _fillColor != Color.Transparent && _fillColor != BackColor) + { + if (_fillBrush == null) + { + _fillBrush = new SolidBrush(_fillColor); + } + e.Graphics.FillPath(_fillBrush, graphicsPath); + } + + // 绘制边框 + if (_isShowRect) + { + if (_rectPen == null) + { + _rectPen = new Pen(_rectColor, Math.Max(1, _rectWidth)); // 避免宽度为0 + } + e.Graphics.DrawPath(_rectPen, graphicsPath); + } + } + } + + base.OnPaint(e); + } + #endregion + + #region 辅助方法(优化逻辑+释放资源) + /// + /// 仅在区域脏时更新WindowRegion + /// + private void UpdateWindowRegion() + { + if (_isRadius) + { + using (var path = CreateRoundedRectPath(new Rectangle(-1, -1, Width + 1, Height))) + { + Region = new Region(path); + } + } + else + { + // 恢复矩形区域 + using (var path = new GraphicsPath()) + { + path.AddRectangle(ClientRectangle); + Region = new Region(path); + } + } + } + + /// + /// 创建圆角路径 + /// + /// 绘制矩形 + /// GraphicsPath + private GraphicsPath CreateRoundedRectPath(Rectangle rect) + { + var path = new GraphicsPath(); + if (_isRadius && _cornerRadius > 0) + { + // 优化圆角计算:避免偏移错误 + int radius = Math.Min(_cornerRadius, Math.Min(rect.Width, rect.Height) / 2); + path.AddArc(rect.X, rect.Y, radius, radius, 180f, 90f); + path.AddArc(rect.Right - radius, rect.Y, radius, radius, 270f, 90f); + path.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0f, 90f); + path.AddArc(rect.X, rect.Bottom - radius, radius, radius, 90f, 90f); + path.CloseFigure(); + } + else + { + path.AddRectangle(rect); + } + return path; + } + + /// + /// 释放非托管资源 + /// + /// 是否手动释放 + protected override void Dispose(bool disposing) + { + if (disposing) + { + // 释放绘图对象 + _fillBrush?.Dispose(); + _rectPen?.Dispose(); + components?.Dispose(); + } + base.Dispose(disposing); + } + + /// + /// 控件大小变化时标记区域脏 + /// + /// 尺寸参数 + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + _isRegionDirty = true; + Invalidate(); + } + #endregion + + /// + /// 屏蔽不必要的消息 + /// + /// Windows消息 + protected override void WndProc(ref Message m) + { + if (m.Msg != 20) + { + base.WndProc(ref m); + } + } + } +} diff --git a/JinYuan.ControlLib/CustomComboBox.Designer.cs b/JinYuan.ControlLib/CustomComboBox.Designer.cs new file mode 100644 index 0000000..de3f81a --- /dev/null +++ b/JinYuan.ControlLib/CustomComboBox.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class CustomComboBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/CustomComboBox.cs b/JinYuan.ControlLib/CustomComboBox.cs new file mode 100644 index 0000000..6a0d21c --- /dev/null +++ b/JinYuan.ControlLib/CustomComboBox.cs @@ -0,0 +1,280 @@ +using AntdUI; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class CustomComboBox : ComboBox + { + private Color darkBackColor = Color.FromArgb(30, 30, 30); + private Color lightBackColor = Color.White; + private Color darkForeColor = Color.White; + private Color lightForeColor = Color.Black; + private Color darkBorderColor = Color.FromArgb(64, 64, 64); + private Color lightBorderColor = Color.FromArgb(217, 217, 217); + private Color darkArrowColor = Color.White; + private Color lightArrowColor = Color.Black; + private Color darkWatermarkColor = Color.Gray; + private Color lightWatermarkColor = Color.LightGray; + + private string watermarkText = string.Empty; + [Category("行为")] + public string WatermarkText + { + get { return watermarkText; } + set + { + watermarkText = value; + Invalidate(); + } + } + + private int cornerRadius = 5; // 新增:控制圆角半径的字段 + + [Category("外观")] + [DefaultValue(5)] + public int CornerRadius + { + get { return cornerRadius; } + set + { + if (cornerRadius != value) + { + cornerRadius = value; + Invalidate(); + } + } + } + + public CustomComboBox() + { + SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); + DrawMode = DrawMode.OwnerDrawFixed; + DropDownStyle = ComboBoxStyle.DropDownList; + UpdateTheme(Config.IsDark); + + } + + + + + public void UpdateTheme(bool isDark) + { + BackColor = isDark ? darkBackColor : lightBackColor; + ForeColor = isDark ? darkForeColor : lightForeColor; + Invalidate(); + } + + protected override void OnPaint(PaintEventArgs e) + { + using (var path = CreateRoundedRectangle(new Rectangle(0, 0, Width - 1, Height - 1), cornerRadius)) + { + var g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + + var rect = new Rectangle(0, 0, Width - 1, Height - 1); + var borderColor = Config.IsDark ? darkBorderColor : lightBorderColor; + var arrowColor = Config.IsDark ? darkArrowColor : lightArrowColor; + + // Draw background + using (var brush = new SolidBrush(BackColor)) + { + g.FillPath(brush, path); + } + + // Draw border + using (var pen = new Pen(borderColor)) + { + g.DrawPath(pen, path); + } + + // Draw text or watermark + var textRect = new Rectangle(cornerRadius, 2, Width - 20 - cornerRadius, Height - 4); + var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.Left; + if (SelectedItem != null) + { + string displayText = GetCustomItemText(SelectedItem); + using (var brush = new SolidBrush(ForeColor)) + { + TextRenderer.DrawText(g, displayText, Font, textRect, ForeColor, flags); + } + } + else if (!string.IsNullOrEmpty(watermarkText)) + { + var watermarkColor = Config.IsDark ? darkWatermarkColor : lightWatermarkColor; + TextRenderer.DrawText(g, watermarkText, Font, textRect, watermarkColor, flags); + } + + // Draw arrow + var arrowSize = 8; + var arrowRect = new Rectangle(Width - arrowSize - 8 - cornerRadius, (Height - arrowSize) / 2, arrowSize, arrowSize); + using (var brush = new SolidBrush(arrowColor)) + { + Point[] arrow = { + new Point(arrowRect.Left, arrowRect.Top), + new Point(arrowRect.Right, arrowRect.Top), + new Point(arrowRect.Left + arrowRect.Width / 2, arrowRect.Bottom) + }; + g.FillPolygon(brush, arrow); + } + } + } + + protected override void OnDrawItem(DrawItemEventArgs e) + { + if (e.Index < 0) return; + + // 设置下拉项的背景色 + Color backColor; + Color textColor; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + // 选中项的颜色 + backColor = Config.IsDark ? Color.FromArgb(45, 45, 45) : Color.FromArgb(230, 230, 230); + textColor = Config.IsDark ? darkForeColor : lightForeColor; + } + else + { + // 未选中项的颜色 + backColor = Config.IsDark ? darkBackColor : lightBackColor; + textColor = Config.IsDark ? darkForeColor : lightForeColor; + } + + // 使用新的背景色绘制背景 + using (var backBrush = new SolidBrush(backColor)) + { + e.Graphics.FillRectangle(backBrush, e.Bounds); + } + + // 绘制文本 + if (e.Index >= 0) + { + string itemText = GetCustomItemText(Items[e.Index]); + + // 设置文本边距 + Rectangle textBounds = new Rectangle( + e.Bounds.X + 5, // 左边距 + e.Bounds.Y, + e.Bounds.Width - 10, // 右边距 + e.Bounds.Height + ); + + // 使用TextRenderer绘制文本以获得更好的文本渲染效果 + TextRenderer.DrawText( + e.Graphics, + itemText, + Font, + textBounds, + textColor, + TextFormatFlags.VerticalCenter | TextFormatFlags.Left + ); + } + + // 如果有焦点,绘制焦点矩形 + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) + { + using (Pen focusPen = new Pen(Config.IsDark ? Color.FromArgb(70, 70, 70) : Color.FromArgb(180, 180, 180))) + { + e.Graphics.DrawRectangle(focusPen, new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1)); + } + } + } + + // 添加这个方法来处理下拉列表的外观 + protected override void WndProc(ref System.Windows.Forms.Message m) + { + if (m.Msg == 0x204E) // WM_CTLCOLORLISTBOX + { + // 获取下拉列表的句柄 + var hDC = m.WParam; + var hListBox = m.LParam; + + using (Graphics g = Graphics.FromHdc(hDC)) + { + // 设置下拉列表的背景色 + using (SolidBrush backBrush = new SolidBrush(Config.IsDark ? darkBackColor : lightBackColor)) + { + g.FillRectangle(backBrush, this.DropDownRectangle); + } + } + } + base.WndProc(ref m); + } + + // 获取下拉列表的矩形区域 + private Rectangle DropDownRectangle + { + get + { + return new Rectangle(0, 0, DropDownWidth, ItemHeight * Math.Max(Items.Count, 1)); + } + } + + private string GetCustomItemText(object item) + { + if (item == null) + return string.Empty; + + if (string.IsNullOrEmpty(DisplayMember)) + return item.ToString(); + + PropertyDescriptor descriptor = TypeDescriptor.GetProperties(item).Find(DisplayMember, true); + if (descriptor != null) + return descriptor.GetValue(item)?.ToString() ?? string.Empty; + + return item.ToString(); + } + + public object GetSelectedValue() + { + if (SelectedItem == null) + return null; + + if (string.IsNullOrEmpty(ValueMember)) + return SelectedItem; + + PropertyDescriptor descriptor = TypeDescriptor.GetProperties(SelectedItem).Find(ValueMember, true); + if (descriptor != null) + return descriptor.GetValue(SelectedItem); + + return null; + } + + + private GraphicsPath CreateRoundedRectangle(Rectangle bounds, int radius) + { + int diameter = radius * 2; + Size size = new Size(diameter, diameter); + Rectangle arc = new Rectangle(bounds.Location, size); + GraphicsPath path = new GraphicsPath(); + + if (radius == 0) + { + path.AddRectangle(bounds); + return path; + } + + // 左上角 + path.AddArc(arc, 180, 90); + + // 右上角 + arc.X = bounds.Right - diameter; + path.AddArc(arc, 270, 90); + + // 右下角 + arc.Y = bounds.Bottom - diameter; + path.AddArc(arc, 0, 90); + + // 左下角 + arc.X = bounds.Left; + path.AddArc(arc, 90, 90); + + path.CloseFigure(); + return path; + } + } +} diff --git a/JinYuan.ControlLib/CustomDataGridView.cs b/JinYuan.ControlLib/CustomDataGridView.cs new file mode 100644 index 0000000..3e9d8f6 --- /dev/null +++ b/JinYuan.ControlLib/CustomDataGridView.cs @@ -0,0 +1,233 @@ +using AntdUI; +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public class CustomDataGridView : DataGridView + { + private Color darkBackgroundColor = Color.FromArgb(18, 18, 18); + private Color lightBackgroundColor = Color.White; + private Color darkForeColor = Color.White; + private Color lightForeColor = Color.Black; + private Color darkHeaderBackColor = Color.FromArgb(30, 30, 30); + private Color lightHeaderBackColor = Color.FromArgb(240, 240, 240); + private Color darkSelectedCellColor = Color.FromArgb(64, 64, 64); + private Color lightSelectedCellColor = Color.FromArgb(200, 200, 200); + private Color darkSelectedColumnColor = Color.FromArgb(45, 45, 45); + private Color lightSelectedColumnColor = Color.FromArgb(220, 220, 220); + private Color darkButtonColor = Color.FromArgb(64, 64, 64); + private Color lightButtonColor = Color.FromArgb(240, 240, 240); + private Color darkComboBoxColor = Color.FromArgb(45, 45, 45); + private Color lightComboBoxColor = Color.FromArgb(250, 250, 250); + + public CustomDataGridView() + { + InitializeComponent(); + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + UpdateTheme(Config.IsDark); + } + + private void InitializeComponent() + { + this.RowHeadersVisible = true; + this.AllowUserToAddRows = false; + this.AllowUserToDeleteRows = false; + this.AllowUserToResizeRows = false; + this.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + this.MultiSelect = false; + this.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal; + this.BorderStyle = BorderStyle.None; + this.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.None; + this.EnableHeadersVisualStyles = false; + + this.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; + this.ColumnHeadersDefaultCellStyle.Font = new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Bold); + this.ColumnHeadersHeight = 30; + + this.RowHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; + this.RowHeadersWidth = 50; + + // 设置默认的行高 + this.RowTemplate.Height = 28; + } + + public void UpdateTheme(bool isDark) + { + // 基础颜色 + this.BackgroundColor = isDark ? darkBackgroundColor : lightBackgroundColor; + this.ForeColor = isDark ? darkForeColor : lightForeColor; + this.GridColor = isDark ? Color.DimGray : Color.LightGray; + + // 列头样式 + this.ColumnHeadersDefaultCellStyle.BackColor = isDark ? darkHeaderBackColor : lightHeaderBackColor; + this.ColumnHeadersDefaultCellStyle.ForeColor = isDark ? darkForeColor : lightForeColor; + this.ColumnHeadersDefaultCellStyle.SelectionBackColor = isDark ? darkSelectedColumnColor : lightSelectedColumnColor; + this.ColumnHeadersDefaultCellStyle.SelectionForeColor = isDark ? darkForeColor : lightForeColor; + + // 行头样式 + this.RowHeadersDefaultCellStyle.BackColor = isDark ? darkHeaderBackColor : lightHeaderBackColor; + this.RowHeadersDefaultCellStyle.ForeColor = isDark ? darkForeColor : lightForeColor; + this.RowHeadersDefaultCellStyle.SelectionBackColor = isDark ? darkSelectedCellColor : lightSelectedCellColor; + this.RowHeadersDefaultCellStyle.SelectionForeColor = isDark ? darkForeColor : lightForeColor; + + // 默认单元格样式 + this.DefaultCellStyle.BackColor = this.BackgroundColor; + this.DefaultCellStyle.ForeColor = this.ForeColor; + this.DefaultCellStyle.SelectionBackColor = isDark ? darkSelectedCellColor : lightSelectedCellColor; + this.DefaultCellStyle.SelectionForeColor = isDark ? darkForeColor : lightForeColor; + + // 更新所有列的样式 + foreach (DataGridViewColumn column in this.Columns) + { + if (column is DataGridViewComboBoxColumn comboBoxColumn) + { + // ComboBox列样式 + comboBoxColumn.DefaultCellStyle.BackColor = isDark ? darkComboBoxColor : lightComboBoxColor; + comboBoxColumn.DefaultCellStyle.ForeColor = isDark ? darkForeColor : lightForeColor; + comboBoxColumn.DefaultCellStyle.SelectionBackColor = isDark ? darkSelectedCellColor : lightSelectedCellColor; + comboBoxColumn.DefaultCellStyle.SelectionForeColor = isDark ? darkForeColor : lightForeColor; + comboBoxColumn.FlatStyle = FlatStyle.Flat; + } + else if (column is DataGridViewButtonColumn buttonColumn) + { + // Button列样式 + DataGridViewCellStyle buttonStyle = new DataGridViewCellStyle(); + buttonStyle.BackColor = isDark ? darkButtonColor : lightButtonColor; + buttonStyle.ForeColor = isDark ? darkForeColor : lightForeColor; + buttonStyle.SelectionBackColor = isDark ? darkSelectedCellColor : lightSelectedCellColor; + buttonStyle.SelectionForeColor = isDark ? darkForeColor : lightForeColor; + buttonStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; + buttonColumn.DefaultCellStyle = buttonStyle; + buttonColumn.FlatStyle = FlatStyle.Flat; + } + } + + this.Invalidate(); + } + + protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e) + { + if (e.RowIndex == -1 && e.ColumnIndex >= 0) + { + // 绘制列头 + e.PaintBackground(e.CellBounds, true); + Rectangle newRect = new Rectangle(e.CellBounds.X + 2, e.CellBounds.Y + 2, + e.CellBounds.Width - 4, e.CellBounds.Height - 4); + + using (var brush = new SolidBrush(e.CellStyle.ForeColor)) + { + e.Graphics.DrawString(e.Value?.ToString(), this.ColumnHeadersDefaultCellStyle.Font, + brush, newRect, new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }); + } + e.Handled = true; + } + else if (e.RowIndex >= 0 && e.ColumnIndex == -1) + { + // 绘制行头(行号) + e.PaintBackground(e.CellBounds, true); + Rectangle newRect = new Rectangle(e.CellBounds.X + 2, e.CellBounds.Y + 2, + e.CellBounds.Width - 4, e.CellBounds.Height - 4); + + string rowNumber = (e.RowIndex + 1).ToString(); + + // 判断当前行是否被选中 + bool isSelected = this.Rows[e.RowIndex].Selected; + Color textColor; + + if (isSelected) + { + // 如果行被选中,使用选中状态的前景色 + textColor = this.RowHeadersDefaultCellStyle.SelectionForeColor; + } + else + { + // 如果行未被选中,使用普通状态的前景色 + textColor = Config.IsDark ? darkForeColor : lightForeColor; + } + + using (var brush = new SolidBrush(textColor)) + { + e.Graphics.DrawString(rowNumber, this.RowHeadersDefaultCellStyle.Font, + brush, newRect, new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }); + } + e.Handled = true; + } + else if (e.ColumnIndex >= 0 && e.RowIndex >= 0) + { + // 处理按钮列的绘制 + if (this.Columns[e.ColumnIndex] is DataGridViewButtonColumn) + { + e.PaintBackground(e.CellBounds, true); + Rectangle buttonBounds = new Rectangle(e.CellBounds.X + 2, e.CellBounds.Y + 2, + e.CellBounds.Width - 4, e.CellBounds.Height - 4); + + using (var buttonBrush = new SolidBrush(e.CellStyle.BackColor)) + using (var textBrush = new SolidBrush(e.CellStyle.ForeColor)) + { + // 绘制按钮背景 + e.Graphics.FillRectangle(buttonBrush, buttonBounds); + + // 绘制按钮文本 + string buttonText = e.Value?.ToString() ?? string.Empty; + e.Graphics.DrawString(buttonText, this.Font, textBrush, + buttonBounds, new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }); + } + e.Handled = true; + } + else + { + base.OnCellPainting(e); + } + } + else + { + base.OnCellPainting(e); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + // 绘制列头底部边框 + using (var pen = new Pen(Config.IsDark ? Color.DimGray : Color.LightGray)) + { + e.Graphics.DrawLine(pen, 0, this.ColumnHeadersHeight, this.Width, this.ColumnHeadersHeight); + } + } + + protected override void OnColumnHeadersHeightChanged(EventArgs e) + { + base.OnColumnHeadersHeightChanged(e); + this.ColumnHeadersHeight = 30; + } + + protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e) + { + base.OnDataBindingComplete(e); + + // 重新应用主题样式 + UpdateTheme(Config.IsDark); + } + } +} diff --git a/JinYuan.ControlLib/CustomGroupBox.Designer.cs b/JinYuan.ControlLib/CustomGroupBox.Designer.cs new file mode 100644 index 0000000..fce89ce --- /dev/null +++ b/JinYuan.ControlLib/CustomGroupBox.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class CustomGroupBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/CustomGroupBox.cs b/JinYuan.ControlLib/CustomGroupBox.cs new file mode 100644 index 0000000..91efe94 --- /dev/null +++ b/JinYuan.ControlLib/CustomGroupBox.cs @@ -0,0 +1,137 @@ +using AntdUI; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class CustomGroupBox : GroupBox + { + private Color darkBorderColor = Color.FromArgb(64, 64, 64); + private Color lightBorderColor = Color.FromArgb(217, 217, 217); + private Color darkForeColor = Color.White; + private Color lightForeColor = Color.Black; + private const int TextPadding = 4; + + public Color BorderColor { get; set; } = Color.Gray; + + + private float _borderWidth = 1f; + private float _cornerRadius = 5f; + + [Category("Appearance")] + [DefaultValue(1f)] + public float BorderWidth + { + get => _borderWidth; + set + { + _borderWidth = value; + Invalidate(); + } + } + + [Category("Appearance")] + [DefaultValue(5f)] + public float CornerRadius + { + get => _cornerRadius; + set + { + _cornerRadius = value; + Invalidate(); + } + } + + public CustomGroupBox() + { + SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); + UpdateTheme(Config.IsDark); + + } + + + + public void UpdateTheme(bool isDark) + { + ForeColor = isDark ? darkForeColor : lightForeColor; + Invalidate(); + } + + protected override void OnPaint(PaintEventArgs e) + { + var g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + + var borderColor = Config.IsDark ? darkBorderColor : lightBorderColor; + var textSize = g.MeasureString(Text, Font); + var textWidth = (int)Math.Ceiling(textSize.Width) + TextPadding * 2; + var textHeight = (int)Math.Ceiling(textSize.Height); + + var textRect = new Rectangle(TextPadding, 0, textWidth, textHeight); + var borderRect = new Rectangle((int)(_borderWidth / 2), textHeight / 2, + Width - 1 - (int)_borderWidth, Height - textHeight / 2 - 1 - (int)_borderWidth); + + //绘制边框颜色 + using (var pen = new Pen(BorderColor, BorderWidth)) + { + e.Graphics.DrawRectangle(pen, 0, 0, Width - BorderWidth, Height - BorderWidth); + } + + // 绘制背景 + using (var brush = new SolidBrush(BackColor)) + { + g.FillRectangle(brush, ClientRectangle); + } + + // 创建圆角矩形路径 + using (var path = GetRoundedRectanglePath(borderRect, _cornerRadius)) + { + // 绘制边框 + using (var pen = new Pen(borderColor, _borderWidth)) + { + g.DrawPath(pen, path); + } + } + + // 绘制标题文本背景 + using (var brush = new SolidBrush(BackColor)) + { + g.FillRectangle(brush, textRect); + } + + // 绘制标题文本 + using (var brush = new SolidBrush(ForeColor)) + { + g.DrawString(Text, Font, brush, textRect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); + } + } + + private GraphicsPath GetRoundedRectanglePath(Rectangle rect, float radius) + { + GraphicsPath path = new GraphicsPath(); + float diameter = radius * 2; + RectangleF arcRect = new RectangleF(rect.Location, new SizeF(diameter, diameter)); + + // 左上角 + path.AddArc(arcRect, 180, 90); + + // 顶边 + arcRect.X = rect.Right - diameter; + path.AddArc(arcRect, 270, 90); + + // 右边 + arcRect.Y = rect.Bottom - diameter; + path.AddArc(arcRect, 0, 90); + + // 底边 + arcRect.X = rect.Left; + path.AddArc(arcRect, 90, 90); + + path.CloseFigure(); + return path; + } + } +} diff --git a/JinYuan.ControlLib/CustomRichTextBox.Designer.cs b/JinYuan.ControlLib/CustomRichTextBox.Designer.cs new file mode 100644 index 0000000..aa3874d --- /dev/null +++ b/JinYuan.ControlLib/CustomRichTextBox.Designer.cs @@ -0,0 +1,37 @@ +namespace JinYuan.ControlLib +{ + partial class CustomRichTextBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + HandleCreated -= CustomRichTextBox_HandleCreated; + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/CustomRichTextBox.cs b/JinYuan.ControlLib/CustomRichTextBox.cs new file mode 100644 index 0000000..4c1ec02 --- /dev/null +++ b/JinYuan.ControlLib/CustomRichTextBox.cs @@ -0,0 +1,442 @@ +using AntdUI; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + + public partial class CustomRichTextBox : RichTextBox + { + private Color darkBackColor = Color.Black; + private Color lightBackColor = Color.White; + private Color darkForeColor = Color.White; + private Color lightForeColor = Color.Black; + private Color darkBorderColor = Color.FromArgb(64, 64, 64); + private Color lightBorderColor = Color.FromArgb(217, 217, 217); + private bool isDarkTheme; + private const int BatchSize = 5000; + private bool isUpdatingTheme = false; + private bool isInitialized = false; + + public CustomRichTextBox() + { + BorderStyle = BorderStyle.None; + SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); + + // 在句柄创建后初始化主题 + HandleCreated += CustomRichTextBox_HandleCreated; + } + + private void CustomRichTextBox_HandleCreated(object sender, EventArgs e) + { + if (!isInitialized) + { + isInitialized = true; + InitializeThemeAsync(); + } + } + + private async void InitializeThemeAsync() + { + try + { + await UpdateThemeAsync(Config.IsDark).ConfigureAwait(false); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Theme initialization failed: {ex.Message}"); + } + } + + public async Task UpdateThemeAsync(bool isDark) + { + if (isDarkTheme == isDark || isUpdatingTheme || !IsHandleCreated) return; + + isUpdatingTheme = true; + isDarkTheme = isDark; + + try + { + if (InvokeRequired) + { + await Task.Run(() => + { + Invoke((MethodInvoker)(() => UpdateThemeInternal())); + }).ConfigureAwait(false); + } + else + { + UpdateThemeInternal(); + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Theme update failed: {ex.Message}"); + } + finally + { + isUpdatingTheme = false; + } + } + + private void UpdateThemeInternal() + { + if (!IsHandleCreated) return; + + BackColor = isDarkTheme ? darkBackColor : lightBackColor; + ForeColor = isDarkTheme ? darkForeColor : lightForeColor; + + SuspendLayout(); + try + { + int visibleStart = GetCharIndexFromPosition(new Point(0, 0)); + int visibleEnd = GetCharIndexFromPosition(new Point(ClientSize.Width, ClientSize.Height)); + + // Update visible text first + UpdateTextColors(visibleStart, visibleEnd - visibleStart); + + // Then update the rest in batches + for (int i = 0; i < TextLength; i += BatchSize) + { + if (i >= visibleStart && i < visibleEnd) continue; + int length = Math.Min(BatchSize, TextLength - i); + UpdateTextColors(i, length); + if (i % (BatchSize * 10) == 0) Application.DoEvents(); + } + } + finally + { + ResumeLayout(); + } + + Invalidate(); + } + + private void UpdateTextColors(int start, int length) + { + if (start < 0 || length <= 0 || start + length > TextLength) return; + + Select(start, length); + SelectionColor = ForeColor; + SelectionBackColor = BackColor; + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + using (var pen = new Pen(isDarkTheme ? darkBorderColor : lightBorderColor)) + { + e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); + } + } + + protected override void OnTextChanged(EventArgs e) + { + base.OnTextChanged(e); + + if (!isUpdatingTheme && TextLength > 0 && IsHandleCreated) + { + int start = TextLength - 1; + int length = 1; + if (start < 0) start = 0; + if (start + length > TextLength) length = TextLength - start; + + UpdateTextColors(start, length); + SelectionLength = 0; + SelectionStart = TextLength; + } + } + + [Browsable(true)] + [Category("Appearance")] + [DefaultValue(typeof(Color), "30, 30, 30")] + public Color DarkBackColor + { + get => darkBackColor; + set + { + if (darkBackColor != value) + { + darkBackColor = value; + if (isDarkTheme && IsHandleCreated) SafeRefreshTheme(); + } + } + } + + [Browsable(true)] + [Category("Appearance")] + [DefaultValue(typeof(Color), "White")] + public Color LightBackColor + { + get => lightBackColor; + set + { + if (lightBackColor != value) + { + lightBackColor = value; + if (!isDarkTheme && IsHandleCreated) SafeRefreshTheme(); + } + } + } + + [Browsable(true)] + [Category("Appearance")] + [DefaultValue(typeof(Color), "White")] + public Color DarkForeColor + { + get => darkForeColor; + set + { + if (darkForeColor != value) + { + darkForeColor = value; + if (isDarkTheme && IsHandleCreated) SafeRefreshTheme(); + } + } + } + + [Browsable(true)] + [Category("Appearance")] + [DefaultValue(typeof(Color), "Black")] + public Color LightForeColor + { + get => lightForeColor; + set + { + if (lightForeColor != value) + { + lightForeColor = value; + if (!isDarkTheme && IsHandleCreated) SafeRefreshTheme(); + } + } + } + + [Browsable(true)] + [Category("Appearance")] + [DefaultValue(typeof(Color), "64, 64, 64")] + public Color DarkBorderColor + { + get => darkBorderColor; + set + { + if (darkBorderColor != value) + { + darkBorderColor = value; + if (isDarkTheme && IsHandleCreated) Invalidate(); + } + } + } + + [Browsable(true)] + [Category("Appearance")] + [DefaultValue(typeof(Color), "217, 217, 217")] + public Color LightBorderColor + { + get => lightBorderColor; + set + { + if (lightBorderColor != value) + { + lightBorderColor = value; + if (!isDarkTheme && IsHandleCreated) Invalidate(); + } + } + } + + private async void SafeRefreshTheme() + { + try + { + await RefreshThemeAsync().ConfigureAwait(false); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Theme refresh failed: {ex.Message}"); + } + } + + public async Task RefreshThemeAsync() + { + if (!IsHandleCreated) return; + await UpdateThemeAsync(isDarkTheme).ConfigureAwait(false); + } + + + } +} +//public partial class CustomRichTextBox : RichTextBox +//{ +// private Color darkBackColor = Color.Black; +// private Color lightBackColor = Color.White; +// private Color darkForeColor = Color.White; +// private Color lightForeColor = Color.Black; +// private Color darkBorderColor = Color.FromArgb(64, 64, 64); +// private Color lightBorderColor = Color.FromArgb(217, 217, 217); +// private bool isDarkTheme; + +// private const int BatchSize = 5000; // 每批处理的字符数 +// private bool isUpdatingTheme = false; + +// public CustomRichTextBox() +// { +// BorderStyle = BorderStyle.None; +// SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); + +// InitializeThemeAsync(); +// } + + +// private async void InitializeThemeAsync() +// { +// await UpdateThemeAsync(Config.IsDark); +// } + +// public async Task UpdateThemeAsync(bool isDark) +// { +// if (isDarkTheme == isDark || isUpdatingTheme) return; + +// isUpdatingTheme = true; +// isDarkTheme = isDark; + +// try +// { +// await Task.Run(async () => +// { +// await InvokeAsync(() => +// { +// BackColor = isDark ? darkBackColor : lightBackColor; +// ForeColor = isDark ? darkForeColor : lightForeColor; + +// SuspendLayout(); +// try +// { +// int visibleStart = GetCharIndexFromPosition(new Point(0, 0)); +// int visibleEnd = GetCharIndexFromPosition(new Point(ClientSize.Width, ClientSize.Height)); + +// // Update visible text first +// UpdateTextColors(visibleStart, visibleEnd - visibleStart); + +// // Then update the rest in batches +// for (int i = 0; i < TextLength; i += BatchSize) +// { +// if (i >= visibleStart && i < visibleEnd) continue; // Skip already updated visible part +// int length = Math.Min(BatchSize, TextLength - i); +// UpdateTextColors(i, length); +// if (i % (BatchSize * 10) == 0) Application.DoEvents(); +// } +// } +// finally +// { +// ResumeLayout(); +// } + +// Invalidate(); +// }); +// }); +// } +// finally +// { +// isUpdatingTheme = false; +// } +// } + +// private void UpdateTextColors(int start, int length) +// { +// Select(start, length); +// SelectionColor = ForeColor; +// SelectionBackColor = BackColor; +// } + +// protected override void OnPaint(PaintEventArgs e) +// { +// base.OnPaint(e); +// using (var pen = new Pen(isDarkTheme ? darkBorderColor : lightBorderColor)) +// { +// e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); +// } +// } + +// protected override void OnTextChanged(EventArgs e) +// { +// base.OnTextChanged(e); + +// if (!isUpdatingTheme && TextLength > 0) +// { +// int start = TextLength - 1; +// int length = 1; +// if (start < 0) start = 0; +// if (start + length > TextLength) length = TextLength - start; + +// UpdateTextColors(start, length); +// SelectionLength = 0; +// SelectionStart = TextLength; +// } +// } + +// [Browsable(true)] +// [Category("Appearance")] +// [DefaultValue(typeof(Color), "30, 30, 30")] +// public Color DarkBackColor +// { +// get => darkBackColor; +// set { darkBackColor = value; if (isDarkTheme) RefreshThemeAsync(); } +// } + +// [Browsable(true)] +// [Category("Appearance")] +// [DefaultValue(typeof(Color), "White")] +// public Color LightBackColor +// { +// get => lightBackColor; +// set { lightBackColor = value; if (!isDarkTheme) RefreshThemeAsync(); } +// } + +// [Browsable(true)] +// [Category("Appearance")] +// [DefaultValue(typeof(Color), "White")] +// public Color DarkForeColor +// { +// get => darkForeColor; +// set { darkForeColor = value; if (isDarkTheme) RefreshThemeAsync(); } +// } + +// [Browsable(true)] +// [Category("Appearance")] +// [DefaultValue(typeof(Color), "Black")] +// public Color LightForeColor +// { +// get => lightForeColor; +// set { lightForeColor = value; if (!isDarkTheme) RefreshThemeAsync(); } +// } + +// [Browsable(true)] +// [Category("Appearance")] +// [DefaultValue(typeof(Color), "64, 64, 64")] +// public Color DarkBorderColor +// { +// get => darkBorderColor; +// set { darkBorderColor = value; if (isDarkTheme) Invalidate(); } +// } + +// [Browsable(true)] +// [Category("Appearance")] +// [DefaultValue(typeof(Color), "217, 217, 217")] +// public Color LightBorderColor +// { +// get => lightBorderColor; +// set { lightBorderColor = value; if (!isDarkTheme) Invalidate(); } +// } + +// public async Task RefreshThemeAsync() +// { +// await UpdateThemeAsync(isDarkTheme); +// } + +// private Task InvokeAsync(Action action) +// { +// return Task.Factory.FromAsync(BeginInvoke(action), EndInvoke); +// } +//} diff --git a/JinYuan.ControlLib/DataGridView/DataGridViewCellEntity.cs b/JinYuan.ControlLib/DataGridView/DataGridViewCellEntity.cs new file mode 100644 index 0000000..3640850 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/DataGridViewCellEntity.cs @@ -0,0 +1,40 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class DataGridViewCellEntity. + /// + public class DataGridViewCellEntity + { + /// + /// Gets or sets the title. + /// + /// The title. + public string Title { get; set; } + /// + /// Gets or sets the width. + /// + /// The width. + public int Width { get; set; } + /// + /// Gets or sets the type of the width. + /// + /// The type of the width. + public System.Windows.Forms.SizeType WidthType { get; set; } + + } +} diff --git a/JinYuan.ControlLib/DataGridView/DataGridViewCellEventArgs.cs b/JinYuan.ControlLib/DataGridView/DataGridViewCellEventArgs.cs new file mode 100644 index 0000000..5ae6b39 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/DataGridViewCellEventArgs.cs @@ -0,0 +1,45 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class DataGridViewEventArgs. + /// Implements the + /// + /// + public class DataGridViewEventArgs : EventArgs + { + /// + /// Gets or sets the cell control. + /// + /// The cell control. + public Control CellControl { get; set; } + /// + /// Gets or sets the index of the cell. + /// + /// The index of the cell. + public int CellIndex { get; set; } + /// + /// Gets or sets the index of the row. + /// + /// The index of the row. + public int RowIndex { get; set; } + + } +} diff --git a/JinYuan.ControlLib/DataGridView/DataGridViewCellEventHandler.cs b/JinYuan.ControlLib/DataGridView/DataGridViewCellEventHandler.cs new file mode 100644 index 0000000..d18702e --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/DataGridViewCellEventHandler.cs @@ -0,0 +1,38 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; +using System.Runtime.InteropServices; + +namespace JinYuan.ControlLib +{ + /// + /// Delegate DataGridViewEventHandler + /// + /// The sender. + /// The instance containing the event data. + [Serializable] + [ComVisible(true)] + public delegate void DataGridViewEventHandler(object sender, DataGridViewEventArgs e); + + /// + /// Delegate DataGridViewRowCustomEventHandler + /// + /// The sender. + /// The instance containing the event data. + [Serializable] + [ComVisible(true)] + public delegate void DataGridViewRowCustomEventHandler(object sender, DataGridViewRowCustomEventArgs e); +} diff --git a/JinYuan.ControlLib/DataGridView/DataGridViewColumnEntity.cs b/JinYuan.ControlLib/DataGridView/DataGridViewColumnEntity.cs new file mode 100644 index 0000000..2b200a4 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/DataGridViewColumnEntity.cs @@ -0,0 +1,79 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; +using System.Drawing; + +namespace JinYuan.ControlLib +{ + /// + /// Class DataGridViewColumnEntity. + /// + public class DataGridViewColumnEntity + { + /// + /// Gets or sets the head text. + /// + /// The head text. + public string HeadText { get; set; } + /// + /// Gets or sets the width. + /// + /// The width. + public int Width { get; set; } + /// + /// Gets or sets the type of the width. + /// + /// The type of the width. + public System.Windows.Forms.SizeType WidthType { get; set; } + /// + /// Gets or sets the data field. + /// + /// The data field. + public string DataField { get; set; } + /// + /// Gets or sets the format. + /// + /// The format. + public Func Format { get; set; } + /// + /// The text align + /// + private ContentAlignment _TextAlign = ContentAlignment.MiddleCenter; + /// + /// Gets or sets the text align. + /// + /// The text align. + public ContentAlignment TextAlign { get { return _TextAlign; } set { _TextAlign = value; } } + /// + /// 自定义的单元格控件,一个实现IDataGridViewCustomCell的Control + /// + /// The custom cell. + private Type customCellType = null; + public Type CustomCellType + { + get + { + return customCellType; + } + set + { + if (!typeof(IDataGridViewCustomCell).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(System.Windows.Forms.Control))) + throw new Exception("行控件没有实现IDataGridViewCustomCell接口"); + customCellType = value; + } + } + } +} diff --git a/JinYuan.ControlLib/DataGridView/DataGridViewRowCustomEventArgs.cs b/JinYuan.ControlLib/DataGridView/DataGridViewRowCustomEventArgs.cs new file mode 100644 index 0000000..59fab8a --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/DataGridViewRowCustomEventArgs.cs @@ -0,0 +1,36 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-27-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; + +namespace JinYuan.ControlLib +{ + /// + /// Class DataGridViewRowCustomEventArgs. + /// Implements the + /// + /// + public class DataGridViewRowCustomEventArgs : EventArgs + { + /// + /// Gets or sets the name of the event. + /// + /// The name of the event. + public string EventName { get; set; } + + public object Data { get; set; } + + } +} diff --git a/JinYuan.ControlLib/DataGridView/IDataGridViewCustomCell.cs b/JinYuan.ControlLib/DataGridView/IDataGridViewCustomCell.cs new file mode 100644 index 0000000..5b63737 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/IDataGridViewCustomCell.cs @@ -0,0 +1,19 @@ +namespace JinYuan.ControlLib +{ + public interface IDataGridViewCustomCell + { + /// + /// 绑定行关联的数据 + /// + /// The object. + void SetBindSource(object obj); + /// + /// 自定义事件传递,用于单元格向行中传递此事件 + /// + event DataGridViewRowCustomEventHandler RowCustomEvent; + /// + /// 关联数据源 + /// + object DataSource { get; } + } +} diff --git a/JinYuan.ControlLib/DataGridView/IDataGridViewRow.cs b/JinYuan.ControlLib/DataGridView/IDataGridViewRow.cs new file mode 100644 index 0000000..d3ea3fc --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/IDataGridViewRow.cs @@ -0,0 +1,87 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System.Collections.Generic; + +namespace JinYuan.ControlLib +{ + /// + /// Interface IDataGridViewRow + /// + public interface IDataGridViewRow + { + /// + /// Occurs when [row custom event]. + /// + event DataGridViewRowCustomEventHandler RowCustomEvent; + /// + /// CheckBox选中事件 + /// + event DataGridViewEventHandler CheckBoxChangeEvent; + /// + /// 点击单元格事件 + /// + event DataGridViewEventHandler CellClick; + /// + /// 数据源改变事件 + /// + event DataGridViewEventHandler SourceChanged; + /// + /// 列参数,用于创建列数和宽度 + /// + /// The columns. + List Columns { get; set; } + /// + /// Gets or sets a value indicating whether this instance is show CheckBox. + /// + /// true if this instance is show CheckBox; otherwise, false. + bool IsShowCheckBox { get; set; } + /// + /// 是否选中 + /// + /// true if this instance is checked; otherwise, false. + bool IsChecked { get; set; } + + /// + /// 数据源 + /// + /// The data source. + object DataSource { get; set; } + /// + /// 添加单元格元素,仅做添加控件操作,不做数据绑定,数据绑定使用BindingCells + /// + void ReloadCells(); + /// + /// 绑定数据到Cell + /// + /// 返回true则表示已处理过,否则将进行默认绑定(通常只针对有Text值的控件) + void BindingCellData(); + /// + /// 设置选中状态,通常为设置颜色即可 + /// + /// 是否选中 + void SetSelect(bool blnSelected); + /// + /// 行高 + /// + /// The height of the row. + int RowHeight { get; set; } + /// + /// 行号 + /// + /// The Index of the row. + int RowIndex { get; set; } + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridView.Designer.cs b/JinYuan.ControlLib/DataGridView/UCDataGridView.Designer.cs new file mode 100644 index 0000000..1c4a93c --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridView.Designer.cs @@ -0,0 +1,147 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class UCDataGridView. + /// Implements the + /// + /// + partial class UCDataGridView + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.panHead = new System.Windows.Forms.Panel(); + this.panColumns = new System.Windows.Forms.TableLayoutPanel(); + this.panHeadLeft = new System.Windows.Forms.Panel(); + this.panRow = new System.Windows.Forms.FlowLayoutPanel(); + this.ucSplitLine_H1 = new JinYuan.ControlLib.UCSplitLine_H(); + this.panHead.SuspendLayout(); + this.SuspendLayout(); + // + // panHead + // + this.panHead.Controls.Add(this.panColumns); + this.panHead.Controls.Add(this.panHeadLeft); + this.panHead.Controls.Add(this.ucSplitLine_H1); + this.panHead.Location = new System.Drawing.Point(0, 0); + this.panHead.Name = "panHead"; + this.panHead.Size = new System.Drawing.Size(1061, 40); + this.panHead.TabIndex = 0; + // + // panColumns + // + this.panColumns.ColumnCount = 1; + this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.panColumns.Dock = System.Windows.Forms.DockStyle.Fill; + this.panColumns.Location = new System.Drawing.Point(0, 0); + this.panColumns.Name = "panColumns"; + this.panColumns.RowCount = 1; + this.panColumns.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.panColumns.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.panColumns.Size = new System.Drawing.Size(1061, 39); + this.panColumns.TabIndex = 1; + // + // panHeadLeft + // + this.panHeadLeft.Dock = System.Windows.Forms.DockStyle.Left; + this.panHeadLeft.Location = new System.Drawing.Point(0, 0); + this.panHeadLeft.Name = "panHeadLeft"; + this.panHeadLeft.Size = new System.Drawing.Size(0, 39); + this.panHeadLeft.TabIndex = 2; + // + // panRow + // + this.panRow.AutoScroll = true; + this.panRow.Dock = System.Windows.Forms.DockStyle.Fill; + this.panRow.Location = new System.Drawing.Point(0, 40); + this.panRow.Name = "panRow"; + this.panRow.Size = new System.Drawing.Size(317, 225); + this.panRow.TabIndex = 1; + this.panRow.Scroll += new System.Windows.Forms.ScrollEventHandler(this.panRow_Scroll); + // + // ucSplitLine_H1 + // + this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232))))); + this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 39); + this.ucSplitLine_H1.Name = "ucSplitLine_H1"; + this.ucSplitLine_H1.Size = new System.Drawing.Size(1061, 1); + this.ucSplitLine_H1.TabIndex = 0; + this.ucSplitLine_H1.TabStop = false; + // + // UCDataGridView + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.White; + this.Controls.Add(this.panRow); + this.Controls.Add(this.panHead); + this.Name = "UCDataGridView"; + this.Padding = new System.Windows.Forms.Padding(0, 40, 0, 0); + this.Size = new System.Drawing.Size(317, 265); + this.Scroll += new System.Windows.Forms.ScrollEventHandler(this.UCDataGridView_Scroll); + this.SizeChanged += new System.EventHandler(this.UCDataGridView_SizeChanged); + this.panHead.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + /// + /// The pan head + /// + private System.Windows.Forms.Panel panHead; + /// + /// The pan columns + /// + private System.Windows.Forms.TableLayoutPanel panColumns; + /// + /// The uc split line h1 + /// + private UCSplitLine_H ucSplitLine_H1; + /// + /// The pan head left + /// + private System.Windows.Forms.Panel panHeadLeft; + private System.Windows.Forms.FlowLayoutPanel panRow; + + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridView.cs b/JinYuan.ControlLib/DataGridView/UCDataGridView.cs new file mode 100644 index 0000000..aad6a50 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridView.cs @@ -0,0 +1,815 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using JinYuan.ControlLib.UCHelper; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCDataGridView. + /// Implements the + /// + /// + public partial class UCDataGridView : UserControl + { + #region 属性 + /// + /// The m head pading left + /// + private int m_headPadingLeft = 0; + + /// + /// Gets or sets the head pading left. + /// + /// The head pading left. + [Description("标题左侧间距"), Category("自定义")] + public int HeadPadingLeft + { + get { return m_headPadingLeft; } + set + { + m_headPadingLeft = value; + this.panHeadLeft.Width = m_headPadingLeft; + } + } + + /// + /// The m head font + /// + private Font m_headFont = new Font("微软雅黑", 12F); + /// + /// 标题字体 + /// + /// The head font. + [Description("标题字体"), Category("自定义")] + public Font HeadFont + { + get { return m_headFont; } + set { m_headFont = value; } + } + /// + /// The m head text color + /// + private Color m_headTextColor = Color.Black; + /// + /// 标题字体颜色 + /// + /// The color of the head text. + [Description("标题文字颜色"), Category("自定义")] + public Color HeadTextColor + { + get { return m_headTextColor; } + set { m_headTextColor = value; } + } + + /// + /// The m is show head + /// + private bool m_isShowHead = true; + /// + /// 是否显示标题 + /// + /// true if this instance is show head; otherwise, false. + [Description("是否显示标题"), Category("自定义")] + public bool IsShowHead + { + get { return m_isShowHead; } + set + { + if (m_isShowHead != value) + { + m_isShowHead = value; + panHead.Visible = value; + if (value) + { + this.panRow.Location = new Point(0, panHead.Height); + this.panRow.Height = this.panRow.Height - panHead.Height; + } + else + { + this.panRow.Location = new Point(0, 0); + this.panRow.Height = this.panRow.Height + panHead.Height; + } + } + } + } + /// + /// The m head height + /// + private int m_headHeight = 40; + /// + /// 标题高度 + /// + /// The height of the head. + [Description("标题高度"), Category("自定义")] + public int HeadHeight + { + get { return m_headHeight; } + set + { + m_headHeight = value; + panHead.Height = value; + this.Padding = new Padding(0, value, 0, 0); + } + } + + /// + /// The m is show CheckBox + /// + private bool m_isShowCheckBox = false; + /// + /// 是否显示复选框 + /// + /// true if this instance is show CheckBox; otherwise, false. + [Description("是否显示选择框"), Category("自定义")] + public bool IsShowCheckBox + { + get { return m_isShowCheckBox; } + set + { + if (value != m_isShowCheckBox) + { + m_isShowCheckBox = value; + LoadColumns(); + } + } + } + + /// + /// The m row height + /// + private int m_rowHeight = 40; + /// + /// 行高 + /// + /// The height of the row. + [Description("数据行高"), Category("自定义")] + public int RowHeight + { + get { return m_rowHeight; } + set { m_rowHeight = value; } + } + + + /// + /// Gets the show count. + /// + /// The show count. + [Description("当前高度可显示行个数"), Category("自定义")] + public int ShowCount + { + get + { + return this.panRow.Height / (m_rowHeight); + } + } + + /// + /// The m columns + /// + private List m_columns = null; + /// + /// 列 + /// + /// The columns. + [Description("列"), Category("自定义")] + public List Columns + { + get { return m_columns; } + set + { + m_columns = value; + LoadColumns(); + } + } + + /// + /// The m data source + /// + private object m_dataSource = null; + /// + /// 数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource + /// + /// The data source. + /// 数据源不是有效的数据类型,请使用Datatable或列表 + /// 数据源不是有效的数据类型,请使用Datatable或列表 + [Description("数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource"), Category("自定义")] + public object DataSource + { + get { return m_dataSource; } + set + { + if (value != null) + { + if (!(value is DataTable) && (!typeof(IList).IsAssignableFrom(value.GetType()))) + { + throw new Exception("数据源不是有效的数据类型,请使用Datatable或列表"); + } + } + m_dataSource = value; + if (m_columns != null && m_columns.Count > 0) + { + ReloadSource(); + } + if (BindingSourceEvent != null) + { + BindingSourceEvent(this, null); + } + } + } + + /// + /// Gets the rows. + /// + /// The rows. + public List Rows { get; private set; } + + /// + /// The m row type + /// + private Type m_rowType = typeof(UCDataGridViewRow); + /// + /// 行元素类型,默认UCDataGridViewItem + /// + /// The type of the row. + /// 行控件没有实现IDataGridViewRow接口 + /// 行控件没有实现IDataGridViewRow接口 + [Description("行控件类型,默认UCDataGridViewRow,如果不满足请自定义行控件实现接口IDataGridViewRow"), Category("自定义")] + public Type RowType + { + get { return m_rowType; } + set + { + if (value == null) + return; + if (!typeof(IDataGridViewRow).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control))) + throw new Exception("行控件没有实现IDataGridViewRow接口"); + m_rowType = value; + if (m_columns != null && m_columns.Count > 0) + ReloadSource(); + } + } + + /// + /// The m select row + /// + IDataGridViewRow m_selectRow = null; + /// + /// 选中的节点 + /// + /// The select row. + [Description("选中行"), Category("自定义")] + public IDataGridViewRow SelectRow + { + get { return m_selectRow; } + private set { m_selectRow = value; } + } + + + /// + /// 选中的行,如果显示CheckBox,则以CheckBox选中为准 + /// + /// The select rows. + [Description("选中的行,如果显示CheckBox,则以CheckBox选中为准"), Category("自定义")] + public List SelectRows + { + get + { + return GetSelectRows(); + } + } + + /// + /// Gets the select rows. + /// + /// List<IDataGridViewRow>. + private List GetSelectRows() + { + List lst = new List(); + if (m_isShowCheckBox) + { + if (Rows != null && Rows.Count > 0) + lst.AddRange(Rows.FindAll(p => p.IsChecked)); + } + else + { + if (m_selectRow != null) + lst.AddRange(new List() { m_selectRow }); + } + if (Rows != null && Rows.Count > 0 && m_rowType == typeof(UCDataGridViewTreeRow)) + { + foreach (UCDataGridViewTreeRow row in Rows) + { + lst.AddRange(FindTreeRowSelected(row)); + } + } + return lst; + } + + private List FindTreeRowSelected(UCDataGridViewTreeRow row) + { + List lst = new List(); + var _lst = row.ChildrenRows.FindAll(p => p.IsChecked); + lst.AddRange(_lst); + foreach (UCDataGridViewTreeRow _row in row.ChildrenRows) + { + lst.AddRange(FindTreeRowSelected(_row)); + } + return lst; + } + + /// + /// Finds the child grid. + /// + /// The c. + /// UCDataGridView. + private UCDataGridView FindChildGrid(Control c) + { + foreach (Control item in c.Controls) + { + if (item is UCDataGridView) + return item as UCDataGridView; + else if (item.Controls.Count > 0) + { + var grid = FindChildGrid(item); + if (grid != null) + return grid; + } + } + return null; + } + [Bindable(false)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool AutoScroll + { + get + { + return base.AutoScroll; + } + set + { + base.AutoScroll = value; + } + } + #region 事件 + /// + /// The head CheckBox change event + /// + [Description("选中标题选择框事件"), Category("自定义")] + public EventHandler HeadCheckBoxChangeEvent; + /// + /// The head column click event + /// + [Description("标题点击事件"), Category("自定义")] + public EventHandler HeadColumnClickEvent; + /// + /// Occurs when [item click]. + /// + [Description("项点击事件"), Category("自定义")] + public event DataGridViewEventHandler ItemClick; + /// + /// Occurs when [source changed]. + /// + [Description("行数据源改变事件"), Category("自定义")] + public event DataGridViewEventHandler RowSourceChangedEvent; + /// + /// Occurs when [row custom event]. + /// + [Description("预留的自定义的事件,比如你需要在行上放置删改等按钮时,可以通过此事件传递出来"), Category("自定义")] + public event DataGridViewRowCustomEventHandler RowCustomEvent; + [Description("绑定数据源后事件"), Category("自定义")] + public event EventHandler BindingSourceEvent; + #endregion + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public UCDataGridView() + { + InitializeComponent(); + } + + #region 私有方法 + #region 加载column + /// + /// 功能描述:加载column + /// 作  者:HZH + /// 创建日期:2019-08-08 17:51:50 + /// 任务编号:POS + /// + private void LoadColumns() + { + try + { + if (DesignMode) + { return; } + + ControlHelper.FreezeControl(this.panHead, true); + + this.panRow.Controls.Clear(); + this.panColumns.Controls.Clear(); + this.panColumns.ColumnStyles.Clear(); + + + if (m_columns != null && m_columns.Count() > 0) + { + int _width = 0; + m_columns.ForEach(p => + { + if (p.WidthType == SizeType.Absolute) + { + _width += p.Width; + } + else if (p.WidthType == SizeType.Percent) + { + _width += (int)((p.Width / 100f) * this.Width); + } + }); + if (m_isShowCheckBox) + _width += 30; + if (_width > this.Width) + { + //this.panRow.Width = _width; + this.panHead.Width = _width; + } + else + { + if (m_columns.Any(p => p.WidthType == SizeType.AutoSize)) + { + //this.panRow.Width = this.Width; + this.panHead.Width = this.Width; + } + else + { + //this.panRow.Width = _width; + this.panHead.Width = _width; + } + } + m_columns.FindAll(p => p.WidthType == SizeType.Absolute); + m_columns.FindAll(p => p.WidthType == SizeType.Percent); + int intColumnsCount = m_columns.Count(); + if (m_isShowCheckBox) + { + intColumnsCount++; + } + this.panColumns.ColumnCount = intColumnsCount; + for (int i = 0; i < intColumnsCount; i++) + { + Control c = null; + if (i == 0 && m_isShowCheckBox) + { + this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F)); + + UCCheckBox box = new UCCheckBox(); + box.TextValue = ""; + box.Size = new Size(30, 30); + box.CheckedChangeEvent += (a, b) => + { + Rows.ForEach(p => p.IsChecked = box.Checked); + if (HeadCheckBoxChangeEvent != null) + { + HeadCheckBoxChangeEvent(a, b); + } + }; + c = box; + } + else + { + var item = m_columns[i - (m_isShowCheckBox ? 1 : 0)]; + this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, item.Width)); + Label lbl = new Label(); + lbl.Name = "dgvColumns_" + i; + lbl.Text = item.HeadText; + lbl.Font = m_headFont; + lbl.ForeColor = m_headTextColor; + lbl.TextAlign = ContentAlignment.MiddleCenter; + lbl.AutoSize = false; + lbl.Dock = DockStyle.Fill; + lbl.MouseDown += (a, b) => + { + if (HeadColumnClickEvent != null) + { + HeadColumnClickEvent(a, b); + } + }; + c = lbl; + } + this.panColumns.Controls.Add(c, i, 0); + } + + } + } + finally + { + ControlHelper.FreezeControl(this.panHead, false); + } + } + #endregion + + #endregion + + + + #region 公共函数 + /// + /// 刷新数据 + /// + public void ReloadSource() + { + if (DesignMode) + { return; } + try + { + ControlHelper.FreezeControl(this, true); + panHead.Location = new Point(0, 0); + Rows = new List(); + if (m_columns == null || m_columns.Count <= 0) + return; + if (m_dataSource != null) + { + int intIndex = 0; + + int intSourceCount = 0; + if (m_dataSource is DataTable) + { + intSourceCount = (m_dataSource as DataTable).Rows.Count; + } + else if (typeof(IList).IsAssignableFrom(m_dataSource.GetType())) + { + intSourceCount = (m_dataSource as IList).Count; + } + + foreach (Control item in this.panRow.Controls) + { + if (intIndex >= intSourceCount) + { + item.Visible = false; + } + else + { + var row = (item as IDataGridViewRow); + row.IsShowCheckBox = m_isShowCheckBox; + if (m_dataSource is DataTable) + { + row.DataSource = (m_dataSource as DataTable).Rows[intIndex]; + } + else + { + row.DataSource = (m_dataSource as IList)[intIndex]; + } + row.BindingCellData(); + if (row.RowHeight != m_rowHeight) + row.RowHeight = m_rowHeight; + item.Visible = true; + item.Width = panHead.Width; + + Rows.Add(row); + row.RowIndex = Rows.IndexOf(row); + } + intIndex++; + } + + if (intIndex < intSourceCount) + { + for (int i = intIndex; i < intSourceCount; i++) + { + IDataGridViewRow row = (IDataGridViewRow)Activator.CreateInstance(m_rowType); + if (m_dataSource is DataTable) + { + row.DataSource = (m_dataSource as DataTable).Rows[i]; + } + else + { + row.DataSource = (m_dataSource as IList)[i]; + } + row.Columns = m_columns; + List lstCells = new List(); + row.IsShowCheckBox = m_isShowCheckBox; + row.ReloadCells(); + row.BindingCellData(); + + Control rowControl = (row as Control); + rowControl.Width = panHead.Width; + row.RowHeight = m_rowHeight; + row.CellClick += (a, b) => { this.FindForm().ActiveControl = this; rowControl.Focus(); SetSelectRow(rowControl, b); }; + row.CheckBoxChangeEvent += (a, b) => { SetSelectRow(rowControl, b); }; + row.RowCustomEvent += (a, b) => { if (RowCustomEvent != null) { RowCustomEvent(a, b); } }; + row.SourceChanged += RowSourceChanged; + Rows.Add(row); + row.RowIndex = Rows.IndexOf(row); + this.panRow.Controls.Add(rowControl); + + } + } + + //this.panRow.Height = intSourceCount * RowHeight; + } + else + { + foreach (Control item in this.panRow.Controls) + { + item.Visible = false; + } + } + } + finally + { + ControlHelper.FreezeControl(this, false); + } + } + + /// + /// 快捷键 + /// + /// 通过引用传递的 ,它表示要处理的窗口消息。 + /// 值之一,它表示要处理的键。 + /// 如果字符已由控件处理,则为 true;否则为 false。 + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Up) + { + Previous(); + } + else if (keyData == Keys.Down) + { + Next(); + } + else if (keyData == Keys.Home) + { + First(); + } + else if (keyData == Keys.End) + { + End(); + } + return base.ProcessCmdKey(ref msg, keyData); + } + /// + /// 选中第一个 + /// + public void First() + { + if (Rows == null || Rows.Count <= 0) + return; + Control c = null; + c = (Rows[0] as Control); + SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = 0 }); + } + /// + /// 选中上一个 + /// + public void Previous() + { + if (Rows == null || Rows.Count <= 0) + return; + Control c = null; + + int index = Rows.IndexOf(m_selectRow); + if (index - 1 >= 0) + { + c = (Rows[index - 1] as Control); + SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index - 1 }); + } + } + /// + /// 选中下一个 + /// + public void Next() + { + if (Rows == null || Rows.Count <= 0) + return; + Control c = null; + + int index = Rows.IndexOf(m_selectRow); + if (index + 1 < Rows.Count) + { + c = (Rows[index + 1] as Control); + SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index + 1 }); + } + } + /// + /// 选中最后一个 + /// + public void End() + { + if (Rows == null || Rows.Count <= 0) + return; + Control c = null; + c = (Rows[Rows.Count - 1] as Control); + SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = Rows.Count - 1 }); + } + + #endregion + + #region 事件 + /// + /// Rows the source changed. + /// + /// The sender. + /// The instance containing the event data. + void RowSourceChanged(object sender, DataGridViewEventArgs e) + { + if (RowSourceChangedEvent != null) + RowSourceChangedEvent(sender, e); + } + /// + /// Sets the select row. + /// + /// The item. + /// The instance containing the event data. + private void SetSelectRow(Control item, DataGridViewEventArgs e) + { + try + { + ControlHelper.FreezeControl(this, true); + if (item == null) + return; + if (item.Visible == false) + return; + this.FindForm().ActiveControl = this; + this.FindForm().ActiveControl = item; + if (m_selectRow != item) + { + if (m_selectRow != null) + { + m_selectRow.SetSelect(false); + } + m_selectRow = item as IDataGridViewRow; + m_selectRow.SetSelect(true); + + if (this.panRow.Controls.Count > 0) + { + if (item.Location.Y < 0) + { + this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.Controls[this.panRow.Controls.Count - 1].Location.Y) + item.Location.Y); + } + else if (item.Location.Y + m_rowHeight > this.panRow.Height) + { + this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.AutoScrollPosition.Y) + item.Location.Y - this.panRow.Height + m_rowHeight); + } + } + } + + + if (ItemClick != null) + { + ItemClick(item, e); + } + } + finally + { + ControlHelper.FreezeControl(this, false); + } + } + + #endregion + + private void UCDataGridView_SizeChanged(object sender, EventArgs e) + { + //LoadColumns(); + //ReloadSource(); + } + + private void UCDataGridView_Scroll(object sender, ScrollEventArgs e) + { + //if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) + //{ + // panHead.Location = new Point(0, this.VerticalScroll.Value + this.panRow.Location.Y - panHead.Height - 2); + //} + } + + private void panRow_Scroll(object sender, ScrollEventArgs e) + { + if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll && this.panRow.Controls.Count > 0) + { + Console.WriteLine(this.panRow.HorizontalScroll.Value); + Console.WriteLine(this.panRow.Controls[0].Location.X); + panHead.Location = new Point(this.panRow.HorizontalScroll.Value * -1, 0); + } + } + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridView.resx b/JinYuan.ControlLib/DataGridView/UCDataGridView.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridView.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.Designer.cs b/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.Designer.cs new file mode 100644 index 0000000..12646a7 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.Designer.cs @@ -0,0 +1,102 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class UCDataGridViewRow. + /// Implements the + /// + /// + partial class UCDataGridViewRow + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.ucSplitLine_H1 = new JinYuan.ControlLib.UCSplitLine_H(); + this.panCells = new System.Windows.Forms.TableLayoutPanel(); + this.SuspendLayout(); + // + // ucSplitLine_H1 + // + this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232))))); + this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.ucSplitLine_H1.Location = new System.Drawing.Point(0, 55); + this.ucSplitLine_H1.Name = "ucSplitLine_H1"; + this.ucSplitLine_H1.Size = new System.Drawing.Size(661, 1); + this.ucSplitLine_H1.TabIndex = 0; + this.ucSplitLine_H1.TabStop = false; + // + // panCells + // + this.panCells.ColumnCount = 1; + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.panCells.Dock = System.Windows.Forms.DockStyle.Fill; + this.panCells.Location = new System.Drawing.Point(0, 0); + this.panCells.Name = "panCells"; + this.panCells.RowCount = 1; + this.panCells.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.panCells.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.panCells.Size = new System.Drawing.Size(661, 55); + this.panCells.TabIndex = 1; + // + // UCDataGridViewItem + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.White; + this.Controls.Add(this.panCells); + this.Controls.Add(this.ucSplitLine_H1); + this.Name = "UCDataGridViewItem"; + this.Size = new System.Drawing.Size(661, 56); + this.ResumeLayout(false); + + } + + #endregion + + /// + /// The uc split line h1 + /// + private UCSplitLine_H ucSplitLine_H1; + /// + /// The pan cells + /// + private System.Windows.Forms.TableLayoutPanel panCells; + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.cs b/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.cs new file mode 100644 index 0000000..a03fea8 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.cs @@ -0,0 +1,332 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-09-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using JinYuan.ControlLib.UCHelper; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCDataGridViewRow. + /// Implements the + /// Implements the + /// + /// + /// + [ToolboxItem(false)] + public partial class UCDataGridViewRow : UserControl, IDataGridViewRow + { + + #region 属性 + /// + /// CheckBox选中事件 + /// + public event DataGridViewEventHandler CheckBoxChangeEvent; + /// + /// Occurs when [row custom event]. + /// + public event DataGridViewRowCustomEventHandler RowCustomEvent; + /// + /// 点击单元格事件 + /// + public event DataGridViewEventHandler CellClick; + + /// + /// 数据源改变事件 + /// + public event DataGridViewEventHandler SourceChanged; + + /// + /// 列参数,用于创建列数和宽度 + /// + /// The columns. + public List Columns + { + get; + set; + } + + /// + /// 数据源 + /// + /// The data source. + public object DataSource + { + get; + set; + } + + /// + /// 行号 + /// + /// The Index of the row. + public int RowIndex { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is show CheckBox. + /// + /// true if this instance is show CheckBox; otherwise, false. + public bool IsShowCheckBox + { + get; + set; + } + /// + /// The m is checked + /// + private bool m_isChecked; + /// + /// 是否选中 + /// + /// true if this instance is checked; otherwise, false. + public bool IsChecked + { + get + { + return m_isChecked; + } + + set + { + if (m_isChecked != value) + { + m_isChecked = value; + (this.panCells.Controls.Find("check", false)[0] as UCCheckBox).Checked = value; + } + } + } + /// + /// The m row height + /// + int m_rowHeight = 40; + /// + /// 行高 + /// + /// The height of the row. + public int RowHeight + { + get + { + return m_rowHeight; + } + set + { + m_rowHeight = value; + this.Height = value; + } + } + + #endregion + + /// + /// Initializes a new instance of the class. + /// + public UCDataGridViewRow() + { + InitializeComponent(); + } + + /// + /// 绑定数据到Cell + /// + /// 返回true则表示已处理过,否则将进行默认绑定(通常只针对有Text值的控件) + public void BindingCellData() + { + if (DataSource != null) + { + for (int i = 0; i < Columns.Count; i++) + { + DataGridViewColumnEntity com = Columns[i]; + var cs = this.panCells.Controls.Find("lbl_" + com.DataField, false); + if (cs != null && cs.Length > 0) + { + if (DataSource is DataRow) + { + DataRow row = DataSource as DataRow; + if (com.Format != null) + { + cs[0].Text = com.Format(row[com.DataField]); + } + else + { + cs[0].Text = row[com.DataField].ToStringExt(); + } + } + else + { + var pro = DataSource.GetType().GetProperty(com.DataField); + + if (pro != null) + { + var value = pro.GetValue(DataSource, null); + if (com.Format != null) + { + cs[0].Text = com.Format(value); + } + else + { + cs[0].Text = value.ToStringExt(); + } + } + } + } + } + } + foreach (Control item in this.panCells.Controls) + { + if (item is IDataGridViewCustomCell) + { + IDataGridViewCustomCell cell = item as IDataGridViewCustomCell; + cell.RowCustomEvent += cell_RowCustomEvent; + cell.SetBindSource(DataSource); + } + } + } + + void cell_RowCustomEvent(object sender, DataGridViewRowCustomEventArgs e) + { + if (RowCustomEvent != null) + { + RowCustomEvent(sender, e); + } + } + + /// + /// Handles the MouseDown event of the Item control. + /// + /// The source of the event. + /// The instance containing the event data. + void Item_MouseDown(object sender, MouseEventArgs e) + { + if (CellClick != null) + { + CellClick(this, new DataGridViewEventArgs() + { + CellControl = this, + CellIndex = (sender as Control).Tag.ToInt(), + RowIndex = this.RowIndex + }); + } + } + + /// + /// 设置选中状态,通常为设置颜色即可 + /// + /// 是否选中 + public void SetSelect(bool blnSelected) + { + if (blnSelected) + { + this.BackColor = Color.FromArgb(255, 247, 245); + } + else + { + this.BackColor = Color.Transparent; + } + } + + /// + /// Reloads the cells. + /// + public void ReloadCells() + { + try + { + ControlHelper.FreezeControl(this, true); + this.panCells.Controls.Clear(); + this.panCells.ColumnStyles.Clear(); + + int intColumnsCount = Columns.Count(); + if (Columns != null && intColumnsCount > 0) + { + if (IsShowCheckBox) + { + intColumnsCount++; + } + this.panCells.ColumnCount = intColumnsCount; + for (int i = 0; i < intColumnsCount; i++) + { + Control c = null; + if (i == 0 && IsShowCheckBox) + { + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F)); + + UCCheckBox box = new UCCheckBox(); + box.Name = "check"; + box.TextValue = ""; + box.Size = new Size(30, 30); + box.Dock = DockStyle.Fill; + box.CheckedChangeEvent += (a, b) => + { + IsChecked = box.Checked; + if (CheckBoxChangeEvent != null) + { + CheckBoxChangeEvent(a, new DataGridViewEventArgs() + { + RowIndex = this.RowIndex, + CellControl = box, + CellIndex = 0 + }); + } + }; + c = box; + } + else + { + var item = Columns[i - (IsShowCheckBox ? 1 : 0)]; + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, item.Width)); + + if (item.CustomCellType == null) + { + Label lbl = new Label(); + lbl.Tag = i - (IsShowCheckBox ? 1 : 0); + lbl.Name = "lbl_" + item.DataField; + lbl.Font = new Font("微软雅黑", 12); + lbl.ForeColor = Color.Black; + lbl.AutoSize = false; + lbl.Dock = DockStyle.Fill; + lbl.TextAlign = item.TextAlign; + lbl.MouseDown += (a, b) => + { + Item_MouseDown(a, b); + }; + c = lbl; + } + else + { + Control cc = (Control)Activator.CreateInstance(item.CustomCellType); + cc.Dock = DockStyle.Fill; + c = cc; + } + } + this.panCells.Controls.Add(c, i, 0); + } + + } + } + finally + { + ControlHelper.FreezeControl(this, false); + } + } + + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.resx b/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridViewRow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.Designer.cs b/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.Designer.cs new file mode 100644 index 0000000..68b4c86 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.Designer.cs @@ -0,0 +1,149 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-23-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class UCDataGridViewTreeRow. + /// Implements the + /// + /// + partial class UCDataGridViewTreeRow + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.panCells = new System.Windows.Forms.TableLayoutPanel(); + this.panLeft = new System.Windows.Forms.Panel(); + this.panMain = new System.Windows.Forms.Panel(); + this.ucSplitLine_H1 = new JinYuan.ControlLib.UCSplitLine_H(); + this.ucSplitLine_V1 = new JinYuan.ControlLib.UCSplitLine_V(); + this.panMain.SuspendLayout(); + this.SuspendLayout(); + // + // panCells + // + this.panCells.ColumnCount = 1; + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.panCells.Dock = System.Windows.Forms.DockStyle.Fill; + this.panCells.Location = new System.Drawing.Point(24, 0); + this.panCells.Name = "panCells"; + this.panCells.RowCount = 1; + this.panCells.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.panCells.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 55F)); + this.panCells.Size = new System.Drawing.Size(636, 64); + this.panCells.TabIndex = 2; + // + // panLeft + // + this.panLeft.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.panLeft.Dock = System.Windows.Forms.DockStyle.Left; + this.panLeft.Location = new System.Drawing.Point(0, 0); + this.panLeft.Name = "panLeft"; + this.panLeft.Size = new System.Drawing.Size(24, 64); + this.panLeft.TabIndex = 0; + this.panLeft.Tag = "0"; + this.panLeft.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panLeft_MouseDown); + // + // panMain + // + this.panMain.Controls.Add(this.panCells); + this.panMain.Controls.Add(this.panLeft); + this.panMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.panMain.Location = new System.Drawing.Point(1, 0); + this.panMain.Name = "panMain"; + this.panMain.Size = new System.Drawing.Size(660, 64); + this.panMain.TabIndex = 0; + // + // ucSplitLine_H1 + // + this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232))))); + this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.ucSplitLine_H1.Location = new System.Drawing.Point(1, 64); + this.ucSplitLine_H1.Name = "ucSplitLine_H1"; + this.ucSplitLine_H1.Size = new System.Drawing.Size(660, 1); + this.ucSplitLine_H1.TabIndex = 1; + this.ucSplitLine_H1.TabStop = false; + // + // ucSplitLine_V1 + // + this.ucSplitLine_V1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232))))); + this.ucSplitLine_V1.Dock = System.Windows.Forms.DockStyle.Left; + this.ucSplitLine_V1.Location = new System.Drawing.Point(0, 0); + this.ucSplitLine_V1.Name = "ucSplitLine_V1"; + this.ucSplitLine_V1.Size = new System.Drawing.Size(1, 65); + this.ucSplitLine_V1.TabIndex = 0; + this.ucSplitLine_V1.TabStop = false; + this.ucSplitLine_V1.Visible = false; + // + // UCDataGridViewTreeRow + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.White; + this.Controls.Add(this.panMain); + this.Controls.Add(this.ucSplitLine_H1); + this.Controls.Add(this.ucSplitLine_V1); + this.Name = "UCDataGridViewTreeRow"; + this.Size = new System.Drawing.Size(661, 65); + this.panMain.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + /// + /// The pan cells + /// + private System.Windows.Forms.TableLayoutPanel panCells; + /// + /// The uc split line h1 + /// + private UCSplitLine_H ucSplitLine_H1; + /// + /// The pan left + /// + private System.Windows.Forms.Panel panLeft; + /// + /// The pan main + /// + private System.Windows.Forms.Panel panMain; + private UCSplitLine_V ucSplitLine_V1; + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.cs b/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.cs new file mode 100644 index 0000000..8b77ef1 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.cs @@ -0,0 +1,475 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-23-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using JinYuan.ControlLib.UCHelper; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCDataGridViewTreeRow. + /// Implements the + /// Implements the + /// + /// + /// + [ToolboxItem(false)] + public partial class UCDataGridViewTreeRow : UserControl, IDataGridViewRow + { + #region 属性 + /// + /// CheckBox选中事件 + /// + public event DataGridViewEventHandler CheckBoxChangeEvent; + + /// + /// 点击单元格事件 + /// + public event DataGridViewEventHandler CellClick; + + /// + /// 数据源改变事件 + /// + public event DataGridViewEventHandler SourceChanged; + /// + /// Occurs when [row custom event]. + /// + public event DataGridViewRowCustomEventHandler RowCustomEvent; + /// + /// 列参数,用于创建列数和宽度 + /// + /// The columns. + public List Columns + { + get; + set; + } + + /// + /// 数据源 + /// + /// The data source. + public object DataSource + { + get; + set; + } + + private int rowLevel = 0; + /// + /// 折叠的第几层,用于缩进 + /// + public int RowLevel + { + get { return rowLevel; } + set + { + rowLevel = value; + this.Padding = new Padding(this.panLeft.Width / 2 * value, this.Padding.Top, this.panLeft.Right, this.Padding.Bottom); + this.ucSplitLine_V1.Visible = value > 0; + } + } + + /// + /// 行号,树状图目前没有给予行号 + /// + /// The Index of the row. + public int RowIndex { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is show CheckBox. + /// + /// true if this instance is show CheckBox; otherwise, false. + public bool IsShowCheckBox + { + get; + set; + } + /// + /// The m is checked + /// + private bool m_isChecked; + /// + /// 是否选中 + /// + /// true if this instance is checked; otherwise, false. + public bool IsChecked + { + get + { + return m_isChecked; + } + + set + { + if (m_isChecked != value) + { + m_isChecked = value; + (this.panCells.Controls.Find("check", false)[0] as UCCheckBox).Checked = value; + } + } + } + + /// + /// The m row height + /// + int m_rowHeight = 40; + /// + /// 行高 + /// + /// The height of the row. + public int RowHeight + { + get + { + return m_rowHeight; + } + set + { + m_rowHeight = value; + this.Height = value; + } + } + private List childrenRows = new List(); + + public List ChildrenRows + { + get { return childrenRows; } + set { childrenRows = value; } + } + private bool? isOpened = false; + /// + /// 是否打开状态 + /// + public bool? IsOpened + { + get { return isOpened; } + set + { + isOpened = value; + if (value.HasValue) + { + panLeft.Enabled = true; + if (value.Value) + { + panLeft.BackgroundImage = Properties.Resources.caret_down; + } + else + { + panLeft.BackgroundImage = Properties.Resources.caret_right; + } + } + else + { + panLeft.BackgroundImage = null; + panLeft.Enabled = false; + } + } + } + #endregion + + /// + /// Initializes a new instance of the class. + /// + public UCDataGridViewTreeRow() + { + InitializeComponent(); + } + + /// + /// 绑定数据到Cell + /// + public void BindingCellData() + { + for (int i = 0; i < Columns.Count; i++) + { + DataGridViewColumnEntity com = Columns[i]; + var cs = this.panCells.Controls.Find("lbl_" + com.DataField, false); + if (cs != null && cs.Length > 0) + { + var pro = DataSource.GetType().GetProperty(com.DataField); + if (pro != null) + { + var value = pro.GetValue(DataSource, null); + if (com.Format != null) + { + cs[0].Text = com.Format(value); + } + else + { + cs[0].Text = value.ToStringExt(); + } + } + } + } + foreach (Control item in this.panCells.Controls) + { + if (item is IDataGridViewCustomCell) + { + IDataGridViewCustomCell cell = item as IDataGridViewCustomCell; + cell.RowCustomEvent += cell_RowCustomEvent; + cell.SetBindSource(DataSource); + } + } + IsOpened = false; + var proChildrens = DataSource.GetType().GetProperty("Childrens"); + if (proChildrens != null) + { + var value = proChildrens.GetValue(DataSource, null); + if (value != null) + { + } + else + { + IsOpened = null; + } + } + else + { + IsOpened = null; + } + } + + void cell_RowCustomEvent(object sender, DataGridViewRowCustomEventArgs e) + { + if (RowCustomEvent != null) + RowCustomEvent(sender, e); + } + + /// + /// Handles the MouseDown event of the Item control. + /// + /// The source of the event. + /// The instance containing the event data. + void Item_MouseDown(object sender, MouseEventArgs e) + { + if (CellClick != null) + { + CellClick(this, new DataGridViewEventArgs() + { + CellControl = this, + CellIndex = (sender as Control).Tag.ToInt() + }); + } + } + + /// + /// 设置选中状态,通常为设置颜色即可 + /// + /// 是否选中 + public void SetSelect(bool blnSelected) + { + if (blnSelected) + { + this.panMain.BackColor = Color.FromArgb(255, 247, 245); + } + else + { + this.panMain.BackColor = Color.Transparent; + } + } + + /// + /// 添加单元格元素,仅做添加控件操作,不做数据绑定,数据绑定使用BindingCells + /// + public void ReloadCells() + { + try + { + ControlHelper.FreezeControl(this, true); + this.panCells.Controls.Clear(); + this.panCells.ColumnStyles.Clear(); + + int intColumnsCount = Columns.Count(); + if (Columns != null && intColumnsCount > 0) + { + if (IsShowCheckBox) + { + intColumnsCount++; + } + this.panCells.ColumnCount = intColumnsCount; + bool blnFirst = true; + for (int i = 0; i < intColumnsCount; i++) + { + Control c = null; + if (i == 0 && IsShowCheckBox) + { + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F)); + + UCCheckBox box = new UCCheckBox(); + box.Name = "check"; + box.TextValue = ""; + box.Size = new Size(30, 30); + box.Dock = DockStyle.Fill; + box.CheckedChangeEvent += box_CheckedChangeEvent; + c = box; + } + else + { + var item = Columns[i - (IsShowCheckBox ? 1 : 0)]; + var w = item.Width - (blnFirst ? (this.panLeft.Width / 2 * rowLevel) : 0); + if (w < 5) + w = 5; + this.panCells.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, w)); + blnFirst = false; + if (item.CustomCellType == null) + { + Label lbl = new Label(); + lbl.Tag = i - (IsShowCheckBox ? 1 : 0); + lbl.Name = "lbl_" + item.DataField; + lbl.Font = new Font("微软雅黑", 12); + lbl.ForeColor = Color.Black; + lbl.AutoSize = false; + lbl.Dock = DockStyle.Fill; + lbl.TextAlign = item.TextAlign; + lbl.MouseDown += (a, b) => + { + Item_MouseDown(a, b); + }; + c = lbl; + } + else + { + Control cc = (Control)Activator.CreateInstance(item.CustomCellType); + cc.Dock = DockStyle.Fill; + c = cc; + } + } + this.panCells.Controls.Add(c, i, 0); + } + + } + } + finally + { + ControlHelper.FreezeControl(this, false); + } + } + + void box_CheckedChangeEvent(object sender, EventArgs e) + { + IsChecked = ((UCCheckBox)sender).Checked; + } + + + + /// + /// Handles the MouseDown event of the panLeft control. + /// + /// The source of the event. + /// The instance containing the event data. + private void panLeft_MouseDown(object sender, MouseEventArgs e) + { + try + { + if (!IsOpened.HasValue) + return; + ControlHelper.FreezeControl(this.FindForm(), true); + if (!IsOpened.Value) + { + + IsOpened = !IsOpened; + if (childrenRows.Count > 0) + { + childrenRows.ForEach(p => + { + p.IsChecked = IsChecked; + p.Visible = true; + }); + } + else + { + var proChildrens = DataSource.GetType().GetProperty("Childrens"); + if (proChildrens != null) + { + var value = proChildrens.GetValue(DataSource, null); + int intSourceCount = 0; + if (value is DataTable) + { + intSourceCount = (value as DataTable).Rows.Count; + } + else if (typeof(IList).IsAssignableFrom(value.GetType())) + { + intSourceCount = (value as IList).Count; + } + for (int i = intSourceCount - 1; i >= 0; i--) + { + UCDataGridViewTreeRow row = new UCDataGridViewTreeRow(); + if (value is DataTable) + { + row.DataSource = (value as DataTable).Rows[i]; + } + else + { + row.DataSource = (value as IList)[i]; + } + row.RowLevel = RowLevel + 1; + row.Columns = Columns; + row.IsShowCheckBox = IsShowCheckBox; + row.ReloadCells(); + row.BindingCellData(); + + Control rowControl = (row as Control); + row.RowHeight = m_rowHeight; + rowControl.Width = this.Width; + //rowControl.Dock = DockStyle.Top; + row.CellClick += (a, b) => { CellClick(rowControl, b); }; + row.CheckBoxChangeEvent += (a, b) => { CheckBoxChangeEvent(rowControl, b); }; + row.RowCustomEvent += (a, b) => { if (RowCustomEvent != null) { RowCustomEvent(a, b); } }; + row.SourceChanged += SourceChanged; + ChildrenRows.Add(row); + row.RowIndex = ChildrenRows.IndexOf(row); + + this.Parent.Controls.Add(rowControl); + var index = this.Parent.Controls.GetChildIndex(this); + this.Parent.Controls.SetChildIndex(row, index + 1); + + } + } + } + } + else + { + HideChildrenRows(this); + this.Height = m_rowHeight; + } + } + finally + { + ControlHelper.FreezeControl(this.FindForm(), false); + } + } + + private void HideChildrenRows(UCDataGridViewTreeRow row) + { + if (row.ChildrenRows.Count > 0) + { + foreach (var item in row.ChildrenRows) + { + HideChildrenRows(item); + item.Hide(); + } + row.IsOpened = false; + } + } + } +} diff --git a/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.resx b/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/DataGridView/UCDataGridViewTreeRow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/DialPlate.Designer.cs b/JinYuan.ControlLib/DialPlate.Designer.cs new file mode 100644 index 0000000..7ba3d27 --- /dev/null +++ b/JinYuan.ControlLib/DialPlate.Designer.cs @@ -0,0 +1,48 @@ +namespace JinYuan.ControlLib +{ + partial class DialPlate + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // DialPlate + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(28)))), ((int)(((byte)(68))))); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "DialPlate"; + this.Size = new System.Drawing.Size(329, 202); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/DialPlate.cs b/JinYuan.ControlLib/DialPlate.cs new file mode 100644 index 0000000..21bff0c --- /dev/null +++ b/JinYuan.ControlLib/DialPlate.cs @@ -0,0 +1,341 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class DialPlate : UserControl + { + public DialPlate() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + stringFormat.Alignment = StringAlignment.Center; + stringFormat.LineAlignment = StringAlignment.Center; + } + + private StringFormat stringFormat = new StringFormat(); + + #region 外环设计 + private Color alarmColor = Color.FromArgb(36, 184, 196); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取报警颜色")] + public Color AlarmColor + { + get { return alarmColor; } + set + { + alarmColor = value; + this.Invalidate(); + } + } + + private Color rightColor = Color.FromArgb(187, 187, 187); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取圆环整体颜色")] + public Color RightColor + { + get { return rightColor; } + set + { + rightColor = value; + this.Invalidate(); + } + } + + + private float alarmAngle = 120.0f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取报警角度")] + public float AlarmAngle + { + get { return alarmAngle; } + set + { + alarmAngle = value; + this.Invalidate(); + } + } + + private int outThickness = 8; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取外环宽度")] + public int OutThickness + { + get { return outThickness; } + set + { + outThickness = value; + this.Invalidate(); + } + } + #endregion + + #region 内环设计 + private float tempScale = 0.8f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取温度环比列,默认小于1.0f")] + public float TempScale + { + get { return tempScale; } + set + { + if (value > 1.0f) return; + tempScale = value; + this.Invalidate(); + } + } + + private Color tempColor = Color.FromArgb(36, 184, 196); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取温度环颜色")] + public Color TempColor + { + get { return tempColor; } + set + { + tempColor = value; + this.Invalidate(); + } + } + + + private float humidityScale = 0.4f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取湿度环比列,默认小于1.0f")] + public float HumidityScale + { + get { return humidityScale; } + set + { + if (value > 1.0f) return; + humidityScale = value; + this.Invalidate(); + } + } + + private Color humidityColor = Color.FromArgb(36, 184, 196); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取湿度环颜色")] + public Color HumidityColor + { + get { return humidityColor; } + set + { + humidityColor = value; + this.Invalidate(); + } + } + + private int inThickness = 16; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取内环宽度")] + public int InThickness + { + get { return inThickness; } + set + { + inThickness = value; + this.Invalidate(); + } + } + #endregion + + #region 刻度环设计 + private float textScale = 0.6f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取刻度环比列,默认小于1.0f")] + public float MyProperty + { + get { return textScale; } + set + { + if (value > 1.0f) return; + textScale = value; + this.Invalidate(); + } + } + + private float rangeMin = 0.0f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取刻度量程低限")] + public float RangeMin + { + get { return rangeMin; } + set + { + if (value > rangeMax) return; + rangeMin = value; + this.Invalidate(); + } + } + + private float rangeMax = 90.0f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取刻度量程高限")] + public float RangeMax + { + get { return rangeMax; } + set + { + if (value < rangeMin) return; + rangeMax = value; + this.Invalidate(); + } + } + + #endregion + + #region 实时显示 + private float temp = 10.0f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取温度实时值")] + public float Temp + { + get { return temp; } + set + { + if (value < rangeMin) + value = rangeMin; + if (value > rangeMax) + value = rangeMax; + temp = value; + this.Invalidate(); + } + } + + private float humidity = 10.0f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取湿度实时值")] + public float Humidity + { + get { return humidity; } + set + { + if (value < rangeMin) + value = rangeMin; + if (value > rangeMax) + value = rangeMax; + humidity = value; + this.Invalidate(); + } + } + #endregion + + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + //获取画布并设置 + Graphics g = e.Graphics; + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + //异常情况处理 + if (this.Width <= 20 || this.Height <= 20) return; + + if (this.Height < this.Width / 2) return; + + //画外环 + Pen pen = new Pen(alarmColor, OutThickness); + + g.DrawArc(pen, new RectangleF(10, 10, this.Width - 20, this.Width - 20), 180, alarmAngle); + + pen = new Pen(rightColor, OutThickness); + + g.DrawArc(pen, new RectangleF(10, 10, this.Width - 20, this.Width - 20), 180 + alarmAngle, 180 - alarmAngle); + + //转移坐标系 + g.TranslateTransform(this.Width * 0.5f, this.Width * 0.5f); + + //旋转坐标系 + g.RotateTransform(-90); + + SolidBrush solidBrush; + for (int i = 0; i < 7; i++) + { + if (30 * i <= alarmAngle) + { + solidBrush = new SolidBrush(alarmColor); + } + else + { + solidBrush = new SolidBrush(rightColor); + } + float x = -0.3f; + float width = 6.0f; + float height = outThickness + 4; + float y = (this.Width * 0.5f - 10 + height * 0.5f) * (-1.0f); + g.FillRectangle(solidBrush, new RectangleF(x, y, width, height)); + + g.RotateTransform(30); + } + + //坐标系旋转回去 + g.RotateTransform(-210); + g.RotateTransform(90); + + ////绘制刻度 + float rangeAvg = ((rangeMax - rangeMin) % 6 == 0) ? Convert.ToSingle((rangeMax - rangeMin) / 6) : Convert.ToSingle(((rangeMax - rangeMin) / 6).ToString("f1")); + + for (int i = 0; i < 7; i++) + { + float angle = -180.0f + i * 30.0f; + + float pointX = Convert.ToSingle(this.Width * textScale * 0.5f * Math.Cos(angle * Math.PI / 180.0f)); + float pointY = Convert.ToSingle(this.Width * textScale * 0.5f * Math.Sin(angle * Math.PI / 180.0f)); + + string text = (rangeMin + rangeAvg * i).ToString(); + + SizeF size = g.MeasureString(text, this.Font); + + RectangleF rectangle = new RectangleF(pointX - size.Width * 0.5f, pointY, size.Width, size.Height); + + g.DrawString(text, this.Font, new SolidBrush(this.ForeColor), rectangle, stringFormat); + } + + ////绘制实际温度湿度环 + //pen = new Pen(tempColor, inThickness); + + //float sweepAngle = (temp - rangeMin) / (rangeMax - rangeMin) * 180.0f; + + //float xx = this.Width * tempScale * 0.5f * (-1.0f); + //float yy = this.Width * tempScale * 0.5f * (-1.0f); + + //g.DrawArc(pen, new RectangleF(xx, yy, this.Width * tempScale, this.Width * tempScale), 180.0f, sweepAngle); + + + //pen = new Pen(humidityColor, inThickness); + + //sweepAngle = (humidity - rangeMin) / (rangeMax - rangeMin) * 180.0f; + + //xx = this.Width * humidityScale * 0.5f * (-1.0f); + //yy = this.Width * humidityScale * 0.5f * (-1.0f); + + //g.DrawArc(pen, new RectangleF(xx, yy, this.Width * humidityScale, this.Width * humidityScale), 180.0f, sweepAngle); + } + } +} diff --git a/JinYuan.ControlLib/DialPlate.resx b/JinYuan.ControlLib/DialPlate.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/DialPlate.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/FanShapedSchedule.Designer.cs b/JinYuan.ControlLib/FanShapedSchedule.Designer.cs new file mode 100644 index 0000000..bbbee55 --- /dev/null +++ b/JinYuan.ControlLib/FanShapedSchedule.Designer.cs @@ -0,0 +1,37 @@ +namespace JinYuan.ControlLib +{ + partial class FanShapedSchedule + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/FanShapedSchedule.cs b/JinYuan.ControlLib/FanShapedSchedule.cs new file mode 100644 index 0000000..842e737 --- /dev/null +++ b/JinYuan.ControlLib/FanShapedSchedule.cs @@ -0,0 +1,88 @@ +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class FanShapedSchedule : UserControl + { + public FanShapedSchedule() + { + InitializeComponent(); + } + + + //最大值 + private float maxValue = 100; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置最大值")] + public float MaxValue + { + get { return maxValue; } + set + { + maxValue = value; + this.Invalidate(); + } + } + + //实际值 + private float actureValue = 60; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置实际值")] + public float ActureValue + { + get { return actureValue; } + set + { + actureValue = value; + this.Invalidate(); + } + } + + //文字显示值 + private float PercentVal = 0; + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + // 获取画布 + Graphics graphics = e.Graphics; + + //消除锯齿 + graphics.SmoothingMode = SmoothingMode.AntiAlias; + //文字显示效果 + graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + //插补模式 + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + //图片呈现质量 + graphics.CompositingQuality = CompositingQuality.HighQuality; + + + // 绘制底圆 + SolidBrush brush1 = new SolidBrush(Color.FromArgb(93, 107, 153)); + Rectangle rectangle1 = new Rectangle(1, 1, this.Width - 2, this.Height - 2); + graphics.FillEllipse(brush1, rectangle1); + + //绘制扇形 + Rectangle rectangle2 = new Rectangle(1, 1, this.Width - 2, this.Height - 2); + LinearGradientBrush brush2 = new LinearGradientBrush(rectangle2, Color.Blue, Color.Red, 150.0f, true); + this.PercentVal = (ActureValue / MaxValue) * 100; + graphics.FillPie(brush2, rectangle2, -90, (ActureValue / MaxValue) * 360f); + + //绘制上圆 + SolidBrush solidBrushElipse = new SolidBrush(this.BackColor); + Rectangle rectangle3 = new Rectangle(15, 15, this.Width - 30, this.Height - 30); + graphics.FillEllipse(solidBrushElipse, rectangle3); + + //绘制文字 + Font font = new Font("微软雅黑", 15); + PointF point = new PointF(((float)this.Width) / 2.0f - 27, ((float)this.Height) / 2.0f - 10); + graphics.DrawString(this.PercentVal.ToString("0.0") + "%", font, Brushes.Coral, point); + } + } +} diff --git a/JinYuan.ControlLib/FlatComboBox.Designer.cs b/JinYuan.ControlLib/FlatComboBox.Designer.cs new file mode 100644 index 0000000..8fad653 --- /dev/null +++ b/JinYuan.ControlLib/FlatComboBox.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class FlatComboBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/FlatComboBox.cs b/JinYuan.ControlLib/FlatComboBox.cs new file mode 100644 index 0000000..7611b1d --- /dev/null +++ b/JinYuan.ControlLib/FlatComboBox.cs @@ -0,0 +1,171 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class FlatComboBox : ComboBox + { + private Color borderColor = Color.Gray; + [DefaultValue(typeof(Color), "Gray")] + public Color BorderColor + { + get { return borderColor; } + set + { + if (borderColor != value) + { + borderColor = value; + Invalidate(); + } + } + } + private Color buttonColor = Color.LightGray; + [DefaultValue(typeof(Color), "LightGray")] + public Color ButtonColor + { + get { return buttonColor; } + set + { + if (buttonColor != value) + { + buttonColor = value; + Invalidate(); + } + } + } + protected override void WndProc(ref Message m) + { + if (m.Msg == WM_PAINT && DropDownStyle != ComboBoxStyle.Simple) + { + var clientRect = ClientRectangle; + var dropDownButtonWidth = SystemInformation.HorizontalScrollBarArrowWidth; + var outerBorder = new Rectangle(clientRect.Location, + new Size(clientRect.Width - 1, clientRect.Height - 1)); + var innerBorder = new Rectangle(outerBorder.X + 1, outerBorder.Y + 1, + outerBorder.Width - dropDownButtonWidth - 2, outerBorder.Height - 2); + var innerInnerBorder = new Rectangle(innerBorder.X + 1, innerBorder.Y + 1, + innerBorder.Width - 2, innerBorder.Height - 2); + var dropDownRect = new Rectangle(innerBorder.Right + 1, innerBorder.Y, + dropDownButtonWidth, innerBorder.Height + 1); + if (RightToLeft == RightToLeft.Yes) + { + innerBorder.X = clientRect.Width - innerBorder.Right; + innerInnerBorder.X = clientRect.Width - innerInnerBorder.Right; + dropDownRect.X = clientRect.Width - dropDownRect.Right; + dropDownRect.Width += 1; + } + var innerBorderColor = Enabled ? BackColor : SystemColors.Control; + var outerBorderColor = Enabled ? BorderColor : SystemColors.ControlDark; + var buttonColor = Enabled ? ButtonColor : SystemColors.Control; + var middle = new Point(dropDownRect.Left + dropDownRect.Width / 2, + dropDownRect.Top + dropDownRect.Height / 2); + var arrow = new Point[] + { + new Point(middle.X - 3, middle.Y - 2), + new Point(middle.X + 4, middle.Y - 2), + new Point(middle.X, middle.Y + 2) + }; + var ps = new PAINTSTRUCT(); + bool shoulEndPaint = false; + IntPtr dc; + if (m.WParam == IntPtr.Zero) + { + dc = BeginPaint(Handle, ref ps); + m.WParam = dc; + shoulEndPaint = true; + } + else + { + dc = m.WParam; + } + var rgn = CreateRectRgn(innerInnerBorder.Left, innerInnerBorder.Top, + innerInnerBorder.Right, innerInnerBorder.Bottom); + SelectClipRgn(dc, rgn); + DefWndProc(ref m); + DeleteObject(rgn); + rgn = CreateRectRgn(clientRect.Left, clientRect.Top, + clientRect.Right, clientRect.Bottom); + SelectClipRgn(dc, rgn); + using (var g = Graphics.FromHdc(dc)) + { + using (var b = new SolidBrush(buttonColor)) + { + g.FillRectangle(b, dropDownRect); + } + using (var b = new SolidBrush(outerBorderColor)) + { + g.FillPolygon(b, arrow); + } + using (var p = new Pen(innerBorderColor)) + { + g.DrawRectangle(p, innerBorder); + g.DrawRectangle(p, innerInnerBorder); + } + using (var p = new Pen(outerBorderColor)) + { + g.DrawRectangle(p, outerBorder); + } + } + if (shoulEndPaint) + EndPaint(Handle, ref ps); + DeleteObject(rgn); + } + else + base.WndProc(ref m); + } + + private const int WM_PAINT = 0xF; + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int L, T, R, B; + } + [StructLayout(LayoutKind.Sequential)] + public struct PAINTSTRUCT + { + public IntPtr hdc; + public bool fErase; + public int rcPaint_left; + public int rcPaint_top; + public int rcPaint_right; + public int rcPaint_bottom; + public bool fRestore; + public bool fIncUpdate; + public int reserved1; + public int reserved2; + public int reserved3; + public int reserved4; + public int reserved5; + public int reserved6; + public int reserved7; + public int reserved8; + } + [DllImport("user32.dll")] + private static extern IntPtr BeginPaint(IntPtr hWnd, + [In, Out] ref PAINTSTRUCT lpPaint); + + [DllImport("user32.dll")] + private static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint); + + [DllImport("gdi32.dll")] + public static extern int SelectClipRgn(IntPtr hDC, IntPtr hRgn); + + [DllImport("user32.dll")] + public static extern int GetUpdateRgn(IntPtr hwnd, IntPtr hrgn, bool fErase); + public enum RegionFlags + { + ERROR = 0, + NULLREGION = 1, + SIMPLEREGION = 2, + COMPLEXREGION = 3, + } + [DllImport("gdi32.dll")] + internal static extern bool DeleteObject(IntPtr hObject); + + [DllImport("gdi32.dll")] + private static extern IntPtr CreateRectRgn(int x1, int y1, int x2, int y2); + } +} diff --git a/JinYuan.ControlLib/Forms/FrmBase.Designer.cs b/JinYuan.ControlLib/Forms/FrmBase.Designer.cs new file mode 100644 index 0000000..dca7834 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmBase.Designer.cs @@ -0,0 +1,74 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib.Forms +{ + /// + /// Class FrmBase. + /// Implements the + /// + /// + partial class FrmBase + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmBase)); + this.SuspendLayout(); + // + // FrmBase + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(247)))), ((int)(((byte)(247)))), ((int)(((byte)(247))))); + this.ClientSize = new System.Drawing.Size(331, 371); + this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(66)))), ((int)(((byte)(66)))), ((int)(((byte)(66))))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Name = "FrmBase"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "FrmBase"; + this.Load += new System.EventHandler(this.FrmBase_Load); + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/Forms/FrmBase.cs b/JinYuan.ControlLib/Forms/FrmBase.cs new file mode 100644 index 0000000..5a23190 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmBase.cs @@ -0,0 +1,622 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using JinYuan.ControlLib.UCHelper; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.Forms +{ + /// + /// Class FrmBase. + /// Implements the + /// + /// + [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(System.ComponentModel.Design.IDesigner))] + public partial class FrmBase : Form + { + /// + /// Gets or sets the hot keys. + /// + /// The hot keys. + [Description("定义的热键列表"), Category("自定义")] + public Dictionary HotKeys { get; set; } + /// + /// Delegate HotKeyEventHandler + /// + /// The string hot key. + /// true if XXXX, false otherwise. + public delegate bool HotKeyEventHandler(string strHotKey); + /// + /// 热键事件 + /// + [Description("热键事件"), Category("自定义")] + public event HotKeyEventHandler HotKeyDown; + #region 字段属性 + + /// + /// 失去焦点关闭 + /// + bool _isLoseFocusClose = false; + /// + /// 是否重绘边框样式 + /// + private bool _redraw = false; + /// + /// 是否显示圆角 + /// + private bool _isShowRegion = false; + /// + /// 边圆角大小 + /// + private int _regionRadius = 10; + /// + /// 边框颜色 + /// + private Color _borderStyleColor; + /// + /// 边框宽度 + /// + private int _borderStyleSize; + /// + /// 边框样式 + /// + private ButtonBorderStyle _borderStyleType; + /// + /// 是否显示模态 + /// + private bool _isShowMaskDialog = false; + /// + /// 蒙版窗体 + /// + /// true if this instance is show mask dialog; otherwise, false. + [Description("是否显示蒙版窗体")] + public bool IsShowMaskDialog + { + get + { + return this._isShowMaskDialog; + } + set + { + this._isShowMaskDialog = value; + } + } + /// + /// 边框宽度 + /// + /// The size of the border style. + [Description("边框宽度")] + public int BorderStyleSize + { + get + { + return this._borderStyleSize; + } + set + { + this._borderStyleSize = value; + } + } + /// + /// 边框颜色 + /// + /// The color of the border style. + [Description("边框颜色")] + public Color BorderStyleColor + { + get + { + return this._borderStyleColor; + } + set + { + this._borderStyleColor = value; + } + } + /// + /// 边框样式 + /// + /// The type of the border style. + [Description("边框样式")] + public ButtonBorderStyle BorderStyleType + { + get + { + return this._borderStyleType; + } + set + { + this._borderStyleType = value; + } + } + /// + /// 边框圆角 + /// + /// The region radius. + [Description("边框圆角")] + public int RegionRadius + { + get + { + return this._regionRadius; + } + set + { + this._regionRadius = Math.Max(value, 1); + } + } + /// + /// 是否显示自定义绘制内容 + /// + /// true if this instance is show region; otherwise, false. + [Description("是否显示自定义绘制内容")] + public bool IsShowRegion + { + get + { + return this._isShowRegion; + } + set + { + this._isShowRegion = value; + } + } + /// + /// 是否显示重绘边框 + /// + /// true if redraw; otherwise, false. + [Description("是否显示重绘边框")] + public bool Redraw + { + get + { + return this._redraw; + } + set + { + this._redraw = value; + } + } + + /// + /// The is full size + /// + private bool _isFullSize = true; + /// + /// 是否全屏 + /// + /// true if this instance is full size; otherwise, false. + [Description("是否全屏")] + public virtual bool IsFullSize + { + get { return _isFullSize; } + set { _isFullSize = value; } + } + /// + /// 失去焦点自动关闭 + /// + /// true if this instance is lose focus close; otherwise, false. + [Description("失去焦点自动关闭")] + public bool IsLoseFocusClose + { + get + { + return this._isLoseFocusClose; + } + set + { + this._isLoseFocusClose = value; + } + } + #endregion + + /// + /// Gets a value indicating whether this instance is desing mode. + /// + /// true if this instance is desing mode; otherwise, false. + private bool IsDesingMode + { + get + { + bool ReturnFlag = false; + if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) + ReturnFlag = true; + else if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv") + ReturnFlag = true; + return ReturnFlag; + } + } + + #region 初始化 + /// + /// Initializes a new instance of the class. + /// + public FrmBase() + { + InitializeComponent(); + base.SetStyle(ControlStyles.UserPaint, true); + base.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + base.SetStyle(ControlStyles.DoubleBuffer, true); + //base.HandleCreated += new EventHandler(this.FrmBase_HandleCreated); + //base.HandleDestroyed += new EventHandler(this.FrmBase_HandleDestroyed); + this.KeyDown += FrmBase_KeyDown; + this.FormClosing += FrmBase_FormClosing; + } + + /// + /// Handles the FormClosing event of the FrmBase control. + /// + /// The source of the event. + /// The instance containing the event data. + void FrmBase_FormClosing(object sender, FormClosingEventArgs e) + { + if (_isLoseFocusClose) + { + MouseHook.OnMouseActivity -= hook_OnMouseActivity; + } + } + + + /// + /// Handles the Load event of the FrmBase control. + /// + /// The source of the event. + /// The instance containing the event data. + private void FrmBase_Load(object sender, EventArgs e) + { + if (!IsDesingMode) + { + if (_isFullSize) + SetFullSize(); + } + if (_isLoseFocusClose) + { + MouseHook.OnMouseActivity += hook_OnMouseActivity; + } + } + + #endregion + + #region 方法区 + + + /// + /// Handles the OnMouseActivity event of the hook control. + /// + /// The source of the event. + /// The instance containing the event data. + void hook_OnMouseActivity(object sender, MouseEventArgs e) + { + try + { + if (this._isLoseFocusClose && e.Clicks > 0) + { + if (e.Button == System.Windows.Forms.MouseButtons.Left || e.Button == System.Windows.Forms.MouseButtons.Right) + { + if (!this.IsDisposed) + { + if (!this.ClientRectangle.Contains(this.PointToClient(e.Location))) + { + base.Close(); + } + } + } + } + } + catch { } + } + + + /// + /// 全屏 + /// + public void SetFullSize() + { + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + } + /// + /// Does the escape. + /// + protected virtual void DoEsc() + { + base.Close(); + } + + /// + /// Does the enter. + /// + protected virtual void DoEnter() + { + } + + /// + /// 设置重绘区域 + /// + public void SetWindowRegion() + { + GraphicsPath path = new GraphicsPath(); + Rectangle rect = new Rectangle(-1, -1, base.Width + 1, base.Height); + path = this.GetRoundedRectPath(rect, this._regionRadius); + base.Region = new Region(path); + } + /// + /// 获取重绘区域 + /// + /// The rect. + /// The radius. + /// GraphicsPath. + private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius) + { + Rectangle rect2 = new Rectangle(rect.Location, new Size(radius, radius)); + GraphicsPath graphicsPath = new GraphicsPath(); + graphicsPath.AddArc(rect2, 180f, 90f); + rect2.X = rect.Right - radius; + graphicsPath.AddArc(rect2, 270f, 90f); + rect2.Y = rect.Bottom - radius; + rect2.Width += 1; + rect2.Height += 1; + graphicsPath.AddArc(rect2, 360f, 90f); + rect2.X = rect.Left; + graphicsPath.AddArc(rect2, 90f, 90f); + graphicsPath.CloseFigure(); + return graphicsPath; + } + + /// + /// 将窗体显示为具有指定所有者的模式对话框。 + /// + /// 任何实现 (表示将拥有模式对话框的顶级窗口)的对象。 + /// 值之一。 + /// + /// + /// + /// + /// + /// + /// + public new DialogResult ShowDialog(IWin32Window owner) + { + try + { + if (this._isShowMaskDialog && owner != null) + { + var frmOwner = (Control)owner; + FrmTransparent _frmTransparent = new FrmTransparent(); + _frmTransparent.Width = frmOwner.Width; + _frmTransparent.Height = frmOwner.Height; + Point location = frmOwner.PointToScreen(new Point(0, 0)); + _frmTransparent.Location = location; + _frmTransparent.frmchild = this; + _frmTransparent.IsShowMaskDialog = false; + return _frmTransparent.ShowDialog(owner); + } + else + { + return base.ShowDialog(owner); + } + } + catch (NullReferenceException) + { + return System.Windows.Forms.DialogResult.None; + } + } + + /// + /// 将窗体显示为模式对话框,并将当前活动窗口设置为它的所有者。 + /// + /// 值之一。 + /// + /// + /// + /// + /// + /// + /// + public new DialogResult ShowDialog() + { + return base.ShowDialog(); + } + #endregion + + #region 事件区 + + + /// + /// 关闭时发生 + /// + /// 一个包含事件数据的 。 + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + if (base.Owner != null && base.Owner is FrmTransparent) + { + (base.Owner as FrmTransparent).Close(); + } + } + + /// + /// 快捷键 + /// + /// 通过引用传递的 ,它表示要处理的 Win32 消息。 + /// 值之一,它表示要处理的键。 + /// 如果控件处理并使用击键,则为 true;否则为 false,以允许进一步处理。 + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + int num = 256; + int num2 = 260; + bool result; + if (msg.Msg == num | msg.Msg == num2) + { + if (keyData == (Keys)262259) + { + result = true; + return result; + } + if (keyData != Keys.Enter) + { + if (keyData == Keys.Escape) + { + this.DoEsc(); + } + } + else + { + this.DoEnter(); + } + } + result = false; + if (result) + return result; + else + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Handles the KeyDown event of the FrmBase control. + /// + /// The source of the event. + /// The instance containing the event data. + protected void FrmBase_KeyDown(object sender, KeyEventArgs e) + { + if (HotKeyDown != null && HotKeys != null) + { + bool blnCtrl = false; + bool blnAlt = false; + bool blnShift = false; + if (e.Control) + blnCtrl = true; + if (e.Alt) + blnAlt = true; + if (e.Shift) + blnShift = true; + if (HotKeys.ContainsKey(e.KeyValue)) + { + string strKey = string.Empty; + if (blnCtrl) + { + strKey += "Ctrl+"; + } + if (blnAlt) + { + strKey += "Alt+"; + } + if (blnShift) + { + strKey += "Shift+"; + } + strKey += HotKeys[e.KeyValue]; + + if (HotKeyDown(strKey)) + { + e.Handled = true; + e.SuppressKeyPress = true; + } + } + } + } + + /// + /// 重绘事件 + /// + /// 包含事件数据的 。 + protected override void OnPaint(PaintEventArgs e) + { + if (this._isShowRegion) + { + this.SetWindowRegion(); + } + base.OnPaint(e); + if (this._redraw) + { + ControlPaint.DrawBorder(e.Graphics, base.ClientRectangle, this._borderStyleColor, this._borderStyleSize, this._borderStyleType, this._borderStyleColor, this._borderStyleSize, this._borderStyleType, this._borderStyleColor, this._borderStyleSize, this._borderStyleType, this._borderStyleColor, this._borderStyleSize, this._borderStyleType); + } + } + #endregion + + + #region 窗体拖动 English:Form drag + /// + /// Releases the capture. + /// + /// true if XXXX, false otherwise. + [DllImport("user32.dll")] + public static extern bool ReleaseCapture(); + /// + /// Sends the message. + /// + /// The HWND. + /// The w MSG. + /// The w parameter. + /// The l parameter. + /// true if XXXX, false otherwise. + [DllImport("user32.dll")] + public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); + + /// + /// The wm syscommand + /// + public const int WM_SYSCOMMAND = 0x0112; + /// + /// The sc move + /// + public const int SC_MOVE = 0xF010; + /// + /// The htcaption + /// + public const int HTCAPTION = 0x0002; + + /// + /// 通过Windows的API控制窗体的拖动 + /// + /// The HWND. + public static void MouseDown(IntPtr hwnd) + { + ReleaseCapture(); + SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); + } + #endregion + + /// + /// 在构造函数中调用设置窗体移动 + /// + /// The cs. + protected void InitFormMove(params Control[] cs) + { + foreach (Control c in cs) + { + if (c != null && !c.IsDisposed) + c.MouseDown += c_MouseDown; + } + } + + /// + /// Handles the MouseDown event of the c control. + /// + /// The source of the event. + /// The instance containing the event data. + void c_MouseDown(object sender, MouseEventArgs e) + { + MouseDown(this.Handle); + } + } +} diff --git a/JinYuan.ControlLib/Forms/FrmBase.resx b/JinYuan.ControlLib/Forms/FrmBase.resx new file mode 100644 index 0000000..be524d1 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmBase.resx @@ -0,0 +1,1185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAeIAAAAEAIAAo+AAAFgAAACgAAAB4AAAAAAEAAAEAIAAAAAAAAPAAAGDqAABg6gAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVAG9vbwBCQkQAPz9LADw9 + RQA7P0cAPEBHAD1ARgA9QUYAO0BGADtDRQA7QUEAO0BAADk+PgA9QkIAPkJCADtBRAA4RkgAOUZGADxA + QAA8QEAAOUZGADhGSAA7QUQAPkJCAD1CQgA5Pj4AO0BAADtAQQA7QEUAO0BGAD1BRgA9QEYAPEBHADs/ + RwA8PUUAPz9LAEJCRABvb28AVVVVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVVUAGRksAD4+ + RAA4QUUAOEBEADk7PABBQ0MAO0NFADs/RwA6QUUAPENDADxDQwA8Q0MAPENDADtCQwA1REIASjRkADw3 + RgE6PUoBPD9JAT0/RwI9QEcCO0BGAjtDRQI7QUEDO0BABDk+PgQ+QkIEPkJCBTtBRAU4R0gFOUZGBTxA + QAY8QEAGOUZGBThHSAU7QUQFPkJCBT5CQgQ5Pj4EO0BABDtAQQM7QEUCO0BGAj1ARwI9P0cCPD9JATo9 + SgE8N0YBSjRkADVEQgA7QkMAPENDADxDQwA8Q0MAPENDADxBQwA8QUcAPUFIADdGSQA3SUkAOz9DADlC + RgBAP0UAGxsvAFVVVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0tQwAkIz8APDxLADxCRAA8QkUAO0JEADtE + QwBaUDUAMztIADo8PwFBQ0MDO0NFBDtARgY4P0cIPEFDCz1BRQ08QkUPPEFDETtBRBM8Q0MVPENEFzxC + Qxk8QkQaPEJEGzxCRBw8QkQdPEJEHjxDRB88Q0MgPENDIDxDQyA8Q0MhPENDITxDQyE8Q0QhPENDITxD + QyI8Q0MiPENDITxDRCE8Q0MhPENDITxDQyE8Q0MgPENDIDxDQyA8QkQfPEJEHjxCRB08QkQcPEJEGzxC + RBo8QkMZPENEFzxDQxU7QUQTPEFDETxCRQ89QUUNPEFBCzo/QQg8QUcGPUFHBTdFSAM4R0gBNTtIAFFJ + MAA6REMAO0JEADxCRQA8QEQAPD1LACQjPwAtLUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAMzMzAERQVAA+RkgAPkNFAD1CRABETUMAPDtNATxCRAQ8QkUIO0JFDDxC + RBA7QkQVO0JEGTxCQxw8Q0MePENDIDxCRCI8Q0QkPENDJTxDQyU8Q0MmPENDJjxDQyY8Q0MnPENDJzxD + Qyc8Q0MnPENDJzxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxD + Qyc8Q0MnPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MlPENDJTxDQyQ8Q0QjPENEITtDRB88Q0QcO0JEGTtD + RBU8QkQQO0JFDDxBRQg8P0QEPDtNAURMQwA8QkQAPkNFAEBHSgBHUlYAMzMzAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPkREAEBGRwA4SlMAPUJEBTtBQgw8Q0QUPEJEGzxDQyA8Q0MjPENDJTxD + QyY8Q0MmPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MnPENDJzxD + QyY8Q0MmPENDJTxDQyM8QkMgPEJEGzxERBQ8QUIMPUJEBUJVXwBBRkcAPkREAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAP0REAEFDRAI8QkMTPENDIDxDQyU8Q0MmPENDJzxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxDQyY8Q0MlPENEIDxCRBNBQ0QCP0REAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPkNDAD9ERAY8QkMhPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MnPENDJz1CQyFAREQGPkNEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAP0BAAD86PAA7P0IIPUJEFDxCRB48Q0MjPENDJjxDQyY8Q0MnPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyc8Q0MmPENDJjxDQyM8QkMePUJDFDtAQghDP0AAQ0NEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQEBAAEE+QAA7P0IAEjkEADlDRgM5QkIIOkNEDjxCRBQ8Q0MZPEJDHjxD + QyE8Q0MjPENDJTxDQyY8Q0MmPENDJjxDQyc8Q0MnPENDJzxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJTxDQyQ8Q0MjPENDIzxDQyQ8Q0MlPENDJTxD + QyY8Q0MmPENDJTxDQyU8Q0MkPENDIzxDQyI8Q0MjPENDJTxDQyU8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxDQyc8Q0MnPENDJjxDQyY8Q0MmPENDJTxD + QyM8Q0MhPEJDHjxDQxk8QkQUO0NFDjpDQgg7PkYDE3Y6ADs/QgBFQUQAREREAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQAAADYAPUZMADhERQA7Q0MAPENCAEFJSAA8QkQBO0BEAjtB + RgU5Q0QIPUFECzxBQg49Q0IRPENEFDxBRRc8QkUaPEJDHTxDQx48Q0MgPEJDITxDRCM8Q0MkPENDJDxD + QyU8Q0MlPENDJTxDQyY8Q0MmPENDJDxDQyM8Q0MlPENDMDxCREM8QkVcPEFFdDxBRYs8QUWdPEFFqTxB + RbA8QUWyPEFFrjxBRaU8QUWXPEFFhDxCRW08QkRVPEJDPTxCQy08Q0MkPENDIzxDQyU8Q0MmPENDJTxD + QyU8Q0MlPENDJDxDQyQ8Q0QjPEJDITxDQyA8Q0MePEJDHTxCRBo8QkUYPEJFFTxDRBI9QkMPPkFECzpE + RQg7QUcFOz9EAj5ERgE+RkYAPUNDADxERAA6PkYAPTtHAAAABwBVVVUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODg4ADAzMgA8QkQAO0BEADtC + RgA6Q0QAPUFEAD5ERgA6REQAPkM+AAAA/wBAQ1sBOjxHAjxCRQM7QEUEOkBFBTtCRQY9Q0MIPEFECTxC + Qws9QkUMO0JEDTxBRAs9Q0QRPEFGLTxBRWA8QUWaPEFFxjxBReQ8QUX1O0BE/jtARP87QET/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/87QET/O0BE/zxBRfw8QUXwPEFF3jxBRb08QUWNPEFFUjxCRSM8QUUNO0NECztC + RQw8QkMLPEFECT1DQwg7QkUGOkBFBTtARQQ8QkUDOjxHAkRDWQFAL24AOksuADxDQAA8QkQAPUFEADpE + RQA7QkYAO0BEAD1ERQA1OTgAPz8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARkZGAC0tLQBAQUEAO0NFAEhPOgBGR2MAOjtHAD1CRgA7QEYAOj9FADtCRQA8Q0MAPEJDADxC + RAA8QUUAO0JGDDxBRUQ8QUWUPEFF1TxBRfc7QET/Oj9D/zo/Q/88QUX/REhM/0tQU/9SV1r/Wl5i/19j + Zv9hZWj/XWFl/1dbX/9PVFf/SU1R/0FGSv87QET/Oj9D/zo/Q/87QET/PEFF8jxBRck8QUWBPEFFMztD + SAU8QUUAO0JEADxDQwA7QkUAOj9FADtARgA9QkYAOjtHAEdHYwBHUDwAPUFIADxDRwBCQkEAR0dHAEBA + QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0BGADxBRQA8QEYAPEFGAD1B + RQ08QUVUPEFFtjxBRfI7QET/Oj9D/z1CRv9MUVT/aGxv/4mMjv+oqqv/vr/A/8/Q0f/b3Nz/4ODh/+Li + 4//j4+P/4eHi/97f3//X2Nn/ysvM/7i5u/+goqT/gIOG/2FlaP9HTFD/O0BE/zo/Q/87QET/PEFF6DxB + RaA8QUU+OUJGBTxCRQBCQ0UAP0NGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QUQASzZFADxBRQA8P0gDPEFFRjxB + RbM8QUX2O0BE/zo/RP9KT1P/c3d5/6aoqf/P0NH/5+fn//Dw8P/z8/P/8/Pz//Ly8v/x8fH/8fHx//Hx + 8f/x8fH/8fHx//Hx8f/y8vH/8vLy//Pz8//y8vL/7+/v/+Lj4//HyMn/m52f/2hsb/9ESU3/Oj9D/ztA + RP88QUXsPEFFljxBRSg5P0QAPEFFAD1ARQA2Q0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBM + UwAmWGIAPEFGADxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRR08QUWMPEFF7TtA + RP87QET/UlZa/42Qkv/Jy8v/6urq//Ly8v/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/y8vL/8vLy/+Xl5f+9vr//fH+C/0hN + Uf86P0P/PEFF/zxBRdc8QUVgPEBEBzxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRQA8QUUAO0FFADRL + TwA2SEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRQA7REQAPEFFADxB + RQA8QUQAPUJEADxARQI8QUUFPEFFBzxBRQg8QUUIPEFFCDxBRQg8QUUIPEFFPzxBRcU8QUX/Oj9D/0pP + U/+LjZD/0NHS//Dw8P/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/z8vL/6+zs/8HD + xP90eHr/QUZJ/zo/RP88QUX1PEFFkTxBRRo8QUUHPEFFCDxBRQg8QUUIPEFFCDxBRgY7QkYDPUBEADxB + RQA8QUUAPEFFAD1DQwA9Q0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA9QUUAPEFFADxBRQA3W0UAPEFFFDxB + RTQ8QUVdPEFFgDxBRZ08QUWxPEFFvDxBRcI8QUXDPEFFwzxBRcM8QUXEPEFF5ztARP89Qkb/bXF0/8LD + xP/u7u7/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/n5+j/qKmr/1RYXP86P0P/PEFF/TxBRdM8QUXCPEFFwzxBRcM8QUXDPEFFvjxBRbM8QUWfPEFFgzxB + RWA8QUU3PEFFFT1HPwE8QUUAPUFFAD1ARAA9QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/RUcAP0RGAD1BRQA7QUUAPEFFFDxBRUs8QUWSPEFFyzxB + Re08QUX8O0BE/zo/Q/86P0P/Oj9D/zo/Q/86P0P/Oj9D/zo/Q/86P0P/OT5C/0VKTv+SlZf/4uPj//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/x8fH/8fHx/8vMzf9rb3L/O0BE/zk+Q/86P0P/Oj9D/zo/Q/86P0P/Oj9D/zo/Q/86P0P/O0BE/zxB + Rf08QUXuPEFFzjxBRZU8QUVQPUFGFztCRgA8QUUAO0BCAD0+QAAAgIAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAOkVGAC5fRwA8QUUAOj9FAD1BRSI8QUV1PEFFyDxBRfU7QET/OT5D/ztA + RP9BRkr/TlNW/1tfYv9mam3/b3N1/3N2ef90d3r/c3d6/3N3ev9zdnn/eHx+/7O1t//t7e3/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/c3N3/j5GT/3N2ef9zd3r/c3d6/3N3ev9zd3r/cHR3/2hsbv9cYGP/T1RX/0JH + Sv87QET/OT5D/ztARP88QUX3PEFFyzxBRXc8QUUjPUNGADxBRAAoblQAOkVGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAA8QEUAPUFGADxARQA8QUUZPEFFdjxBRdY8QUX+Oj9D/zxBRf9NUlX/cHN2/5ib + nf+7vb7/0dLT/+Dh4f/o6On/6urr/+vr6//r6+v/6+vr/+vr6//r6+v/7Ozt//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/7+/v/+vr6//r6+v/6+vr/+vr6//r6+v/6uvr/+np6f/i4uL/09TU/72/ + wP+bnZ//cnZ4/05TVv88QUX/Oj9D/zxBRf88QUXYPEFFdztCRBk8QEUAPUFEAD1ARAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAOkJCAD1BRgA8QUQAPT9GBDxBRU88QUXFPEFF/jo/Q/8/REj/YmZp/5yeoP/Pz9D/6enq//Ly + 8v/z8/P/8vLy//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8vLy//Pz + 8v/y8vL/6urq/9DR0v+eoKL/Y2dq/0BFSf86P0P/PEFF/jxBRcY8QUVPPkBEBD1BRQA7QUQAP0BHAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA+QUYAQEFGADxBRQA8QUQVPEFFijxBRfA7QET/PUJG/2Jmaf+qrK3/4OHh//Ly8v/y8vL/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/y8vL/4eHi/6utr/9jZ2r/PUJG/ztARP88QUXwPEFFij1BRRU8QUUAOEdJADpF + RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADpE + RwA8Q0cAO0FFADxBRSo8QUW1PEFF/jo/Q/9NUlb/mJqc/97e3//y8vL/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/7+/v/9PU + 1P/T1NT/7+/v//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/e39//mZud/05TVv86P0P/PEFF/jxBRbQ8QUUrPj9DADtB + RAA7PkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOURIADpE + RwA9P0UAPEJGOzxBRc07QUX/PEFF/2hsb//Excb/8PDw//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/0NHS/1ld + YP9ZXWD/0NHS//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8PDw/8XGx/9pbXD/PEFF/zxBRf88QUXNPEFFOjxD + RwA9QEMAP0NGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QEMAO0JGAD1A + QwA8QUVAPEFF1ztARP8/REj/goWI/93d3v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0BF + SP9ARUj/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/d3t7/goSH/z9ESP87QET/PEFF1jxB + RT48QEQAPUFFADw/QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlCQwA6P0IAPEJGADxB + RTk8QUXXO0BE/0JHSv+TlZf/5+jo//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0FG + Sf9BRkn/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8fH/5+fn/5GUlv9BRkr/O0BE/zxB + RdU8QUU3PEJGAD09QABAQEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1ARQA8QEUAPEFFKDxB + Rcs7QET/QUZK/5eanP/r6+v/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0FG + Sf9BRkn/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+vr6/+WmZv/QUZK/ztA + RP88QUXJPEFFJzxBRQA7QUYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBGADxARQA7QEQTPEFFsDxB + Rf8+Q0f/kZOV/+vr6//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/19fX/ury9/0FG + Sf9BRkn/ury9//X19f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/q6+v/kJOV/z5D + R/88QUX/PEFFrj1BRRI8QUUAPEJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9PUcAPEBGADw/RwM8QUWEPEFF/TtA + RP9/goX/5ufn//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/6+vs/9LT0/+xs7T/fH+C/z5D + R/8+Q0f/fYCD/7O1tv/U1db/7e3t//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5ubm/36B + hP87QET/PEFF/TxBRYM7REQDPEJFAD09SQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAA/wAAPEFFADxBRUw8QUXuOj9D/2Zq + bf/b29z/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/+vr6/+8vr//en1//09TV/8+Q0f/O0BE/zxB + Rf88QUX/O0BE/z9DR/9RVln/gIOF/8PFxv/t7e7/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9rb + 2/9laWz/Oj9D/zxBRe48QUVLPEJEADtMKQArVVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRgA8QUUAPEFFGTxBRcU7QET/TVFV/8LD + xP/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/2NnZ/4SHif9GSk7/OT5C/zo/Q/89Qkb/QEVI/0JG + Sf9CRkn/QERI/z1CRv86P0P/OT9D/0pOUv+Mj5H/3t/f//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/BwsP/TFBU/ztARP88QUXDPEFFGDxBRQA5QUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRQA/OUIAPEFFezxBRf49Qkb/l5qc//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/KzMz/ZGdr/zo/Q/87QET/QEVI/01QUf9aW1r/YmFg/2Rj + Yf9kY2H/YWFg/1laWv9MTlD/P0RH/zpARP88QUX/bnF0/9TV1f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/v7+//lpmb/z1CRv88QUX+PEFFeEM+RQA5QkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JEADxBRQA8QUUrPEFF3To/Q/9kaGv/39/g//Hx + 8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9DR0v9eYmb/OT9D/zxBRf9KTU//X19e/2hnZf9qaGX/aWdl/2ln + Zf9pZ2X/aWdl/2poZf9oZmT/XV1d/0hLTf88QUX/Oj9D/2lsb//Y2dr/8vHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/x8fH/3t/f/2Roa/86P0P/PEFF3DxBRSk8QUUAPEJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0FFADpCQwE8QUWJPEFF/0JHS/+xs7T/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/5OTk/3J1eP86P0P/PUJG/1BSU/9mZWP/amdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/amhl/2VjYv9NT1H/PEFF/zpARP98gIL/6Ojo//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy/7Cys/9CRkr/PEFF/zxBRYc+QEkBPEFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5RkgAPEJFADxBRSc8QUXeOj9D/25ydf/m5+f/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/y8vL/qKqr/z5DR/88QUX/TlBS/2dlZP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9mZGP/S05Q/ztARP9BRkr/sLKz//Ly8v/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx/+bm5v9tcXT/Oj9D/zxBRd08QUUmPEFFAD1ARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1SkwAPz5CADxBRXg8QUX/QUZK/7K0tf/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/m5+f/am5x/zk+Qv9ESEv/Y2Jh/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qZ2X/YWFg/0JGSf85PkL/b3J1/+jo6P/x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v+xs7T/QUZK/zxBRf88QUV1PEFGADs/QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA8QUUAPEFGFDxBRcg6P0P/ZGhr/+Li4//x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/U1NX/TlJW/zo/RP9RU1T/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1BSU/86P0P/T1NX/9XW1v/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/h4uL/YmZq/zo/Q/88QUXGPEJFEjxBRQA9PUkAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFA7OQA8QUUAPEFFSjxBRfU8QUX/nJ6g//Ly8v/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/Oz9D/Sk9S/ztARP9UVVb/amhm/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amhm/1RVVv87QET/Sk9S/87P0P/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/y8fH/mpye/ztARP88QUX0PEFFSDxBRQA5L1QAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtBRAAfAAAAPEFFjztARP9MUVT/zs7P//Ly8v/w8PD/8fHw//Hx + 8P/v7/D/7/Dw//Hx8P/x8fD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/f4OD/XWFk/zk/Q/9FSUv/YWFg/2poZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qaGX/YWFg/0VIS/85P0P/XWFk/9/g4P/x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8P/x8fD/7/Dw/+/v + 8P/x8fD/8fHw//Dw8P/y8vL/zM7O/0tQVP87QET/PEFFjStPRAA+QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtBRQA7QUUTPEFFyzo/Q/9vc3b/6enp//Hx8P/w8PD/4eTy/8bO + 9/+2wvn/t8L5/8jQ9v/k5vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/nZ+h/z1CRv87QET/RUhL/1lZWf9lZGL/aWdl/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2pnZf9qaGX/aWdl/2ZkY/9ZWVr/REhL/ztARP8+Q0f/nqCi//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+Tm8v/I0Pb/t8L5/7bC + +f/Gzvf/4eTy//Dw8P/x8fD/6Onp/25xdP86P0P/PEFFyT1BRhI9QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQEBAADxBRQA8QUU5PEFF7ztARP+bnZ//8vLy/+/w8P/P1vX/obD9/5Sm + //+Spf//kqX//5Sm//+ks/z/1dr1//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/5eXm/4SHif8+Q0f/Oj9D/z1CRv9GSUz/UVNU/1pbW/9gYF//Y2Jh/2Rj + Yv9kY2L/Y2Jh/2BgX/9aW1v/UVNU/0ZJTP89Qkb/Oj9D/z5DR/+Fh4r/5ebm//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/1Nr1/6Sz/P+Upv//kqX//5Kl + //+Upv//obD9/8/W9f/w8PD/8vLy/5mcnv87QET/PEFF7jxBRTg8QUUAN0lJAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAMUVXADxBRQA8QUVpO0BE/kRJTf/BwsP/8/Py/9fc9P+crP7/k6X//5Sm + //+Upv//lKb//5Sm//+Tpf//oLD9/93h8//x8fD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+bm5/+eoKL/VFlc/zxBRf85PkL/O0BE/z1CRv8/REf/QkZJ/0NH + Sv9DR0r/QkZJ/z9ER/89Qkb/O0BE/zk+Qv87QET/VFhc/56gov/m5+f/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8P/d4fP/oLD9/5Ol//+Upv//lKb//5Sm + //+Upv//k6X//5yt/v/Y3PT/8/Py/8DCw/9ESEz/O0FF/jxBRWg8QUUATC0+AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFAD5CRQE8QUWYOj9E/1ZaXv/b29z/7u/y/7K++v+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//7nE+f/v7/D/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx + 8f/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/w8PD/1dXW/5yfoP9obG//TFBU/z5DR/87QET/OT9D/zk+ + Qv85PkL/OT9D/ztARP8+Q0f/TFBU/2hsb/+anJ7/09TV//Dw8P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx + 8f/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+/v8P+5xPn/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+yvvr/7u/y/9rb2/9VWl3/OkBE/zxBRZY+RUkBPEJGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRQw8QUW9OT5C/21xdP/r6+r/5Ofy/5+v/f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6Wz/P/p6vH/8PDw//Dw8P/w8PD/8PDw//Ly8v/x8fH/6Ojo/+Hh + 4f/g4OH/5eXm/+7u7v/y8vL/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//Hx8f/n5+f/z9DQ/7W3uP+doKH/j5GU/4eK + jP+Hioz/j5GU/52gof+2t7j/z9DQ/+fn5//x8fH/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//Ly8v/u7u7/5eXm/+Dg + 4f/h4eH/6Ojo//Hx8f/y8vL/8PDw//Dw8P/w8PD/8PDw/+jq8f+ls/z/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+fr/3/5Ofy/+rq6v9scHP/OT5C/zxBRbw8QUULPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFGADxBRho8QUXZOj9D/4aJi//x8fD/4OPz/5ys/v+Tpv//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6Gw/f/l5/L/8fHw//Dw8P/x8fH/7e3t/8bHyP+PkpT/bHBz/1xg + ZP9bX2L/Zmpt/36ChP+mqKr/0dLT/+zs7P/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8vLy//Pz8//y8vL/8vLy//Hx + 8f/x8fH/8vLy//Ly8v/z8/P/8vLy//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/s7Oz/0dLT/6aoqf9+gYT/Zmpt/1tf + Yv9cYGT/bHBz/4+SlP/Gx8j/7Ozt//Hx8f/w8PD/8fHw/+Xn8v+hsP3/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Om//+crP7/4OPz//Hx8P+FiIr/Oj9D/zxBRdk8QUUaPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRS88QUXoO0BE/52fof/z8vL/5ujy/6Kx/f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6i2/P/q6/H/8PDw//Ly8f/e3t//i46Q/0lOUv86P0P/OT5C/zk/ + Q/85P0P/OT5C/zk+Qv89Qkb/T1NX/3p9gP+3ubr/5eXl//Ly8v/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/y8vL/5eXl/7e5uv97foH/T1NX/z1BRf85PkL/OT5C/zk/ + Q/85P0P/OT5C/zo/Q/9JTlH/iYyP/97e3//y8vH/8PDw/+rr8f+ntvz/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+isf3/5ujy//Py8v+cnqD/O0BE/zxBRec8QUUuPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRUE8QUXzPEFF/66wsf/z8/P/7+/w/7nE+f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//lKb//8HK+P/w8PD/8fHx/9vb3P9xdHf/O0BE/ztARP8/REf/R0tN/01P + Uf9OUFL/Sk1P/0NHSv89Qkb/Oj9E/zk+Q/9DR0v/am1w/6+wsv/k5eX/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/+Tl5f+usLL/am1w/0JHS/85PkP/Oj9E/z1CRv9DR0r/Sk1P/05Q + Uv9NUFH/R0tN/z9DR/87QET/O0BE/3F1eP/b3Nz/8fHx//Dw8P/Byvj/k6b//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+6xPn/7+/w//Pz8/+tr7H/PEFF/zxBRfI8QUVAPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRU08QUX6QUZJ/7m6vP/z8/P/8fHw/+Dj8/+ks/z/k6X//5Sm + //+Upv//lKb//5Sm//+Tpf//qbf8/+Xn8v/x8fH/6Ojo/36Bg/87QET/PEFF/0lMTv9dXV3/Z2Vj/2ln + Zf9pZ2X/aGZk/2RjYf9bW1v/TU9R/0FFSf87QET/OT5C/0BFSf9tcXP/vL2+/+zt7f/y8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Lx8f/s7O3/u72+/21wc/9ARUn/OT5C/ztARP9BRUj/TU9R/1tbW/9kY2H/aGZk/2ln + Zf9pZ2X/Z2Vj/11dXf9ITE7/PEFF/ztARP9+goT/6Ojp//Hx8P/k5/L/qbf8/5Ol//+Upv//lKb//5Sm + //+Upv//k6X//6Sz/f/g4/P/8fHw//Pz8/+4urv/QEVJ/zxBRfo8QUVNPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVc7QET+RUlN/8DCw//z8/L/8PDw//Hw8P/c4PP/rrv7/5ip + /v+Upv//lKb//5mq/v+yvvr/4OPz//Hx8P/y8vL/rK6w/0FFSf87QET/Sk1P/2VjYv9qaGX/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/aGZl/2FgX/9SU1T/QkZJ/ztARf85PkP/R0tP/4mLjv/a2tv/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy/9ra2/+Ii47/RktP/zk+Q/87QEX/QkZJ/1JUVf9hYF//aGZl/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2poZf9lY2L/Sk1P/ztARP9BRkr/ra+w//Ly8v/x8fD/4OPz/7K++v+Zqv7/lKb//5Sm + //+Yqf7/rrv7/9zg8//w8PD/8PDw//Pz8//AwcL/RElN/ztARP48QUVWPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRV07QET/R0tP/8XHyP/y8vL/8PDw//Dw8P/x8fD/6uvx/9fc + 9P/J0fb/ytL2/9nd9P/s7PH/8fHw//Hx8f/i4uP/ZWls/zk+Q/9DR0r/YmFg/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/YmFg/1FTVP9ARUj/O0BE/ztARP9jZ2r/wcLD//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/wMLD/2Jmaf87QET/O0BE/0BFSP9RU1T/YmFg/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/YWFg/0NHSv85PkL/Zmpt/+Lj4//x8fH/8fHw/+zs8f/Z3fT/ytH2/8nR + 9v/X3PT/6uvx//Hx8P/w8PD/8PDw//Ly8v/Fxsf/RktP/ztARP88QUVcPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVw7QET/R0tP/8jJyv/z8/P/8PDw//Dw8P/w8PD/8PDw//Hx + 8P/x8fD/8fHw//Hx8P/w8PD/8PDw//Py8v+5urv/QkdK/zxBRf9UVVb/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9fXl7/SUxO/zxBRf86P0P/TlNW/6yu + sP/u7u7/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+7u + 7v+srrD/TlNW/zo/Q/88QUX/SUxO/15eXv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1NVVf87QET/QkdL/7m7vP/z8vL/8PDw//Dw8P/x8fD/8fHw//Hx + 8P/x8fD/8PDw//Dw8P/w8PD/8PDw//Pz8//Hycr/RktP/ztARP88QUVbPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVY7QET+RUlN/8fIyf/09PT/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+KjY//OT9D/0FFSP9hYF//aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qZ2X/ZmRj/1JUVf8/Q0f/Oj9D/0ZL + T/+jpaf/7u7u//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fD/7e7u/6Kk + pv9GS0//Oj9D/z9DR/9TVFX/ZmRj/2pnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2FgX/9ARUj/OT9D/4qNj//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//T09P/GyMn/RElN/ztARP48QUVVPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRUw8QUX6QEVJ/8HCw//39vb/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+bm5/9na27/OT5C/0lLTv9nZWT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9ZWVr/QUVJ/zo/ + Q/9GSk7/p6mr/+/v7//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/p6mr/0ZK + Tv86P0P/QUVJ/1laWv9oZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dlZP9IS07/OT5C/2hrbv/m5+f/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//f39v/AwsP/QEVJ/zxBRfk8QUVLPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRT88QUXxPEFF/7W3uf/6+vr/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vHx/9jZ2f9TV1v/Oj9D/1BSVP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/XFtb/0FF + Sf86P0P/S1BU/7u9vv/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Lx8f+8vb7/TFBU/zo/ + Q/9BRUn/W1tc/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9QUlP/Oj9D/1NXW//Y2dr/8vHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//r6+v+1t7j/PEFF/zxBRfE8QUU+PEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRSw8QUXmOj9D/6Kkpv/8/Pz/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8zNzv9HTE//O0BE/1ZXV/9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1pa + Wv8/REf/Oj9D/15iZf/X2Nn/8vLx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLx/9fY2P9eYWX/Oj9D/z9E + R/9aWlv/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9WV1f/O0BE/0dMUP/Mzs7/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//z8/P+hpKb/Oj9D/zxBReY8QUUsPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRBg8QUXXOT5C/4mMjv/9/f3/8/Pz//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8LDxP9ESEz/PEFF/1lZWv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9UVVb/PUJF/ztARP+Ii43/7e3t//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/7e3t/4eKjf87QET/PUJG/1RV + Vv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9ZWVn/PEFF/0RITP/CxMX/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8/Pz//39/f+JjI7/OT5C/zxBRdc8QUUYPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxCRQs8QUW5OT5C/29ydf/39/f/9/f3//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/7/Awf9DSEv/PEFF/1paWv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2lnZf9pZ2X/aWdl/2ln + Zf9mZWP/Sk1P/zpARP9JTlL/xcbH//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/xMXG/0lOUf86QET/Sk1P/2Zl + Y/9pZ2X/aWdl/2lnZf9pZ2X/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9aWlr/PEFF/0NIS/+/wMH/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/9/f3//f39/9vcnX/OT5C/zxBRbk8QUUKPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAO0FEADZFOAA8QUWVOj9D/1ldYf/o6en//Pz8//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8XGx/9ESU3/PEFF/1hZWf9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ZlY/9hYF//YF9e/2NiYf9oZmT/aWdl/2ln + Zf9qaGX/Xl1d/z9ER/86P0P/gIOF/+3t7f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/t7e3/f4OF/zo/Q/8/REf/Xl1d/2po + Zf9pZ2X/aWdl/2hmZP9jYmH/YF9e/2FgX/9mZWP/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9YWFn/PEFF/0RJTf/Fx8j/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH//f38/+jp6f9YXWD/Oj9D/zxBRZVCLzwAPEBEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAATE9YADxBRQA8QUVuO0BE/0dLT//S09T///////T09P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9DR0v9KTlL/O0BE/1RVVv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9nZWP/V1dY/0ZKTP9ARUj/P0RH/0JGSf9NT1H/YF9f/2ln + Zf9pZ2X/aGZk/0xPUf86P0P/TlNW/9DR0v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/S09P/T1RY/zo/Q/9MT1H/aGZk/2ln + Zf9pZ2X/YF9f/01PUf9CRkn/P0RH/0BFSP9GSkz/V1dY/2dlY/9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9UVVb/O0BE/0pPU//R0tL/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/09PT//////9HS0/9GS0//O0BE/zxBRW08QUUAR1JRAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAACwwMADxBRQA8QUVCPEFF9D1CRv+wsrP///////j4+P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/9zc3f9YXF//Oj9D/09RUv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ZlY/9OUFL/PUJG/ztARf88QUX/PEFF/zxBRf87QEX/QkZJ/1xc + XP9pZ2X/amhl/1tbW/89Qkb/PEFF/6Olp//y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v+kpqj/PUJG/z1CRv9bW1v/amhl/2ln + Zf9cXFz/QkZJ/ztARf88QUX/PEFF/zxBRf87QEX/PUJG/05QUv9mZWP/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9PUVL/Oj9D/1hcYP/c3d3/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/4+Pj//////6+xs/89Qkb/PEFF9DxBRUE8QUUACwsMAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUgPEFF2zk+Qv+LjpD//v7+//39/f/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+np6f9rb3L/OT5C/0hLTf9nZWT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1RWVv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/O0BF/0RI + S/9jYmH/amhl/2VjYv9ER0r/OT5C/3p9gP/s7e3/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+zs7f95fX//OT5C/0RIS/9lY2L/amhl/2Ni + Yf9ESEv/O0BF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf9UVlb/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dlZP9IS03/OT5C/2xwc//p6en/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/9/f3//v7+/4uOkP85PkL/PEFF2jxBRR88QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRQA9QkUIPEFFtDo/Q/9laWz/8vLy///////39/f/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+JjI7/OT5D/0FGSf9jYmD/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZGNi/0RHSv87QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxB + Rf9VVlf/aWdl/2hmZf9MTlD/OT9D/11hZf/i4uP/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+Hi4v9dYWT/OT9D/0xOUP9oZ2X/aWdl/1RW + Vv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztBRf9ER0v/ZGNi/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2JiYP9BRkn/OT5D/4qNj//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//f39///////8fLy/2VpbP86P0P/PEFFsztCRQc7QkUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRwA9P0MAPEFFfTtARP9KT1P/1tfY///////8/Pz/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Pz8/+usLL/PkNH/z1CRv9aW1v/amhl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/XV1d/z5DRv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + RP9LTU//aGZk/2lnZf9TVFX/Oj9E/09UV//T09T/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9LT0/9PU1f/Oj9E/1NUVf9qZ2X/aGZk/0tN + T/87QET/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf8+Q0b/XV1d/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/amhl/1paW/89Qkb/PkNH/6+xs//z8/P/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy//z8/P//////1tfY/0pPUv87QET/PEFFfD5BRgA7QUQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEpMgA8QUUAPEFFRzxBRfU8QUX/ra+x////////////9vb2//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/S09T/T1RX/zo/Q/9PUVL/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/Wltb/z1CRv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + Rf9IS07/Z2Vk/2poZv9XWFj/O0BE/0dMUP/Iycr/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8fIyf9HS0//O0BE/1dYWP9qaGb/Z2Vj/0hL + Tf87QEX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf89Qkb/Wltb/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/05RUv86P0P/UFRY/9PU1P/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/9vb2////////////rK+w/zxBRf88QUX0PEFERjxBRQBDSlUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACtVVQA8QUUAPEFFGjxBRdQ5PkL/fICC//r6+////////Pz8//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/q6ur/c3d6/zk+Qv9DR0r/ZGNh/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/Xl5d/z5DR/88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + RP9MTlD/aGZk/2poZv9ZWVn/PEFF/0NITP/CxMX/8/Pz//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8/Pz/8LDxP9DSEz/PEFF/1lZWv9qaGb/aGZk/0tO + UP87QET/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf8+Q0f/Xl5d/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZGJh/0NHSv85PkL/dXh7/+rr6//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL//Pz8///////6+vr/fH+C/zk+Qv88QUXUPEFFGjxBRQAzMzMAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkUAP0NGAjxBRZw6QET/VFlc/+Pk5P////////////f3 + 9//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/qaus/z5DR/89QUX/WFlZ/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZWRi/0VJTP87QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxB + Rf9XV1j/amdl/2poZv9ZWVn/PEFF/0RJTf/DxMX/8/Pz//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8/Pz/8LExf9DSEz/PEFF/1lZWf9qaGb/amdl/1ZX + WP88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztBRf9FSUz/ZWRi/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/WFhZ/z1BRf8+Q0f/qqyu//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/39/f////////////j4+T/VFhc/zpARP88QUWcPkJFAj1CRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkYAPEFFADxBRVk8QUX7PkNH/7W3uP////////////39 + /f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/2dra/1hcX/86P0P/SEtN/2ZlY/9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1dYWf89Qkb/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/O0BF/0dK + Tf9lY2L/aWdl/2poZv9XV1j/O0BE/0hNUP/Jysv/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8jKyv9ITVD/O0BE/1dXWP9qaGb/aWdl/2Vj + Yv9HSk3/O0BF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/z1CRv9YWFj/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9mZWP/SEtN/zo/Q/9ZXWD/2tvb//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/9/f3///////////+0trj/PkNH/zxBRfo8QUVZPEFFADxCRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAPEFFADxBRSA8QUXZOT5C/32Ag//6+/v///////// + ///5+fn/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/5OVl/87QET/PUJG/1laWv9qZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dmZP9SVFX/PkNH/ztARf88QUX/PEFF/ztARf88QUX/RklM/2Bf + Xv9pZ2X/aWdl/2lnZf9SVFX/Oj9D/1BVWP/U1dX/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9TU1f9QVFj/Oj9D/1JUVf9pZ2X/aWdl/2ln + Zf9fX17/RUlM/zxBRf87QEX/PEFF/zxBRf87QEX/PkNH/1JUVf9oZmT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2pnZf9ZWlr/PUJG/ztARP+Ulpj/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//n5 + +f////////////r6+v98f4L/OT5C/zxBRdk8QUUfPEFFAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JGADtERgM8QUWbO0BE/1BUWP/c3d7///////// + ///+/v7/9PT0//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9PU1P9UWFz/Oj9D/0ZKTP9lY2L/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9oZmT/W1tb/0tOUP9ER0r/QkZK/0ZKTP9SVFX/Y2Jh/2ln + Zf9pZ2X/aWdl/2hnZf9MTlD/OT9D/11hZf/i4+P/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+Lj4/9dYWT/OT9D/0xOUP9pZ2X/aWdl/2ln + Zf9pZ2X/Y2Jh/1JUVf9GSkz/QkZK/0RHSv9LTlD/W1tb/2hmZP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2VkYv9GSkz/Oj9D/1VZXP/T1NX/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/9PT0//7+ + /v///////////9vc3f9PVFf/O0BE/zxBRZk8Q0gCPEJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITo9ADxBRQA8QUVNPEFF9jxBRf+jpaf///////// + ////////+/v7//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+Zm53/PEFF/zxBRf9TVFX/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2hmZP9kY2L/Y2Jh/2ZlY/9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2RjYf9DR0r/OT5C/3h8f//s7Oz/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+zs7P94e37/OT5C/0RHSv9kY2L/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9mZWP/Y2Jh/2RjYv9oZmT/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/1JUVf88QUX/PEFF/5mcnv/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/+/v7//// + /////////////6Kkpv88QUX/PEFF9TxBRUw8QUQASysyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASUtNAD1BRQA9QUUTPEFFxjo/Q/9mam3/7/Dw//// + //////////////f39//w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/e39//ZWls/zo/Q/9AREj/XFxc/2pn + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/1ZXWP88QUX/PkNH/6epq//y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v+nqav/PUJG/zxBRf9WV1j/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9qZ2X/XFxc/0BER/86P0P/Zmpt/97f3//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/39/f///////// + ////////7+/v/2VpbP86P0P/PEFFxjxBRBI8QUQAJVtdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9BQgA7QUUAPEFFdjxBRf9BRkr/vL6///// + //////////////7+/v/09PT/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/vL6//0pOUv86P0T/REhL/2Fg + X/9qZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9qZ2X/YmFg/0NHSv86P0P/XGBk/9vc3P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/b29z/XGBj/zo/Q/9DR0r/YmFg/2pn + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2pn + Zf9gYF//REhL/zo/Q/9KT1P/vb/A//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//T09P/+/v7///////// + ////////vL2//0FGSv88QUX/PEFFdTxCRgA3NTkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtCQQA8QUUAPEFFJzxBRd45PkL/d3p9//f3 + 9//////////////////8/Pz/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/7+/v/5yeoP9ARUn/O0BE/0dK + TP9hYWD/amhl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9lZGL/Sk1P/ztARP9ARUn/p6qr//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/p6mr/0BFSf87QET/Sk1P/2Vk + Yv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amhl/2Fh + YP9GSkz/O0BE/0BFSf+dn6H/7+/v//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//z8/P////////////// + ///39/f/dnp8/zk+Qv88QUXdPEFFJjxBRQA4OT4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBASAA9QEUAPz9GATxBRZA7QET/RktP/8fJ + yv//////////////////////+fn5//Hx8f/w8PD/8PDw//Dw8P/w8PD/8fHx/+np6f+Ii47/PUJG/ztA + RP9FSUz/Xl5d/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2Rj + Yv9MT1D/PEFF/ztARP9+gYT/5+jo//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5+jo/36Bg/87QET/PEFF/0xO + UP9kY2L/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/Xl5d/0ZJ + TP87QET/PUJG/4mMjv/p6en/8fHx//Dw8P/w8PD/8PDw//Dw8P/x8fH/+fn5//////////////////// + ///HyMn/RktP/ztARP88QUWPPkBCAT1BRAA8REQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUYAPEFFADxBRTQ8QUXnOj9D/3x/ + gv/4+Pn///////////////////////f39//w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/k5OX/hYiK/z5D + R/87QET/QUVJ/1ZWV/9mZGP/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9pZ2X/Xl5d/0hL + Tf88QUX/Oj9D/21xdP/b3Nz/8vHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vHx/9vb3P9tcHP/Oj9D/zxB + Rf9IS03/Xl5d/2lnZf9qaGX/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2ZkY/9VVlf/QUVJ/ztA + RP8+Q0f/hYiL/+Tl5f/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/39/f///////////////////////j4 + +f97f4L/Oj9D/zxBRec8QUUzPEFFADxBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAPUFEAD5ARAM8QUWXO0BE/0ZL + T//Gx8n///////////////////////7+/v/19fX/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5ubn/5KV + l/9FSk3/Oj9D/z1BRf9HSk3/V1hY/2NiYf9nZmT/aWdl/2lnZf9oZ2X/ZmRj/15eXf9PUVL/QERI/ztA + RP88QUX/cnZ4/9fY2f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/X2Nj/cnV4/zxB + Rf87QET/QERI/09RU/9eXl3/ZmRj/2lnZf9pZ2X/aWdl/2dmZP9jYmH/V1hY/0dKTf89QkX/Oj9D/0VK + Tv+TlZf/5ufn//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//X19f/+/v7//////////////////////8bH + yP9GS0//O0BE/zxBRZY9QUYDPUFFAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0FGADxBRQA8QUU0PEFF5To/ + Q/91eHv/9PX1///////////////////////9/f3/9PT0//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+zt + 7f+xs7T/XWFk/ztBRf86P0P/PEFF/0JGSf9JTE7/TlBS/09RUv9MTlD/RklM/z9DR/87QET/OT5D/0dM + UP+NkJL/4ODg//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/4ODg/42P + kv9HTFD/OT5D/ztARP8/Q0f/RklM/0xOUP9PUVL/TlBS/0lMTv9CRkn/PEFF/zo/Q/88QUX/XWFl/7Kz + tf/t7e3/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/9PT0//39/f//////////////////////9PT1/3R4 + e/86P0P/PEFF5D1BRTQ8QUUAP0VBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRQA8QUUhPEFF1TtB + Rf9CRkr/t7m7/////////////////////////////Pz8//Pz8//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL/2dra/5aYmv9ZXWD/PkNH/zk+Qv85PkL/OT5D/zk/Q/85PkL/OT5C/zo/Q/9HTFD/dHd6/76/ + wP/t7e3/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+3t + 7f+9v8D/dHd6/0dMT/86P0P/OT5C/zk+Qv85P0P/OT5D/zk+Qv85PkL/PkNH/1ldYf+WmJv/2dra//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/z8/P//Pz8////////////////////////////t7i6/0JG + Sv88QUX/PEFF0zxBRR88QUUAPUFEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQkUAPEFFADtBRQc8QUWWPEFF/zxB + Rf86P0P/YmZp/+jp6f////////////////////////////z8/P/z8/P/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx//Dw8P/a2tv/r7Cy/4KFh/9obG//XGBj/1ldYf9hZWj/dHd6/5eZm//Fxsf/6enp//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL/6Onp/8XGx/+XmZv/dHd6/2FlaP9ZXWH/XGBj/2hsb/+ChYf/r7Gy/9rb2//w8PD/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/8/Pz////////////////////////////o6en/YmZp/zo/ + Q/88QUX/PEFF/jxBRZI+QUQGPUFEAD5AQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRUYAO0FFADxBRVU8QUX0PEFF/0FF + SP89Qkb/PEFF/5mbnf/9/f3////////////////////////////8/Pz/8/Pz//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/8vLy/+/v7//m5uf/3+Dg/97e3//i4uP/6+zs//Ly8v/y8vL/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx//Ly8v/y8vL/6+zs/+Li4//e3t//3+Dg/+bm5//v7+//8vLy//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8/Pz//v7+/////////////////////////////39/f+Ym53/PEFF/z1C + Rf9BRUj/PEFF/zxBRfI8QUVSPEFFAEY8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5BRgA8QUUAPEFFGTxBRcg8QUX/QUZJ/1xc + XP9IS03/Oj9E/0xQVP/Mzc7//////////////////////////////////Pz8//Pz8//w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8fHx//Hx8f/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/x8fH/8fHx//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/z8/P//Pz8/////////////////////////////////8vMzf9LUFP/Oj9E/0hL + Tf9bW1v/QUVJ/zxBRf88QUXGPUBFGDxBRQA9QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRgA8QUYAPEFFcTxBRf08QUX/VFVW/2po + Zf9dXVz/P0RH/zk/Q/9ucXT/7e3u//////////////////////////////////z8/P/09PT/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//T09P/8/Pz/////////////////////////////////7e3t/21xdP85P0P/P0RI/11d + XP9qZ2X/U1VW/zxBRf88QUX9PEFFcDtCRgA+QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPUBFADxBRQA8QUUfPEFF0zxBRf9FSUv/ZWNi/2ln + Zf9pZ2X/UVNU/zxBRf88QUX/lpmb//z8/P/////////////////////////////////9/f3/9fX1//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/9fX1//39/f/////////////////////////////////8/Pz/lpmb/zxBRf88QUX/UVNU/2ln + Zf9pZ2X/ZGNi/0VJS/88QUX/PEFF0jxBRR48QUUAPkFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPkBGADtCRQA8QUVtPEFF/j1CRv9XWFj/aWdl/2ln + Zf9pZ2X/ZWNi/0dLTf87QET/R0xQ/72/wP///////////////////////////////////////v7+//f3 + 9//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx + 8f/39/f//v7+//////////////////////////////////////++v8D/R0xQ/ztARP9HSk3/ZWNi/2ln + Zf9pZ2X/aWdl/1dXWP89QkX/PEFF/TxBRW06QUQAP0FHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBFADxARRE8QUXBPEFF/0RIS/9lY2L/aWdl/2ln + Zf9pZ2X/aWdl/1FSVP88QUX/Oj9D/1ldYf/Z2tv///////////////////////////////////////// + ///6+vr/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//r6 + +v///////////////////////////////////////////9na2v9ZXmH/Oj9D/ztBRf9OUFL/aWdl/2ln + Zf9pZ2X/aWdl/2VjYv9FSEv/PEFF/zxBRcE8QEURPEBFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkQAPEFFADxBRUU8QUX0PEFF/1NUVf9pZ2X/aWdl/2ln + Zf9pZ2X/Y2Jh/0NHSv87QEX/O0BE/zo/Q/9xdXf/6+zs//////////////////////////////////// + /////////Pz8//X19f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/19fX//Pz8//// + ////////////////////////////////////////6+zs/3B0d/86P0P/O0BE/ztBRf9BRUj/YGBf/2ln + Zf9pZ2X/aWdl/2lnZf9TVFX/PEFF/zxBRfQ8QUVGPEFFADtARgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+Q0QAOkBFADxBRYc8QUX/QERH/2BfXv9qZ2X/aWdl/2ln + Zf9pZ2X/VldX/zxBRf9BRkr/Wl5h/z5DR/87QUT/hYmL//X19f////////////////////////////// + //////////////7+/v/5+fn/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//n5+f/+/v7///////// + ///////////////////////////////////09fX/homL/zxBRf89Qkb/YWVp/0VKTf87QET/UlNV/2ln + Zf9pZ2X/aWdl/2pnZf9gX1//QERI/zxBRf88QUWJPURCADs/RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEFFEDxBRcQ7QEX/SEtN/2dlY/9pZ2X/aWdl/2ln + Zf9nZWP/SEtN/zo/Q/9cYGT/wMHC/21xc/86P0P/P0RI/5eanP/5+fn///////////////////////// + /////////////////////////Pz8//b29v/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/29vb//Pz8//////////////////// + //////////////////////////////n5+f+Xmpz/P0NH/zo/Q/9tcXT/x8jI/2drbv85P0P/RUhL/2Vk + Yv9pZ2X/aWdl/2lnZf9nZWT/SEtO/ztARf88QUXGPEFFETxBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFGRgA8QUUAPEFFLjxBRek8QUX/UlRV/2lnZf9pZ2X/aWdl/2pn + Zf9gX17/QERH/zo/Q/+JjI7/4uLi/8fHyP9eYmX/OT5C/0FGSv+ipaf//Pz8//////////////////// + ///////////////////////////////////7+/v/9fX1//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/9PT0//v7+/////////////////////////////// + /////////////////////////Pz8/6Olp/9CR0r/OT5C/15iZf/Hx8j/5OPj/5eZm/88QUX/PkNG/11d + XP9qaGX/aWdl/2lnZf9pZ2X/U1RV/zxBRf88QUXqPEFFMDxBRQA7PkIAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEVJRwA8QUUAPEFFVzxBRfo9Qkb/W1tb/2poZf9pZ2X/aWdl/2po + Zf9XWFj/PEFF/0NHS/+ztLX/4uLi/+Li4v+8vb7/Vlte/zk+Qv9FSU3/p6mr//v7+/////////////// + /////////////////////////////////////////v7+//r6+v/19fX/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//T09P/6+vr//v7+//////////////////////////////////// + ///////////////////7+/z/p6qr/0VKTf85PkL/Vlpd/7y9vv/i4uL/4uLi/72+v/9ITVD/O0BE/1RV + Vv9pZ2X/aWdl/2lnZf9qaGX/W1xb/z1CRv88QUX7PEFFWjxBRQA6PUEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1CRAA7QEYAPEFFfTxBRf9ARUj/YWBf/2lnZf9pZ2X/aWdl/2ln + Zf9PUVL/Oj9D/1NXW//Mzc3/4eHh/+Dg4P/i4eH/tba4/1JWWf85PkL/RElN/6Wnqf/6+vr///////// + ///////////////////////////////////////////////////+/v7/+/v7//b29v/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/29vb/+/v7//7+/v////////////////////////////////////////////// + //////////////v7+/+lqKr/RElN/zk+Qv9RVln/tba3/+Hh4f/g4OD/4eHh/9PT1P9bX2L/Oj9D/0xO + UP9oZmX/aWdl/2lnZf9pZ2X/YmFg/0FFSP88QUX/PEFFgTxBRgA8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA9QkUBPEFFmjxBRf9DR0r/ZWRi/2lnZf9pZ2X/aWdl/2hm + ZP9JTE7/OT5C/2VpbP/Z2dr/4ODg/+Dg4P/g4OD/4eHh/7K0tf9SVln/OT5C/0NITP+cnqD/9/f3//// + ///////////////////////////////////////////////////////////////////9/f3/+Pj4//T0 + 9P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx + 8f/09PT/+Pj4//z8/P////////////////////////////////////////////////////////////// + ////////9/f3/52fof9DSEz/OT5C/1FVWf+xs7T/4eHh/+Dg4P/g4OD/4ODg/9zc3P9vc3b/OT5C/0ZK + TP9nZWT/aWdl/2lnZf9pZ2X/ZWRj/0RIS/88QUX/PEFFnz1ARgI8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUFPEFFsztBRf9HSk3/Z2Vk/2lnZf9pZ2X/aWdl/2Zl + Y/9GSUz/OT5C/3V4e//d3d3/4ODg/+Dg4P/g4OD/4ODg/+Hh4f+ztLX/VFhb/zk+Qv9ARUn/jpGT/+/v + 7/////////////////////////////////////////////////////////////////////////////7+ + /v/8/Pz/+Pj4//X19f/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/19fX/+Pj4//z8 + /P/+/v7///////////////////////////////////////////////////////////////////////// + ///v7/D/jZCT/0BFSf85PkL/VFhb/7O0tf/h4eH/4ODg/+Dg4P/g4OD/4ODg/9/f3/9/goT/OT5C/0RI + Sv9lY2L/aWdl/2lnZf9pZ2X/Z2Zk/0hLTf87QUX/PEFFuDpDRwY6REcAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADlFRwA6Q0cIPEFFvztARf9KTU//aGZk/2lnZf9pZ2X/aWdl/2Vk + Yv9ESEv/OT5C/3t+gP/e3t7/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/h4eH/ubq8/1peYf86P0P/PEFF/3h8 + fv/h4uP///////////////////////////////////////////////////////////////////////// + ///////////////////9/f3/+/v7//j4+P/29vb/9PT0//Ly8v/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx8f/y8vL/9PT0//b29v/4+Pj/+/v7//39/f////////////// + /////////////////////////////////////////////////////////////////////////////+Hi + 4v95fH//PEFF/zo/Q/9aXmH/ubq7/+Hh4f/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P+ChYf/OT5C/0NH + Sv9kY2H/aWdl/2lnZf9pZ2X/aGZk/0tNUP87QEX/PEFFxDtCRQs7Q0UAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpCRAA7QkQLPEFFxDtARf9LTlD/aGZk/2lnZf9pZ2X/aWdl/2Zk + Y/9FSEv/OT5D/3R3ef/b29v/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4uHh/8LDw/9nam3/O0BE/zo/ + Q/9hZWn/x8nK//7+/v////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//7+/v/8/Pz/+/v7//r6+v/6+vr/+fn5//n5 + +f/5+fn/+fn5//r6+v/6+vr/+/v7//z8/P/+/v7//v7+//////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7/yMnK/2Jl + af86P0P/O0BE/2Zqbf/CwsP/4uLh/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9ra2v96fH7/OT9D/0NH + Sv9kY2H/aWdl/2lnZf9pZ2X/aGZk/0xOUP87QEX/PEFFyDxBRhA7QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpCRgA7QkYLPEFFwztARf9LTU//aGZk/2lnZf9pZ2X/aWdl/2dl + ZP9GSkz/Oj9D/2dqbP/Pzs7/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Li4v/Nzs7/eHt+/z9E + R/85PkL/TVFV/6Olp//y8vP///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////Lz8/+jpaf/TFFU/zk+ + Qv8/Q0f/eHt+/83Ozv/i4uL/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/83My/9tb3L/Oj9D/0VI + S/9mZGP/aWdl/2lnZf9pZ2X/aGZk/0xOUP87QEX/PEFFyTxBRhA8QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRgA7QkYGPEFFuTtARf9JTE//aGZk/2lnZf9pZ2X/aWdl/2hm + ZP9KTU//Oj9D/1hcX/+9u7v/2tra/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/h4eH/2NjY/5KU + lv9ITFD/OT5C/z5DR/93en3/1NXW//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////1NbW/3d7ff8+Q0f/OT5C/0hN + UP+SlZb/19jY/+Hh4f/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/19fW/727u/9dYGP/Oj9D/0lM + Tv9oZmT/aWdl/2lnZf9pZ2X/aGZk/0tNT/87QEX/PEFFwTxARgk9QEYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUDPEFFqTtARf9IS07/aGZl/2lnZf9pZ2X/aWdl/2ln + Zf9RU1T/O0BE/0pOUf+qqan/ysnI/93d3P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4eHh/9/f + 3/+vsLL/XWFk/ztARP85PkL/UVVZ/6Gjpf/s7e3///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////+zt7f+hpKb/UVVZ/zk+Qv87QET/XWFk/66w + sf/f39//4eHh/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/b29r/yMbF/62srP9MUVT/OkBE/09R + U/9pZ2X/aWdl/2lnZf9pZ2X/aGdl/0lMT/87QEX/PEFFszxBRAU8QUQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA6REkAPEFFiztARf9GSk3/amlo/2lnZf9pZ2X/aWdl/2po + Zf9aWlr/PUJG/z5DRv+QkJH/wsC//8vKyf/d3Nz/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/i4uL/y8zM/4CDhf9ESU3/OT5C/z1CRv9mam3/ury9//T19f////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////09fX/uru9/2drbv89Qkb/OT5C/0RJTf9/goX/y8vM/+Li + 4v/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9vb2//Ix8b/wsC+/5OUlP8/REf/PEFF/1lZ + Wf9qaGX/aWdl/2lnZf9pZ2X/a2lo/0dLTv87QET/PEFFljpAQwE8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRwA8QUUAPEFFaTxBRf9BRUn/bm1t/2xqZ/9pZ2X/aWdl/2ln + Zf9jYmH/QkZJ/zo/Q/9oa23/vLu6/8C+vf/Ix8b/2djY/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/g4OD/4eHh/9zc3P+sra//YGRn/z1CRv84PkL/QkdL/3J2eP/AwcP/9PT0//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////9PX1/8HCw/9zd3n/QkdL/zg+Qv88QUX/YGRn/6utrv/c3Nz/4eHh/+Dg + 4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/2NjY/8fGxf/Avr3/vbu7/2tucP86P0P/QkZJ/2Jh + YP9pZ2X/aWdl/2lnZf9raWf/b25t/0JHSv88QUX/PEFFczxBRQA8QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpARgA8QUUAPEFFQDxBRfE8QUX/aGhp/3VzcP9pZ2X/aWdl/2ln + Zf9pZ2X/TlBS/ztARP9GSk7/oKCg/8LAv//Avr3/w8LB/9HQz//c3Nz/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/g4OD/4ODg/+Dg4P/i4uL/0NHR/5SWmP9SVln/O0BE/zk+Qv9DSEz/b3N2/7W3uP/r7Oz///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////+vs7P+3ubr/cXV4/0NITP85PkL/O0BE/1FWWf+SlZb/0NDR/+Li4v/g4OD/4ODg/+Dg + 4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9zc3P/R0M//w8LB/8C+vf/CwL//oqGh/0dLT/87QET/TU9R/2hm + Zf9pZ2X/aWdl/2lnZf9zcW//a2tr/z1CRv88QUX2PEFFSjxBRQAxNjoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEFFGTxBRdQ7QET/WFpc/4J/ff9samj/aWdl/2ln + Zf9qZ2X/Xl5d/z9ER/86P0T/aGtt/7q5uP/Bv77/wL69/8C+vf/GxMP/0M/P/9nY2P/d3d3/4N/f/+Dg + 4P/g4OD/4ODg/+Dg4P/e3t7/3Nvb/9TT0/+xsLD/eHp8/0tPUv86P0P/OD1B/z9ESP9fY2b/mJud/9PU + 1f/19fX///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////X1 + 9f/T1NX/mpye/2BkZ/8/REj/OD1B/zo/Q/9LT1P/eHp7/7CwsP/U09P/3Nvb/97e3v/g4OD/4ODg/+Dg + 4P/g4OD/4N/f/93d3f/Z2Nj/0M/O/8bEw//Avr3/wL69/8G/vv+6ubj/aWtu/zpARP8/Q0f/XV1d/2pn + Zf9pZ2X/aWdl/2tpZ/+Bfnz/W11f/ztARP88QUXcO0FFIDxBRQBVVVUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7QkUAO0NFAzxBRaA7QET/RkpN/4B+ff97eHf/aWdl/2ln + Zf9pZ2X/aGZk/05QUv87QET/QEVI/4iJiv/Avr3/wL69/8C+vf/Avr3/wL69/8LAv//GxcT/ysnI/83M + y//Ozc3/zczM/8vKyf/HxsX/w8HA/8C+vv/Bv77/v728/6inp/96fH3/UVVY/z5DR/86P0P/O0BE/0lO + Uv9ucXX/oKOl/8zNzv/t7e7//Pz8//////////////////////////////////////////////////// + /////////////////////////////////////////////////////////Pz8/+7u7//P0NH/oKOl/21x + dP9JTlL/O0BE/zo/Q/8+Q0b/UFRX/3p8ff+op6f/v728/8G/vv/Av77/w8HA/8fGxf/Lysn/zczM/87N + zf/NzMv/ysnI/8bFxP/CwL//wL69/8C+vf/Avr3/wL69/8C+vf+HiIn/QEVI/ztARP9NUFL/aGZk/2ln + Zf9pZ2X/aWdl/3l2dP+CgH//SU1Q/ztARP88QUWsO0BEBztARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QEQAPEFFADxBRVg8QUX6PEFF/2pqa/+Kh4X/dHJw/2ln + Zf9pZ2X/aWdl/2JhYP9DR0r/O0BE/0dMT/+VlZb/wb++/8C+vf/Avr3/wL69/8C+vf/Avr3/v728/8C+ + vf/Avr3/wL69/7+9vP/Avr3/wL69/8C+vf/Avr3/wL69/8LAvv/CwL//mpqb/0pOUv87QET/PEFF/ztA + RP85PkL/Oj9D/0VKTv9fY2b/goWI/6epq//Iycr/39/g/+/v8P/5+fn//f39//////////////////// + /////////////////////////f39//n5+f/v7/D/39/g/8jJyv+nqav/goWI/2BkZ/9HTE//Oj9D/zk+ + Qv87QET/PEFF/ztARP9FSU3/kJGR/8G/vv/CwL//wL69/8C+vf/Avr3/wL69/8C+vf+/vbz/wL69/8C+ + vf/Avr3/v728/8C+vf/Avr3/wL69/8C+vf/Avr3/wL69/5KTk/9HS07/O0BE/0NHSv9iYWD/aWdl/2ln + Zf9pZ2X/cnBu/4qGhP9ubm//PUJG/zxBRf08QUVlPEFFAEFGSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRhk8QUXOO0BE/05RVP+Gg4L/iIWD/3Fv + bf9pZ2X/aWdl/2lnZf9bW1v/P0RH/zpARP9JTVH/j4+Q/768u//Bv77/wL69/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wL69/8C+vf/Avr3/wb++/7+9vP+bm5v/WFxf/zxBRf88QUX/SEtO/1FS + VP9KTVD/QUZJ/ztARP86P0P/OT5C/zxBRf9CR0r/UFRY/2BkZ/9xdHf/g4eJ/5GUlv+doKL/pKao/6iq + rP+oqqz/pKao/52gov+RlJb/g4aJ/3B0d/9gZGf/UFRY/0JHSv88QUX/OT5C/zo/Q/87QET/QUVJ/0pN + UP9RU1T/TE5Q/z1BRf88QUX/TlJV/42Ojv+7ubj/wsC//8C+vf/Avr3/wL69/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wL69/8G/vv+9u7r/i4yN/0hMUP86QET/QERI/1tbW/9pZ2X/aWdl/2ln + Zf9vbWv/hoOB/4iFhP9SVVf/O0BE/zxBRdk8QUUhPEFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JGAD5AQwA8QUV3PEFF/j1CRv9ra2v/jYqI/4aD + gf9xb23/aWdl/2lnZf9pZ2X/V1hY/z9DR/87QET/Q0hL/3Z4ev+ura3/wb++/8G/vv/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wb++/8LAv/+/vr3/qqqp/3d4ev9GSk7/OkBE/zxBRf9MTlD/ZWRj/3h1 + c/+DgX//enl4/2ZnaP9ESEv/PEFF/zxBRf88QUX9O0BE/zo/Q/85PkL/OT5C/zk/Q/86P0P/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/85P0P/OT5C/zk+Qv86P0P/O0BE/zxBRf48QUX/PEFF/0RJTP9mZ2j/eXh3/4OB + f/93dXP/aGZk/1FSVP8+Q0b/OkBE/0BFSf9pa27/oJ+g/7y6uv/CwL//wb++/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8G/vv/CwL//wL69/6qpqf9xc3X/QUZK/ztARP8/REf/WFlZ/2lnZf9pZ2X/aWdl/3Bt + a/+EgX//jYqI/3BwcP8/Q0f/PEFF/zxBRYY/UEsAPEJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPT9EADxBRQA8QUYfPEFF0TtARP9JTE//f359/42K + iP+HhIL/c3Fv/2lnZf9pZ2X/aWdl/1hZWf9BRUn/O0BE/zxBRf9SVVn/gIGD/6empv+6uLf/wL69/8G/ + vv/CwL//wsC//8G/vv++vbz/tLOz/52dnf91d3n/TVFU/ztARP87QET/P0RH/1NUVf9raWf/fnx5/4uI + hv+Nioj/jYqI/25ubv9ARUn/PEFF/zxBRco8QUVoPEFFgjxBRaE8QUW8PEFFzzxBRdk8QUXiPEFF5jxB + Rek8QUXpPEFF5jxBReI8QUXZPEFFzzxBRbw8QUWhPEFFgTxBRWo8QUXOPEFF/0FGSf9wcHD/jYqI/42K + iP+LiIb/fnt5/2xqaf9YWFn/QkZJ/ztARP86P0P/RUpO/2hrbf+RkpL/rays/7u5uP+/vr3/wb++/8G/ + vv/Avr3/vry8/7a0tP+goKD/eHp7/01RVf87QET/O0BE/0JGSf9aWlr/aWdl/2lnZf9pZ2X/cnBu/4aD + gf+Nioj/g4GA/01QU/87QET/PEFF3TxBRSk8QUUAPUFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAAD9BQgA7QUYAPEFFZTxBRfk7QEX/WVtd/4iG + hP+Nioj/iYaE/3l3df9samf/aWdl/2lnZf9fXl7/SUxO/z1CRf86P0T/PEFF/0hMUP9dYGP/c3V3/4KD + hP+IiYr/hoeI/3x+f/9qbW//VVhc/0JHS/86QET/OkBE/z1CRv9IS07/X19f/3Vzcf+Gg4H/jImH/4yJ + h/+MiYf/cXFx/0NHS/87QEX/PEFF4TxBRT48QUQAPEFDADtBRQQ7QkUJPEFFEjxBRR08QkUoPEFFLTxB + RTE8QUUxPEFFLTxCRSg7QUUdPEFFEjtCRQk8Q0QEO0BGADxBRQA8QUVEPEFF5TtARP9ESEz/dHNz/42K + h/+MiYf/jImH/4aDgf92dHL/Y2Jh/01PUf8/REf/O0BE/zo/Q/8+Q0f/TFBU/19iZP9wcnT/enx+/31/ + gP93eXv/aWtu/1ZaXf9ESEz/O0BE/zpARP89Qkb/Sk1P/2BfX/9pZ2X/aWdl/2tpZ/95d3X/iIaE/42K + iP+Kh4X/X2Bi/zxBRf88QUX9PEFFdjtETgA9QEIAOkZGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1BRAA8QUYAPEJGDTxBRag8QUX/PkNG/2Zn + aP+LiIb/jImH/4yJh/+DgH7/dHFv/2tpZ/9pZ2X/ZmRj/1dYWP9HSkz/PkJG/ztARP86P0P/Oj9D/zpA + RP87QET/O0BE/zo/Q/86P0P/Oj9D/ztARP8/Q0f/SUxO/1xcXP9ycG7/goB+/4uIhv+MiYf/jImH/4yJ + h/9wb3D/REhM/ztARP88QUXsPEFFWT5CRwA7QUYAPEFHADxBRQA7QUUAPEFFADxBRQA8QkUAPEFFADxB + RQA8QUUAPEFFADxCRQA7QUUAPEFFADtCRQA8QkUAPUNEADxBRgA7P0QAPEFFXzxBRe87QET/RUpN/3Jy + cv+MiYf/jImH/4yJh/+LiIb/g4B+/3Nxb/9gYF//TVBR/0FGSf88QUX/OkBE/zk/Q/86P0P/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/87QET/P0NH/0lMTv9aWlr/ZmVj/2lnZf9raWf/dHFv/4OAfv+MiYf/jImH/4yJ + h/9sbG3/P0RI/zxBRf88QUW5PEBFFDxARQA9QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7QUUAPEFGADtBRSk8QUXRPEFF/0BF + SP9ra2z/i4iG/4yJh/+MiYf/ioeF/4J/ff92dHL/bWtp/2poZv9lZGL/XFxb/1BSU/9HS03/QkZJ/0BE + SP8/REf/P0RH/0FFSP9ER0r/S01P/1ZXWP9mZWT/d3Vz/4SBf/+LiIb/jImH/4yJh/+Nioj/ioeF/2lq + a/9CRkr/O0BE/zxBRe88QUVmQUhCATxCRAA7QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRgA8QUYAPENJAjxBRW48QUXzO0BE/0NH + S/9sbW3/i4iG/42KiP+MiYf/jImH/4uIhv+EgX//eHZ0/2loZ/9aW1v/T1FS/0dKTf9DR0r/QUVJ/0FF + Sf9CRkn/RUhL/0tNT/9TVFX/Xl5d/2ZlY/9qaGb/bmtp/3Z0cv+Cf33/ioeF/4yJh/+MiYf/jImH/3Fx + cf9DR0v/O0BF/zxBRd48QUU3PUFFAEBFSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkcAPEJGADxBRAA8QUVFPEFF4jtB + Rf9BRUn/aGlp/4qHhf+Nioj/jImH/4yJh/+LiIb/h4SC/4B9e/94dnT/c3Fv/29ta/9raWf/Z2Zk/2Rj + Yv9jYmL/ZWRk/2ppaP9ycG7/enh2/4OAfv+JhoT/jImH/4yJh/+MiYf/jImH/42KiP+DgYD/XV9g/z9E + R/87QUX/PEFF6DxBRWA8PEICPEFEAD1CRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQA8QUYAPEFGADxARwQ8QUVpPEFF7DtA + Rf9AREj/YGJj/4WCgf+Nioj/jImH/4yJh/+MiYf/jImH/4mGhP+DgH7/e3l2/3Nxb/9ta2r/aGdl/2Zl + ZP9mZWT/aWdm/2xqaP9wbWv/c3Fv/3h2dP+AfXv/h4SC/4uIhv+MiYf/jImH/4yJh/+LiIb/b29v/0RI + S/87QET/PEFF7DxBRVY5QUMAPUBFADI2OgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFGADxBRQA8QEcAPEFFUTxB + ReQ7QUX/P0NH/15fYf+DgX//jYqI/4yJh/+MiYf/jImH/42Jh/+MiYf/i4iG/4mGhP+HhIL/hoOB/4aD + gf+IhYL/iYaE/4qHhf+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+Nioj/ioeF/3Nycv9OUVT/PEFF/zxB + Rf88QUXaPEFFT0Y0XgA8QEQAPEBEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBGADxARQA3REIBPEFFVzxB + ReA8QUX/PEFF/1FTVv92dXX/i4iG/42KiP+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+Kh4X/iYaD/4eE + gv+Gg4H/hoOB/4eEgv+JhoT/i4iG/4yJh/+MiYf/jImH/4yJh/+MiYf/jYqI/4aEgv9kZWb/QUVJ/ztA + RP88QUXuPEFFZTtGRAE9QUUAPUFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRAA8QUQAPEJGADxB + RUo8QUXYPEFF/zxBRf9NUFP/cnFx/4mGhP+Nioj/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jYqI/4qHhv95eHf/Wlxe/0BFSP87QET/PEFF/jxB + RbU8QUUyPEFGADxBRAA8QkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRAA8QkUAPUBGADxB + RTo8QUW/PEFF/ztARP9CRkr/Xl9h/317ev+LiIb/jYqI/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/42KiP+LiIb/eHd3/1NWWP89Qkb/PEFF/zxB + ReU8QUVdO0hIAjxCRgA9QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEBFADxB + RAA8QUUzPEFFtzxBRf07QET/QERI/1VYWv9zcnL/hoOC/4yJh/+Nioj/jYqI/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+Nioj/jYqI/4yJh/+Fg4H/c3Jy/1lbXf9CR0r/O0BE/zxBRf88QUXkPEFFfDxB + RRQ8QUUAPEJEADxCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEJFADtA + RAA8QUUaPEFFiTxBReo8QUX/O0FF/0RJTP9dX2D/d3Z2/4eFg/+Niof/jYqI/42KiP+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jYmH/42KiP+Nioj/iYaE/3l4d/9cXV//QkdK/ztARP88QUX/PEFFyTxB + REQ/TEYAO0JFADtDRgBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + RdI8QUXZPEFF1zxBRc48QUW5PEFFmzxBRXM8QUVCPEFGFzA9XwA8QUUAPEFEAD5ESAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPj5EADY/QQA5PEAAO0FEADxBRQA8QUUAPEBGADxCRQU8QUULPEFFDjxB + RQ88QUUMPEFECDtAQgI8QUUAPEFFADxARQA9P0UAO0NGAEM6PwAAgIAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAyR08APEJFADxBRQA8QUUAPEFFADtBQwA8QUYHPEFFDTxB + RhI8QUUZPEFFFjxBRRA7QUUKO0BHAjxBRQA8QUUAPEFGADtBRwA9O0oAOkVGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+QkYAPEJEADxBRQA8QUUAPEFFADxB + RQA8QUUAPEFFADxBRAA/PkMAPj5EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAOkFJAD1BRgA8QUYAPEFFADxB + RgA8QUUAPEFFADxBRQA7QUUAPEFGADk9QgA6PkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAD///////////////////8A////////////////////AP///////////////////wD///////////// + //////8A//////8AAAAAAP//////AP///+AAAAAAAAAAB////wD///4AAAAAAAAAAAB///8A///gAAAA + AAAAAAAAB///AP//4AAAAAAAAAAAAAf//wD//+AAAAAAAAAAAAAH//8A///gAAAAAAAAAAAAB///AP// + 4AAAAAAAAAAAAAf//wD//+AAAAAAAAAAAAAH//8A///wAAAAAAAAAAAAD///AP///4AAAAAAAAAAAf// + /wD////8AAAAAAAAAD////8A//////8AAAAAAP//////AP/////+AAAAAAA//////wD////4AAAAAAAA + AB////8A////wAAAAAAAAAAD////AP///gAAAAAAAAAAAH///wD///AAAAAAAAAAAAAP//8A///gAAAA + AAAAAAAAB///AP//wAAAAAAAAAAAAAP//wD//wAAAAAAAAAAAAAA//8A//4AAAAAAAAAAAAAAH//AP/8 + AAAAAAAAAAAAAAA//wD/+AAAAAAAAAAAAAAAH/8A//AAAAAAAAAAAAAAAA//AP/gAAAAAAAAAAAAAAAH + /wD/4AAAAAAAAAAAAAAAB/8A/8AAAAAAAAAAAAAAAAP/AP+AAAAAAAAAAAAAAAAB/wD/AAAAAAAAAAAA + AAAAAP8A/wAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA/wD+AAAAAAAAAAAAAAAAAH8A/gAAAAAA + AAAAAAAAAAB/APwAAAAAAAAAAAAAAAAAPwD8AAAAAAAAAAAAAAAAAD8A+AAAAAAAAAAAAAAAAAAfAPgA + AAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPAAAAAAAAAAAAAAAAAA + DwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAA + AAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAA + AAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAA + AAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAA + DwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAA + AAAAAA8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAA + AAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD8AAAAAAAAAAAAAAAAAD8A/AAAAAAAAAAAAAAAAAA/APwA + AAAAAAAAAAAAAAAAPwD+AAAAAAAAAAAAAAAAAH8A/gAAAAAAAAAAAAAAAAB/AP4AAAAAAAAAAAAAAAAA + fwD/AAAAAAAAAAAAAAAAAP8A/wAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA/wD/gAAAAAAAAAAA + AAAAAf8A/4AAAAAAAAAAAAAAAAH/AP/AAAAAAAAAAAAAAAAD/wD/wAAAAAAAAAAAAAAAA/8A/4AAAAAA + AAAAAAAAAAH/AP+AAAAAAAAAAAAAAAAB/wD/AAAAAAAAAAAAAAAAAP8A/wAAAAAAAAAAAAAAAAD/AP4A + AAAAAAAAAAAAAAAAfwD+AAAAAAAAAAAAAAAAAH8A/gAAAAAAAAAAAAAAAAB/APwAAAAAAAAAAAAAAAAA + PwD8AAAAAAAAAAAAAAAAAD8A/AAAAAAAAAAAAAAAAAA/APgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAA + AAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAA + AAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgA + AAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAA + HwD8AAAAAAAAAAAAAAAAAB8A/AAAAAAAAAAAAAAAAAA/APwAAAAAAAAAAAAAAAAAPwD+AAAAAAAAAAAA + AAAAAD8A/gAAAAAAAAAAAAAAAAB/AP4AAAAAAAAAAAAAAAAAfwD+AAAAAAAAAAAAAAAAAH8A/wAAAAAA + AAAAAAAAAAD/AP+AAAAAAA//8AAAAAAA/wD/gAAAAAAf//AAAAAAAf8A/8AAAAAAP//8AAAAAAP/AP/g + AAAAAH///gAAAAAH/wD/8AAAAAD///8AAAAAB/8A//gAAAAB////gAAAAB//AP/8AAAAA////8AAAAA/ + /wD//wAAAA/////wAAAAf/8A///AAAA//////AAAAf//AP//4AAA//////8AAAf//wD///8AH/////// + 8AB///8A////////////////////AP///////////////////wD///////////////////8A//////// + ////////////AA== + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Forms/FrmTransparent.Designer.cs b/JinYuan.ControlLib/Forms/FrmTransparent.Designer.cs new file mode 100644 index 0000000..73670a4 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmTransparent.Designer.cs @@ -0,0 +1,73 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib.Forms +{ + /// + /// Class FrmTransparent. + /// Implements the + /// + /// + partial class FrmTransparent + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmTransparent)); + this.SuspendLayout(); + // + // FrmTransparent + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(284, 262); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "FrmTransparent"; + this.Opacity = 0.5D; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "FrmTransparent"; + this.Load += new System.EventHandler(this.FrmTransparent_Load); + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/Forms/FrmTransparent.cs b/JinYuan.ControlLib/Forms/FrmTransparent.cs new file mode 100644 index 0000000..a7689f2 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmTransparent.cs @@ -0,0 +1,169 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.Forms +{ + /// + /// Class FrmTransparent. + /// Implements the + /// + /// + public partial class FrmTransparent : FrmBase + { + /// + /// The wm activate + /// + private const int WM_ACTIVATE = 6; + + /// + /// The wm activateapp + /// + private const int WM_ACTIVATEAPP = 28; + + /// + /// The wm ncactivate + /// + private const int WM_NCACTIVATE = 134; + + /// + /// The wa inactive + /// + private const int WA_INACTIVE = 0; + + /// + /// The wm mouseactivate + /// + private const int WM_MOUSEACTIVATE = 33; + + /// + /// The ma noactivate + /// + private const int MA_NOACTIVATE = 3; + /// + /// Gets the create parameters. + /// + /// The create parameters. + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED + return cp; + } + } + /// + /// Gets or sets the frmchild. + /// + /// The frmchild. + public FrmBase frmchild + { + get; + set; + } + /// + /// Initializes a new instance of the class. + /// + public FrmTransparent() + { + InitializeComponent(); + + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + + MethodInfo method = base.GetType().GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod); + method.Invoke(this, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, new object[] + { + ControlStyles.Selectable, + false + }, Application.CurrentCulture); + } + + /// + /// 引发 事件。 + /// + /// 一个包含事件数据的 。 + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + base.ShowInTaskbar = false; + base.ShowIcon = true; + } + /// + /// Sets the active window. + /// + /// The handle. + /// IntPtr. + [DllImport("user32.dll")] + private static extern IntPtr SetActiveWindow(IntPtr handle); + + /// + /// WNDs the proc. + /// + /// 要处理的 Windows 。 + protected override void WndProc(ref Message m) + { + if (m.Msg == 33) + { + m.Result = new IntPtr(3); + } + else + { + if (m.Msg == 134) + { + if (((int)m.WParam & 65535) != 0) + { + if (m.LParam != IntPtr.Zero) + { + FrmTransparent.SetActiveWindow(m.LParam); + } + else + { + FrmTransparent.SetActiveWindow(IntPtr.Zero); + } + } + } + else if (m.Msg == 2000) + { + } + base.WndProc(ref m); + } + } + + /// + /// Handles the Load event of the FrmTransparent control. + /// + /// The source of the event. + /// The instance containing the event data. + private void FrmTransparent_Load(object sender, EventArgs e) + { + if (frmchild != null) + { + frmchild.IsShowMaskDialog = false; + var dia = frmchild.ShowDialog(this); + this.DialogResult = dia; + } + } + } +} diff --git a/JinYuan.ControlLib/Forms/FrmTransparent.resx b/JinYuan.ControlLib/Forms/FrmTransparent.resx new file mode 100644 index 0000000..be524d1 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmTransparent.resx @@ -0,0 +1,1185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAeIAAAAEAIAAo+AAAFgAAACgAAAB4AAAAAAEAAAEAIAAAAAAAAPAAAGDqAABg6gAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVAG9vbwBCQkQAPz9LADw9 + RQA7P0cAPEBHAD1ARgA9QUYAO0BGADtDRQA7QUEAO0BAADk+PgA9QkIAPkJCADtBRAA4RkgAOUZGADxA + QAA8QEAAOUZGADhGSAA7QUQAPkJCAD1CQgA5Pj4AO0BAADtAQQA7QEUAO0BGAD1BRgA9QEYAPEBHADs/ + RwA8PUUAPz9LAEJCRABvb28AVVVVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVVUAGRksAD4+ + RAA4QUUAOEBEADk7PABBQ0MAO0NFADs/RwA6QUUAPENDADxDQwA8Q0MAPENDADtCQwA1REIASjRkADw3 + RgE6PUoBPD9JAT0/RwI9QEcCO0BGAjtDRQI7QUEDO0BABDk+PgQ+QkIEPkJCBTtBRAU4R0gFOUZGBTxA + QAY8QEAGOUZGBThHSAU7QUQFPkJCBT5CQgQ5Pj4EO0BABDtAQQM7QEUCO0BGAj1ARwI9P0cCPD9JATo9 + SgE8N0YBSjRkADVEQgA7QkMAPENDADxDQwA8Q0MAPENDADxBQwA8QUcAPUFIADdGSQA3SUkAOz9DADlC + RgBAP0UAGxsvAFVVVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0tQwAkIz8APDxLADxCRAA8QkUAO0JEADtE + QwBaUDUAMztIADo8PwFBQ0MDO0NFBDtARgY4P0cIPEFDCz1BRQ08QkUPPEFDETtBRBM8Q0MVPENEFzxC + Qxk8QkQaPEJEGzxCRBw8QkQdPEJEHjxDRB88Q0MgPENDIDxDQyA8Q0MhPENDITxDQyE8Q0QhPENDITxD + QyI8Q0MiPENDITxDRCE8Q0MhPENDITxDQyE8Q0MgPENDIDxDQyA8QkQfPEJEHjxCRB08QkQcPEJEGzxC + RBo8QkMZPENEFzxDQxU7QUQTPEFDETxCRQ89QUUNPEFBCzo/QQg8QUcGPUFHBTdFSAM4R0gBNTtIAFFJ + MAA6REMAO0JEADxCRQA8QEQAPD1LACQjPwAtLUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAMzMzAERQVAA+RkgAPkNFAD1CRABETUMAPDtNATxCRAQ8QkUIO0JFDDxC + RBA7QkQVO0JEGTxCQxw8Q0MePENDIDxCRCI8Q0QkPENDJTxDQyU8Q0MmPENDJjxDQyY8Q0MnPENDJzxD + Qyc8Q0MnPENDJzxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxD + Qyc8Q0MnPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MlPENDJTxDQyQ8Q0QjPENEITtDRB88Q0QcO0JEGTtD + RBU8QkQQO0JFDDxBRQg8P0QEPDtNAURMQwA8QkQAPkNFAEBHSgBHUlYAMzMzAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPkREAEBGRwA4SlMAPUJEBTtBQgw8Q0QUPEJEGzxDQyA8Q0MjPENDJTxD + QyY8Q0MmPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MnPENDJzxD + QyY8Q0MmPENDJTxDQyM8QkMgPEJEGzxERBQ8QUIMPUJEBUJVXwBBRkcAPkREAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAP0REAEFDRAI8QkMTPENDIDxDQyU8Q0MmPENDJzxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxDQyY8Q0MlPENEIDxCRBNBQ0QCP0REAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPkNDAD9ERAY8QkMhPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MnPENDJz1CQyFAREQGPkNEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAP0BAAD86PAA7P0IIPUJEFDxCRB48Q0MjPENDJjxDQyY8Q0MnPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyc8Q0MmPENDJjxDQyM8QkMePUJDFDtAQghDP0AAQ0NEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQEBAAEE+QAA7P0IAEjkEADlDRgM5QkIIOkNEDjxCRBQ8Q0MZPEJDHjxD + QyE8Q0MjPENDJTxDQyY8Q0MmPENDJjxDQyc8Q0MnPENDJzxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJTxDQyQ8Q0MjPENDIzxDQyQ8Q0MlPENDJTxD + QyY8Q0MmPENDJTxDQyU8Q0MkPENDIzxDQyI8Q0MjPENDJTxDQyU8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxDQyc8Q0MnPENDJjxDQyY8Q0MmPENDJTxD + QyM8Q0MhPEJDHjxDQxk8QkQUO0NFDjpDQgg7PkYDE3Y6ADs/QgBFQUQAREREAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQAAADYAPUZMADhERQA7Q0MAPENCAEFJSAA8QkQBO0BEAjtB + RgU5Q0QIPUFECzxBQg49Q0IRPENEFDxBRRc8QkUaPEJDHTxDQx48Q0MgPEJDITxDRCM8Q0MkPENDJDxD + QyU8Q0MlPENDJTxDQyY8Q0MmPENDJDxDQyM8Q0MlPENDMDxCREM8QkVcPEFFdDxBRYs8QUWdPEFFqTxB + RbA8QUWyPEFFrjxBRaU8QUWXPEFFhDxCRW08QkRVPEJDPTxCQy08Q0MkPENDIzxDQyU8Q0MmPENDJTxD + QyU8Q0MlPENDJDxDQyQ8Q0QjPEJDITxDQyA8Q0MePEJDHTxCRBo8QkUYPEJFFTxDRBI9QkMPPkFECzpE + RQg7QUcFOz9EAj5ERgE+RkYAPUNDADxERAA6PkYAPTtHAAAABwBVVVUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODg4ADAzMgA8QkQAO0BEADtC + RgA6Q0QAPUFEAD5ERgA6REQAPkM+AAAA/wBAQ1sBOjxHAjxCRQM7QEUEOkBFBTtCRQY9Q0MIPEFECTxC + Qws9QkUMO0JEDTxBRAs9Q0QRPEFGLTxBRWA8QUWaPEFFxjxBReQ8QUX1O0BE/jtARP87QET/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/87QET/O0BE/zxBRfw8QUXwPEFF3jxBRb08QUWNPEFFUjxCRSM8QUUNO0NECztC + RQw8QkMLPEFECT1DQwg7QkUGOkBFBTtARQQ8QkUDOjxHAkRDWQFAL24AOksuADxDQAA8QkQAPUFEADpE + RQA7QkYAO0BEAD1ERQA1OTgAPz8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARkZGAC0tLQBAQUEAO0NFAEhPOgBGR2MAOjtHAD1CRgA7QEYAOj9FADtCRQA8Q0MAPEJDADxC + RAA8QUUAO0JGDDxBRUQ8QUWUPEFF1TxBRfc7QET/Oj9D/zo/Q/88QUX/REhM/0tQU/9SV1r/Wl5i/19j + Zv9hZWj/XWFl/1dbX/9PVFf/SU1R/0FGSv87QET/Oj9D/zo/Q/87QET/PEFF8jxBRck8QUWBPEFFMztD + SAU8QUUAO0JEADxDQwA7QkUAOj9FADtARgA9QkYAOjtHAEdHYwBHUDwAPUFIADxDRwBCQkEAR0dHAEBA + QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0BGADxBRQA8QEYAPEFGAD1B + RQ08QUVUPEFFtjxBRfI7QET/Oj9D/z1CRv9MUVT/aGxv/4mMjv+oqqv/vr/A/8/Q0f/b3Nz/4ODh/+Li + 4//j4+P/4eHi/97f3//X2Nn/ysvM/7i5u/+goqT/gIOG/2FlaP9HTFD/O0BE/zo/Q/87QET/PEFF6DxB + RaA8QUU+OUJGBTxCRQBCQ0UAP0NGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QUQASzZFADxBRQA8P0gDPEFFRjxB + RbM8QUX2O0BE/zo/RP9KT1P/c3d5/6aoqf/P0NH/5+fn//Dw8P/z8/P/8/Pz//Ly8v/x8fH/8fHx//Hx + 8f/x8fH/8fHx//Hx8f/y8vH/8vLy//Pz8//y8vL/7+/v/+Lj4//HyMn/m52f/2hsb/9ESU3/Oj9D/ztA + RP88QUXsPEFFljxBRSg5P0QAPEFFAD1ARQA2Q0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBM + UwAmWGIAPEFGADxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRR08QUWMPEFF7TtA + RP87QET/UlZa/42Qkv/Jy8v/6urq//Ly8v/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/y8vL/8vLy/+Xl5f+9vr//fH+C/0hN + Uf86P0P/PEFF/zxBRdc8QUVgPEBEBzxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRQA8QUUAO0FFADRL + TwA2SEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRQA7REQAPEFFADxB + RQA8QUQAPUJEADxARQI8QUUFPEFFBzxBRQg8QUUIPEFFCDxBRQg8QUUIPEFFPzxBRcU8QUX/Oj9D/0pP + U/+LjZD/0NHS//Dw8P/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/z8vL/6+zs/8HD + xP90eHr/QUZJ/zo/RP88QUX1PEFFkTxBRRo8QUUHPEFFCDxBRQg8QUUIPEFFCDxBRgY7QkYDPUBEADxB + RQA8QUUAPEFFAD1DQwA9Q0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA9QUUAPEFFADxBRQA3W0UAPEFFFDxB + RTQ8QUVdPEFFgDxBRZ08QUWxPEFFvDxBRcI8QUXDPEFFwzxBRcM8QUXEPEFF5ztARP89Qkb/bXF0/8LD + xP/u7u7/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/n5+j/qKmr/1RYXP86P0P/PEFF/TxBRdM8QUXCPEFFwzxBRcM8QUXDPEFFvjxBRbM8QUWfPEFFgzxB + RWA8QUU3PEFFFT1HPwE8QUUAPUFFAD1ARAA9QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/RUcAP0RGAD1BRQA7QUUAPEFFFDxBRUs8QUWSPEFFyzxB + Re08QUX8O0BE/zo/Q/86P0P/Oj9D/zo/Q/86P0P/Oj9D/zo/Q/86P0P/OT5C/0VKTv+SlZf/4uPj//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/x8fH/8fHx/8vMzf9rb3L/O0BE/zk+Q/86P0P/Oj9D/zo/Q/86P0P/Oj9D/zo/Q/86P0P/O0BE/zxB + Rf08QUXuPEFFzjxBRZU8QUVQPUFGFztCRgA8QUUAO0BCAD0+QAAAgIAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAOkVGAC5fRwA8QUUAOj9FAD1BRSI8QUV1PEFFyDxBRfU7QET/OT5D/ztA + RP9BRkr/TlNW/1tfYv9mam3/b3N1/3N2ef90d3r/c3d6/3N3ev9zdnn/eHx+/7O1t//t7e3/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/c3N3/j5GT/3N2ef9zd3r/c3d6/3N3ev9zd3r/cHR3/2hsbv9cYGP/T1RX/0JH + Sv87QET/OT5D/ztARP88QUX3PEFFyzxBRXc8QUUjPUNGADxBRAAoblQAOkVGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAA8QEUAPUFGADxARQA8QUUZPEFFdjxBRdY8QUX+Oj9D/zxBRf9NUlX/cHN2/5ib + nf+7vb7/0dLT/+Dh4f/o6On/6urr/+vr6//r6+v/6+vr/+vr6//r6+v/7Ozt//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/7+/v/+vr6//r6+v/6+vr/+vr6//r6+v/6uvr/+np6f/i4uL/09TU/72/ + wP+bnZ//cnZ4/05TVv88QUX/Oj9D/zxBRf88QUXYPEFFdztCRBk8QEUAPUFEAD1ARAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAOkJCAD1BRgA8QUQAPT9GBDxBRU88QUXFPEFF/jo/Q/8/REj/YmZp/5yeoP/Pz9D/6enq//Ly + 8v/z8/P/8vLy//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8vLy//Pz + 8v/y8vL/6urq/9DR0v+eoKL/Y2dq/0BFSf86P0P/PEFF/jxBRcY8QUVPPkBEBD1BRQA7QUQAP0BHAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA+QUYAQEFGADxBRQA8QUQVPEFFijxBRfA7QET/PUJG/2Jmaf+qrK3/4OHh//Ly8v/y8vL/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/y8vL/4eHi/6utr/9jZ2r/PUJG/ztARP88QUXwPEFFij1BRRU8QUUAOEdJADpF + RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADpE + RwA8Q0cAO0FFADxBRSo8QUW1PEFF/jo/Q/9NUlb/mJqc/97e3//y8vL/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/7+/v/9PU + 1P/T1NT/7+/v//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/e39//mZud/05TVv86P0P/PEFF/jxBRbQ8QUUrPj9DADtB + RAA7PkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOURIADpE + RwA9P0UAPEJGOzxBRc07QUX/PEFF/2hsb//Excb/8PDw//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/0NHS/1ld + YP9ZXWD/0NHS//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8PDw/8XGx/9pbXD/PEFF/zxBRf88QUXNPEFFOjxD + RwA9QEMAP0NGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QEMAO0JGAD1A + QwA8QUVAPEFF1ztARP8/REj/goWI/93d3v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0BF + SP9ARUj/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/d3t7/goSH/z9ESP87QET/PEFF1jxB + RT48QEQAPUFFADw/QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlCQwA6P0IAPEJGADxB + RTk8QUXXO0BE/0JHSv+TlZf/5+jo//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0FG + Sf9BRkn/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8fH/5+fn/5GUlv9BRkr/O0BE/zxB + RdU8QUU3PEJGAD09QABAQEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1ARQA8QEUAPEFFKDxB + Rcs7QET/QUZK/5eanP/r6+v/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0FG + Sf9BRkn/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+vr6/+WmZv/QUZK/ztA + RP88QUXJPEFFJzxBRQA7QUYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBGADxARQA7QEQTPEFFsDxB + Rf8+Q0f/kZOV/+vr6//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/19fX/ury9/0FG + Sf9BRkn/ury9//X19f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/q6+v/kJOV/z5D + R/88QUX/PEFFrj1BRRI8QUUAPEJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9PUcAPEBGADw/RwM8QUWEPEFF/TtA + RP9/goX/5ufn//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/6+vs/9LT0/+xs7T/fH+C/z5D + R/8+Q0f/fYCD/7O1tv/U1db/7e3t//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5ubm/36B + hP87QET/PEFF/TxBRYM7REQDPEJFAD09SQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAA/wAAPEFFADxBRUw8QUXuOj9D/2Zq + bf/b29z/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/+vr6/+8vr//en1//09TV/8+Q0f/O0BE/zxB + Rf88QUX/O0BE/z9DR/9RVln/gIOF/8PFxv/t7e7/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9rb + 2/9laWz/Oj9D/zxBRe48QUVLPEJEADtMKQArVVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRgA8QUUAPEFFGTxBRcU7QET/TVFV/8LD + xP/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/2NnZ/4SHif9GSk7/OT5C/zo/Q/89Qkb/QEVI/0JG + Sf9CRkn/QERI/z1CRv86P0P/OT9D/0pOUv+Mj5H/3t/f//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/BwsP/TFBU/ztARP88QUXDPEFFGDxBRQA5QUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRQA/OUIAPEFFezxBRf49Qkb/l5qc//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/KzMz/ZGdr/zo/Q/87QET/QEVI/01QUf9aW1r/YmFg/2Rj + Yf9kY2H/YWFg/1laWv9MTlD/P0RH/zpARP88QUX/bnF0/9TV1f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/v7+//lpmb/z1CRv88QUX+PEFFeEM+RQA5QkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JEADxBRQA8QUUrPEFF3To/Q/9kaGv/39/g//Hx + 8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9DR0v9eYmb/OT9D/zxBRf9KTU//X19e/2hnZf9qaGX/aWdl/2ln + Zf9pZ2X/aWdl/2poZf9oZmT/XV1d/0hLTf88QUX/Oj9D/2lsb//Y2dr/8vHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/x8fH/3t/f/2Roa/86P0P/PEFF3DxBRSk8QUUAPEJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0FFADpCQwE8QUWJPEFF/0JHS/+xs7T/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/5OTk/3J1eP86P0P/PUJG/1BSU/9mZWP/amdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/amhl/2VjYv9NT1H/PEFF/zpARP98gIL/6Ojo//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy/7Cys/9CRkr/PEFF/zxBRYc+QEkBPEFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5RkgAPEJFADxBRSc8QUXeOj9D/25ydf/m5+f/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/y8vL/qKqr/z5DR/88QUX/TlBS/2dlZP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9mZGP/S05Q/ztARP9BRkr/sLKz//Ly8v/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx/+bm5v9tcXT/Oj9D/zxBRd08QUUmPEFFAD1ARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1SkwAPz5CADxBRXg8QUX/QUZK/7K0tf/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/m5+f/am5x/zk+Qv9ESEv/Y2Jh/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qZ2X/YWFg/0JGSf85PkL/b3J1/+jo6P/x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v+xs7T/QUZK/zxBRf88QUV1PEFGADs/QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA8QUUAPEFGFDxBRcg6P0P/ZGhr/+Li4//x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/U1NX/TlJW/zo/RP9RU1T/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1BSU/86P0P/T1NX/9XW1v/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/h4uL/YmZq/zo/Q/88QUXGPEJFEjxBRQA9PUkAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFA7OQA8QUUAPEFFSjxBRfU8QUX/nJ6g//Ly8v/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/Oz9D/Sk9S/ztARP9UVVb/amhm/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amhm/1RVVv87QET/Sk9S/87P0P/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/y8fH/mpye/ztARP88QUX0PEFFSDxBRQA5L1QAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtBRAAfAAAAPEFFjztARP9MUVT/zs7P//Ly8v/w8PD/8fHw//Hx + 8P/v7/D/7/Dw//Hx8P/x8fD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/f4OD/XWFk/zk/Q/9FSUv/YWFg/2poZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qaGX/YWFg/0VIS/85P0P/XWFk/9/g4P/x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8P/x8fD/7/Dw/+/v + 8P/x8fD/8fHw//Dw8P/y8vL/zM7O/0tQVP87QET/PEFFjStPRAA+QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtBRQA7QUUTPEFFyzo/Q/9vc3b/6enp//Hx8P/w8PD/4eTy/8bO + 9/+2wvn/t8L5/8jQ9v/k5vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/nZ+h/z1CRv87QET/RUhL/1lZWf9lZGL/aWdl/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2pnZf9qaGX/aWdl/2ZkY/9ZWVr/REhL/ztARP8+Q0f/nqCi//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+Tm8v/I0Pb/t8L5/7bC + +f/Gzvf/4eTy//Dw8P/x8fD/6Onp/25xdP86P0P/PEFFyT1BRhI9QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQEBAADxBRQA8QUU5PEFF7ztARP+bnZ//8vLy/+/w8P/P1vX/obD9/5Sm + //+Spf//kqX//5Sm//+ks/z/1dr1//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/5eXm/4SHif8+Q0f/Oj9D/z1CRv9GSUz/UVNU/1pbW/9gYF//Y2Jh/2Rj + Yv9kY2L/Y2Jh/2BgX/9aW1v/UVNU/0ZJTP89Qkb/Oj9D/z5DR/+Fh4r/5ebm//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/1Nr1/6Sz/P+Upv//kqX//5Kl + //+Upv//obD9/8/W9f/w8PD/8vLy/5mcnv87QET/PEFF7jxBRTg8QUUAN0lJAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAMUVXADxBRQA8QUVpO0BE/kRJTf/BwsP/8/Py/9fc9P+crP7/k6X//5Sm + //+Upv//lKb//5Sm//+Tpf//oLD9/93h8//x8fD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+bm5/+eoKL/VFlc/zxBRf85PkL/O0BE/z1CRv8/REf/QkZJ/0NH + Sv9DR0r/QkZJ/z9ER/89Qkb/O0BE/zk+Qv87QET/VFhc/56gov/m5+f/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8P/d4fP/oLD9/5Ol//+Upv//lKb//5Sm + //+Upv//k6X//5yt/v/Y3PT/8/Py/8DCw/9ESEz/O0FF/jxBRWg8QUUATC0+AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFAD5CRQE8QUWYOj9E/1ZaXv/b29z/7u/y/7K++v+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//7nE+f/v7/D/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx + 8f/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/w8PD/1dXW/5yfoP9obG//TFBU/z5DR/87QET/OT9D/zk+ + Qv85PkL/OT9D/ztARP8+Q0f/TFBU/2hsb/+anJ7/09TV//Dw8P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx + 8f/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+/v8P+5xPn/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+yvvr/7u/y/9rb2/9VWl3/OkBE/zxBRZY+RUkBPEJGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRQw8QUW9OT5C/21xdP/r6+r/5Ofy/5+v/f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6Wz/P/p6vH/8PDw//Dw8P/w8PD/8PDw//Ly8v/x8fH/6Ojo/+Hh + 4f/g4OH/5eXm/+7u7v/y8vL/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//Hx8f/n5+f/z9DQ/7W3uP+doKH/j5GU/4eK + jP+Hioz/j5GU/52gof+2t7j/z9DQ/+fn5//x8fH/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//Ly8v/u7u7/5eXm/+Dg + 4f/h4eH/6Ojo//Hx8f/y8vL/8PDw//Dw8P/w8PD/8PDw/+jq8f+ls/z/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+fr/3/5Ofy/+rq6v9scHP/OT5C/zxBRbw8QUULPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFGADxBRho8QUXZOj9D/4aJi//x8fD/4OPz/5ys/v+Tpv//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6Gw/f/l5/L/8fHw//Dw8P/x8fH/7e3t/8bHyP+PkpT/bHBz/1xg + ZP9bX2L/Zmpt/36ChP+mqKr/0dLT/+zs7P/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8vLy//Pz8//y8vL/8vLy//Hx + 8f/x8fH/8vLy//Ly8v/z8/P/8vLy//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/s7Oz/0dLT/6aoqf9+gYT/Zmpt/1tf + Yv9cYGT/bHBz/4+SlP/Gx8j/7Ozt//Hx8f/w8PD/8fHw/+Xn8v+hsP3/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Om//+crP7/4OPz//Hx8P+FiIr/Oj9D/zxBRdk8QUUaPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRS88QUXoO0BE/52fof/z8vL/5ujy/6Kx/f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6i2/P/q6/H/8PDw//Ly8f/e3t//i46Q/0lOUv86P0P/OT5C/zk/ + Q/85P0P/OT5C/zk+Qv89Qkb/T1NX/3p9gP+3ubr/5eXl//Ly8v/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/y8vL/5eXl/7e5uv97foH/T1NX/z1BRf85PkL/OT5C/zk/ + Q/85P0P/OT5C/zo/Q/9JTlH/iYyP/97e3//y8vH/8PDw/+rr8f+ntvz/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+isf3/5ujy//Py8v+cnqD/O0BE/zxBRec8QUUuPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRUE8QUXzPEFF/66wsf/z8/P/7+/w/7nE+f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//lKb//8HK+P/w8PD/8fHx/9vb3P9xdHf/O0BE/ztARP8/REf/R0tN/01P + Uf9OUFL/Sk1P/0NHSv89Qkb/Oj9E/zk+Q/9DR0v/am1w/6+wsv/k5eX/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/+Tl5f+usLL/am1w/0JHS/85PkP/Oj9E/z1CRv9DR0r/Sk1P/05Q + Uv9NUFH/R0tN/z9DR/87QET/O0BE/3F1eP/b3Nz/8fHx//Dw8P/Byvj/k6b//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+6xPn/7+/w//Pz8/+tr7H/PEFF/zxBRfI8QUVAPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRU08QUX6QUZJ/7m6vP/z8/P/8fHw/+Dj8/+ks/z/k6X//5Sm + //+Upv//lKb//5Sm//+Tpf//qbf8/+Xn8v/x8fH/6Ojo/36Bg/87QET/PEFF/0lMTv9dXV3/Z2Vj/2ln + Zf9pZ2X/aGZk/2RjYf9bW1v/TU9R/0FFSf87QET/OT5C/0BFSf9tcXP/vL2+/+zt7f/y8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Lx8f/s7O3/u72+/21wc/9ARUn/OT5C/ztARP9BRUj/TU9R/1tbW/9kY2H/aGZk/2ln + Zf9pZ2X/Z2Vj/11dXf9ITE7/PEFF/ztARP9+goT/6Ojp//Hx8P/k5/L/qbf8/5Ol//+Upv//lKb//5Sm + //+Upv//k6X//6Sz/f/g4/P/8fHw//Pz8/+4urv/QEVJ/zxBRfo8QUVNPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVc7QET+RUlN/8DCw//z8/L/8PDw//Hw8P/c4PP/rrv7/5ip + /v+Upv//lKb//5mq/v+yvvr/4OPz//Hx8P/y8vL/rK6w/0FFSf87QET/Sk1P/2VjYv9qaGX/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/aGZl/2FgX/9SU1T/QkZJ/ztARf85PkP/R0tP/4mLjv/a2tv/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy/9ra2/+Ii47/RktP/zk+Q/87QEX/QkZJ/1JUVf9hYF//aGZl/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2poZf9lY2L/Sk1P/ztARP9BRkr/ra+w//Ly8v/x8fD/4OPz/7K++v+Zqv7/lKb//5Sm + //+Yqf7/rrv7/9zg8//w8PD/8PDw//Pz8//AwcL/RElN/ztARP48QUVWPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRV07QET/R0tP/8XHyP/y8vL/8PDw//Dw8P/x8fD/6uvx/9fc + 9P/J0fb/ytL2/9nd9P/s7PH/8fHw//Hx8f/i4uP/ZWls/zk+Q/9DR0r/YmFg/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/YmFg/1FTVP9ARUj/O0BE/ztARP9jZ2r/wcLD//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/wMLD/2Jmaf87QET/O0BE/0BFSP9RU1T/YmFg/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/YWFg/0NHSv85PkL/Zmpt/+Lj4//x8fH/8fHw/+zs8f/Z3fT/ytH2/8nR + 9v/X3PT/6uvx//Hx8P/w8PD/8PDw//Ly8v/Fxsf/RktP/ztARP88QUVcPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVw7QET/R0tP/8jJyv/z8/P/8PDw//Dw8P/w8PD/8PDw//Hx + 8P/x8fD/8fHw//Hx8P/w8PD/8PDw//Py8v+5urv/QkdK/zxBRf9UVVb/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9fXl7/SUxO/zxBRf86P0P/TlNW/6yu + sP/u7u7/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+7u + 7v+srrD/TlNW/zo/Q/88QUX/SUxO/15eXv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1NVVf87QET/QkdL/7m7vP/z8vL/8PDw//Dw8P/x8fD/8fHw//Hx + 8P/x8fD/8PDw//Dw8P/w8PD/8PDw//Pz8//Hycr/RktP/ztARP88QUVbPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVY7QET+RUlN/8fIyf/09PT/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+KjY//OT9D/0FFSP9hYF//aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qZ2X/ZmRj/1JUVf8/Q0f/Oj9D/0ZL + T/+jpaf/7u7u//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fD/7e7u/6Kk + pv9GS0//Oj9D/z9DR/9TVFX/ZmRj/2pnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2FgX/9ARUj/OT9D/4qNj//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//T09P/GyMn/RElN/ztARP48QUVVPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRUw8QUX6QEVJ/8HCw//39vb/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+bm5/9na27/OT5C/0lLTv9nZWT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9ZWVr/QUVJ/zo/ + Q/9GSk7/p6mr/+/v7//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/p6mr/0ZK + Tv86P0P/QUVJ/1laWv9oZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dlZP9IS07/OT5C/2hrbv/m5+f/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//f39v/AwsP/QEVJ/zxBRfk8QUVLPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRT88QUXxPEFF/7W3uf/6+vr/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vHx/9jZ2f9TV1v/Oj9D/1BSVP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/XFtb/0FF + Sf86P0P/S1BU/7u9vv/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Lx8f+8vb7/TFBU/zo/ + Q/9BRUn/W1tc/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9QUlP/Oj9D/1NXW//Y2dr/8vHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//r6+v+1t7j/PEFF/zxBRfE8QUU+PEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRSw8QUXmOj9D/6Kkpv/8/Pz/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8zNzv9HTE//O0BE/1ZXV/9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1pa + Wv8/REf/Oj9D/15iZf/X2Nn/8vLx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLx/9fY2P9eYWX/Oj9D/z9E + R/9aWlv/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9WV1f/O0BE/0dMUP/Mzs7/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//z8/P+hpKb/Oj9D/zxBReY8QUUsPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRBg8QUXXOT5C/4mMjv/9/f3/8/Pz//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8LDxP9ESEz/PEFF/1lZWv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9UVVb/PUJF/ztARP+Ii43/7e3t//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/7e3t/4eKjf87QET/PUJG/1RV + Vv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9ZWVn/PEFF/0RITP/CxMX/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8/Pz//39/f+JjI7/OT5C/zxBRdc8QUUYPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxCRQs8QUW5OT5C/29ydf/39/f/9/f3//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/7/Awf9DSEv/PEFF/1paWv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2lnZf9pZ2X/aWdl/2ln + Zf9mZWP/Sk1P/zpARP9JTlL/xcbH//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/xMXG/0lOUf86QET/Sk1P/2Zl + Y/9pZ2X/aWdl/2lnZf9pZ2X/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9aWlr/PEFF/0NIS/+/wMH/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/9/f3//f39/9vcnX/OT5C/zxBRbk8QUUKPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAO0FEADZFOAA8QUWVOj9D/1ldYf/o6en//Pz8//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8XGx/9ESU3/PEFF/1hZWf9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ZlY/9hYF//YF9e/2NiYf9oZmT/aWdl/2ln + Zf9qaGX/Xl1d/z9ER/86P0P/gIOF/+3t7f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/t7e3/f4OF/zo/Q/8/REf/Xl1d/2po + Zf9pZ2X/aWdl/2hmZP9jYmH/YF9e/2FgX/9mZWP/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9YWFn/PEFF/0RJTf/Fx8j/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH//f38/+jp6f9YXWD/Oj9D/zxBRZVCLzwAPEBEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAATE9YADxBRQA8QUVuO0BE/0dLT//S09T///////T09P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9DR0v9KTlL/O0BE/1RVVv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9nZWP/V1dY/0ZKTP9ARUj/P0RH/0JGSf9NT1H/YF9f/2ln + Zf9pZ2X/aGZk/0xPUf86P0P/TlNW/9DR0v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/S09P/T1RY/zo/Q/9MT1H/aGZk/2ln + Zf9pZ2X/YF9f/01PUf9CRkn/P0RH/0BFSP9GSkz/V1dY/2dlY/9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9UVVb/O0BE/0pPU//R0tL/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/09PT//////9HS0/9GS0//O0BE/zxBRW08QUUAR1JRAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAACwwMADxBRQA8QUVCPEFF9D1CRv+wsrP///////j4+P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/9zc3f9YXF//Oj9D/09RUv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ZlY/9OUFL/PUJG/ztARf88QUX/PEFF/zxBRf87QEX/QkZJ/1xc + XP9pZ2X/amhl/1tbW/89Qkb/PEFF/6Olp//y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v+kpqj/PUJG/z1CRv9bW1v/amhl/2ln + Zf9cXFz/QkZJ/ztARf88QUX/PEFF/zxBRf87QEX/PUJG/05QUv9mZWP/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9PUVL/Oj9D/1hcYP/c3d3/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/4+Pj//////6+xs/89Qkb/PEFF9DxBRUE8QUUACwsMAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUgPEFF2zk+Qv+LjpD//v7+//39/f/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+np6f9rb3L/OT5C/0hLTf9nZWT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1RWVv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/O0BF/0RI + S/9jYmH/amhl/2VjYv9ER0r/OT5C/3p9gP/s7e3/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+zs7f95fX//OT5C/0RIS/9lY2L/amhl/2Ni + Yf9ESEv/O0BF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf9UVlb/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dlZP9IS03/OT5C/2xwc//p6en/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/9/f3//v7+/4uOkP85PkL/PEFF2jxBRR88QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRQA9QkUIPEFFtDo/Q/9laWz/8vLy///////39/f/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+JjI7/OT5D/0FGSf9jYmD/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZGNi/0RHSv87QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxB + Rf9VVlf/aWdl/2hmZf9MTlD/OT9D/11hZf/i4uP/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+Hi4v9dYWT/OT9D/0xOUP9oZ2X/aWdl/1RW + Vv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztBRf9ER0v/ZGNi/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2JiYP9BRkn/OT5D/4qNj//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//f39///////8fLy/2VpbP86P0P/PEFFsztCRQc7QkUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRwA9P0MAPEFFfTtARP9KT1P/1tfY///////8/Pz/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Pz8/+usLL/PkNH/z1CRv9aW1v/amhl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/XV1d/z5DRv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + RP9LTU//aGZk/2lnZf9TVFX/Oj9E/09UV//T09T/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9LT0/9PU1f/Oj9E/1NUVf9qZ2X/aGZk/0tN + T/87QET/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf8+Q0b/XV1d/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/amhl/1paW/89Qkb/PkNH/6+xs//z8/P/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy//z8/P//////1tfY/0pPUv87QET/PEFFfD5BRgA7QUQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEpMgA8QUUAPEFFRzxBRfU8QUX/ra+x////////////9vb2//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/S09T/T1RX/zo/Q/9PUVL/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/Wltb/z1CRv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + Rf9IS07/Z2Vk/2poZv9XWFj/O0BE/0dMUP/Iycr/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8fIyf9HS0//O0BE/1dYWP9qaGb/Z2Vj/0hL + Tf87QEX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf89Qkb/Wltb/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/05RUv86P0P/UFRY/9PU1P/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/9vb2////////////rK+w/zxBRf88QUX0PEFERjxBRQBDSlUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACtVVQA8QUUAPEFFGjxBRdQ5PkL/fICC//r6+////////Pz8//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/q6ur/c3d6/zk+Qv9DR0r/ZGNh/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/Xl5d/z5DR/88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + RP9MTlD/aGZk/2poZv9ZWVn/PEFF/0NITP/CxMX/8/Pz//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8/Pz/8LDxP9DSEz/PEFF/1lZWv9qaGb/aGZk/0tO + UP87QET/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf8+Q0f/Xl5d/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZGJh/0NHSv85PkL/dXh7/+rr6//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL//Pz8///////6+vr/fH+C/zk+Qv88QUXUPEFFGjxBRQAzMzMAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkUAP0NGAjxBRZw6QET/VFlc/+Pk5P////////////f3 + 9//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/qaus/z5DR/89QUX/WFlZ/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZWRi/0VJTP87QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxB + Rf9XV1j/amdl/2poZv9ZWVn/PEFF/0RJTf/DxMX/8/Pz//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8/Pz/8LExf9DSEz/PEFF/1lZWf9qaGb/amdl/1ZX + WP88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztBRf9FSUz/ZWRi/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/WFhZ/z1BRf8+Q0f/qqyu//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/39/f////////////j4+T/VFhc/zpARP88QUWcPkJFAj1CRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkYAPEFFADxBRVk8QUX7PkNH/7W3uP////////////39 + /f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/2dra/1hcX/86P0P/SEtN/2ZlY/9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1dYWf89Qkb/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/O0BF/0dK + Tf9lY2L/aWdl/2poZv9XV1j/O0BE/0hNUP/Jysv/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8jKyv9ITVD/O0BE/1dXWP9qaGb/aWdl/2Vj + Yv9HSk3/O0BF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/z1CRv9YWFj/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9mZWP/SEtN/zo/Q/9ZXWD/2tvb//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/9/f3///////////+0trj/PkNH/zxBRfo8QUVZPEFFADxCRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAPEFFADxBRSA8QUXZOT5C/32Ag//6+/v///////// + ///5+fn/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/5OVl/87QET/PUJG/1laWv9qZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dmZP9SVFX/PkNH/ztARf88QUX/PEFF/ztARf88QUX/RklM/2Bf + Xv9pZ2X/aWdl/2lnZf9SVFX/Oj9D/1BVWP/U1dX/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9TU1f9QVFj/Oj9D/1JUVf9pZ2X/aWdl/2ln + Zf9fX17/RUlM/zxBRf87QEX/PEFF/zxBRf87QEX/PkNH/1JUVf9oZmT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2pnZf9ZWlr/PUJG/ztARP+Ulpj/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//n5 + +f////////////r6+v98f4L/OT5C/zxBRdk8QUUfPEFFAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JGADtERgM8QUWbO0BE/1BUWP/c3d7///////// + ///+/v7/9PT0//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9PU1P9UWFz/Oj9D/0ZKTP9lY2L/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9oZmT/W1tb/0tOUP9ER0r/QkZK/0ZKTP9SVFX/Y2Jh/2ln + Zf9pZ2X/aWdl/2hnZf9MTlD/OT9D/11hZf/i4+P/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+Lj4/9dYWT/OT9D/0xOUP9pZ2X/aWdl/2ln + Zf9pZ2X/Y2Jh/1JUVf9GSkz/QkZK/0RHSv9LTlD/W1tb/2hmZP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2VkYv9GSkz/Oj9D/1VZXP/T1NX/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/9PT0//7+ + /v///////////9vc3f9PVFf/O0BE/zxBRZk8Q0gCPEJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITo9ADxBRQA8QUVNPEFF9jxBRf+jpaf///////// + ////////+/v7//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+Zm53/PEFF/zxBRf9TVFX/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2hmZP9kY2L/Y2Jh/2ZlY/9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2RjYf9DR0r/OT5C/3h8f//s7Oz/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+zs7P94e37/OT5C/0RHSv9kY2L/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9mZWP/Y2Jh/2RjYv9oZmT/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/1JUVf88QUX/PEFF/5mcnv/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/+/v7//// + /////////////6Kkpv88QUX/PEFF9TxBRUw8QUQASysyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASUtNAD1BRQA9QUUTPEFFxjo/Q/9mam3/7/Dw//// + //////////////f39//w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/e39//ZWls/zo/Q/9AREj/XFxc/2pn + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/1ZXWP88QUX/PkNH/6epq//y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v+nqav/PUJG/zxBRf9WV1j/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9qZ2X/XFxc/0BER/86P0P/Zmpt/97f3//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/39/f///////// + ////////7+/v/2VpbP86P0P/PEFFxjxBRBI8QUQAJVtdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9BQgA7QUUAPEFFdjxBRf9BRkr/vL6///// + //////////////7+/v/09PT/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/vL6//0pOUv86P0T/REhL/2Fg + X/9qZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9qZ2X/YmFg/0NHSv86P0P/XGBk/9vc3P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/b29z/XGBj/zo/Q/9DR0r/YmFg/2pn + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2pn + Zf9gYF//REhL/zo/Q/9KT1P/vb/A//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//T09P/+/v7///////// + ////////vL2//0FGSv88QUX/PEFFdTxCRgA3NTkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtCQQA8QUUAPEFFJzxBRd45PkL/d3p9//f3 + 9//////////////////8/Pz/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/7+/v/5yeoP9ARUn/O0BE/0dK + TP9hYWD/amhl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9lZGL/Sk1P/ztARP9ARUn/p6qr//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/p6mr/0BFSf87QET/Sk1P/2Vk + Yv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amhl/2Fh + YP9GSkz/O0BE/0BFSf+dn6H/7+/v//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//z8/P////////////// + ///39/f/dnp8/zk+Qv88QUXdPEFFJjxBRQA4OT4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBASAA9QEUAPz9GATxBRZA7QET/RktP/8fJ + yv//////////////////////+fn5//Hx8f/w8PD/8PDw//Dw8P/w8PD/8fHx/+np6f+Ii47/PUJG/ztA + RP9FSUz/Xl5d/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2Rj + Yv9MT1D/PEFF/ztARP9+gYT/5+jo//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5+jo/36Bg/87QET/PEFF/0xO + UP9kY2L/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/Xl5d/0ZJ + TP87QET/PUJG/4mMjv/p6en/8fHx//Dw8P/w8PD/8PDw//Dw8P/x8fH/+fn5//////////////////// + ///HyMn/RktP/ztARP88QUWPPkBCAT1BRAA8REQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUYAPEFFADxBRTQ8QUXnOj9D/3x/ + gv/4+Pn///////////////////////f39//w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/k5OX/hYiK/z5D + R/87QET/QUVJ/1ZWV/9mZGP/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9pZ2X/Xl5d/0hL + Tf88QUX/Oj9D/21xdP/b3Nz/8vHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vHx/9vb3P9tcHP/Oj9D/zxB + Rf9IS03/Xl5d/2lnZf9qaGX/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2ZkY/9VVlf/QUVJ/ztA + RP8+Q0f/hYiL/+Tl5f/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/39/f///////////////////////j4 + +f97f4L/Oj9D/zxBRec8QUUzPEFFADxBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAPUFEAD5ARAM8QUWXO0BE/0ZL + T//Gx8n///////////////////////7+/v/19fX/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5ubn/5KV + l/9FSk3/Oj9D/z1BRf9HSk3/V1hY/2NiYf9nZmT/aWdl/2lnZf9oZ2X/ZmRj/15eXf9PUVL/QERI/ztA + RP88QUX/cnZ4/9fY2f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/X2Nj/cnV4/zxB + Rf87QET/QERI/09RU/9eXl3/ZmRj/2lnZf9pZ2X/aWdl/2dmZP9jYmH/V1hY/0dKTf89QkX/Oj9D/0VK + Tv+TlZf/5ufn//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//X19f/+/v7//////////////////////8bH + yP9GS0//O0BE/zxBRZY9QUYDPUFFAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0FGADxBRQA8QUU0PEFF5To/ + Q/91eHv/9PX1///////////////////////9/f3/9PT0//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+zt + 7f+xs7T/XWFk/ztBRf86P0P/PEFF/0JGSf9JTE7/TlBS/09RUv9MTlD/RklM/z9DR/87QET/OT5D/0dM + UP+NkJL/4ODg//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/4ODg/42P + kv9HTFD/OT5D/ztARP8/Q0f/RklM/0xOUP9PUVL/TlBS/0lMTv9CRkn/PEFF/zo/Q/88QUX/XWFl/7Kz + tf/t7e3/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/9PT0//39/f//////////////////////9PT1/3R4 + e/86P0P/PEFF5D1BRTQ8QUUAP0VBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRQA8QUUhPEFF1TtB + Rf9CRkr/t7m7/////////////////////////////Pz8//Pz8//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL/2dra/5aYmv9ZXWD/PkNH/zk+Qv85PkL/OT5D/zk/Q/85PkL/OT5C/zo/Q/9HTFD/dHd6/76/ + wP/t7e3/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+3t + 7f+9v8D/dHd6/0dMT/86P0P/OT5C/zk+Qv85P0P/OT5D/zk+Qv85PkL/PkNH/1ldYf+WmJv/2dra//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/z8/P//Pz8////////////////////////////t7i6/0JG + Sv88QUX/PEFF0zxBRR88QUUAPUFEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQkUAPEFFADtBRQc8QUWWPEFF/zxB + Rf86P0P/YmZp/+jp6f////////////////////////////z8/P/z8/P/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx//Dw8P/a2tv/r7Cy/4KFh/9obG//XGBj/1ldYf9hZWj/dHd6/5eZm//Fxsf/6enp//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL/6Onp/8XGx/+XmZv/dHd6/2FlaP9ZXWH/XGBj/2hsb/+ChYf/r7Gy/9rb2//w8PD/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/8/Pz////////////////////////////o6en/YmZp/zo/ + Q/88QUX/PEFF/jxBRZI+QUQGPUFEAD5AQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRUYAO0FFADxBRVU8QUX0PEFF/0FF + SP89Qkb/PEFF/5mbnf/9/f3////////////////////////////8/Pz/8/Pz//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/8vLy/+/v7//m5uf/3+Dg/97e3//i4uP/6+zs//Ly8v/y8vL/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx//Ly8v/y8vL/6+zs/+Li4//e3t//3+Dg/+bm5//v7+//8vLy//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8/Pz//v7+/////////////////////////////39/f+Ym53/PEFF/z1C + Rf9BRUj/PEFF/zxBRfI8QUVSPEFFAEY8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5BRgA8QUUAPEFFGTxBRcg8QUX/QUZJ/1xc + XP9IS03/Oj9E/0xQVP/Mzc7//////////////////////////////////Pz8//Pz8//w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8fHx//Hx8f/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/x8fH/8fHx//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/z8/P//Pz8/////////////////////////////////8vMzf9LUFP/Oj9E/0hL + Tf9bW1v/QUVJ/zxBRf88QUXGPUBFGDxBRQA9QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRgA8QUYAPEFFcTxBRf08QUX/VFVW/2po + Zf9dXVz/P0RH/zk/Q/9ucXT/7e3u//////////////////////////////////z8/P/09PT/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//T09P/8/Pz/////////////////////////////////7e3t/21xdP85P0P/P0RI/11d + XP9qZ2X/U1VW/zxBRf88QUX9PEFFcDtCRgA+QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPUBFADxBRQA8QUUfPEFF0zxBRf9FSUv/ZWNi/2ln + Zf9pZ2X/UVNU/zxBRf88QUX/lpmb//z8/P/////////////////////////////////9/f3/9fX1//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/9fX1//39/f/////////////////////////////////8/Pz/lpmb/zxBRf88QUX/UVNU/2ln + Zf9pZ2X/ZGNi/0VJS/88QUX/PEFF0jxBRR48QUUAPkFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPkBGADtCRQA8QUVtPEFF/j1CRv9XWFj/aWdl/2ln + Zf9pZ2X/ZWNi/0dLTf87QET/R0xQ/72/wP///////////////////////////////////////v7+//f3 + 9//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx + 8f/39/f//v7+//////////////////////////////////////++v8D/R0xQ/ztARP9HSk3/ZWNi/2ln + Zf9pZ2X/aWdl/1dXWP89QkX/PEFF/TxBRW06QUQAP0FHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBFADxARRE8QUXBPEFF/0RIS/9lY2L/aWdl/2ln + Zf9pZ2X/aWdl/1FSVP88QUX/Oj9D/1ldYf/Z2tv///////////////////////////////////////// + ///6+vr/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//r6 + +v///////////////////////////////////////////9na2v9ZXmH/Oj9D/ztBRf9OUFL/aWdl/2ln + Zf9pZ2X/aWdl/2VjYv9FSEv/PEFF/zxBRcE8QEURPEBFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkQAPEFFADxBRUU8QUX0PEFF/1NUVf9pZ2X/aWdl/2ln + Zf9pZ2X/Y2Jh/0NHSv87QEX/O0BE/zo/Q/9xdXf/6+zs//////////////////////////////////// + /////////Pz8//X19f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/19fX//Pz8//// + ////////////////////////////////////////6+zs/3B0d/86P0P/O0BE/ztBRf9BRUj/YGBf/2ln + Zf9pZ2X/aWdl/2lnZf9TVFX/PEFF/zxBRfQ8QUVGPEFFADtARgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+Q0QAOkBFADxBRYc8QUX/QERH/2BfXv9qZ2X/aWdl/2ln + Zf9pZ2X/VldX/zxBRf9BRkr/Wl5h/z5DR/87QUT/hYmL//X19f////////////////////////////// + //////////////7+/v/5+fn/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//n5+f/+/v7///////// + ///////////////////////////////////09fX/homL/zxBRf89Qkb/YWVp/0VKTf87QET/UlNV/2ln + Zf9pZ2X/aWdl/2pnZf9gX1//QERI/zxBRf88QUWJPURCADs/RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEFFEDxBRcQ7QEX/SEtN/2dlY/9pZ2X/aWdl/2ln + Zf9nZWP/SEtN/zo/Q/9cYGT/wMHC/21xc/86P0P/P0RI/5eanP/5+fn///////////////////////// + /////////////////////////Pz8//b29v/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/29vb//Pz8//////////////////// + //////////////////////////////n5+f+Xmpz/P0NH/zo/Q/9tcXT/x8jI/2drbv85P0P/RUhL/2Vk + Yv9pZ2X/aWdl/2lnZf9nZWT/SEtO/ztARf88QUXGPEFFETxBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFGRgA8QUUAPEFFLjxBRek8QUX/UlRV/2lnZf9pZ2X/aWdl/2pn + Zf9gX17/QERH/zo/Q/+JjI7/4uLi/8fHyP9eYmX/OT5C/0FGSv+ipaf//Pz8//////////////////// + ///////////////////////////////////7+/v/9fX1//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/9PT0//v7+/////////////////////////////// + /////////////////////////Pz8/6Olp/9CR0r/OT5C/15iZf/Hx8j/5OPj/5eZm/88QUX/PkNG/11d + XP9qaGX/aWdl/2lnZf9pZ2X/U1RV/zxBRf88QUXqPEFFMDxBRQA7PkIAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEVJRwA8QUUAPEFFVzxBRfo9Qkb/W1tb/2poZf9pZ2X/aWdl/2po + Zf9XWFj/PEFF/0NHS/+ztLX/4uLi/+Li4v+8vb7/Vlte/zk+Qv9FSU3/p6mr//v7+/////////////// + /////////////////////////////////////////v7+//r6+v/19fX/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//T09P/6+vr//v7+//////////////////////////////////// + ///////////////////7+/z/p6qr/0VKTf85PkL/Vlpd/7y9vv/i4uL/4uLi/72+v/9ITVD/O0BE/1RV + Vv9pZ2X/aWdl/2lnZf9qaGX/W1xb/z1CRv88QUX7PEFFWjxBRQA6PUEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1CRAA7QEYAPEFFfTxBRf9ARUj/YWBf/2lnZf9pZ2X/aWdl/2ln + Zf9PUVL/Oj9D/1NXW//Mzc3/4eHh/+Dg4P/i4eH/tba4/1JWWf85PkL/RElN/6Wnqf/6+vr///////// + ///////////////////////////////////////////////////+/v7/+/v7//b29v/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/29vb/+/v7//7+/v////////////////////////////////////////////// + //////////////v7+/+lqKr/RElN/zk+Qv9RVln/tba3/+Hh4f/g4OD/4eHh/9PT1P9bX2L/Oj9D/0xO + UP9oZmX/aWdl/2lnZf9pZ2X/YmFg/0FFSP88QUX/PEFFgTxBRgA8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA9QkUBPEFFmjxBRf9DR0r/ZWRi/2lnZf9pZ2X/aWdl/2hm + ZP9JTE7/OT5C/2VpbP/Z2dr/4ODg/+Dg4P/g4OD/4eHh/7K0tf9SVln/OT5C/0NITP+cnqD/9/f3//// + ///////////////////////////////////////////////////////////////////9/f3/+Pj4//T0 + 9P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx + 8f/09PT/+Pj4//z8/P////////////////////////////////////////////////////////////// + ////////9/f3/52fof9DSEz/OT5C/1FVWf+xs7T/4eHh/+Dg4P/g4OD/4ODg/9zc3P9vc3b/OT5C/0ZK + TP9nZWT/aWdl/2lnZf9pZ2X/ZWRj/0RIS/88QUX/PEFFnz1ARgI8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUFPEFFsztBRf9HSk3/Z2Vk/2lnZf9pZ2X/aWdl/2Zl + Y/9GSUz/OT5C/3V4e//d3d3/4ODg/+Dg4P/g4OD/4ODg/+Hh4f+ztLX/VFhb/zk+Qv9ARUn/jpGT/+/v + 7/////////////////////////////////////////////////////////////////////////////7+ + /v/8/Pz/+Pj4//X19f/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/19fX/+Pj4//z8 + /P/+/v7///////////////////////////////////////////////////////////////////////// + ///v7/D/jZCT/0BFSf85PkL/VFhb/7O0tf/h4eH/4ODg/+Dg4P/g4OD/4ODg/9/f3/9/goT/OT5C/0RI + Sv9lY2L/aWdl/2lnZf9pZ2X/Z2Zk/0hLTf87QUX/PEFFuDpDRwY6REcAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADlFRwA6Q0cIPEFFvztARf9KTU//aGZk/2lnZf9pZ2X/aWdl/2Vk + Yv9ESEv/OT5C/3t+gP/e3t7/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/h4eH/ubq8/1peYf86P0P/PEFF/3h8 + fv/h4uP///////////////////////////////////////////////////////////////////////// + ///////////////////9/f3/+/v7//j4+P/29vb/9PT0//Ly8v/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx8f/y8vL/9PT0//b29v/4+Pj/+/v7//39/f////////////// + /////////////////////////////////////////////////////////////////////////////+Hi + 4v95fH//PEFF/zo/Q/9aXmH/ubq7/+Hh4f/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P+ChYf/OT5C/0NH + Sv9kY2H/aWdl/2lnZf9pZ2X/aGZk/0tNUP87QEX/PEFFxDtCRQs7Q0UAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpCRAA7QkQLPEFFxDtARf9LTlD/aGZk/2lnZf9pZ2X/aWdl/2Zk + Y/9FSEv/OT5D/3R3ef/b29v/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4uHh/8LDw/9nam3/O0BE/zo/ + Q/9hZWn/x8nK//7+/v////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//7+/v/8/Pz/+/v7//r6+v/6+vr/+fn5//n5 + +f/5+fn/+fn5//r6+v/6+vr/+/v7//z8/P/+/v7//v7+//////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7/yMnK/2Jl + af86P0P/O0BE/2Zqbf/CwsP/4uLh/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9ra2v96fH7/OT9D/0NH + Sv9kY2H/aWdl/2lnZf9pZ2X/aGZk/0xOUP87QEX/PEFFyDxBRhA7QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpCRgA7QkYLPEFFwztARf9LTU//aGZk/2lnZf9pZ2X/aWdl/2dl + ZP9GSkz/Oj9D/2dqbP/Pzs7/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Li4v/Nzs7/eHt+/z9E + R/85PkL/TVFV/6Olp//y8vP///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////Lz8/+jpaf/TFFU/zk+ + Qv8/Q0f/eHt+/83Ozv/i4uL/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/83My/9tb3L/Oj9D/0VI + S/9mZGP/aWdl/2lnZf9pZ2X/aGZk/0xOUP87QEX/PEFFyTxBRhA8QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRgA7QkYGPEFFuTtARf9JTE//aGZk/2lnZf9pZ2X/aWdl/2hm + ZP9KTU//Oj9D/1hcX/+9u7v/2tra/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/h4eH/2NjY/5KU + lv9ITFD/OT5C/z5DR/93en3/1NXW//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////1NbW/3d7ff8+Q0f/OT5C/0hN + UP+SlZb/19jY/+Hh4f/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/19fW/727u/9dYGP/Oj9D/0lM + Tv9oZmT/aWdl/2lnZf9pZ2X/aGZk/0tNT/87QEX/PEFFwTxARgk9QEYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUDPEFFqTtARf9IS07/aGZl/2lnZf9pZ2X/aWdl/2ln + Zf9RU1T/O0BE/0pOUf+qqan/ysnI/93d3P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4eHh/9/f + 3/+vsLL/XWFk/ztARP85PkL/UVVZ/6Gjpf/s7e3///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////+zt7f+hpKb/UVVZ/zk+Qv87QET/XWFk/66w + sf/f39//4eHh/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/b29r/yMbF/62srP9MUVT/OkBE/09R + U/9pZ2X/aWdl/2lnZf9pZ2X/aGdl/0lMT/87QEX/PEFFszxBRAU8QUQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA6REkAPEFFiztARf9GSk3/amlo/2lnZf9pZ2X/aWdl/2po + Zf9aWlr/PUJG/z5DRv+QkJH/wsC//8vKyf/d3Nz/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/i4uL/y8zM/4CDhf9ESU3/OT5C/z1CRv9mam3/ury9//T19f////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////09fX/uru9/2drbv89Qkb/OT5C/0RJTf9/goX/y8vM/+Li + 4v/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9vb2//Ix8b/wsC+/5OUlP8/REf/PEFF/1lZ + Wf9qaGX/aWdl/2lnZf9pZ2X/a2lo/0dLTv87QET/PEFFljpAQwE8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRwA8QUUAPEFFaTxBRf9BRUn/bm1t/2xqZ/9pZ2X/aWdl/2ln + Zf9jYmH/QkZJ/zo/Q/9oa23/vLu6/8C+vf/Ix8b/2djY/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/g4OD/4eHh/9zc3P+sra//YGRn/z1CRv84PkL/QkdL/3J2eP/AwcP/9PT0//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////9PX1/8HCw/9zd3n/QkdL/zg+Qv88QUX/YGRn/6utrv/c3Nz/4eHh/+Dg + 4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/2NjY/8fGxf/Avr3/vbu7/2tucP86P0P/QkZJ/2Jh + YP9pZ2X/aWdl/2lnZf9raWf/b25t/0JHSv88QUX/PEFFczxBRQA8QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpARgA8QUUAPEFFQDxBRfE8QUX/aGhp/3VzcP9pZ2X/aWdl/2ln + Zf9pZ2X/TlBS/ztARP9GSk7/oKCg/8LAv//Avr3/w8LB/9HQz//c3Nz/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/g4OD/4ODg/+Dg4P/i4uL/0NHR/5SWmP9SVln/O0BE/zk+Qv9DSEz/b3N2/7W3uP/r7Oz///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////+vs7P+3ubr/cXV4/0NITP85PkL/O0BE/1FWWf+SlZb/0NDR/+Li4v/g4OD/4ODg/+Dg + 4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9zc3P/R0M//w8LB/8C+vf/CwL//oqGh/0dLT/87QET/TU9R/2hm + Zf9pZ2X/aWdl/2lnZf9zcW//a2tr/z1CRv88QUX2PEFFSjxBRQAxNjoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEFFGTxBRdQ7QET/WFpc/4J/ff9samj/aWdl/2ln + Zf9qZ2X/Xl5d/z9ER/86P0T/aGtt/7q5uP/Bv77/wL69/8C+vf/GxMP/0M/P/9nY2P/d3d3/4N/f/+Dg + 4P/g4OD/4ODg/+Dg4P/e3t7/3Nvb/9TT0/+xsLD/eHp8/0tPUv86P0P/OD1B/z9ESP9fY2b/mJud/9PU + 1f/19fX///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////X1 + 9f/T1NX/mpye/2BkZ/8/REj/OD1B/zo/Q/9LT1P/eHp7/7CwsP/U09P/3Nvb/97e3v/g4OD/4ODg/+Dg + 4P/g4OD/4N/f/93d3f/Z2Nj/0M/O/8bEw//Avr3/wL69/8G/vv+6ubj/aWtu/zpARP8/Q0f/XV1d/2pn + Zf9pZ2X/aWdl/2tpZ/+Bfnz/W11f/ztARP88QUXcO0FFIDxBRQBVVVUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7QkUAO0NFAzxBRaA7QET/RkpN/4B+ff97eHf/aWdl/2ln + Zf9pZ2X/aGZk/05QUv87QET/QEVI/4iJiv/Avr3/wL69/8C+vf/Avr3/wL69/8LAv//GxcT/ysnI/83M + y//Ozc3/zczM/8vKyf/HxsX/w8HA/8C+vv/Bv77/v728/6inp/96fH3/UVVY/z5DR/86P0P/O0BE/0lO + Uv9ucXX/oKOl/8zNzv/t7e7//Pz8//////////////////////////////////////////////////// + /////////////////////////////////////////////////////////Pz8/+7u7//P0NH/oKOl/21x + dP9JTlL/O0BE/zo/Q/8+Q0b/UFRX/3p8ff+op6f/v728/8G/vv/Av77/w8HA/8fGxf/Lysn/zczM/87N + zf/NzMv/ysnI/8bFxP/CwL//wL69/8C+vf/Avr3/wL69/8C+vf+HiIn/QEVI/ztARP9NUFL/aGZk/2ln + Zf9pZ2X/aWdl/3l2dP+CgH//SU1Q/ztARP88QUWsO0BEBztARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QEQAPEFFADxBRVg8QUX6PEFF/2pqa/+Kh4X/dHJw/2ln + Zf9pZ2X/aWdl/2JhYP9DR0r/O0BE/0dMT/+VlZb/wb++/8C+vf/Avr3/wL69/8C+vf/Avr3/v728/8C+ + vf/Avr3/wL69/7+9vP/Avr3/wL69/8C+vf/Avr3/wL69/8LAvv/CwL//mpqb/0pOUv87QET/PEFF/ztA + RP85PkL/Oj9D/0VKTv9fY2b/goWI/6epq//Iycr/39/g/+/v8P/5+fn//f39//////////////////// + /////////////////////////f39//n5+f/v7/D/39/g/8jJyv+nqav/goWI/2BkZ/9HTE//Oj9D/zk+ + Qv87QET/PEFF/ztARP9FSU3/kJGR/8G/vv/CwL//wL69/8C+vf/Avr3/wL69/8C+vf+/vbz/wL69/8C+ + vf/Avr3/v728/8C+vf/Avr3/wL69/8C+vf/Avr3/wL69/5KTk/9HS07/O0BE/0NHSv9iYWD/aWdl/2ln + Zf9pZ2X/cnBu/4qGhP9ubm//PUJG/zxBRf08QUVlPEFFAEFGSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRhk8QUXOO0BE/05RVP+Gg4L/iIWD/3Fv + bf9pZ2X/aWdl/2lnZf9bW1v/P0RH/zpARP9JTVH/j4+Q/768u//Bv77/wL69/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wL69/8C+vf/Avr3/wb++/7+9vP+bm5v/WFxf/zxBRf88QUX/SEtO/1FS + VP9KTVD/QUZJ/ztARP86P0P/OT5C/zxBRf9CR0r/UFRY/2BkZ/9xdHf/g4eJ/5GUlv+doKL/pKao/6iq + rP+oqqz/pKao/52gov+RlJb/g4aJ/3B0d/9gZGf/UFRY/0JHSv88QUX/OT5C/zo/Q/87QET/QUVJ/0pN + UP9RU1T/TE5Q/z1BRf88QUX/TlJV/42Ojv+7ubj/wsC//8C+vf/Avr3/wL69/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wL69/8G/vv+9u7r/i4yN/0hMUP86QET/QERI/1tbW/9pZ2X/aWdl/2ln + Zf9vbWv/hoOB/4iFhP9SVVf/O0BE/zxBRdk8QUUhPEFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JGAD5AQwA8QUV3PEFF/j1CRv9ra2v/jYqI/4aD + gf9xb23/aWdl/2lnZf9pZ2X/V1hY/z9DR/87QET/Q0hL/3Z4ev+ura3/wb++/8G/vv/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wb++/8LAv/+/vr3/qqqp/3d4ev9GSk7/OkBE/zxBRf9MTlD/ZWRj/3h1 + c/+DgX//enl4/2ZnaP9ESEv/PEFF/zxBRf88QUX9O0BE/zo/Q/85PkL/OT5C/zk/Q/86P0P/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/85P0P/OT5C/zk+Qv86P0P/O0BE/zxBRf48QUX/PEFF/0RJTP9mZ2j/eXh3/4OB + f/93dXP/aGZk/1FSVP8+Q0b/OkBE/0BFSf9pa27/oJ+g/7y6uv/CwL//wb++/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8G/vv/CwL//wL69/6qpqf9xc3X/QUZK/ztARP8/REf/WFlZ/2lnZf9pZ2X/aWdl/3Bt + a/+EgX//jYqI/3BwcP8/Q0f/PEFF/zxBRYY/UEsAPEJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPT9EADxBRQA8QUYfPEFF0TtARP9JTE//f359/42K + iP+HhIL/c3Fv/2lnZf9pZ2X/aWdl/1hZWf9BRUn/O0BE/zxBRf9SVVn/gIGD/6empv+6uLf/wL69/8G/ + vv/CwL//wsC//8G/vv++vbz/tLOz/52dnf91d3n/TVFU/ztARP87QET/P0RH/1NUVf9raWf/fnx5/4uI + hv+Nioj/jYqI/25ubv9ARUn/PEFF/zxBRco8QUVoPEFFgjxBRaE8QUW8PEFFzzxBRdk8QUXiPEFF5jxB + Rek8QUXpPEFF5jxBReI8QUXZPEFFzzxBRbw8QUWhPEFFgTxBRWo8QUXOPEFF/0FGSf9wcHD/jYqI/42K + iP+LiIb/fnt5/2xqaf9YWFn/QkZJ/ztARP86P0P/RUpO/2hrbf+RkpL/rays/7u5uP+/vr3/wb++/8G/ + vv/Avr3/vry8/7a0tP+goKD/eHp7/01RVf87QET/O0BE/0JGSf9aWlr/aWdl/2lnZf9pZ2X/cnBu/4aD + gf+Nioj/g4GA/01QU/87QET/PEFF3TxBRSk8QUUAPUFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAAD9BQgA7QUYAPEFFZTxBRfk7QEX/WVtd/4iG + hP+Nioj/iYaE/3l3df9samf/aWdl/2lnZf9fXl7/SUxO/z1CRf86P0T/PEFF/0hMUP9dYGP/c3V3/4KD + hP+IiYr/hoeI/3x+f/9qbW//VVhc/0JHS/86QET/OkBE/z1CRv9IS07/X19f/3Vzcf+Gg4H/jImH/4yJ + h/+MiYf/cXFx/0NHS/87QEX/PEFF4TxBRT48QUQAPEFDADtBRQQ7QkUJPEFFEjxBRR08QkUoPEFFLTxB + RTE8QUUxPEFFLTxCRSg7QUUdPEFFEjtCRQk8Q0QEO0BGADxBRQA8QUVEPEFF5TtARP9ESEz/dHNz/42K + h/+MiYf/jImH/4aDgf92dHL/Y2Jh/01PUf8/REf/O0BE/zo/Q/8+Q0f/TFBU/19iZP9wcnT/enx+/31/ + gP93eXv/aWtu/1ZaXf9ESEz/O0BE/zpARP89Qkb/Sk1P/2BfX/9pZ2X/aWdl/2tpZ/95d3X/iIaE/42K + iP+Kh4X/X2Bi/zxBRf88QUX9PEFFdjtETgA9QEIAOkZGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1BRAA8QUYAPEJGDTxBRag8QUX/PkNG/2Zn + aP+LiIb/jImH/4yJh/+DgH7/dHFv/2tpZ/9pZ2X/ZmRj/1dYWP9HSkz/PkJG/ztARP86P0P/Oj9D/zpA + RP87QET/O0BE/zo/Q/86P0P/Oj9D/ztARP8/Q0f/SUxO/1xcXP9ycG7/goB+/4uIhv+MiYf/jImH/4yJ + h/9wb3D/REhM/ztARP88QUXsPEFFWT5CRwA7QUYAPEFHADxBRQA7QUUAPEFFADxBRQA8QkUAPEFFADxB + RQA8QUUAPEFFADxCRQA7QUUAPEFFADtCRQA8QkUAPUNEADxBRgA7P0QAPEFFXzxBRe87QET/RUpN/3Jy + cv+MiYf/jImH/4yJh/+LiIb/g4B+/3Nxb/9gYF//TVBR/0FGSf88QUX/OkBE/zk/Q/86P0P/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/87QET/P0NH/0lMTv9aWlr/ZmVj/2lnZf9raWf/dHFv/4OAfv+MiYf/jImH/4yJ + h/9sbG3/P0RI/zxBRf88QUW5PEBFFDxARQA9QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7QUUAPEFGADtBRSk8QUXRPEFF/0BF + SP9ra2z/i4iG/4yJh/+MiYf/ioeF/4J/ff92dHL/bWtp/2poZv9lZGL/XFxb/1BSU/9HS03/QkZJ/0BE + SP8/REf/P0RH/0FFSP9ER0r/S01P/1ZXWP9mZWT/d3Vz/4SBf/+LiIb/jImH/4yJh/+Nioj/ioeF/2lq + a/9CRkr/O0BE/zxBRe88QUVmQUhCATxCRAA7QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRgA8QUYAPENJAjxBRW48QUXzO0BE/0NH + S/9sbW3/i4iG/42KiP+MiYf/jImH/4uIhv+EgX//eHZ0/2loZ/9aW1v/T1FS/0dKTf9DR0r/QUVJ/0FF + Sf9CRkn/RUhL/0tNT/9TVFX/Xl5d/2ZlY/9qaGb/bmtp/3Z0cv+Cf33/ioeF/4yJh/+MiYf/jImH/3Fx + cf9DR0v/O0BF/zxBRd48QUU3PUFFAEBFSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkcAPEJGADxBRAA8QUVFPEFF4jtB + Rf9BRUn/aGlp/4qHhf+Nioj/jImH/4yJh/+LiIb/h4SC/4B9e/94dnT/c3Fv/29ta/9raWf/Z2Zk/2Rj + Yv9jYmL/ZWRk/2ppaP9ycG7/enh2/4OAfv+JhoT/jImH/4yJh/+MiYf/jImH/42KiP+DgYD/XV9g/z9E + R/87QUX/PEFF6DxBRWA8PEICPEFEAD1CRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQA8QUYAPEFGADxARwQ8QUVpPEFF7DtA + Rf9AREj/YGJj/4WCgf+Nioj/jImH/4yJh/+MiYf/jImH/4mGhP+DgH7/e3l2/3Nxb/9ta2r/aGdl/2Zl + ZP9mZWT/aWdm/2xqaP9wbWv/c3Fv/3h2dP+AfXv/h4SC/4uIhv+MiYf/jImH/4yJh/+LiIb/b29v/0RI + S/87QET/PEFF7DxBRVY5QUMAPUBFADI2OgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFGADxBRQA8QEcAPEFFUTxB + ReQ7QUX/P0NH/15fYf+DgX//jYqI/4yJh/+MiYf/jImH/42Jh/+MiYf/i4iG/4mGhP+HhIL/hoOB/4aD + gf+IhYL/iYaE/4qHhf+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+Nioj/ioeF/3Nycv9OUVT/PEFF/zxB + Rf88QUXaPEFFT0Y0XgA8QEQAPEBEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBGADxARQA3REIBPEFFVzxB + ReA8QUX/PEFF/1FTVv92dXX/i4iG/42KiP+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+Kh4X/iYaD/4eE + gv+Gg4H/hoOB/4eEgv+JhoT/i4iG/4yJh/+MiYf/jImH/4yJh/+MiYf/jYqI/4aEgv9kZWb/QUVJ/ztA + RP88QUXuPEFFZTtGRAE9QUUAPUFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRAA8QUQAPEJGADxB + RUo8QUXYPEFF/zxBRf9NUFP/cnFx/4mGhP+Nioj/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jYqI/4qHhv95eHf/Wlxe/0BFSP87QET/PEFF/jxB + RbU8QUUyPEFGADxBRAA8QkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRAA8QkUAPUBGADxB + RTo8QUW/PEFF/ztARP9CRkr/Xl9h/317ev+LiIb/jYqI/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/42KiP+LiIb/eHd3/1NWWP89Qkb/PEFF/zxB + ReU8QUVdO0hIAjxCRgA9QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEBFADxB + RAA8QUUzPEFFtzxBRf07QET/QERI/1VYWv9zcnL/hoOC/4yJh/+Nioj/jYqI/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+Nioj/jYqI/4yJh/+Fg4H/c3Jy/1lbXf9CR0r/O0BE/zxBRf88QUXkPEFFfDxB + RRQ8QUUAPEJEADxCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEJFADtA + RAA8QUUaPEFFiTxBReo8QUX/O0FF/0RJTP9dX2D/d3Z2/4eFg/+Niof/jYqI/42KiP+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jYmH/42KiP+Nioj/iYaE/3l4d/9cXV//QkdK/ztARP88QUX/PEFFyTxB + REQ/TEYAO0JFADtDRgBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + RdI8QUXZPEFF1zxBRc48QUW5PEFFmzxBRXM8QUVCPEFGFzA9XwA8QUUAPEFEAD5ESAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPj5EADY/QQA5PEAAO0FEADxBRQA8QUUAPEBGADxCRQU8QUULPEFFDjxB + RQ88QUUMPEFECDtAQgI8QUUAPEFFADxARQA9P0UAO0NGAEM6PwAAgIAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAyR08APEJFADxBRQA8QUUAPEFFADtBQwA8QUYHPEFFDTxB + RhI8QUUZPEFFFjxBRRA7QUUKO0BHAjxBRQA8QUUAPEFGADtBRwA9O0oAOkVGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+QkYAPEJEADxBRQA8QUUAPEFFADxB + RQA8QUUAPEFFADxBRAA/PkMAPj5EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAOkFJAD1BRgA8QUYAPEFFADxB + RgA8QUUAPEFFADxBRQA7QUUAPEFGADk9QgA6PkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAD///////////////////8A////////////////////AP///////////////////wD///////////// + //////8A//////8AAAAAAP//////AP///+AAAAAAAAAAB////wD///4AAAAAAAAAAAB///8A///gAAAA + AAAAAAAAB///AP//4AAAAAAAAAAAAAf//wD//+AAAAAAAAAAAAAH//8A///gAAAAAAAAAAAAB///AP// + 4AAAAAAAAAAAAAf//wD//+AAAAAAAAAAAAAH//8A///wAAAAAAAAAAAAD///AP///4AAAAAAAAAAAf// + /wD////8AAAAAAAAAD////8A//////8AAAAAAP//////AP/////+AAAAAAA//////wD////4AAAAAAAA + AB////8A////wAAAAAAAAAAD////AP///gAAAAAAAAAAAH///wD///AAAAAAAAAAAAAP//8A///gAAAA + AAAAAAAAB///AP//wAAAAAAAAAAAAAP//wD//wAAAAAAAAAAAAAA//8A//4AAAAAAAAAAAAAAH//AP/8 + AAAAAAAAAAAAAAA//wD/+AAAAAAAAAAAAAAAH/8A//AAAAAAAAAAAAAAAA//AP/gAAAAAAAAAAAAAAAH + /wD/4AAAAAAAAAAAAAAAB/8A/8AAAAAAAAAAAAAAAAP/AP+AAAAAAAAAAAAAAAAB/wD/AAAAAAAAAAAA + AAAAAP8A/wAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA/wD+AAAAAAAAAAAAAAAAAH8A/gAAAAAA + AAAAAAAAAAB/APwAAAAAAAAAAAAAAAAAPwD8AAAAAAAAAAAAAAAAAD8A+AAAAAAAAAAAAAAAAAAfAPgA + AAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPAAAAAAAAAAAAAAAAAA + DwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAA + AAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAA + AAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAA + AAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAA + DwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAA + AAAAAA8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAA + AAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD8AAAAAAAAAAAAAAAAAD8A/AAAAAAAAAAAAAAAAAA/APwA + AAAAAAAAAAAAAAAAPwD+AAAAAAAAAAAAAAAAAH8A/gAAAAAAAAAAAAAAAAB/AP4AAAAAAAAAAAAAAAAA + fwD/AAAAAAAAAAAAAAAAAP8A/wAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA/wD/gAAAAAAAAAAA + AAAAAf8A/4AAAAAAAAAAAAAAAAH/AP/AAAAAAAAAAAAAAAAD/wD/wAAAAAAAAAAAAAAAA/8A/4AAAAAA + AAAAAAAAAAH/AP+AAAAAAAAAAAAAAAAB/wD/AAAAAAAAAAAAAAAAAP8A/wAAAAAAAAAAAAAAAAD/AP4A + AAAAAAAAAAAAAAAAfwD+AAAAAAAAAAAAAAAAAH8A/gAAAAAAAAAAAAAAAAB/APwAAAAAAAAAAAAAAAAA + PwD8AAAAAAAAAAAAAAAAAD8A/AAAAAAAAAAAAAAAAAA/APgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAA + AAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAA + AAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgA + AAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAA + HwD8AAAAAAAAAAAAAAAAAB8A/AAAAAAAAAAAAAAAAAA/APwAAAAAAAAAAAAAAAAAPwD+AAAAAAAAAAAA + AAAAAD8A/gAAAAAAAAAAAAAAAAB/AP4AAAAAAAAAAAAAAAAAfwD+AAAAAAAAAAAAAAAAAH8A/wAAAAAA + AAAAAAAAAAD/AP+AAAAAAA//8AAAAAAA/wD/gAAAAAAf//AAAAAAAf8A/8AAAAAAP//8AAAAAAP/AP/g + AAAAAH///gAAAAAH/wD/8AAAAAD///8AAAAAB/8A//gAAAAB////gAAAAB//AP/8AAAAA////8AAAAA/ + /wD//wAAAA/////wAAAAf/8A///AAAA//////AAAAf//AP//4AAA//////8AAAf//wD///8AH/////// + 8AB///8A////////////////////AP///////////////////wD///////////////////8A//////// + ////////////AA== + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Forms/FrmWaiting.Designer.cs b/JinYuan.ControlLib/Forms/FrmWaiting.Designer.cs new file mode 100644 index 0000000..6ff2b7a --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmWaiting.Designer.cs @@ -0,0 +1,162 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib.Forms +{ + /// + /// Class FrmWaiting. + /// Implements the + /// + /// + partial class FrmWaiting + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmWaiting)); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.label1 = new System.Windows.Forms.Label(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.label2 = new System.Windows.Forms.Label(); + this.timer2 = new System.Windows.Forms.Timer(this.components); + this.SuspendLayout(); + // + // imageList1 + // + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); + this.imageList1.TransparentColor = System.Drawing.Color.White; + this.imageList1.Images.SetKeyName(0, "0.png"); + this.imageList1.Images.SetKeyName(1, "1.png"); + this.imageList1.Images.SetKeyName(2, "2.png"); + this.imageList1.Images.SetKeyName(3, "3.png"); + this.imageList1.Images.SetKeyName(4, "4.png"); + this.imageList1.Images.SetKeyName(5, "5.png"); + this.imageList1.Images.SetKeyName(6, "6.png"); + this.imageList1.Images.SetKeyName(7, "7.png"); + this.imageList1.Images.SetKeyName(8, "8.png"); + this.imageList1.Images.SetKeyName(9, "9.png"); + this.imageList1.Images.SetKeyName(10, "10.png"); + this.imageList1.Images.SetKeyName(11, "11.png"); + this.imageList1.Images.SetKeyName(12, "12.png"); + this.imageList1.Images.SetKeyName(13, "13.png"); + this.imageList1.Images.SetKeyName(14, "14.png"); + this.imageList1.Images.SetKeyName(15, "15.png"); + this.imageList1.Images.SetKeyName(16, "16.png"); + this.imageList1.Images.SetKeyName(17, "17.png"); + this.imageList1.Images.SetKeyName(18, "18.png"); + this.imageList1.Images.SetKeyName(19, "19.png"); + // + // label1 + // + this.label1.Dock = System.Windows.Forms.DockStyle.Top; + this.label1.Image = global::JinYuan.ControlLib.Properties.Resources.loading; + this.label1.Location = new System.Drawing.Point(0, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(276, 196); + this.label1.TabIndex = 0; + // + // timer1 + // + this.timer1.Interval = 20; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // label2 + // + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Font = new System.Drawing.Font("微软雅黑", 12F); + this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.label2.Location = new System.Drawing.Point(0, 196); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(276, 30); + this.label2.TabIndex = 1; + this.label2.Text = "处理正在进行中,请稍候..."; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // timer2 + // + this.timer2.Tick += new System.EventHandler(this.timer2_Tick); + // + // FrmWaiting + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(247)))), ((int)(((byte)(247)))), ((int)(((byte)(247))))); + this.ClientSize = new System.Drawing.Size(276, 244); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.IsFullSize = false; + this.Name = "FrmWaiting"; + this.Opacity = 0D; + this.RegionRadius = 20; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = ""; + this.TopMost = true; + this.TransparencyKey = System.Drawing.Color.FromArgb(((int)(((byte)(247)))), ((int)(((byte)(247)))), ((int)(((byte)(247))))); + this.VisibleChanged += new System.EventHandler(this.FrmWaiting_VisibleChanged); + this.ResumeLayout(false); + + } + + #endregion + + /// + /// The image list1 + /// + private System.Windows.Forms.ImageList imageList1; + /// + /// The label1 + /// + private System.Windows.Forms.Label label1; + /// + /// The timer1 + /// + private System.Windows.Forms.Timer timer1; + /// + /// The label2 + /// + private System.Windows.Forms.Label label2; + /// + /// The timer2 + /// + private System.Windows.Forms.Timer timer2; + + + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/Forms/FrmWaiting.cs b/JinYuan.ControlLib/Forms/FrmWaiting.cs new file mode 100644 index 0000000..541c783 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmWaiting.cs @@ -0,0 +1,103 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.Forms +{ + /// + /// Class FrmWaiting. + /// Implements the + /// + /// + public partial class FrmWaiting : FrmBase + { + /// + /// Gets or sets the MSG. + /// + /// The MSG. + public string Msg { get { return label2.Text; } set { label2.Text = value; } } + /// + /// Initializes a new instance of the class. + /// + public FrmWaiting() + { + base.SetStyle(ControlStyles.UserPaint, true); + base.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + base.SetStyle(ControlStyles.DoubleBuffer, true); + InitializeComponent(); + } + + /// + /// Handles the Tick event of the timer1 control. + /// + /// The source of the event. + /// The instance containing the event data. + private void timer1_Tick(object sender, EventArgs e) + { + if (this.label1.ImageIndex == this.imageList1.Images.Count - 1) + this.label1.ImageIndex = 0; + else + this.label1.ImageIndex++; + + } + + /// + /// Handles the VisibleChanged event of the FrmWaiting control. + /// + /// The source of the event. + /// The instance containing the event data. + private void FrmWaiting_VisibleChanged(object sender, EventArgs e) + { + //this.timer1.Enabled = this.Visible; + } + + /// + /// Does the escape. + /// + protected override void DoEsc() + { + + } + + /// + /// Handles the Tick event of the timer2 control. + /// + /// The source of the event. + /// The instance containing the event data. + private void timer2_Tick(object sender, EventArgs e) + { + base.Opacity = 1.0; + this.timer2.Enabled = false; + } + + /// + /// Shows the form. + /// + /// The int sleep. + public void ShowForm(int intSleep = 1) + { + base.Opacity = 0.0; + if (intSleep <= 0) + { + intSleep = 1; + } + base.Show(); + this.timer2.Interval = intSleep; + this.timer2.Enabled = true; + } + } +} diff --git a/JinYuan.ControlLib/Forms/FrmWaiting.resx b/JinYuan.ControlLib/Forms/FrmWaiting.resx new file mode 100644 index 0000000..c182949 --- /dev/null +++ b/JinYuan.ControlLib/Forms/FrmWaiting.resx @@ -0,0 +1,2214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 132, 17 + + + 222, 17 + + + + + AAABAAEAeIAAAAEAIAAo+AAAFgAAACgAAAB4AAAAAAEAAAEAIAAAAAAAAPAAAGDqAABg6gAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVAG9vbwBCQkQAPz9LADw9 + RQA7P0cAPEBHAD1ARgA9QUYAO0BGADtDRQA7QUEAO0BAADk+PgA9QkIAPkJCADtBRAA4RkgAOUZGADxA + QAA8QEAAOUZGADhGSAA7QUQAPkJCAD1CQgA5Pj4AO0BAADtAQQA7QEUAO0BGAD1BRgA9QEYAPEBHADs/ + RwA8PUUAPz9LAEJCRABvb28AVVVVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVVUAGRksAD4+ + RAA4QUUAOEBEADk7PABBQ0MAO0NFADs/RwA6QUUAPENDADxDQwA8Q0MAPENDADtCQwA1REIASjRkADw3 + RgE6PUoBPD9JAT0/RwI9QEcCO0BGAjtDRQI7QUEDO0BABDk+PgQ+QkIEPkJCBTtBRAU4R0gFOUZGBTxA + QAY8QEAGOUZGBThHSAU7QUQFPkJCBT5CQgQ5Pj4EO0BABDtAQQM7QEUCO0BGAj1ARwI9P0cCPD9JATo9 + SgE8N0YBSjRkADVEQgA7QkMAPENDADxDQwA8Q0MAPENDADxBQwA8QUcAPUFIADdGSQA3SUkAOz9DADlC + RgBAP0UAGxsvAFVVVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0tQwAkIz8APDxLADxCRAA8QkUAO0JEADtE + QwBaUDUAMztIADo8PwFBQ0MDO0NFBDtARgY4P0cIPEFDCz1BRQ08QkUPPEFDETtBRBM8Q0MVPENEFzxC + Qxk8QkQaPEJEGzxCRBw8QkQdPEJEHjxDRB88Q0MgPENDIDxDQyA8Q0MhPENDITxDQyE8Q0QhPENDITxD + QyI8Q0MiPENDITxDRCE8Q0MhPENDITxDQyE8Q0MgPENDIDxDQyA8QkQfPEJEHjxCRB08QkQcPEJEGzxC + RBo8QkMZPENEFzxDQxU7QUQTPEFDETxCRQ89QUUNPEFBCzo/QQg8QUcGPUFHBTdFSAM4R0gBNTtIAFFJ + MAA6REMAO0JEADxCRQA8QEQAPD1LACQjPwAtLUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAMzMzAERQVAA+RkgAPkNFAD1CRABETUMAPDtNATxCRAQ8QkUIO0JFDDxC + RBA7QkQVO0JEGTxCQxw8Q0MePENDIDxCRCI8Q0QkPENDJTxDQyU8Q0MmPENDJjxDQyY8Q0MnPENDJzxD + Qyc8Q0MnPENDJzxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxD + Qyc8Q0MnPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MlPENDJTxDQyQ8Q0QjPENEITtDRB88Q0QcO0JEGTtD + RBU8QkQQO0JFDDxBRQg8P0QEPDtNAURMQwA8QkQAPkNFAEBHSgBHUlYAMzMzAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPkREAEBGRwA4SlMAPUJEBTtBQgw8Q0QUPEJEGzxDQyA8Q0MjPENDJTxD + QyY8Q0MmPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MnPENDJzxD + QyY8Q0MmPENDJTxDQyM8QkMgPEJEGzxERBQ8QUIMPUJEBUJVXwBBRkcAPkREAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAP0REAEFDRAI8QkMTPENDIDxDQyU8Q0MmPENDJzxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxDQyY8Q0MlPENEIDxCRBNBQ0QCP0REAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPkNDAD9ERAY8QkMhPENDJzxDQyc8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MnPENDJz1CQyFAREQGPkNEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAP0BAAD86PAA7P0IIPUJEFDxCRB48Q0MjPENDJjxDQyY8Q0MnPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyc8Q0MmPENDJjxDQyM8QkMePUJDFDtAQghDP0AAQ0NEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQEBAAEE+QAA7P0IAEjkEADlDRgM5QkIIOkNEDjxCRBQ8Q0MZPEJDHjxD + QyE8Q0MjPENDJTxDQyY8Q0MmPENDJjxDQyc8Q0MnPENDJzxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJTxDQyQ8Q0MjPENDIzxDQyQ8Q0MlPENDJTxD + QyY8Q0MmPENDJTxDQyU8Q0MkPENDIzxDQyI8Q0MjPENDJTxDQyU8Q0MmPENDJjxDQyY8Q0MmPENDJjxD + QyY8Q0MmPENDJjxDQyY8Q0MmPENDJjxDQyY8Q0MmPENDJzxDQyc8Q0MnPENDJjxDQyY8Q0MmPENDJTxD + QyM8Q0MhPEJDHjxDQxk8QkQUO0NFDjpDQgg7PkYDE3Y6ADs/QgBFQUQAREREAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQAAADYAPUZMADhERQA7Q0MAPENCAEFJSAA8QkQBO0BEAjtB + RgU5Q0QIPUFECzxBQg49Q0IRPENEFDxBRRc8QkUaPEJDHTxDQx48Q0MgPEJDITxDRCM8Q0MkPENDJDxD + QyU8Q0MlPENDJTxDQyY8Q0MmPENDJDxDQyM8Q0MlPENDMDxCREM8QkVcPEFFdDxBRYs8QUWdPEFFqTxB + RbA8QUWyPEFFrjxBRaU8QUWXPEFFhDxCRW08QkRVPEJDPTxCQy08Q0MkPENDIzxDQyU8Q0MmPENDJTxD + QyU8Q0MlPENDJDxDQyQ8Q0QjPEJDITxDQyA8Q0MePEJDHTxCRBo8QkUYPEJFFTxDRBI9QkMPPkFECzpE + RQg7QUcFOz9EAj5ERgE+RkYAPUNDADxERAA6PkYAPTtHAAAABwBVVVUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODg4ADAzMgA8QkQAO0BEADtC + RgA6Q0QAPUFEAD5ERgA6REQAPkM+AAAA/wBAQ1sBOjxHAjxCRQM7QEUEOkBFBTtCRQY9Q0MIPEFECTxC + Qws9QkUMO0JEDTxBRAs9Q0QRPEFGLTxBRWA8QUWaPEFFxjxBReQ8QUX1O0BE/jtARP87QET/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/87QET/O0BE/zxBRfw8QUXwPEFF3jxBRb08QUWNPEFFUjxCRSM8QUUNO0NECztC + RQw8QkMLPEFECT1DQwg7QkUGOkBFBTtARQQ8QkUDOjxHAkRDWQFAL24AOksuADxDQAA8QkQAPUFEADpE + RQA7QkYAO0BEAD1ERQA1OTgAPz8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAARkZGAC0tLQBAQUEAO0NFAEhPOgBGR2MAOjtHAD1CRgA7QEYAOj9FADtCRQA8Q0MAPEJDADxC + RAA8QUUAO0JGDDxBRUQ8QUWUPEFF1TxBRfc7QET/Oj9D/zo/Q/88QUX/REhM/0tQU/9SV1r/Wl5i/19j + Zv9hZWj/XWFl/1dbX/9PVFf/SU1R/0FGSv87QET/Oj9D/zo/Q/87QET/PEFF8jxBRck8QUWBPEFFMztD + SAU8QUUAO0JEADxDQwA7QkUAOj9FADtARgA9QkYAOjtHAEdHYwBHUDwAPUFIADxDRwBCQkEAR0dHAEBA + QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0BGADxBRQA8QEYAPEFGAD1B + RQ08QUVUPEFFtjxBRfI7QET/Oj9D/z1CRv9MUVT/aGxv/4mMjv+oqqv/vr/A/8/Q0f/b3Nz/4ODh/+Li + 4//j4+P/4eHi/97f3//X2Nn/ysvM/7i5u/+goqT/gIOG/2FlaP9HTFD/O0BE/zo/Q/87QET/PEFF6DxB + RaA8QUU+OUJGBTxCRQBCQ0UAP0NGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QUQASzZFADxBRQA8P0gDPEFFRjxB + RbM8QUX2O0BE/zo/RP9KT1P/c3d5/6aoqf/P0NH/5+fn//Dw8P/z8/P/8/Pz//Ly8v/x8fH/8fHx//Hx + 8f/x8fH/8fHx//Hx8f/y8vH/8vLy//Pz8//y8vL/7+/v/+Lj4//HyMn/m52f/2hsb/9ESU3/Oj9D/ztA + RP88QUXsPEFFljxBRSg5P0QAPEFFAD1ARQA2Q0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBM + UwAmWGIAPEFGADxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRR08QUWMPEFF7TtA + RP87QET/UlZa/42Qkv/Jy8v/6urq//Ly8v/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/y8vL/8vLy/+Xl5f+9vr//fH+C/0hN + Uf86P0P/PEFF/zxBRdc8QUVgPEBEBzxBRQA8QUUAPEFFADxBRQA8QUUAPEFFADxBRQA8QUUAO0FFADRL + TwA2SEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRQA7REQAPEFFADxB + RQA8QUQAPUJEADxARQI8QUUFPEFFBzxBRQg8QUUIPEFFCDxBRQg8QUUIPEFFPzxBRcU8QUX/Oj9D/0pP + U/+LjZD/0NHS//Dw8P/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/z8vL/6+zs/8HD + xP90eHr/QUZJ/zo/RP88QUX1PEFFkTxBRRo8QUUHPEFFCDxBRQg8QUUIPEFFCDxBRgY7QkYDPUBEADxB + RQA8QUUAPEFFAD1DQwA9Q0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA9QUUAPEFFADxBRQA3W0UAPEFFFDxB + RTQ8QUVdPEFFgDxBRZ08QUWxPEFFvDxBRcI8QUXDPEFFwzxBRcM8QUXEPEFF5ztARP89Qkb/bXF0/8LD + xP/u7u7/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/n5+j/qKmr/1RYXP86P0P/PEFF/TxBRdM8QUXCPEFFwzxBRcM8QUXDPEFFvjxBRbM8QUWfPEFFgzxB + RWA8QUU3PEFFFT1HPwE8QUUAPUFFAD1ARAA9QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/RUcAP0RGAD1BRQA7QUUAPEFFFDxBRUs8QUWSPEFFyzxB + Re08QUX8O0BE/zo/Q/86P0P/Oj9D/zo/Q/86P0P/Oj9D/zo/Q/86P0P/OT5C/0VKTv+SlZf/4uPj//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/x8fH/8fHx/8vMzf9rb3L/O0BE/zk+Q/86P0P/Oj9D/zo/Q/86P0P/Oj9D/zo/Q/86P0P/O0BE/zxB + Rf08QUXuPEFFzjxBRZU8QUVQPUFGFztCRgA8QUUAO0BCAD0+QAAAgIAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAOkVGAC5fRwA8QUUAOj9FAD1BRSI8QUV1PEFFyDxBRfU7QET/OT5D/ztA + RP9BRkr/TlNW/1tfYv9mam3/b3N1/3N2ef90d3r/c3d6/3N3ev9zdnn/eHx+/7O1t//t7e3/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/c3N3/j5GT/3N2ef9zd3r/c3d6/3N3ev9zd3r/cHR3/2hsbv9cYGP/T1RX/0JH + Sv87QET/OT5D/ztARP88QUX3PEFFyzxBRXc8QUUjPUNGADxBRAAoblQAOkVGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAA8QEUAPUFGADxARQA8QUUZPEFFdjxBRdY8QUX+Oj9D/zxBRf9NUlX/cHN2/5ib + nf+7vb7/0dLT/+Dh4f/o6On/6urr/+vr6//r6+v/6+vr/+vr6//r6+v/7Ozt//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/7+/v/+vr6//r6+v/6+vr/+vr6//r6+v/6uvr/+np6f/i4uL/09TU/72/ + wP+bnZ//cnZ4/05TVv88QUX/Oj9D/zxBRf88QUXYPEFFdztCRBk8QEUAPUFEAD1ARAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAOkJCAD1BRgA8QUQAPT9GBDxBRU88QUXFPEFF/jo/Q/8/REj/YmZp/5yeoP/Pz9D/6enq//Ly + 8v/z8/P/8vLy//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8vLy//Pz + 8v/y8vL/6urq/9DR0v+eoKL/Y2dq/0BFSf86P0P/PEFF/jxBRcY8QUVPPkBEBD1BRQA7QUQAP0BHAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA+QUYAQEFGADxBRQA8QUQVPEFFijxBRfA7QET/PUJG/2Jmaf+qrK3/4OHh//Ly8v/y8vL/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/y8vL/4eHi/6utr/9jZ2r/PUJG/ztARP88QUXwPEFFij1BRRU8QUUAOEdJADpF + RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADpE + RwA8Q0cAO0FFADxBRSo8QUW1PEFF/jo/Q/9NUlb/mJqc/97e3//y8vL/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/7+/v/9PU + 1P/T1NT/7+/v//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/e39//mZud/05TVv86P0P/PEFF/jxBRbQ8QUUrPj9DADtB + RAA7PkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOURIADpE + RwA9P0UAPEJGOzxBRc07QUX/PEFF/2hsb//Excb/8PDw//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/0NHS/1ld + YP9ZXWD/0NHS//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8PDw/8XGx/9pbXD/PEFF/zxBRf88QUXNPEFFOjxD + RwA9QEMAP0NGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QEMAO0JGAD1A + QwA8QUVAPEFF1ztARP8/REj/goWI/93d3v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0BF + SP9ARUj/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/d3t7/goSH/z9ESP87QET/PEFF1jxB + RT48QEQAPUFFADw/QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlCQwA6P0IAPEJGADxB + RTk8QUXXO0BE/0JHSv+TlZf/5+jo//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0FG + Sf9BRkn/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8fH/5+fn/5GUlv9BRkr/O0BE/zxB + RdU8QUU3PEJGAD09QABAQEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1ARQA8QEUAPEFFKDxB + Rcs7QET/QUZK/5eanP/r6+v/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/ubu8/0FG + Sf9BRkn/ubu8//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+vr6/+WmZv/QUZK/ztA + RP88QUXJPEFFJzxBRQA7QUYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBGADxARQA7QEQTPEFFsDxB + Rf8+Q0f/kZOV/+vr6//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/19fX/ury9/0FG + Sf9BRkn/ury9//X19f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/q6+v/kJOV/z5D + R/88QUX/PEFFrj1BRRI8QUUAPEJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9PUcAPEBGADw/RwM8QUWEPEFF/TtA + RP9/goX/5ufn//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/6+vs/9LT0/+xs7T/fH+C/z5D + R/8+Q0f/fYCD/7O1tv/U1db/7e3t//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5ubm/36B + hP87QET/PEFF/TxBRYM7REQDPEJFAD09SQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAA/wAAPEFFADxBRUw8QUXuOj9D/2Zq + bf/b29z/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/+vr6/+8vr//en1//09TV/8+Q0f/O0BE/zxB + Rf88QUX/O0BE/z9DR/9RVln/gIOF/8PFxv/t7e7/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9rb + 2/9laWz/Oj9D/zxBRe48QUVLPEJEADtMKQArVVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRgA8QUUAPEFFGTxBRcU7QET/TVFV/8LD + xP/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/2NnZ/4SHif9GSk7/OT5C/zo/Q/89Qkb/QEVI/0JG + Sf9CRkn/QERI/z1CRv86P0P/OT9D/0pOUv+Mj5H/3t/f//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/BwsP/TFBU/ztARP88QUXDPEFFGDxBRQA5QUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRQA/OUIAPEFFezxBRf49Qkb/l5qc//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/KzMz/ZGdr/zo/Q/87QET/QEVI/01QUf9aW1r/YmFg/2Rj + Yf9kY2H/YWFg/1laWv9MTlD/P0RH/zpARP88QUX/bnF0/9TV1f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/v7+//lpmb/z1CRv88QUX+PEFFeEM+RQA5QkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JEADxBRQA8QUUrPEFF3To/Q/9kaGv/39/g//Hx + 8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9DR0v9eYmb/OT9D/zxBRf9KTU//X19e/2hnZf9qaGX/aWdl/2ln + Zf9pZ2X/aWdl/2poZf9oZmT/XV1d/0hLTf88QUX/Oj9D/2lsb//Y2dr/8vHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/x8fH/3t/f/2Roa/86P0P/PEFF3DxBRSk8QUUAPEJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0FFADpCQwE8QUWJPEFF/0JHS/+xs7T/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/5OTk/3J1eP86P0P/PUJG/1BSU/9mZWP/amdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/amhl/2VjYv9NT1H/PEFF/zpARP98gIL/6Ojo//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy/7Cys/9CRkr/PEFF/zxBRYc+QEkBPEFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5RkgAPEJFADxBRSc8QUXeOj9D/25ydf/m5+f/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/y8vL/qKqr/z5DR/88QUX/TlBS/2dlZP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9mZGP/S05Q/ztARP9BRkr/sLKz//Ly8v/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx/+bm5v9tcXT/Oj9D/zxBRd08QUUmPEFFAD1ARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1SkwAPz5CADxBRXg8QUX/QUZK/7K0tf/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/m5+f/am5x/zk+Qv9ESEv/Y2Jh/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qZ2X/YWFg/0JGSf85PkL/b3J1/+jo6P/x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v+xs7T/QUZK/zxBRf88QUV1PEFGADs/QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA8QUUAPEFGFDxBRcg6P0P/ZGhr/+Li4//x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/U1NX/TlJW/zo/RP9RU1T/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1BSU/86P0P/T1NX/9XW1v/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/h4uL/YmZq/zo/Q/88QUXGPEJFEjxBRQA9PUkAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFA7OQA8QUUAPEFFSjxBRfU8QUX/nJ6g//Ly8v/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/Oz9D/Sk9S/ztARP9UVVb/amhm/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amhm/1RVVv87QET/Sk9S/87P0P/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/y8fH/mpye/ztARP88QUX0PEFFSDxBRQA5L1QAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtBRAAfAAAAPEFFjztARP9MUVT/zs7P//Ly8v/w8PD/8fHw//Hx + 8P/v7/D/7/Dw//Hx8P/x8fD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Hx8f/f4OD/XWFk/zk/Q/9FSUv/YWFg/2poZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qaGX/YWFg/0VIS/85P0P/XWFk/9/g4P/x8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8P/x8fD/7/Dw/+/v + 8P/x8fD/8fHw//Dw8P/y8vL/zM7O/0tQVP87QET/PEFFjStPRAA+QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtBRQA7QUUTPEFFyzo/Q/9vc3b/6enp//Hx8P/w8PD/4eTy/8bO + 9/+2wvn/t8L5/8jQ9v/k5vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/nZ+h/z1CRv87QET/RUhL/1lZWf9lZGL/aWdl/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2pnZf9qaGX/aWdl/2ZkY/9ZWVr/REhL/ztARP8+Q0f/nqCi//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+Tm8v/I0Pb/t8L5/7bC + +f/Gzvf/4eTy//Dw8P/x8fD/6Onp/25xdP86P0P/PEFFyT1BRhI9QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQEBAADxBRQA8QUU5PEFF7ztARP+bnZ//8vLy/+/w8P/P1vX/obD9/5Sm + //+Spf//kqX//5Sm//+ks/z/1dr1//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/5eXm/4SHif8+Q0f/Oj9D/z1CRv9GSUz/UVNU/1pbW/9gYF//Y2Jh/2Rj + Yv9kY2L/Y2Jh/2BgX/9aW1v/UVNU/0ZJTP89Qkb/Oj9D/z5DR/+Fh4r/5ebm//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/1Nr1/6Sz/P+Upv//kqX//5Kl + //+Upv//obD9/8/W9f/w8PD/8vLy/5mcnv87QET/PEFF7jxBRTg8QUUAN0lJAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAMUVXADxBRQA8QUVpO0BE/kRJTf/BwsP/8/Py/9fc9P+crP7/k6X//5Sm + //+Upv//lKb//5Sm//+Tpf//oLD9/93h8//x8fD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+bm5/+eoKL/VFlc/zxBRf85PkL/O0BE/z1CRv8/REf/QkZJ/0NH + Sv9DR0r/QkZJ/z9ER/89Qkb/O0BE/zk+Qv87QET/VFhc/56gov/m5+f/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8P/d4fP/oLD9/5Ol//+Upv//lKb//5Sm + //+Upv//k6X//5yt/v/Y3PT/8/Py/8DCw/9ESEz/O0FF/jxBRWg8QUUATC0+AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFAD5CRQE8QUWYOj9E/1ZaXv/b29z/7u/y/7K++v+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//7nE+f/v7/D/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx + 8f/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/w8PD/1dXW/5yfoP9obG//TFBU/z5DR/87QET/OT9D/zk+ + Qv85PkL/OT9D/ztARP8+Q0f/TFBU/2hsb/+anJ7/09TV//Dw8P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx + 8f/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+/v8P+5xPn/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+yvvr/7u/y/9rb2/9VWl3/OkBE/zxBRZY+RUkBPEJGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRQw8QUW9OT5C/21xdP/r6+r/5Ofy/5+v/f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6Wz/P/p6vH/8PDw//Dw8P/w8PD/8PDw//Ly8v/x8fH/6Ojo/+Hh + 4f/g4OH/5eXm/+7u7v/y8vL/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//Hx8f/n5+f/z9DQ/7W3uP+doKH/j5GU/4eK + jP+Hioz/j5GU/52gof+2t7j/z9DQ/+fn5//x8fH/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//Ly8v/u7u7/5eXm/+Dg + 4f/h4eH/6Ojo//Hx8f/y8vL/8PDw//Dw8P/w8PD/8PDw/+jq8f+ls/z/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+fr/3/5Ofy/+rq6v9scHP/OT5C/zxBRbw8QUULPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFGADxBRho8QUXZOj9D/4aJi//x8fD/4OPz/5ys/v+Tpv//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6Gw/f/l5/L/8fHw//Dw8P/x8fH/7e3t/8bHyP+PkpT/bHBz/1xg + ZP9bX2L/Zmpt/36ChP+mqKr/0dLT/+zs7P/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8vLy//Pz8//y8vL/8vLy//Hx + 8f/x8fH/8vLy//Ly8v/z8/P/8vLy//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/s7Oz/0dLT/6aoqf9+gYT/Zmpt/1tf + Yv9cYGT/bHBz/4+SlP/Gx8j/7Ozt//Hx8f/w8PD/8fHw/+Xn8v+hsP3/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Om//+crP7/4OPz//Hx8P+FiIr/Oj9D/zxBRdk8QUUaPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRS88QUXoO0BE/52fof/z8vL/5ujy/6Kx/f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//k6X//6i2/P/q6/H/8PDw//Ly8f/e3t//i46Q/0lOUv86P0P/OT5C/zk/ + Q/85P0P/OT5C/zk+Qv89Qkb/T1NX/3p9gP+3ubr/5eXl//Ly8v/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/y8vL/5eXl/7e5uv97foH/T1NX/z1BRf85PkL/OT5C/zk/ + Q/85P0P/OT5C/zo/Q/9JTlH/iYyP/97e3//y8vH/8PDw/+rr8f+ntvz/k6X//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+isf3/5ujy//Py8v+cnqD/O0BE/zxBRec8QUUuPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRUE8QUXzPEFF/66wsf/z8/P/7+/w/7nE+f+Tpf//lKb//5Sm + //+Upv//lKb//5Sm//+Upv//lKb//8HK+P/w8PD/8fHx/9vb3P9xdHf/O0BE/ztARP8/REf/R0tN/01P + Uf9OUFL/Sk1P/0NHSv89Qkb/Oj9E/zk+Q/9DR0v/am1w/6+wsv/k5eX/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/+Tl5f+usLL/am1w/0JHS/85PkP/Oj9E/z1CRv9DR0r/Sk1P/05Q + Uv9NUFH/R0tN/z9DR/87QET/O0BE/3F1eP/b3Nz/8fHx//Dw8P/Byvj/k6b//5Sm//+Upv//lKb//5Sm + //+Upv//lKb//5Ol//+6xPn/7+/w//Pz8/+tr7H/PEFF/zxBRfI8QUVAPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRU08QUX6QUZJ/7m6vP/z8/P/8fHw/+Dj8/+ks/z/k6X//5Sm + //+Upv//lKb//5Sm//+Tpf//qbf8/+Xn8v/x8fH/6Ojo/36Bg/87QET/PEFF/0lMTv9dXV3/Z2Vj/2ln + Zf9pZ2X/aGZk/2RjYf9bW1v/TU9R/0FFSf87QET/OT5C/0BFSf9tcXP/vL2+/+zt7f/y8fH/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Lx8f/s7O3/u72+/21wc/9ARUn/OT5C/ztARP9BRUj/TU9R/1tbW/9kY2H/aGZk/2ln + Zf9pZ2X/Z2Vj/11dXf9ITE7/PEFF/ztARP9+goT/6Ojp//Hx8P/k5/L/qbf8/5Ol//+Upv//lKb//5Sm + //+Upv//k6X//6Sz/f/g4/P/8fHw//Pz8/+4urv/QEVJ/zxBRfo8QUVNPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVc7QET+RUlN/8DCw//z8/L/8PDw//Hw8P/c4PP/rrv7/5ip + /v+Upv//lKb//5mq/v+yvvr/4OPz//Hx8P/y8vL/rK6w/0FFSf87QET/Sk1P/2VjYv9qaGX/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/aGZl/2FgX/9SU1T/QkZJ/ztARf85PkP/R0tP/4mLjv/a2tv/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy/9ra2/+Ii47/RktP/zk+Q/87QEX/QkZJ/1JUVf9hYF//aGZl/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2poZf9lY2L/Sk1P/ztARP9BRkr/ra+w//Ly8v/x8fD/4OPz/7K++v+Zqv7/lKb//5Sm + //+Yqf7/rrv7/9zg8//w8PD/8PDw//Pz8//AwcL/RElN/ztARP48QUVWPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRV07QET/R0tP/8XHyP/y8vL/8PDw//Dw8P/x8fD/6uvx/9fc + 9P/J0fb/ytL2/9nd9P/s7PH/8fHw//Hx8f/i4uP/ZWls/zk+Q/9DR0r/YmFg/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/YmFg/1FTVP9ARUj/O0BE/ztARP9jZ2r/wcLD//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/wMLD/2Jmaf87QET/O0BE/0BFSP9RU1T/YmFg/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/YWFg/0NHSv85PkL/Zmpt/+Lj4//x8fH/8fHw/+zs8f/Z3fT/ytH2/8nR + 9v/X3PT/6uvx//Hx8P/w8PD/8PDw//Ly8v/Fxsf/RktP/ztARP88QUVcPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVw7QET/R0tP/8jJyv/z8/P/8PDw//Dw8P/w8PD/8PDw//Hx + 8P/x8fD/8fHw//Hx8P/w8PD/8PDw//Py8v+5urv/QkdK/zxBRf9UVVb/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9fXl7/SUxO/zxBRf86P0P/TlNW/6yu + sP/u7u7/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+7u + 7v+srrD/TlNW/zo/Q/88QUX/SUxO/15eXv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1NVVf87QET/QkdL/7m7vP/z8vL/8PDw//Dw8P/x8fD/8fHw//Hx + 8P/x8fD/8PDw//Dw8P/w8PD/8PDw//Pz8//Hycr/RktP/ztARP88QUVbPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRVY7QET+RUlN/8fIyf/09PT/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+KjY//OT9D/0FFSP9hYF//aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9qZ2X/ZmRj/1JUVf8/Q0f/Oj9D/0ZL + T/+jpaf/7u7u//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fD/7e7u/6Kk + pv9GS0//Oj9D/z9DR/9TVFX/ZmRj/2pnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2FgX/9ARUj/OT9D/4qNj//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//T09P/GyMn/RElN/ztARP48QUVVPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRUw8QUX6QEVJ/8HCw//39vb/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+bm5/9na27/OT5C/0lLTv9nZWT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9ZWVr/QUVJ/zo/ + Q/9GSk7/p6mr/+/v7//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/p6mr/0ZK + Tv86P0P/QUVJ/1laWv9oZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dlZP9IS07/OT5C/2hrbv/m5+f/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//f39v/AwsP/QEVJ/zxBRfk8QUVLPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRT88QUXxPEFF/7W3uf/6+vr/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vHx/9jZ2f9TV1v/Oj9D/1BSVP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/XFtb/0FF + Sf86P0P/S1BU/7u9vv/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Lx8f+8vb7/TFBU/zo/ + Q/9BRUn/W1tc/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9QUlP/Oj9D/1NXW//Y2dr/8vHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//r6+v+1t7j/PEFF/zxBRfE8QUU+PEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRSw8QUXmOj9D/6Kkpv/8/Pz/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8zNzv9HTE//O0BE/1ZXV/9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1pa + Wv8/REf/Oj9D/15iZf/X2Nn/8vLx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLx/9fY2P9eYWX/Oj9D/z9E + R/9aWlv/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9WV1f/O0BE/0dMUP/Mzs7/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//z8/P+hpKb/Oj9D/zxBReY8QUUsPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRBg8QUXXOT5C/4mMjv/9/f3/8/Pz//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8LDxP9ESEz/PEFF/1lZWv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9UVVb/PUJF/ztARP+Ii43/7e3t//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/7e3t/4eKjf87QET/PUJG/1RV + Vv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9ZWVn/PEFF/0RITP/CxMX/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8/Pz//39/f+JjI7/OT5C/zxBRdc8QUUYPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPEFFADxCRQs8QUW5OT5C/29ydf/39/f/9/f3//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/7/Awf9DSEv/PEFF/1paWv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2lnZf9pZ2X/aWdl/2ln + Zf9mZWP/Sk1P/zpARP9JTlL/xcbH//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/xMXG/0lOUf86QET/Sk1P/2Zl + Y/9pZ2X/aWdl/2lnZf9pZ2X/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9aWlr/PEFF/0NIS/+/wMH/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/9/f3//f39/9vcnX/OT5C/zxBRbk8QUUKPEFFAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAO0FEADZFOAA8QUWVOj9D/1ldYf/o6en//Pz8//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8XGx/9ESU3/PEFF/1hZWf9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ZlY/9hYF//YF9e/2NiYf9oZmT/aWdl/2ln + Zf9qaGX/Xl1d/z9ER/86P0P/gIOF/+3t7f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/t7e3/f4OF/zo/Q/8/REf/Xl1d/2po + Zf9pZ2X/aWdl/2hmZP9jYmH/YF9e/2FgX/9mZWP/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9YWFn/PEFF/0RJTf/Fx8j/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH//f38/+jp6f9YXWD/Oj9D/zxBRZVCLzwAPEBEAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAATE9YADxBRQA8QUVuO0BE/0dLT//S09T///////T09P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9DR0v9KTlL/O0BE/1RVVv9qaGX/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9nZWP/V1dY/0ZKTP9ARUj/P0RH/0JGSf9NT1H/YF9f/2ln + Zf9pZ2X/aGZk/0xPUf86P0P/TlNW/9DR0v/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/S09P/T1RY/zo/Q/9MT1H/aGZk/2ln + Zf9pZ2X/YF9f/01PUf9CRkn/P0RH/0BFSP9GSkz/V1dY/2dlY/9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9UVVb/O0BE/0pPU//R0tL/8vLy//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/09PT//////9HS0/9GS0//O0BE/zxBRW08QUUAR1JRAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAACwwMADxBRQA8QUVCPEFF9D1CRv+wsrP///////j4+P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx/9zc3f9YXF//Oj9D/09RUv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ZlY/9OUFL/PUJG/ztARf88QUX/PEFF/zxBRf87QEX/QkZJ/1xc + XP9pZ2X/amhl/1tbW/89Qkb/PEFF/6Olp//y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v+kpqj/PUJG/z1CRv9bW1v/amhl/2ln + Zf9cXFz/QkZJ/ztARf88QUX/PEFF/zxBRf87QEX/PUJG/05QUv9mZWP/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9PUVL/Oj9D/1hcYP/c3d3/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/4+Pj//////6+xs/89Qkb/PEFF9DxBRUE8QUUACwsMAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUgPEFF2zk+Qv+LjpD//v7+//39/f/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+np6f9rb3L/OT5C/0hLTf9nZWT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1RWVv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/O0BF/0RI + S/9jYmH/amhl/2VjYv9ER0r/OT5C/3p9gP/s7e3/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+zs7f95fX//OT5C/0RIS/9lY2L/amhl/2Ni + Yf9ESEv/O0BF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf9UVlb/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dlZP9IS03/OT5C/2xwc//p6en/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/9/f3//v7+/4uOkP85PkL/PEFF2jxBRR88QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRQA9QkUIPEFFtDo/Q/9laWz/8vLy///////39/f/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+JjI7/OT5D/0FGSf9jYmD/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZGNi/0RHSv87QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxB + Rf9VVlf/aWdl/2hmZf9MTlD/OT9D/11hZf/i4uP/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+Hi4v9dYWT/OT9D/0xOUP9oZ2X/aWdl/1RW + Vv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztBRf9ER0v/ZGNi/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2JiYP9BRkn/OT5D/4qNj//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//f39///////8fLy/2VpbP86P0P/PEFFsztCRQc7QkUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRwA9P0MAPEFFfTtARP9KT1P/1tfY///////8/Pz/8vLy//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Pz8/+usLL/PkNH/z1CRv9aW1v/amhl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/XV1d/z5DRv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + RP9LTU//aGZk/2lnZf9TVFX/Oj9E/09UV//T09T/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9LT0/9PU1f/Oj9E/1NUVf9qZ2X/aGZk/0tN + T/87QET/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf8+Q0b/XV1d/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/amhl/1paW/89Qkb/PkNH/6+xs//z8/P/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8vLy//z8/P//////1tfY/0pPUv87QET/PEFFfD5BRgA7QUQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEpMgA8QUUAPEFFRzxBRfU8QUX/ra+x////////////9vb2//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/S09T/T1RX/zo/Q/9PUVL/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qaGX/Wltb/z1CRv88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + Rf9IS07/Z2Vk/2poZv9XWFj/O0BE/0dMUP/Iycr/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8fIyf9HS0//O0BE/1dYWP9qaGb/Z2Vj/0hL + Tf87QEX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf89Qkb/Wltb/2poZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/05RUv86P0P/UFRY/9PU1P/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/9vb2////////////rK+w/zxBRf88QUX0PEFERjxBRQBDSlUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACtVVQA8QUUAPEFFGjxBRdQ5PkL/fICC//r6+////////Pz8//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/q6ur/c3d6/zk+Qv9DR0r/ZGNh/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/Xl5d/z5DR/88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztA + RP9MTlD/aGZk/2poZv9ZWVn/PEFF/0NITP/CxMX/8/Pz//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8/Pz/8LDxP9DSEz/PEFF/1lZWv9qaGb/aGZk/0tO + UP87QET/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf8+Q0f/Xl5d/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZGJh/0NHSv85PkL/dXh7/+rr6//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL//Pz8///////6+vr/fH+C/zk+Qv88QUXUPEFFGjxBRQAzMzMAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkUAP0NGAjxBRZw6QET/VFlc/+Pk5P////////////f3 + 9//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/qaus/z5DR/89QUX/WFlZ/2pnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/ZWRi/0VJTP87QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/zxB + Rf9XV1j/amdl/2poZv9ZWVn/PEFF/0RJTf/DxMX/8/Pz//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8/Pz/8LExf9DSEz/PEFF/1lZWf9qaGb/amdl/1ZX + WP88QUX/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/ztBRf9FSUz/ZWRi/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9qZ2X/WFhZ/z1BRf8+Q0f/qqyu//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/39/f////////////j4+T/VFhc/zpARP88QUWcPkJFAj1CRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkYAPEFFADxBRVk8QUX7PkNH/7W3uP////////////39 + /f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/2dra/1hcX/86P0P/SEtN/2ZlY/9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/1dYWf89Qkb/PEFF/zxBRf88QUX/PEFF/zxBRf88QUX/O0BF/0dK + Tf9lY2L/aWdl/2poZv9XV1j/O0BE/0hNUP/Jysv/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/8jKyv9ITVD/O0BE/1dXWP9qaGb/aWdl/2Vj + Yv9HSk3/O0BF/zxBRf88QUX/PEFF/zxBRf88QUX/PEFF/z1CRv9YWFj/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9mZWP/SEtN/zo/Q/9ZXWD/2tvb//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly + 8v/9/f3///////////+0trj/PkNH/zxBRfo8QUVZPEFFADxCRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAPEFFADxBRSA8QUXZOT5C/32Ag//6+/v///////// + ///5+fn/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/5OVl/87QET/PUJG/1laWv9qZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2dmZP9SVFX/PkNH/ztARf88QUX/PEFF/ztARf88QUX/RklM/2Bf + Xv9pZ2X/aWdl/2lnZf9SVFX/Oj9D/1BVWP/U1dX/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9TU1f9QVFj/Oj9D/1JUVf9pZ2X/aWdl/2ln + Zf9fX17/RUlM/zxBRf87QEX/PEFF/zxBRf87QEX/PkNH/1JUVf9oZmT/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2pnZf9ZWlr/PUJG/ztARP+Ulpj/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//n5 + +f////////////r6+v98f4L/OT5C/zxBRdk8QUUfPEFFAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JGADtERgM8QUWbO0BE/1BUWP/c3d7///////// + ///+/v7/9PT0//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy/9PU1P9UWFz/Oj9D/0ZKTP9lY2L/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9oZmT/W1tb/0tOUP9ER0r/QkZK/0ZKTP9SVFX/Y2Jh/2ln + Zf9pZ2X/aWdl/2hnZf9MTlD/OT9D/11hZf/i4+P/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+Lj4/9dYWT/OT9D/0xOUP9pZ2X/aWdl/2ln + Zf9pZ2X/Y2Jh/1JUVf9GSkz/QkZK/0RHSv9LTlD/W1tb/2hmZP9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2VkYv9GSkz/Oj9D/1VZXP/T1NX/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/9PT0//7+ + /v///////////9vc3f9PVFf/O0BE/zxBRZk8Q0gCPEJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITo9ADxBRQA8QUVNPEFF9jxBRf+jpaf///////// + ////////+/v7//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P+Zm53/PEFF/zxBRf9TVFX/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2hmZP9kY2L/Y2Jh/2ZlY/9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/2RjYf9DR0r/OT5C/3h8f//s7Oz/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw/+zs7P94e37/OT5C/0RHSv9kY2L/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9mZWP/Y2Jh/2RjYv9oZmT/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/1JUVf88QUX/PEFF/5mcnv/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/+/v7//// + /////////////6Kkpv88QUX/PEFF9TxBRUw8QUQASysyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASUtNAD1BRQA9QUUTPEFFxjo/Q/9mam3/7/Dw//// + //////////////f39//w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/e39//ZWls/zo/Q/9AREj/XFxc/2pn + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9pZ2X/aWdl/1ZXWP88QUX/PkNH/6epq//y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v+nqav/PUJG/zxBRf9WV1j/aWdl/2ln + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9qZ2X/XFxc/0BER/86P0P/Zmpt/97f3//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/39/f///////// + ////////7+/v/2VpbP86P0P/PEFFxjxBRBI8QUQAJVtdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9BQgA7QUUAPEFFdjxBRf9BRkr/vL6///// + //////////////7+/v/09PT/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/vL6//0pOUv86P0T/REhL/2Fg + X/9qZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9qZ2X/YmFg/0NHSv86P0P/XGBk/9vc3P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/b29z/XGBj/zo/Q/9DR0r/YmFg/2pn + Zf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2pn + Zf9gYF//REhL/zo/Q/9KT1P/vb/A//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//T09P/+/v7///////// + ////////vL2//0FGSv88QUX/PEFFdTxCRgA3NTkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtCQQA8QUUAPEFFJzxBRd45PkL/d3p9//f3 + 9//////////////////8/Pz/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/7+/v/5yeoP9ARUn/O0BE/0dK + TP9hYWD/amhl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2ln + Zf9lZGL/Sk1P/ztARP9ARUn/p6qr//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/p6mr/0BFSf87QET/Sk1P/2Vk + Yv9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amhl/2Fh + YP9GSkz/O0BE/0BFSf+dn6H/7+/v//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//z8/P////////////// + ///39/f/dnp8/zk+Qv88QUXdPEFFJjxBRQA4OT4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBASAA9QEUAPz9GATxBRZA7QET/RktP/8fJ + yv//////////////////////+fn5//Hx8f/w8PD/8PDw//Dw8P/w8PD/8fHx/+np6f+Ii47/PUJG/ztA + RP9FSUz/Xl5d/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2Rj + Yv9MT1D/PEFF/ztARP9+gYT/5+jo//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5+jo/36Bg/87QET/PEFF/0xO + UP9kY2L/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/Xl5d/0ZJ + TP87QET/PUJG/4mMjv/p6en/8fHx//Dw8P/w8PD/8PDw//Dw8P/x8fH/+fn5//////////////////// + ///HyMn/RktP/ztARP88QUWPPkBCAT1BRAA8REQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUYAPEFFADxBRTQ8QUXnOj9D/3x/ + gv/4+Pn///////////////////////f39//w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/k5OX/hYiK/z5D + R/87QET/QUVJ/1ZWV/9mZGP/amdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/aWdl/2poZf9pZ2X/Xl5d/0hL + Tf88QUX/Oj9D/21xdP/b3Nz/8vHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vHx/9vb3P9tcHP/Oj9D/zxB + Rf9IS03/Xl5d/2lnZf9qaGX/aWdl/2lnZf9pZ2X/aWdl/2lnZf9pZ2X/amdl/2ZkY/9VVlf/QUVJ/ztA + RP8+Q0f/hYiL/+Tl5f/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/39/f///////////////////////j4 + +f97f4L/Oj9D/zxBRec8QUUzPEFFADxBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAPUFEAD5ARAM8QUWXO0BE/0ZL + T//Gx8n///////////////////////7+/v/19fX/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/5ubn/5KV + l/9FSk3/Oj9D/z1BRf9HSk3/V1hY/2NiYf9nZmT/aWdl/2lnZf9oZ2X/ZmRj/15eXf9PUVL/QERI/ztA + RP88QUX/cnZ4/9fY2f/y8vL/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/X2Nj/cnV4/zxB + Rf87QET/QERI/09RU/9eXl3/ZmRj/2lnZf9pZ2X/aWdl/2dmZP9jYmH/V1hY/0dKTf89QkX/Oj9D/0VK + Tv+TlZf/5ufn//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//X19f/+/v7//////////////////////8bH + yP9GS0//O0BE/zxBRZY9QUYDPUFFAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0FGADxBRQA8QUU0PEFF5To/ + Q/91eHv/9PX1///////////////////////9/f3/9PT0//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+zt + 7f+xs7T/XWFk/ztBRf86P0P/PEFF/0JGSf9JTE7/TlBS/09RUv9MTlD/RklM/z9DR/87QET/OT5D/0dM + UP+NkJL/4ODg//Ly8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/y8vL/4ODg/42P + kv9HTFD/OT5D/ztARP8/Q0f/RklM/0xOUP9PUVL/TlBS/0lMTv9CRkn/PEFF/zo/Q/88QUX/XWFl/7Kz + tf/t7e3/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/9PT0//39/f//////////////////////9PT1/3R4 + e/86P0P/PEFF5D1BRTQ8QUUAP0VBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRQA8QUUhPEFF1TtB + Rf9CRkr/t7m7/////////////////////////////Pz8//Pz8//w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL/2dra/5aYmv9ZXWD/PkNH/zk+Qv85PkL/OT5D/zk/Q/85PkL/OT5C/zo/Q/9HTFD/dHd6/76/ + wP/t7e3/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx/+3t + 7f+9v8D/dHd6/0dMT/86P0P/OT5C/zk+Qv85P0P/OT5D/zk+Qv85PkL/PkNH/1ldYf+WmJv/2dra//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/z8/P//Pz8////////////////////////////t7i6/0JG + Sv88QUX/PEFF0zxBRR88QUUAPUFEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQkUAPEFFADtBRQc8QUWWPEFF/zxB + Rf86P0P/YmZp/+jp6f////////////////////////////z8/P/z8/P/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx//Dw8P/a2tv/r7Cy/4KFh/9obG//XGBj/1ldYf9hZWj/dHd6/5eZm//Fxsf/6enp//Ly + 8v/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/y8vL/6Onp/8XGx/+XmZv/dHd6/2FlaP9ZXWH/XGBj/2hsb/+ChYf/r7Gy/9rb2//w8PD/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Ly8v/8/Pz////////////////////////////o6en/YmZp/zo/ + Q/88QUX/PEFF/jxBRZI+QUQGPUFEAD5AQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRUYAO0FFADxBRVU8QUX0PEFF/0FF + SP89Qkb/PEFF/5mbnf/9/f3////////////////////////////8/Pz/8/Pz//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/x8fH/8vLy/+/v7//m5uf/3+Dg/97e3//i4uP/6+zs//Ly8v/y8vL/8fHx//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8fHx//Ly8v/y8vL/6+zs/+Li4//e3t//3+Dg/+bm5//v7+//8vLy//Hx8f/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8/Pz//v7+/////////////////////////////39/f+Ym53/PEFF/z1C + Rf9BRUj/PEFF/zxBRfI8QUVSPEFFAEY8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5BRgA8QUUAPEFFGTxBRcg8QUX/QUZJ/1xc + XP9IS03/Oj9E/0xQVP/Mzc7//////////////////////////////////Pz8//Pz8//w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/8fHx//Hx8f/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/x8fH/8fHx//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/z8/P//Pz8/////////////////////////////////8vMzf9LUFP/Oj9E/0hL + Tf9bW1v/QUVJ/zxBRf88QUXGPUBFGDxBRQA9QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRgA8QUYAPEFFcTxBRf08QUX/VFVW/2po + Zf9dXVz/P0RH/zk/Q/9ucXT/7e3u//////////////////////////////////z8/P/09PT/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//T09P/8/Pz/////////////////////////////////7e3t/21xdP85P0P/P0RI/11d + XP9qZ2X/U1VW/zxBRf88QUX9PEFFcDtCRgA+QUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPUBFADxBRQA8QUUfPEFF0zxBRf9FSUv/ZWNi/2ln + Zf9pZ2X/UVNU/zxBRf88QUX/lpmb//z8/P/////////////////////////////////9/f3/9fX1//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/9fX1//39/f/////////////////////////////////8/Pz/lpmb/zxBRf88QUX/UVNU/2ln + Zf9pZ2X/ZGNi/0VJS/88QUX/PEFF0jxBRR48QUUAPkFGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPkBGADtCRQA8QUVtPEFF/j1CRv9XWFj/aWdl/2ln + Zf9pZ2X/ZWNi/0dLTf87QET/R0xQ/72/wP///////////////////////////////////////v7+//f3 + 9//x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx + 8f/39/f//v7+//////////////////////////////////////++v8D/R0xQ/ztARP9HSk3/ZWNi/2ln + Zf9pZ2X/aWdl/1dXWP89QkX/PEFF/TxBRW06QUQAP0FHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBFADxARRE8QUXBPEFF/0RIS/9lY2L/aWdl/2ln + Zf9pZ2X/aWdl/1FSVP88QUX/Oj9D/1ldYf/Z2tv///////////////////////////////////////// + ///6+vr/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//r6 + +v///////////////////////////////////////////9na2v9ZXmH/Oj9D/ztBRf9OUFL/aWdl/2ln + Zf9pZ2X/aWdl/2VjYv9FSEv/PEFF/zxBRcE8QEURPEBFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkQAPEFFADxBRUU8QUX0PEFF/1NUVf9pZ2X/aWdl/2ln + Zf9pZ2X/Y2Jh/0NHSv87QEX/O0BE/zo/Q/9xdXf/6+zs//////////////////////////////////// + /////////Pz8//X19f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/19fX//Pz8//// + ////////////////////////////////////////6+zs/3B0d/86P0P/O0BE/ztBRf9BRUj/YGBf/2ln + Zf9pZ2X/aWdl/2lnZf9TVFX/PEFF/zxBRfQ8QUVGPEFFADtARgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+Q0QAOkBFADxBRYc8QUX/QERH/2BfXv9qZ2X/aWdl/2ln + Zf9pZ2X/VldX/zxBRf9BRkr/Wl5h/z5DR/87QUT/hYmL//X19f////////////////////////////// + //////////////7+/v/5+fn/8vLy//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8vLy//n5+f/+/v7///////// + ///////////////////////////////////09fX/homL/zxBRf89Qkb/YWVp/0VKTf87QET/UlNV/2ln + Zf9pZ2X/aWdl/2pnZf9gX1//QERI/zxBRf88QUWJPURCADs/RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEFFEDxBRcQ7QEX/SEtN/2dlY/9pZ2X/aWdl/2ln + Zf9nZWP/SEtN/zo/Q/9cYGT/wMHC/21xc/86P0P/P0RI/5eanP/5+fn///////////////////////// + /////////////////////////Pz8//b29v/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx8f/29vb//Pz8//////////////////// + //////////////////////////////n5+f+Xmpz/P0NH/zo/Q/9tcXT/x8jI/2drbv85P0P/RUhL/2Vk + Yv9pZ2X/aWdl/2lnZf9nZWT/SEtO/ztARf88QUXGPEFFETxBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFGRgA8QUUAPEFFLjxBRek8QUX/UlRV/2lnZf9pZ2X/aWdl/2pn + Zf9gX17/QERH/zo/Q/+JjI7/4uLi/8fHyP9eYmX/OT5C/0FGSv+ipaf//Pz8//////////////////// + ///////////////////////////////////7+/v/9fX1//Hx8f/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/x8fH/9PT0//v7+/////////////////////////////// + /////////////////////////Pz8/6Olp/9CR0r/OT5C/15iZf/Hx8j/5OPj/5eZm/88QUX/PkNG/11d + XP9qaGX/aWdl/2lnZf9pZ2X/U1RV/zxBRf88QUXqPEFFMDxBRQA7PkIAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEVJRwA8QUUAPEFFVzxBRfo9Qkb/W1tb/2poZf9pZ2X/aWdl/2po + Zf9XWFj/PEFF/0NHS/+ztLX/4uLi/+Li4v+8vb7/Vlte/zk+Qv9FSU3/p6mr//v7+/////////////// + /////////////////////////////////////////v7+//r6+v/19fX/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//T09P/6+vr//v7+//////////////////////////////////// + ///////////////////7+/z/p6qr/0VKTf85PkL/Vlpd/7y9vv/i4uL/4uLi/72+v/9ITVD/O0BE/1RV + Vv9pZ2X/aWdl/2lnZf9qaGX/W1xb/z1CRv88QUX7PEFFWjxBRQA6PUEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1CRAA7QEYAPEFFfTxBRf9ARUj/YWBf/2lnZf9pZ2X/aWdl/2ln + Zf9PUVL/Oj9D/1NXW//Mzc3/4eHh/+Dg4P/i4eH/tba4/1JWWf85PkL/RElN/6Wnqf/6+vr///////// + ///////////////////////////////////////////////////+/v7/+/v7//b29v/y8vL/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Ly8v/29vb/+/v7//7+/v////////////////////////////////////////////// + //////////////v7+/+lqKr/RElN/zk+Qv9RVln/tba3/+Hh4f/g4OD/4eHh/9PT1P9bX2L/Oj9D/0xO + UP9oZmX/aWdl/2lnZf9pZ2X/YmFg/0FFSP88QUX/PEFFgTxBRgA8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA9QkUBPEFFmjxBRf9DR0r/ZWRi/2lnZf9pZ2X/aWdl/2hm + ZP9JTE7/OT5C/2VpbP/Z2dr/4ODg/+Dg4P/g4OD/4eHh/7K0tf9SVln/OT5C/0NITP+cnqD/9/f3//// + ///////////////////////////////////////////////////////////////////9/f3/+Pj4//T0 + 9P/x8fH/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Hx + 8f/09PT/+Pj4//z8/P////////////////////////////////////////////////////////////// + ////////9/f3/52fof9DSEz/OT5C/1FVWf+xs7T/4eHh/+Dg4P/g4OD/4ODg/9zc3P9vc3b/OT5C/0ZK + TP9nZWT/aWdl/2lnZf9pZ2X/ZWRj/0RIS/88QUX/PEFFnz1ARgI8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUFPEFFsztBRf9HSk3/Z2Vk/2lnZf9pZ2X/aWdl/2Zl + Y/9GSUz/OT5C/3V4e//d3d3/4ODg/+Dg4P/g4OD/4ODg/+Hh4f+ztLX/VFhb/zk+Qv9ARUn/jpGT/+/v + 7/////////////////////////////////////////////////////////////////////////////7+ + /v/8/Pz/+Pj4//X19f/y8vL/8fHx//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Ly8v/19fX/+Pj4//z8 + /P/+/v7///////////////////////////////////////////////////////////////////////// + ///v7/D/jZCT/0BFSf85PkL/VFhb/7O0tf/h4eH/4ODg/+Dg4P/g4OD/4ODg/9/f3/9/goT/OT5C/0RI + Sv9lY2L/aWdl/2lnZf9pZ2X/Z2Zk/0hLTf87QUX/PEFFuDpDRwY6REcAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADlFRwA6Q0cIPEFFvztARf9KTU//aGZk/2lnZf9pZ2X/aWdl/2Vk + Yv9ESEv/OT5C/3t+gP/e3t7/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/h4eH/ubq8/1peYf86P0P/PEFF/3h8 + fv/h4uP///////////////////////////////////////////////////////////////////////// + ///////////////////9/f3/+/v7//j4+P/29vb/9PT0//Ly8v/x8fH/8fHx//Dw8P/w8PD/8PDw//Dw + 8P/w8PD/8PDw//Dw8P/w8PD/8fHx//Hx8f/y8vL/9PT0//b29v/4+Pj/+/v7//39/f////////////// + /////////////////////////////////////////////////////////////////////////////+Hi + 4v95fH//PEFF/zo/Q/9aXmH/ubq7/+Hh4f/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P+ChYf/OT5C/0NH + Sv9kY2H/aWdl/2lnZf9pZ2X/aGZk/0tNUP87QEX/PEFFxDtCRQs7Q0UAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpCRAA7QkQLPEFFxDtARf9LTlD/aGZk/2lnZf9pZ2X/aWdl/2Zk + Y/9FSEv/OT5D/3R3ef/b29v/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4uHh/8LDw/9nam3/O0BE/zo/ + Q/9hZWn/x8nK//7+/v////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//7+/v/8/Pz/+/v7//r6+v/6+vr/+fn5//n5 + +f/5+fn/+fn5//r6+v/6+vr/+/v7//z8/P/+/v7//v7+//////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7/yMnK/2Jl + af86P0P/O0BE/2Zqbf/CwsP/4uLh/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9ra2v96fH7/OT9D/0NH + Sv9kY2H/aWdl/2lnZf9pZ2X/aGZk/0xOUP87QEX/PEFFyDxBRhA7QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpCRgA7QkYLPEFFwztARf9LTU//aGZk/2lnZf9pZ2X/aWdl/2dl + ZP9GSkz/Oj9D/2dqbP/Pzs7/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Li4v/Nzs7/eHt+/z9E + R/85PkL/TVFV/6Olp//y8vP///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////Lz8/+jpaf/TFFU/zk+ + Qv8/Q0f/eHt+/83Ozv/i4uL/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/83My/9tb3L/Oj9D/0VI + S/9mZGP/aWdl/2lnZf9pZ2X/aGZk/0xOUP87QEX/PEFFyTxBRhA8QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADtDRgA7QkYGPEFFuTtARf9JTE//aGZk/2lnZf9pZ2X/aWdl/2hm + ZP9KTU//Oj9D/1hcX/+9u7v/2tra/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/h4eH/2NjY/5KU + lv9ITFD/OT5C/z5DR/93en3/1NXW//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////1NbW/3d7ff8+Q0f/OT5C/0hN + UP+SlZb/19jY/+Hh4f/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/19fW/727u/9dYGP/Oj9D/0lM + Tv9oZmT/aWdl/2lnZf9pZ2X/aGZk/0tNT/87QEX/PEFFwTxARgk9QEYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA8QUUDPEFFqTtARf9IS07/aGZl/2lnZf9pZ2X/aWdl/2ln + Zf9RU1T/O0BE/0pOUf+qqan/ysnI/93d3P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4eHh/9/f + 3/+vsLL/XWFk/ztARP85PkL/UVVZ/6Gjpf/s7e3///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////+zt7f+hpKb/UVVZ/zk+Qv87QET/XWFk/66w + sf/f39//4eHh/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/b29r/yMbF/62srP9MUVT/OkBE/09R + U/9pZ2X/aWdl/2lnZf9pZ2X/aGdl/0lMT/87QEX/PEFFszxBRAU8QUQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRQA6REkAPEFFiztARf9GSk3/amlo/2lnZf9pZ2X/aWdl/2po + Zf9aWlr/PUJG/z5DRv+QkJH/wsC//8vKyf/d3Nz/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/i4uL/y8zM/4CDhf9ESU3/OT5C/z1CRv9mam3/ury9//T19f////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////09fX/uru9/2drbv89Qkb/OT5C/0RJTf9/goX/y8vM/+Li + 4v/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9vb2//Ix8b/wsC+/5OUlP8/REf/PEFF/1lZ + Wf9qaGX/aWdl/2lnZf9pZ2X/a2lo/0dLTv87QET/PEFFljpAQwE8QUUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5CRwA8QUUAPEFFaTxBRf9BRUn/bm1t/2xqZ/9pZ2X/aWdl/2ln + Zf9jYmH/QkZJ/zo/Q/9oa23/vLu6/8C+vf/Ix8b/2djY/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/g4OD/4eHh/9zc3P+sra//YGRn/z1CRv84PkL/QkdL/3J2eP/AwcP/9PT0//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////9PX1/8HCw/9zd3n/QkdL/zg+Qv88QUX/YGRn/6utrv/c3Nz/4eHh/+Dg + 4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/2NjY/8fGxf/Avr3/vbu7/2tucP86P0P/QkZJ/2Jh + YP9pZ2X/aWdl/2lnZf9raWf/b25t/0JHSv88QUX/PEFFczxBRQA8QUYAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAADpARgA8QUUAPEFFQDxBRfE8QUX/aGhp/3VzcP9pZ2X/aWdl/2ln + Zf9pZ2X/TlBS/ztARP9GSk7/oKCg/8LAv//Avr3/w8LB/9HQz//c3Nz/4ODg/+Dg4P/g4OD/4ODg/+Dg + 4P/g4OD/4ODg/+Dg4P/i4uL/0NHR/5SWmP9SVln/O0BE/zk+Qv9DSEz/b3N2/7W3uP/r7Oz///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////+vs7P+3ubr/cXV4/0NITP85PkL/O0BE/1FWWf+SlZb/0NDR/+Li4v/g4OD/4ODg/+Dg + 4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/9zc3P/R0M//w8LB/8C+vf/CwL//oqGh/0dLT/87QET/TU9R/2hm + Zf9pZ2X/aWdl/2lnZf9zcW//a2tr/z1CRv88QUX2PEFFSjxBRQAxNjoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEFFGTxBRdQ7QET/WFpc/4J/ff9samj/aWdl/2ln + Zf9qZ2X/Xl5d/z9ER/86P0T/aGtt/7q5uP/Bv77/wL69/8C+vf/GxMP/0M/P/9nY2P/d3d3/4N/f/+Dg + 4P/g4OD/4ODg/+Dg4P/e3t7/3Nvb/9TT0/+xsLD/eHp8/0tPUv86P0P/OD1B/z9ESP9fY2b/mJud/9PU + 1f/19fX///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////X1 + 9f/T1NX/mpye/2BkZ/8/REj/OD1B/zo/Q/9LT1P/eHp7/7CwsP/U09P/3Nvb/97e3v/g4OD/4ODg/+Dg + 4P/g4OD/4N/f/93d3f/Z2Nj/0M/O/8bEw//Avr3/wL69/8G/vv+6ubj/aWtu/zpARP8/Q0f/XV1d/2pn + Zf9pZ2X/aWdl/2tpZ/+Bfnz/W11f/ztARP88QUXcO0FFIDxBRQBVVVUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7QkUAO0NFAzxBRaA7QET/RkpN/4B+ff97eHf/aWdl/2ln + Zf9pZ2X/aGZk/05QUv87QET/QEVI/4iJiv/Avr3/wL69/8C+vf/Avr3/wL69/8LAv//GxcT/ysnI/83M + y//Ozc3/zczM/8vKyf/HxsX/w8HA/8C+vv/Bv77/v728/6inp/96fH3/UVVY/z5DR/86P0P/O0BE/0lO + Uv9ucXX/oKOl/8zNzv/t7e7//Pz8//////////////////////////////////////////////////// + /////////////////////////////////////////////////////////Pz8/+7u7//P0NH/oKOl/21x + dP9JTlL/O0BE/zo/Q/8+Q0b/UFRX/3p8ff+op6f/v728/8G/vv/Av77/w8HA/8fGxf/Lysn/zczM/87N + zf/NzMv/ysnI/8bFxP/CwL//wL69/8C+vf/Avr3/wL69/8C+vf+HiIn/QEVI/ztARP9NUFL/aGZk/2ln + Zf9pZ2X/aWdl/3l2dP+CgH//SU1Q/ztARP88QUWsO0BEBztARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QEQAPEFFADxBRVg8QUX6PEFF/2pqa/+Kh4X/dHJw/2ln + Zf9pZ2X/aWdl/2JhYP9DR0r/O0BE/0dMT/+VlZb/wb++/8C+vf/Avr3/wL69/8C+vf/Avr3/v728/8C+ + vf/Avr3/wL69/7+9vP/Avr3/wL69/8C+vf/Avr3/wL69/8LAvv/CwL//mpqb/0pOUv87QET/PEFF/ztA + RP85PkL/Oj9D/0VKTv9fY2b/goWI/6epq//Iycr/39/g/+/v8P/5+fn//f39//////////////////// + /////////////////////////f39//n5+f/v7/D/39/g/8jJyv+nqav/goWI/2BkZ/9HTE//Oj9D/zk+ + Qv87QET/PEFF/ztARP9FSU3/kJGR/8G/vv/CwL//wL69/8C+vf/Avr3/wL69/8C+vf+/vbz/wL69/8C+ + vf/Avr3/v728/8C+vf/Avr3/wL69/8C+vf/Avr3/wL69/5KTk/9HS07/O0BE/0NHSv9iYWD/aWdl/2ln + Zf9pZ2X/cnBu/4qGhP9ubm//PUJG/zxBRf08QUVlPEFFAEFGSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFFADxBRhk8QUXOO0BE/05RVP+Gg4L/iIWD/3Fv + bf9pZ2X/aWdl/2lnZf9bW1v/P0RH/zpARP9JTVH/j4+Q/768u//Bv77/wL69/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wL69/8C+vf/Avr3/wb++/7+9vP+bm5v/WFxf/zxBRf88QUX/SEtO/1FS + VP9KTVD/QUZJ/ztARP86P0P/OT5C/zxBRf9CR0r/UFRY/2BkZ/9xdHf/g4eJ/5GUlv+doKL/pKao/6iq + rP+oqqz/pKao/52gov+RlJb/g4aJ/3B0d/9gZGf/UFRY/0JHSv88QUX/OT5C/zo/Q/87QET/QUVJ/0pN + UP9RU1T/TE5Q/z1BRf88QUX/TlJV/42Ojv+7ubj/wsC//8C+vf/Avr3/wL69/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wL69/8G/vv+9u7r/i4yN/0hMUP86QET/QERI/1tbW/9pZ2X/aWdl/2ln + Zf9vbWv/hoOB/4iFhP9SVVf/O0BE/zxBRdk8QUUhPEFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0JGAD5AQwA8QUV3PEFF/j1CRv9ra2v/jYqI/4aD + gf9xb23/aWdl/2lnZf9pZ2X/V1hY/z9DR/87QET/Q0hL/3Z4ev+ura3/wb++/8G/vv/Avr3/wL69/8C+ + vf/Avr3/wL69/8C+vf/Avr3/wb++/8LAv/+/vr3/qqqp/3d4ev9GSk7/OkBE/zxBRf9MTlD/ZWRj/3h1 + c/+DgX//enl4/2ZnaP9ESEv/PEFF/zxBRf88QUX9O0BE/zo/Q/85PkL/OT5C/zk/Q/86P0P/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/85P0P/OT5C/zk+Qv86P0P/O0BE/zxBRf48QUX/PEFF/0RJTP9mZ2j/eXh3/4OB + f/93dXP/aGZk/1FSVP8+Q0b/OkBE/0BFSf9pa27/oJ+g/7y6uv/CwL//wb++/8C+vf/Avr3/wL69/8C+ + vf/Avr3/wL69/8G/vv/CwL//wL69/6qpqf9xc3X/QUZK/ztARP8/REf/WFlZ/2lnZf9pZ2X/aWdl/3Bt + a/+EgX//jYqI/3BwcP8/Q0f/PEFF/zxBRYY/UEsAPEJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPT9EADxBRQA8QUYfPEFF0TtARP9JTE//f359/42K + iP+HhIL/c3Fv/2lnZf9pZ2X/aWdl/1hZWf9BRUn/O0BE/zxBRf9SVVn/gIGD/6empv+6uLf/wL69/8G/ + vv/CwL//wsC//8G/vv++vbz/tLOz/52dnf91d3n/TVFU/ztARP87QET/P0RH/1NUVf9raWf/fnx5/4uI + hv+Nioj/jYqI/25ubv9ARUn/PEFF/zxBRco8QUVoPEFFgjxBRaE8QUW8PEFFzzxBRdk8QUXiPEFF5jxB + Rek8QUXpPEFF5jxBReI8QUXZPEFFzzxBRbw8QUWhPEFFgTxBRWo8QUXOPEFF/0FGSf9wcHD/jYqI/42K + iP+LiIb/fnt5/2xqaf9YWFn/QkZJ/ztARP86P0P/RUpO/2hrbf+RkpL/rays/7u5uP+/vr3/wb++/8G/ + vv/Avr3/vry8/7a0tP+goKD/eHp7/01RVf87QET/O0BE/0JGSf9aWlr/aWdl/2lnZf9pZ2X/cnBu/4aD + gf+Nioj/g4GA/01QU/87QET/PEFF3TxBRSk8QUUAPUFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAAD9BQgA7QUYAPEFFZTxBRfk7QEX/WVtd/4iG + hP+Nioj/iYaE/3l3df9samf/aWdl/2lnZf9fXl7/SUxO/z1CRf86P0T/PEFF/0hMUP9dYGP/c3V3/4KD + hP+IiYr/hoeI/3x+f/9qbW//VVhc/0JHS/86QET/OkBE/z1CRv9IS07/X19f/3Vzcf+Gg4H/jImH/4yJ + h/+MiYf/cXFx/0NHS/87QEX/PEFF4TxBRT48QUQAPEFDADtBRQQ7QkUJPEFFEjxBRR08QkUoPEFFLTxB + RTE8QUUxPEFFLTxCRSg7QUUdPEFFEjtCRQk8Q0QEO0BGADxBRQA8QUVEPEFF5TtARP9ESEz/dHNz/42K + h/+MiYf/jImH/4aDgf92dHL/Y2Jh/01PUf8/REf/O0BE/zo/Q/8+Q0f/TFBU/19iZP9wcnT/enx+/31/ + gP93eXv/aWtu/1ZaXf9ESEz/O0BE/zpARP89Qkb/Sk1P/2BfX/9pZ2X/aWdl/2tpZ/95d3X/iIaE/42K + iP+Kh4X/X2Bi/zxBRf88QUX9PEFFdjtETgA9QEIAOkZGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1BRAA8QUYAPEJGDTxBRag8QUX/PkNG/2Zn + aP+LiIb/jImH/4yJh/+DgH7/dHFv/2tpZ/9pZ2X/ZmRj/1dYWP9HSkz/PkJG/ztARP86P0P/Oj9D/zpA + RP87QET/O0BE/zo/Q/86P0P/Oj9D/ztARP8/Q0f/SUxO/1xcXP9ycG7/goB+/4uIhv+MiYf/jImH/4yJ + h/9wb3D/REhM/ztARP88QUXsPEFFWT5CRwA7QUYAPEFHADxBRQA7QUUAPEFFADxBRQA8QkUAPEFFADxB + RQA8QUUAPEFFADxCRQA7QUUAPEFFADtCRQA8QkUAPUNEADxBRgA7P0QAPEFFXzxBRe87QET/RUpN/3Jy + cv+MiYf/jImH/4yJh/+LiIb/g4B+/3Nxb/9gYF//TVBR/0FGSf88QUX/OkBE/zk/Q/86P0P/Oj9D/zo/ + Q/86P0P/Oj9D/zo/Q/87QET/P0NH/0lMTv9aWlr/ZmVj/2lnZf9raWf/dHFv/4OAfv+MiYf/jImH/4yJ + h/9sbG3/P0RI/zxBRf88QUW5PEBFFDxARQA9QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7QUUAPEFGADtBRSk8QUXRPEFF/0BF + SP9ra2z/i4iG/4yJh/+MiYf/ioeF/4J/ff92dHL/bWtp/2poZv9lZGL/XFxb/1BSU/9HS03/QkZJ/0BE + SP8/REf/P0RH/0FFSP9ER0r/S01P/1ZXWP9mZWT/d3Vz/4SBf/+LiIb/jImH/4yJh/+Nioj/ioeF/2lq + a/9CRkr/O0BE/zxBRe88QUVmQUhCATxCRAA7QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRgA8QUYAPENJAjxBRW48QUXzO0BE/0NH + S/9sbW3/i4iG/42KiP+MiYf/jImH/4uIhv+EgX//eHZ0/2loZ/9aW1v/T1FS/0dKTf9DR0r/QUVJ/0FF + Sf9CRkn/RUhL/0tNT/9TVFX/Xl5d/2ZlY/9qaGb/bmtp/3Z0cv+Cf33/ioeF/4yJh/+MiYf/jImH/3Fx + cf9DR0v/O0BF/zxBRd48QUU3PUFFAEBFSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9QkcAPEJGADxBRAA8QUVFPEFF4jtB + Rf9BRUn/aGlp/4qHhf+Nioj/jImH/4yJh/+LiIb/h4SC/4B9e/94dnT/c3Fv/29ta/9raWf/Z2Zk/2Rj + Yv9jYmL/ZWRk/2ppaP9ycG7/enh2/4OAfv+JhoT/jImH/4yJh/+MiYf/jImH/42KiP+DgYD/XV9g/z9E + R/87QUX/PEFF6DxBRWA8PEICPEFEAD1CRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQA8QUYAPEFGADxARwQ8QUVpPEFF7DtA + Rf9AREj/YGJj/4WCgf+Nioj/jImH/4yJh/+MiYf/jImH/4mGhP+DgH7/e3l2/3Nxb/9ta2r/aGdl/2Zl + ZP9mZWT/aWdm/2xqaP9wbWv/c3Fv/3h2dP+AfXv/h4SC/4uIhv+MiYf/jImH/4yJh/+LiIb/b29v/0RI + S/87QET/PEFF7DxBRVY5QUMAPUBFADI2OgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEFGADxBRQA8QEcAPEFFUTxB + ReQ7QUX/P0NH/15fYf+DgX//jYqI/4yJh/+MiYf/jImH/42Jh/+MiYf/i4iG/4mGhP+HhIL/hoOB/4aD + gf+IhYL/iYaE/4qHhf+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+Nioj/ioeF/3Nycv9OUVT/PEFF/zxB + Rf88QUXaPEFFT0Y0XgA8QEQAPEBEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEBGADxARQA3REIBPEFFVzxB + ReA8QUX/PEFF/1FTVv92dXX/i4iG/42KiP+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+Kh4X/iYaD/4eE + gv+Gg4H/hoOB/4eEgv+JhoT/i4iG/4yJh/+MiYf/jImH/4yJh/+MiYf/jYqI/4aEgv9kZWb/QUVJ/ztA + RP88QUXuPEFFZTtGRAE9QUUAPUFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRAA8QUQAPEJGADxB + RUo8QUXYPEFF/zxBRf9NUFP/cnFx/4mGhP+Nioj/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jYqI/4qHhv95eHf/Wlxe/0BFSP87QET/PEFF/jxB + RbU8QUUyPEFGADxBRAA8QkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxBRAA8QkUAPUBGADxB + RTo8QUW/PEFF/ztARP9CRkr/Xl9h/317ev+LiIb/jYqI/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jImH/4yJh/+MiYf/jImH/42KiP+LiIb/eHd3/1NWWP89Qkb/PEFF/zxB + ReU8QUVdO0hIAjxCRgA9QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEBFADxB + RAA8QUUzPEFFtzxBRf07QET/QERI/1VYWv9zcnL/hoOC/4yJh/+Nioj/jYqI/4yJh/+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+Nioj/jYqI/4yJh/+Fg4H/c3Jy/1lbXf9CR0r/O0BE/zxBRf88QUXkPEFFfDxB + RRQ8QUUAPEJEADxCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QUUAPEJFADtA + RAA8QUUaPEFFiTxBReo8QUX/O0FF/0RJTP9dX2D/d3Z2/4eFg/+Niof/jYqI/42KiP+MiYf/jImH/4yJ + h/+MiYf/jImH/4yJh/+MiYf/jYmH/42KiP+Nioj/iYaE/3l4d/9cXV//QkdK/ztARP88QUX/PEFFyTxB + REQ/TEYAO0JFADtDRgBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + RdI8QUXZPEFF1zxBRc48QUW5PEFFmzxBRXM8QUVCPEFGFzA9XwA8QUUAPEFEAD5ESAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAPj5EADY/QQA5PEAAO0FEADxBRQA8QUUAPEBGADxCRQU8QUULPEFFDjxB + RQ88QUUMPEFECDtAQgI8QUUAPEFFADxARQA9P0UAO0NGAEM6PwAAgIAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAyR08APEJFADxBRQA8QUUAPEFFADtBQwA8QUYHPEFFDTxB + RhI8QUUZPEFFFjxBRRA7QUUKO0BHAjxBRQA8QUUAPEFGADtBRwA9O0oAOkVGAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+QkYAPEJEADxBRQA8QUUAPEFFADxB + RQA8QUUAPEFFADxBRAA/PkMAPj5EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAOkFJAD1BRgA8QUYAPEFFADxB + RgA8QUUAPEFFADxBRQA7QUUAPEFGADk9QgA6PkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAD///////////////////8A////////////////////AP///////////////////wD///////////// + //////8A//////8AAAAAAP//////AP///+AAAAAAAAAAB////wD///4AAAAAAAAAAAB///8A///gAAAA + AAAAAAAAB///AP//4AAAAAAAAAAAAAf//wD//+AAAAAAAAAAAAAH//8A///gAAAAAAAAAAAAB///AP// + 4AAAAAAAAAAAAAf//wD//+AAAAAAAAAAAAAH//8A///wAAAAAAAAAAAAD///AP///4AAAAAAAAAAAf// + /wD////8AAAAAAAAAD////8A//////8AAAAAAP//////AP/////+AAAAAAA//////wD////4AAAAAAAA + AB////8A////wAAAAAAAAAAD////AP///gAAAAAAAAAAAH///wD///AAAAAAAAAAAAAP//8A///gAAAA + AAAAAAAAB///AP//wAAAAAAAAAAAAAP//wD//wAAAAAAAAAAAAAA//8A//4AAAAAAAAAAAAAAH//AP/8 + AAAAAAAAAAAAAAA//wD/+AAAAAAAAAAAAAAAH/8A//AAAAAAAAAAAAAAAA//AP/gAAAAAAAAAAAAAAAH + /wD/4AAAAAAAAAAAAAAAB/8A/8AAAAAAAAAAAAAAAAP/AP+AAAAAAAAAAAAAAAAB/wD/AAAAAAAAAAAA + AAAAAP8A/wAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA/wD+AAAAAAAAAAAAAAAAAH8A/gAAAAAA + AAAAAAAAAAB/APwAAAAAAAAAAAAAAAAAPwD8AAAAAAAAAAAAAAAAAD8A+AAAAAAAAAAAAAAAAAAfAPgA + AAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPAAAAAAAAAAAAAAAAAA + DwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAA + AAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAA + AAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAA + AAAAAAAAAAAAAAAADwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAA + DwDwAAAAAAAAAAAAAAAAAA8A8AAAAAAAAAAAAAAAAAAPAPAAAAAAAAAAAAAAAAAADwDwAAAAAAAAAAAA + AAAAAA8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAA + AAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD8AAAAAAAAAAAAAAAAAD8A/AAAAAAAAAAAAAAAAAA/APwA + AAAAAAAAAAAAAAAAPwD+AAAAAAAAAAAAAAAAAH8A/gAAAAAAAAAAAAAAAAB/AP4AAAAAAAAAAAAAAAAA + fwD/AAAAAAAAAAAAAAAAAP8A/wAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA/wD/gAAAAAAAAAAA + AAAAAf8A/4AAAAAAAAAAAAAAAAH/AP/AAAAAAAAAAAAAAAAD/wD/wAAAAAAAAAAAAAAAA/8A/4AAAAAA + AAAAAAAAAAH/AP+AAAAAAAAAAAAAAAAB/wD/AAAAAAAAAAAAAAAAAP8A/wAAAAAAAAAAAAAAAAD/AP4A + AAAAAAAAAAAAAAAAfwD+AAAAAAAAAAAAAAAAAH8A/gAAAAAAAAAAAAAAAAB/APwAAAAAAAAAAAAAAAAA + PwD8AAAAAAAAAAAAAAAAAD8A/AAAAAAAAAAAAAAAAAA/APgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAA + AAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAA + AAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgA + AAAAAAAAAAAAAAAAHwD4AAAAAAAAAAAAAAAAAB8A+AAAAAAAAAAAAAAAAAAfAPgAAAAAAAAAAAAAAAAA + HwD8AAAAAAAAAAAAAAAAAB8A/AAAAAAAAAAAAAAAAAA/APwAAAAAAAAAAAAAAAAAPwD+AAAAAAAAAAAA + AAAAAD8A/gAAAAAAAAAAAAAAAAB/AP4AAAAAAAAAAAAAAAAAfwD+AAAAAAAAAAAAAAAAAH8A/wAAAAAA + AAAAAAAAAAD/AP+AAAAAAA//8AAAAAAA/wD/gAAAAAAf//AAAAAAAf8A/8AAAAAAP//8AAAAAAP/AP/g + AAAAAH///gAAAAAH/wD/8AAAAAD///8AAAAAB/8A//gAAAAB////gAAAAB//AP/8AAAAA////8AAAAA/ + /wD//wAAAA/////wAAAAf/8A///AAAA//////AAAAf//AP//4AAA//////8AAAf//wD///8AH/////// + 8AB///8A////////////////////AP///////////////////wD///////////////////8A//////// + ////////////AA== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAs + 7QAAAk1TRnQBSQFMAgEBFAEAAaABAAGgAQABxgEAAcYBAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + AwABGAEDAgABpAEEAgABAQEAAQgFAAFgAVsBDhcAAYACAAGAAwACgAEAAYADAAGAAQABgAEAAoACAAPA + AQABwAHcAcABAAHwAcoBpgEAATMFAAEzAQABMwEAATMBAAIzAgADFgEAAxwBAAMiAQADKQEAA1UBAANN + AQADQgEAAzkBAAGAAXwB/wEAAlAB/wEAAZMBAAHWAQAB/wHsAcwBAAHGAdYB7wEAAdYC5wEAAZABqQGt + AgAB/wEzAwABZgMAAZkDAAHMAgABMwMAAjMCAAEzAWYCAAEzAZkCAAEzAcwCAAEzAf8CAAFmAwABZgEz + AgACZgIAAWYBmQIAAWYBzAIAAWYB/wIAAZkDAAGZATMCAAGZAWYCAAKZAgABmQHMAgABmQH/AgABzAMA + AcwBMwIAAcwBZgIAAcwBmQIAAswCAAHMAf8CAAH/AWYCAAH/AZkCAAH/AcwBAAEzAf8CAAH/AQABMwEA + ATMBAAFmAQABMwEAAZkBAAEzAQABzAEAATMBAAH/AQAB/wEzAgADMwEAAjMBZgEAAjMBmQEAAjMBzAEA + AjMB/wEAATMBZgIAATMBZgEzAQABMwJmAQABMwFmAZkBAAEzAWYBzAEAATMBZgH/AQABMwGZAgABMwGZ + ATMBAAEzAZkBZgEAATMCmQEAATMBmQHMAQABMwGZAf8BAAEzAcwCAAEzAcwBMwEAATMBzAFmAQABMwHM + AZkBAAEzAswBAAEzAcwB/wEAATMB/wEzAQABMwH/AWYBAAEzAf8BmQEAATMB/wHMAQABMwL/AQABZgMA + AWYBAAEzAQABZgEAAWYBAAFmAQABmQEAAWYBAAHMAQABZgEAAf8BAAFmATMCAAFmAjMBAAFmATMBZgEA + AWYBMwGZAQABZgEzAcwBAAFmATMB/wEAAmYCAAJmATMBAANmAQACZgGZAQACZgHMAQABZgGZAgABZgGZ + ATMBAAFmAZkBZgEAAWYCmQEAAWYBmQHMAQABZgGZAf8BAAFmAcwCAAFmAcwBMwEAAWYBzAGZAQABZgLM + AQABZgHMAf8BAAFmAf8CAAFmAf8BMwEAAWYB/wGZAQABZgH/AcwBAAHMAQAB/wEAAf8BAAHMAQACmQIA + AZkBMwGZAQABmQEAAZkBAAGZAQABzAEAAZkDAAGZAjMBAAGZAQABZgEAAZkBMwHMAQABmQEAAf8BAAGZ + AWYCAAGZAWYBMwEAAZkBMwFmAQABmQFmAZkBAAGZAWYBzAEAAZkBMwH/AQACmQEzAQACmQFmAQADmQEA + ApkBzAEAApkB/wEAAZkBzAIAAZkBzAEzAQABZgHMAWYBAAGZAcwBmQEAAZkCzAEAAZkBzAH/AQABmQH/ + AgABmQH/ATMBAAGZAcwBZgEAAZkB/wGZAQABmQH/AcwBAAGZAv8BAAHMAwABmQEAATMBAAHMAQABZgEA + AcwBAAGZAQABzAEAAcwBAAGZATMCAAHMAjMBAAHMATMBZgEAAcwBMwGZAQABzAEzAcwBAAHMATMB/wEA + AcwBZgIAAcwBZgEzAQABmQJmAQABzAFmAZkBAAHMAWYBzAEAAZkBZgH/AQABzAGZAgABzAGZATMBAAHM + AZkBZgEAAcwCmQEAAcwBmQHMAQABzAGZAf8BAALMAgACzAEzAQACzAFmAQACzAGZAQADzAEAAswB/wEA + AcwB/wIAAcwB/wEzAQABmQH/AWYBAAHMAf8BmQEAAcwB/wHMAQABzAL/AQABzAEAATMBAAH/AQABZgEA + Af8BAAGZAQABzAEzAgAB/wIzAQAB/wEzAWYBAAH/ATMBmQEAAf8BMwHMAQAB/wEzAf8BAAH/AWYCAAH/ + AWYBMwEAAcwCZgEAAf8BZgGZAQAB/wFmAcwBAAHMAWYB/wEAAf8BmQIAAf8BmQEzAQAB/wGZAWYBAAH/ + ApkBAAH/AZkBzAEAAf8BmQH/AQAB/wHMAgAB/wHMATMBAAH/AcwBZgEAAf8BzAGZAQAB/wLMAQAB/wHM + Af8BAAL/ATMBAAHMAf8BZgEAAv8BmQEAAv8BzAEAAmYB/wEAAWYB/wFmAQABZgL/AQAB/wJmAQAB/wFm + Af8BAAL/AWYBAAEhAQABpQEAA18BAAN3AQADhgEAA5YBAAPLAQADsgEAA9cBAAPdAQAD4wEAA+oBAAPx + AQAD+AEAAfAB+wH/AQABpAKgAQADgAMAAf8CAAH/AwAC/wEAAf8DAAH/AQAB/wEAAv8CAAP//wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + 7QABTQH0LAABGwEsAXWVAAFNAfQsAAEbASwBdZUAAU0B9CwAARsBLAF1lQABTQH0LAABGwEsAXWSAAF1 + BiwB9icAARsFLAGUkAABdQYsAfYnAAEbBSwBlJAAAXUGLAH2JwABGwUsAZSQAAF1BiwB9icAARsFLAGU + jwABdQgsAfYkAAHzCSwBlI0AAXUILAH2JAAB8wksAZSNAAF1CCwB9iQAAfMJLAGUjQABdQgsAfYkAAHz + CSwBlIwAAXUKLCQAARsJLAGUjAABdQosJAABGwksAZSMAAF1CiwkAAEbCSwBlIwAAXUKLCQAARsJLAGU + jAABdQosIwAB9AssAZqLAAF1CiwjAAH0CywBmosAAXUKLCMAAfQLLAGaiwABdQosIwAB9AssAZqKAAF1 + CywjAAH0CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMA + AfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMAAfQLLAGaigABlAFNCiwjAAH0 + CywBmooAAZQBTQosIwAB9AssAZqKAAGUAU0KLCMAAfQLLAGaigABlAFNCiwjAAH0CywBmosAAXUKLCMA + AfQBTQksAU0BGosAAXUKLCMAAfQBTQksAU0BGosAAXUKLCMAAfQBTQksAU0BGosAAXUKLCMAAfQBTQks + AU0BGosAAZQBTQgsAU0kAAH0AU0HLAFNARqMAAGUAU0ILAFNJAAB9AFNBywBTQEajAABlAFNCCwBTSQA + AfQBTQcsAU0BGowAAZQBTQgsAU0kAAH0AU0HLAFNARqNAAGUAU0GLAFNJgAB9AFNBSwBTQGajgABlAFN + BiwBTSYAAfQBTQUsAU0Bmo4AAZQBTQYsAU0mAAH0AU0FLAFNAZqOAAGUAU0GLAFNJgAB9AFNBSwBTQGa + jwABlAZ1KAAB9AV1AZqQAAGUBnUoAAH0BXUBmpAAAZQGdSgAAfQFdQGakAABlAZ1KAAB9AV1AZr/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD9AAH2N/SOAAH2N/SOAAH2N/SOAAH2N/SMAAH2AfQBTTcsAXWLAAH2 + AfQBTTcsAXWLAAH2AfQBTTcsAXWLAAH2AfQBTTcsAXWJAAH2AfMBTTosAXWIAAH2AfMBTTosAXWIAAH2 + AfMBTTosAXWIAAH2AfMBTTosAXWHAAH0AXU9LAGahgAB9AF1PSwBmoYAAfQBdT0sAZqGAAH0AXU9LAGa + hQAB9AF1PSwBTQEahQAB9AF1PSwBTQEahQAB9AF1PSwBTQEahQAB9AF1PSwBTQEahAAB9AF1PSwBTQEa + hQAB9AF1PSwBTQEahQAB9AF1PSwBTQEahQAB9AF1PSwBTQEahQABdQYsOHUBGoYAAXUGLDh1ARqGAAF1 + Biw4dQEahgABdQYsOHUBGoUAAfQBdQUsAXW+AAH0AXUFLAF1vgAB9AF1BSwBdb4AAfQBdQUsAXW+AAF1 + BSwBdb8AAXUFLAF1vwABdQUsAXW/AAF1BSwBdb4AAfQBdQUsAfS+AAH0AXUFLAH0vgAB9AF1BSwB9L4A + AfQBdQUsAfS+AAF1BSwBdb8AAXUFLAF1vwABdQUsAXW/AAF1BSwBdb8AAXUFLAH0vwABdQUsAfS/AAF1 + BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0 + vwABdQUsAfS/AAF1BSwB9L8AAXUFLCMaARucAAF1BSwjGgEbnAABdQUsIxoBG5wAAXUFLCMaARubAAHz + AXUoLAFNDRoB840AAfMBdSgsAU0NGgHzjQAB8wF1KCwBTQ0aAfONAAHzAXUoLAFNDRoB840AAXU3LAF1 + AhoB84oAAXU3LAF1AhoB84oAAXU3LAF1AhoB84oAAXU3LAF1AhoB84oAAXU6LAF1ARoB84gAAXU6LAF1 + ARoB84gAAXU6LAF1ARoB84gAAXU6LAF1ARoB84gAAXU8LAF1ARoB84YAAXU8LAF1ARoB84YAAXU8LAF1 + ARoB84YAAXU8LAF1ARoB84YAAXU+LAF1AfOFAAF1PiwBdQHzhQABdT4sAXUB84UAAXU+LAF1AfOFAAF1 + PywBdQHzhAABdT8sAXUB84QAAXU/LAF1AfOEAAF1PywBdQHzhAABdUAsAZqEAAF1QCwBmoQAAXVALAGa + hAABdUAsAZqEAAF1QCwBdQHzgwABdUAsAXUB84MAAXVALAF1AfODAAF1QCwBdQHzggABGwFNQSwBmoIA + ARsBTUEsAZqCAAEbAU1BLAGaggABGwFNQSwBmoIAAXVCLAF1AfOBAAF1QiwBdQHzgQABdUIsAXUB84EA + AXVCLAF1AfOBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1 + QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBdQEbgAABdUMs + AXUBG4AAAXVDLAF1ARuAAAF1QywBdQEbgAABdUQsAZqAAAF1RCwBmoAAAXVELAGagAABdUQsAZp/AAEa + AU1ELAGafwABGgFNRCwBmn8AARoBTUQsAZp/AAEaAU1ELAGafwABlEUsAZp/AAGURSwBmn8AAZRFLAGa + fwABlEUsAZp/AAGURSwBdQEbfgABlEUsAXUBG34AAZRFLAF1ARt+AAGURSwBdQEbfgABlEYsAZp+AAGU + RiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGa + fgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAXUBG30AAZRGLAF1ARt9AAGURiwBdQEbfQABlEYs + AXUBG30AAZRHLAGafQABlEcsAZp9AAGURywBmn0AAZRHLAGafAABGgFNRywBmnwAARoBTUcsAZp8AAEa + AU1HLAGafAABGgFNRywBmnwAAZRILAGafAABlEgsAZp8AAGUSCwBmnwAAZRILAGafAABlEgsAU0BGnsA + AZRILAFNARp7AAGUSCwBTQEaewABlEgsAU0BGnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGa + ewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGU + SSwBmnsAAZRJLAFNARp6AAGUSSwBTQEaegABlEksAU0BGnoAAZRJLAFNARp6AAGUSiwBmnoAAZRKLAGa + egABlEosAZp6AAGUSiwBmnkAARoBTUosAZp5AAEaAU1KLAGaeQABGgFNSiwBmnkAARoBTUosAZp5AAGU + SywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGa + eQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGU + SywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGa + eQABlEssAZp4AAEaAU1LLAGaeAABGgFNSywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABlEssAZQB9ngA + AZRLLAGUAfZ4AAGUSywBlAH2eAABlEssAZQB9ncAARoBTUssAZp4AAEaAU1LLAGaeAABGgFNSywBmngA + ARoBTUssAZp4AAGUSywBlAH2eAABlEssAZQB9ngAAZRLLAGUAfZ4AAGUSywBlAH2dgABGgF1AU1KLAGU + eAABGgF1AU1KLAGUeAABGgF1AU1KLAGUeAABGgF1AU1KLAGUbgABGgl1AU0ULAErBCwBKwEsBk0BKwNN + ASsjLAGUcQABGgl1AU1JLAGUcQABGgl1AU1JLAGUcQABGgl1AU1JLAGUcAABGgFNDywBGrQAARoBTQ8s + ARq0AAEaAU0PLAEatAABGgFNDywBGrQAARoQLAEbtAABGhAsARu0AAEaECwBG7QAARoQLAEbtAABGg8s + ARq1AAEaDywBGrUAARoPLAEatQABGg8sARq1AAEaDSwBGrcAARoNLAEatwABGg0sARq3AAEaDSwBGrkA + AZoILAEavAABmggsARq8AAGaCCwBGrwAAZoILAEavQAI9r4ACPa+AAj2vgAI9v8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + VQABFhRN/wD/AP8ABgABFhRN/wD/AP8ABgABFhRN/wD/AP8ABgABFhRNEwAB9AGMAbX/AP8A7wABFhRN + EAAB9AHPArQBjQF1AZMBjQG1/wD/ACYAARYTTbIAARYUTQ8AAfQBzwPbAewDegGTAbX/AP8AJQABFhNN + sgABFhRNDwABrgG0A9sB7AJ6AXQBjQGuAbX/AP8AJAABFhNNEgAB9AGuAc8BrgGNAa4BtZkAARYUTQ4A + AfQDtAHPAbQBjQF6AZMBjQGTAXUBB/8A/wAkAAEWE00RAAH0AbQC2wHsAnoBkwHvmAABFhRNDgABzwTb + Aa4BjQGTAY0BdQJ6AZMBtf8A/wAjAAEWE00QAAH0AbQD2wHsA3oBkwHvlwABFhRNDgABzwPbAbQBjQGT + Aa4BkwF6AXUBkwGNAbX/AFwAARYTTbIAARYTTQ8AAfQCzwG0AdsBugGNAXoBdQGTAY0BHAHvlgABFhRN + DgABzwK0Aa4BkwF0AewBkwONAogBtv8AXAABFhNNEQAB9AGuAc8BtAGNApMBjQG1mAABFhNNDwABzwPb + AbQBzwHtAXQBkwHtAnoBkwG1lQABFhRNDgABrgKTAXoBdQKTAXUBkwGMAYgBjwGIAbb/AFwAARYTTRAA + AfQBzwHVAtsB7AJ6AXUBkwG1lwABFhNNDwABzwPbAbQBrgKNAe0CegF1AZMBtZUAARYUTQ4AAY0BdQJ6 + AZMBjQF6AZMBjQGIAYIBiAGOAQf/AFwAARYTTRAAAa4BtAPbAewCegF0AZMBrgG1lgABFhNNDwABzwLb + AbQB7AKTAY0B7QF0AZMCjQG1lQABFhRNDwABkwF6AXUB7QGTAXoBkwGIAY8BiAGCAba9AAHzAq4BjQH3 + mgABFhNNDwAB9AW0AY0BegGTAY0BkwF1AQeWAAEWE00PAAGuAc8BjQGTAXUBkwGNAXUBkwGuAYIBjwGI + AbaVAAEWFE0PAAGNApMBjQF6AXUBjgGIAY8BiAGNAQe7AAHzAc8BtAHbAewBegF1AZMB95gAARYTTQ8A + Ac8D2wG0Aa4B7AGTAY0BkwJ6AZMBtZUAARYTTQ8AAY0DegF0AY0BdAF1AY0CggGPAYgBtZUAARYUTRAA + A40CdQGOAogBjgG2lgABlBRNEAAB8wHPA9sBjQN6AZMB75cAARYTTQ8AAc8D2wG0AY0B7QGuAZMCdQGT + AY4BtZUAARYTTQ8AAa8BkwJ6ApMBegGTAYIBjwKIAY4BB5IAAfYBFgEbARYUTQEAARcPAAGvAfcBkwGZ + AZMCrwEHlwABlBRNEAABzwK0AdsBtAGNAXoBdQGTAo0B75YAARYTTQ8AAc8BugK0Ae0BkwGNAZMBjQHt + AY0CggG2lQABFhNNEAAB9wJ1AewCdQGTAYgBjwGIAY0BvJMAARYZTQEXrQABlBRNDwAB8wLbArQBzwHs + AXUBkwGNAXUBegGTAbWVAAEWE00PAAGuAY0BkwF0AXUCkwF1AZMBjAGIAY8BiAG2lQABFhNNEQACkwGN + AXoBdQGOAYgBjwGOAbyTAAEWG00BF6wAAZQUTQ8AAc8E2wGuA40CegF1AZMBtZUAARYTTQ8AAfcBdQJ6 + AZMBjQF1AXQBjQGIAYIBiAGOAQeVAAEWE00SAAH3AY0BdAGTAY4BggGOAbyTAAEWHU0BF6sAAZQUTQ8A + Ac8C2wK0ApMBjQGTAXQBkwKNAbWVAAEWE00QAAGTAXoBdQKTAXoBkwGCAY8BiAGCAbaWAAEWE00SAAH0 + AbUB9wHvAfcBtQEHkwABvQEXHU0BFwGUqgABlBRNDwABzwK0AY0CkwGNAZMB7QGNAYICiAG2lQABFhNN + EAAB9wGTAXQBjQF6AXUBkwGIAY8BiAGNAbyUAAL0ARYTTQL0AfaqAAG9AeMbTQEXAZSrAAGUFE0PAAGu + AXQBdQF6AXUB7QGTAXUBjgGCAYgBjwGIAbaVAAEWE00RAAH3AZMBjQF6AXUBkwKIAY4BB5QAARYYTQEX + AfSqAAG9ARcLTQEWApQBFwpNARcBlKwAAZQUTQ8AAbUBkwJ6AZMBjQF6AZMBjQGPAogBjgG8lQABFhNN + EgABtQH3ApMCjQG2AQeUAAEWGk0BFwH0qgABvQEXCE0BFgGUAwAClAEXB00BFwGUrQABlBRNDwAB9AGN + AnUBjQGTAXoBkwGIAY8BiAGCAbaWAAEWE00TAAH0A7UBB5UAARYcTQEXAfSqAAG9AeMHTQcAAeMHTQGU + rgABlBRNEAABtQHtAZMBjQF6AXUBkwGIAY8BiAGNAbyWAAEWE02sAAGUHk0BF6sAAb0BFwVNARYHAAGU + ARcFTQGUrwABlBRNEQABtQHvAY0BdAKTAYIBjgG2AbyVAAL0ARYTTQL0qgABvQHjHE0BFwGUrAABvQWU + CQAGlLAAAZQUTRMAAbUB7wIHAbUBvJUAAfYBFhdNARcB9KoAAb0B4xpNARcBlP8AcwABlBRNrQAB9gEW + GU0BFwHzqgABvQHjCU0GlAEXCE0BFwGU/wB0AAGUFE2sAAH0ARYbTQEXAfOqAAG9AeMHTQGUBgABlAEX + Bk0BFwGU/wB1AAGUFE2sAAGUHU0BFwHzqgABvQHjBk0IAAHjBk0BlP8AdAAB9AEAAZQUTQLzqgABGgHj + HE0BFwGUqwABvQaUCAABmgaU/wB0AAH0ARYBvQEWFU0BFwHzqgABGgHjGk0BFwGU/wD/ADYAAfQBFhlN + ARcB86oAARoB4wlNBZQBFwlNARcBlP8A/wA2AAH0ARYbTQEXAfOqAAEaAeMHTQGUBQABmgEXB00BFwGU + /wD/ADYAAfQBFh1NARerAAEaAeMGTQcAAb0BFwZNAZT/AP8ANwABGgHjHU0BF6wAARoGmggAAb0Gmv8A + /wA5AAEaAeMbTQEXAZr/AP8A/AABGgHjCk0BlASaARcJTQEXAZr/AP8A/gABGgHjCE0BlAUAAb0BFwdN + ARcBvf8A/wD/AAEAARoB4wZNAZQHAAHjB00Bvf8A/wD/AAMAARoGvQgACL3/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wDQAAFNAfQsAAEbASwBdZUAAU0B9CwAARsBLAF1lQABTQH0 + LAABGwEsAXWVAAFNAfQsAAEbASwBdZIAAXUGLAH2JwABGwUsAZSQAAF1BiwB9icAARsFLAGUkAABdQYs + AfYnAAEbBSwBlJAAAXUGLAH2JwABGwUsAZSPAAF1CCwB9iQAAfMJLAGUjQABdQgsAfYkAAHzCSwBlI0A + AXUILAH2JAAB8wksAZSNAAF1CCwB9iQAAfMJLAGUjAABdQosJAABGwksAZSMAAF1CiwkAAEbCSwBlIwA + AXUKLCQAARsJLAGUjAABdQosJAABGwksAZSMAAF1CiwjAAH0CywBmosAAXUKLCMAAfQLLAGaiwABdQos + IwAB9AssAZqLAAF1CiwjAAH0CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0 + CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMAAfQLLAGa + igABdQssIwAB9AssAZqKAAGUAU0KLCMAAfQLLAGaigABlAFNCiwjAAH0CywBmooAAZQBTQosIwAB9Ass + AZqKAAGUAU0KLCMAAfQLLAGaiwABdQosIwAB9AFNCSwBTQEaiwABdQosIwAB9AFNCSwBTQEaiwABdQos + IwAB9AFNCSwBTQEaiwABdQosIwAB9AFNCSwBTQEaiwABlAFNCCwBTSQAAfQBTQcsAU0BGowAAZQBTQgs + AU0kAAH0AU0HLAFNARqMAAGUAU0ILAFNJAAB9AFNBywBTQEajAABlAFNCCwBTSQAAfQBTQcsAU0BGo0A + AZQBTQYsAU0mAAH0AU0FLAFNAZqOAAGUAU0GLAFNJgAB9AFNBSwBTQGajgABlAFNBiwBTSYAAfQBTQUs + AU0Bmo4AAZQBTQYsAU0mAAH0AU0FLAFNAZqPAAGUBnUoAAH0BXUBmpAAAZQGdSgAAfQFdQGakAABlAZ1 + KAAB9AV1AZqQAAGUBnUoAAH0BXUBmv8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP0AAfY39I4AAfY39I4A + AfY39I4AAfY39IwAAfYB9AFNNywBdYsAAfYB9AFNNywBdYsAAfYB9AFNNywBdYsAAfYB9AFNNywBdYkA + AfYB8wFNOiwBdYgAAfYB8wFNOiwBdYgAAfYB8wFNOiwBdYgAAfYB8wFNOiwBdYcAAfQBdT0sAZqGAAH0 + AXU9LAGahgAB9AF1PSwBmoYAAfQBdT0sAZqFAAH0AXU9LAFNARqFAAH0AXU9LAFNARqFAAH0AXU9LAFN + ARqFAAH0AXU9LAFNARqEAAH0AXU9LAFNARqFAAH0AXU9LAFNARqFAAH0AXU9LAFNARqFAAH0AXU9LAFN + ARqFAAF1Biw4dQEahgABdQYsOHUBGoYAAXUGLDh1ARqGAAF1Biw4dQEahQAB9AF1BSwBdb4AAfQBdQUs + AXW+AAH0AXUFLAF1vgAB9AF1BSwBdb4AAXUFLAF1vwABdQUsAXW/AAF1BSwBdb8AAXUFLAF1vgAB9AF1 + BSwB9L4AAfQBdQUsAfS+AAH0AXUFLAH0vgAB9AF1BSwB9L4AAXUFLAF1vwABdQUsAXW/AAF1BSwBdb8A + AXUFLAF1vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUs + AfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsIxoBG5wAAXUFLCMa + ARucAAF1BSwjGgEbnAABdQUsIxoBG5sAAfMBdSgsAU0NGgHzjQAB8wF1KCwBTQ0aAfONAAHzAXUoLAFN + DRoB840AAfMBdSgsAU0NGgHzjQABdTcsAXUCGgHzigABdTcsAXUCGgHzigABdTcsAXUCGgHzigABdTcs + AXUCGgHzigABdTosAXUBGgHziAABdTosAXUBGgHziAABdTosAXUBGgHziAABdTosAXUBGgHziAABdTws + AXUBGgHzhgABdTwsAXUBGgHzhgABdTwsAXUBGgHzhgABdTwsAXUBGgHzhgABdT4sAXUB84UAAXU+LAF1 + AfOFAAF1PiwBdQHzhQABdT4sAXUB84UAAXU/LAF1AfOEAAF1PywBdQHzhAABdT8sAXUB84QAAXU/LAF1 + AfOEAAF1QCwBmoQAAXVALAGahAABdUAsAZqEAAF1QCwBmoQAAXVALAF1AfODAAF1QCwBdQHzgwABdUAs + AXUB84MAAXVALAF1AfOCAAEbAU1BLAGaggABGwFNQSwBmoIAARsBTUEsAZqCAAEbAU1BLAGaggABdUIs + AXUB84EAAXVCLAF1AfOBAAF1QiwBdQHzgQABdUIsAXUB84EAAXVDLAGagQABdUMsAZqBAAF1QywBmoEA + AXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMs + AZqBAAF1QywBmoEAAXVDLAF1ARuAAAF1QywBdQEbgAABdUMsAXUBG4AAAXVDLAF1ARuAAAF1RCwBmoAA + AXVELAGagAABdUQsAZqAAAF1RCwBmn8AARoBTUQsAZp/AAEaAU1ELAGafwABGgFNRCwBmn8AARoBTUQs + AZp/AAGURSwBmn8AAZRFLAGafwABlEUsAZp/AAGURSwBmn8AAZRFLAF1ARt+AAGURSwBdQEbfgABlEUs + AXUBG34AAZRFLAF1ARt+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYs + AZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBdQEb + fQABlEYsAXUBG30AAZRGLAF1ARt9AAGURiwBdQEbfQABlEcsAZp9AAGURywBmn0AAZRHLAGafQABlEcs + AZp8AAEaAU1HLAGafAABGgFNRywBmnwAARoBTUcsAZp8AAEaAU1HLAGafAABlEgsAZp8AAGUSCwBmnwA + AZRILAGafAABlEgsAZp8AAGUSCwBTQEaewABlEgsAU0BGnsAAZRILAFNARp7AAGUSCwBTQEaewABlEks + AZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsA + AZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAU0BGnoAAZRJLAFNARp6AAGUSSwBTQEa + egABlEksAU0BGnoAAZRKLAGaegABlEosAZp6AAGUSiwBmnoAAZRKLAGaeQABGgFNSiwBmnkAARoBTUos + AZp5AAEaAU1KLAGaeQABGgFNSiwBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEss + AZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkA + AZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEss + AZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABGgFN + SywBmngAARoBTUssAZp4AAGUSywBlAH2eAABlEssAZQB9ngAAZRLLAGUAfZ4AAGUSywBlAH2dwABGgFN + SywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABGgFNSywBmngAAZRLLAGUAfZ4AAGUSywBlAH2eAABlEss + AZQB9ngAAZRLLAGUAfZ2AAEaAXUBTUosAZR4AAEaAXUBTUosAZR4AAEaAXUBTUosAZR4AAEaAXUBTUos + AZRuAAEaCXUBTTAsASUYLAGUcQABGgl1AU0tLAwlECwBlHEAARoJdQFNMywEKxIsAZRxAAEaCXUBTR0s + AyUBLAErAiUlLAGUcAABGgFNDywBGigAAfMDQwHqhwABGgFNDywBGrQAARoBTQ8sARq0AAEaAU0PLAEa + GwABSgFzAUqWAAEaECwBGygAAeoBEQESAfQB8wHshgABGhAsARu0AAEaECwBG7QAARoQLAEbGQAB7QGZ + AhwBc5YAARoPLAEaKAAB6gJFAfMB6gHsAvQB7IQAARoPLAEatQABGg8sARocAAHqARKXAAEaDywBGhcA + AewBHAGZAZgEmQHrlQABGg0sARoqAAERAUQB6gH0AhEB6gHsAfIB6gHtggABGg0sARq3AAEaDSwBGhsA + AeoBEgEAAfQBEJcAARoNLAEaFwAB7QIcAZgDmQGYApkBcpcAAZoILAEaLQABEQETAfMBEgMRAUMB7AH0 + AfIB7YMAAZoILAEavAABmggsARocAAFtAQAC9AEAARICE5gAAZoILAEaGAABkgEcAZgEmQEcAhQBEgGZ + ARyYAAj2LgAB8wESAQAB8wQRAUMB7AHzAUMB7YMACPa+AAj2GwABbQEAAfYBAAESAeoB7AEcAZgBFJkA + CPYWAAHsAZIBbQFzBpkBEgHtAQcBbQFzAZkB7M4AAfQBEgHrAfMDEQFtAfMBEwERAev/AGoAAesBFAMA + AeoBbQHrARwBmAKZAXMBFLQAAZIBHAG8ARoBbQFzAZkB9AMAAZkBEwGTAb0C69IAAfMB6wEAAfMBEQFt + AfQCRAHrqwABEwMUuAAB6wH0AwABbQHrAXMBmAaZARXBAAEUAerWAAH0AesBAAHzARQBRAFuqQABEgIU + AfQBAAIQtgAB6wH0AgABbQESAewBHAGYA5kBmAJtARwBmQHr/wCbAAHzARQBFQERAW2oAAESARUB9AIA + ARQB6gHrAXMBFbIAAesBFQH0AgABbQESARQBHAaZARMBbgHsARUBmQGYARP/AP8ARgAB6gEVAfQBAAET + ARUBbQFzAZgCmQEUsQAB6wHzAgAC6wEcAbwBFAEcBZkBmAEVARoBvQETARwBmQES/wCHAAEVAUO5AAFt + AkMB9AEAARIBFAHqARwBmASZAXMBFbEAAesBFQHsAZMBGgK9ARMBHAGZAfYCAAKZARQB7QEcAUMDAAEV + /wCDAAEUAkMCAAFDtgABbQFDAfQCAAESARMB6wGYBJkBHAGYApkBQ7AAAesB8wYAARIB9AcAAeoEAAFD + /wCCAAEUAREDAAEVARIBFbQAAesBEQH0AQAB6gERARMBcwGYBZkBSgEUAUMBcwGZAW0BQ7AAAesB9AUA + ARMB9gEAARMBEQcAARH/AIIAARMBEAIAARUBEQFtARwBmQFzARCxAAHrARAB8wEAAeoBQwFtAW4BbQGY + BZkBcwESARoBkwEVAZkBHAERsQABbQUQAQ8B9gQAARQBEAIAAUP/AIEAARICEAH0AQABFAEVAesBmASZ + ARWwAAHrAfMBAAFtARQB7AEaAb0BBwESAZgFmQFzAeoBvQEHAUMCmQFDvwABQ/8AgQABEgEPAfQCAAIU + AXMHmQHrARCvAAHrAg8B9AEaA70BGgEUAfQFAAGZARMBFQERAwABEP8A/wBAAAHqAQ8B9AEAARMBEAFK + ARwFmQFyARMBcgKZARGwAAFtAfQGAAETAfYKAAIP/wD/AD4AAW0CEAH0AQABEgEVAREBcwaZAXIBEgGT + ARIB6wGZAW2xAAFtARAB9AIAARIIEAMAAREBEP8A/wA/AAHrAfMCAAHqARMB7QEaAewB6wEcBZkBSgGT + Ab0BHAESAZkBHAEQsgABbQMQAfQHAAEVAhD/AP8AQQAB6wEPARABEgGTAxoB7QFtAZgBmQIAApkBcwES + ARwBEgHrAgABEP8A/wD/AAMAAesBDwHzBQAB6wERAfQGAAFzARUDAAERAUP/AP8A/wAEAAHrAUMB8wQA + ARMBEQRDAfQFAAJD/wD/AP8ACAAB6wVDAfQEAAETAUMBAAEUAkP/AP8A/wAXAAET/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8AegAF9P8A + /wD/ABQAAfQB8wHPAbQBrgGTAY0B9wH0/wD/AP8AEQAB8wHPAbQC2wHsAnoBdQGNAbX/AP8ATQAE9L4A + Aa4BtAPbAY0CegF0AZMBjQG1/wD/AEoAAfQB8gHPAq4B9wL0lwABlBNNEAAB8wHPBLQBjQF6AZMB7QOT + AfT/AP8ASAAB8wHPArQB7AF6AXQBkwH3AfSWAAGUE00QAAHPA9sBtAGuAY0BkwGNAZMCegGTAbX/AP8A + RwAB8gHPA9sBrgJ6AXUBkwH3AfSVAAGUE00QAAHPA9sBtAHsAY0BrgGTAnUCkwHv/wCDAAb0vQABzwK0 + AdsBtAHsAXoBdQGTAo0B9wH0lAABlBNNEAABzwG6ArQB7QKTAo0BkwGNAoIBtv8AggAB8gLPAa4BkwGN + AfcC9JYAFPQQAAHyAbQB2wO0AY0BdQGTAY0BdAF6AZMBtZQAAZQTTRAAAa4BjQHtAZMBdQGTAe0BdQGT + AYwBiAGPAYgBtv8AgQAB8gG0AtsBjQJ6AXUBjQG1AfSUAAGUFE0QAAHPBNsBrgONAXUBegF1AZMBtZQA + AZQTTRAAAbUBdQJ6AXQBjQJ1AY0BiAGCAogBtb4AAfMB9L8AAfIBtAPbAa4CegF1AZMBjQG1lAABlBRN + EAABzwLbArQCkwGNA5MBjgGNAbaUAAGUE00RAAGTAXoBdQKTAXoBkwGCAY8BiAGCAY4BvLsAAfMB9AHx + Aa4B9wH0AfMB9LsAAfIBzwS0AewBegKTAe0BkwHvAfSTAAGUFE0QAAGuArQB7QKTAY0BkwKNAYICiAG2 + lAABlBNNEQAB7wGTAXQBjQJ1AZMBiAGPAYgBjQG8uwAB8QHPArQB7AF1AZMB7QH3AfS6AAHPA9sBtAHP + AY0BkwHtAZMCegGTAbWTAAGUFE0QAAGuAZMBdAF6AXUCkwF1AZMBggGIAY8BiAG2lAABlBNNEgAB7wGT + AY0BegF1AZMCiAGOAby7AAHwAc8D2wHPA3oBkwH3AfSUAAH0E/MRAAHPA9sBtASNAXoBdQKTAe+TAAGU + FE0QAAG1AZMCegGTAY0BegGTAY0DiAGOAbyUAAGUE00TAAG1Ae8CkwGOAY0BtgG8vAABzwK0AtsBrgF6 + AXUCkwGNAfcB9JMAAZQTTREAAc8DtAHtApMCjQGTAY4BjQGCAbaTAAGUFE0QAAH0AY0CdQHtAZMBegGT + AYgBjwGIAYIBtpUAAZQTTRUAAbUB7wG1Aby9AAHxAbQB1QO0AY0BdQGTAe0BkwF6AZMBtZMAAZQTTREA + Aa4C7QGTAXUBkwHtAXUBkwGMAYIBjwGIAbaTAAGUFE0RAAG1Ae0BkwGNAXoBdQGTAYgBjwGIAY0BvJUA + AZQTTdYAAc8E2wGuAY0B7QGNAXQBegF1AZMBtZMAAZQTTREAAe8BdQJ6AXQBjQF0AXUBjQGIAYICiAG1 + kwABlBRNEgACBwGNAnQBkwGCAYgBjQG8lgABlBNN1gABzwLbArQB7QGTAY0B7QOTAY0B75MAAZQTTRIA + AZMBegF1ApMBegGTAYIBjwGIAYIBjgHwkwABlBRNFAABBwO8ArYBvJcAAZQTTbEAAfQTGxEAAc8CtAHt + ApMB7QGTAe0CjQKIAbaTAAGUE00SAAEHAZMBdQGNAXUBegGTAYgBjwGIAYIBtZQAAZQUTbIAAZQTTbEA + AZQTTREAAa4CkwJ1ApMBdQGTAYIBiAGPAYgBtpMAAZQTTRMAAQcBkwGNAnoBkwGIAY8BjgG2AfCUAAGU + FE2wAAHzAQABlBNNAQABG68AAZQTTREAAe8BkwJ6AZMBjQF6AZMBjQSIAbWTAAGUE00UAAIHApMBjgGC + AY4B8JYAAZQUTa8AAfMBFgEaARYTTQEbAU0BG64AAZQTTREAAfQBjQJ1ApMBegGTAYIBjwGIAYIBjQHw + kwABlBNNFgAEBwHwlwABlBRNrgAB8wEWGE0BFwEbrQABlBNNEgABBwKTAY0CegGTAYgBjwGIAY0B8JQA + AZQTTbIAAZQUTa0AAfMBFhpNARcBG6wAAZQTTRMAAQcCjQJ1AZMBggGIAY4B8ZUAAZQTTbIAAZQUTawA + AfMBFhxNARcBGqsAAZQTTRQAAQcCvAGNAZICvAHwlgABlBNNsAAB8wEAAZQUTQEAARqqAAEaAeMcTQEX + Ab2rAAGUE00XAAEHAfCZAAGUE02vAAHzARYBvQEWFE0BGgFNARqqAAEaAeMaTQEXAb2sAAGUE02yAAGU + E02uAAHzARYZTQEXARqqAAEaAeMKTQGaA70BFwlNARcBva0AAZQTTbIAAZQTTa0AAfMBFhtNARcBGqoA + ARoB4whNAZoEAAEaARcITQG9rgABlBNNsgABlBNNrAAB8wEWHU0BFwEaqgABGgHjBk0BmgYAARoBFwZN + Ab2vAAGUE02wAAEbAQABlBNNrAABGwEWHU0BFwEaqwABGgHjBE0BmggAAeMFTQG9sAABlBNNrwABGwEW + AZoB4xNNARoCvaoAARsB4xtNARcBva0AARoEvQkAARoFvbEAAZQTTa4AARsBFhlNARqqAAEbAeMLTQO9 + ARcKTQEXARr/AHQAAZQTTa0AARsBFhpNARcBGqoAARsB4whNAb0BGgMAAhoBFwhNARr/AHUAAZQTTawA + ARsBFhxNARcBGqoAARsB4wdNBwAB4wdNARr/AHYAAZQTTawAAZQeTQEXqwABGwHjBU0BvQcAARoBFwVN + ARr/AHQAARoCvQHjE00DvakAARsBFhxNARcBGqwAARsFvQkAARoFvf8AdAABGgHjGU0BvakAAfMBFgxN + Ar0B4wtNARcBGv8A/wA2AAEaAeMaTQEXAb2pAAHzARYJTQG9ARoCAAIaARcJTQEa/wD/ADYAARoB4xxN + ARcBvakAAfMBFgdNAb0GAAEaARcHTQEa/wD/ADcAAZQeTQEXqgAB8wEWBk0IAAHjBk0BGv8A/wA4AAHz + ARYcTQEXARqrAAHzBhoIAAca/wD/ADoAAfMBFgxNAhoB4wtNARcBGv8A/wD9AAHzARYJTQIaAgABGwEa + AeMJTQEa/wD/AP8AAfMBFgdNARoGAAEbARcHTQEa/wD/AP8AAgAB8wEWBk0IAAHjBk0BGv8A/wD/AAQA + AfMGGwgABxv/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AJkAAU0B9CwAARsBLAF1lQABTQH0 + LAABGwEsAXWVAAFNAfQsAAEbASwBdZUAAU0B9CwAARsBLAF1kgABdQYsAfYnAAEbBSwBlJAAAXUGLAH2 + JwABGwUsAZSQAAF1BiwB9icAARsFLAGUkAABdQYsAfYnAAEbBSwBlI8AAXUILAH2JAAB8wksAZSNAAF1 + CCwB9iQAAfMJLAGUjQABdQgsAfYkAAHzCSwBlI0AAXUILAH2JAAB8wksAZSMAAF1CiwkAAEbCSwBlIwA + AXUKLCQAARsJLAGUjAABdQosJAABGwksAZSMAAF1CiwkAAEbCSwBlIwAAXUKLCMAAfQLLAGaiwABdQos + IwAB9AssAZqLAAF1CiwjAAH0CywBmosAAXUKLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0 + CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMAAfQLLAGa + igABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAZQBTQosIwAB9AssAZqKAAGUAU0KLCMAAfQLLAGa + igABlAFNCiwjAAH0CywBmooAAZQBTQosIwAB9AssAZqLAAF1CiwjAAH0AU0JLAFNARqLAAF1CiwjAAH0 + AU0JLAFNARqLAAF1CiwjAAH0AU0JLAFNARqLAAF1CiwjAAH0AU0JLAFNARqLAAGUAU0ILAFNJAAB9AFN + BywBTQEajAABlAFNCCwBTSQAAfQBTQcsAU0BGowAAZQBTQgsAU0kAAH0AU0HLAFNARqMAAGUAU0ILAFN + JAAB9AFNBywBTQEajQABlAFNBiwBTSYAAfQBTQUsAU0Bmo4AAZQBTQYsAU0mAAH0AU0FLAFNAZqOAAGU + AU0GLAFNJgAB9AFNBSwBTQGajgABlAFNBiwBTSYAAfQBTQUsAU0Bmo8AAZQGdSgAAfQFdQGakAABlAZ1 + KAAB9AV1AZqQAAGUBnUoAAH0BXUBmpAAAZQGdSgAAfQFdQGa/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /QAB9jf0jgAB9jf0jgAB9jf0jgAB9jf0jAAB9gH0AU03LAF1iwAB9gH0AU03LAF1iwAB9gH0AU03LAF1 + iwAB9gH0AU03LAF1iQAB9gHzAU06LAF1iAAB9gHzAU06LAF1iAAB9gHzAU06LAF1iAAB9gHzAU06LAF1 + hwAB9AF1PSwBmoYAAfQBdT0sAZqGAAH0AXU9LAGahgAB9AF1PSwBmoUAAfQBdT0sAU0BGoUAAfQBdT0s + AU0BGoUAAfQBdT0sAU0BGoUAAfQBdT0sAU0BGoQAAfQBdT0sAU0BGoUAAfQBdT0sAU0BGoUAAfQBdT0s + AU0BGoUAAfQBdT0sAU0BGoUAAXUGLDh1ARqGAAF1Biw4dQEahgABdQYsOHUBGoYAAXUGLDh1ARqFAAH0 + AXUFLAF1vgAB9AF1BSwBdb4AAfQBdQUsAXW+AAH0AXUFLAF1vgABdQUsAXW/AAF1BSwBdb8AAXUFLAF1 + vwABdQUsAXW+AAH0AXUFLAH0vgAB9AF1BSwB9L4AAfQBdQUsAfS+AAH0AXUFLAH0vgABdQUsAXW/AAF1 + BSwBdb8AAXUFLAF1vwABdQUsAXW/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0 + vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1 + BSwjGgEbnAABdQUsIxoBG5wAAXUFLCMaARucAAF1BSwjGgEbmwAB8wF1KCwBTQ0aAfONAAHzAXUoLAFN + DRoB840AAfMBdSgsAU0NGgHzjQAB8wF1KCwBTQ0aAfONAAF1NywBdQIaAfOKAAF1NywBdQIaAfOKAAF1 + NywBdQIaAfOKAAF1NywBdQIaAfOKAAF1OiwBdQEaAfOIAAF1OiwBdQEaAfOIAAF1OiwBdQEaAfOIAAF1 + OiwBdQEaAfOIAAF1PCwBdQEaAfOGAAF1PCwBdQEaAfOGAAF1PCwBdQEaAfOGAAF1PCwBdQEaAfOGAAF1 + PiwBdQHzhQABdT4sAXUB84UAAXU+LAF1AfOFAAF1PiwBdQHzhQABdT8sAXUB84QAAXU/LAF1AfOEAAF1 + PywBdQHzhAABdT8sAXUB84QAAXVALAGahAABdUAsAZqEAAF1QCwBmoQAAXVALAGahAABdUAsAXUB84MA + AXVALAF1AfODAAF1QCwBdQHzgwABdUAsAXUB84IAARsBTUEsAZqCAAEbAU1BLAGaggABGwFNQSwBmoIA + ARsBTUEsAZqCAAF1QiwBdQHzgQABdUIsAXUB84EAAXVCLAF1AfOBAAF1QiwBdQHzgQABdUMsAZqBAAF1 + QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGa + gQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAXUBG4AAAXVDLAF1ARuAAAF1QywBdQEbgAABdUMs + AXUBG4AAAXVELAGagAABdUQsAZqAAAF1RCwBmoAAAXVELAGafwABGgFNRCwBmn8AARoBTUQsAZp/AAEa + AU1ELAGafwABGgFNRCwBmn8AAZRFLAGafwABlEUsAZp/AAGURSwBmn8AAZRFLAGafwABlEUsAXUBG34A + AZRFLAF1ARt+AAGURSwBdQEbfgABlEUsAXUBG34AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGa + fgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGU + RiwBmn4AAZRGLAF1ARt9AAGURiwBdQEbfQABlEYsAXUBG30AAZRGLAF1ARt9AAGURywBmn0AAZRHLAGa + fQABlEcsAZp9AAGURywBmnwAARoBTUcsAZp8AAEaAU1HLAGafAABGgFNRywBmnwAARoBTUcsAZp8AAGU + SCwBmnwAAZRILAGafAABlEgsAZp8AAGUSCwBmnwAAZRILAFNARp7AAGUSCwBTQEaewABlEgsAU0BGnsA + AZRILAFNARp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGU + SSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBTQEaegABlEks + AU0BGnoAAZRJLAFNARp6AAGUSSwBTQEaegABlEosAZp6AAGUSiwBmnoAAZRKLAGaegABlEosAZp5AAEa + AU1KLAGaeQABGgFNSiwBmnkAARoBTUosAZp5AAEaAU1KLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGa + eQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGU + SywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGa + eQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeAABGgFNSywBmngA + ARoBTUssAZp4AAEaAU1LLAGaeAABGgFNSywBmngAAZRLLAGUAfZ4AAGUSywBlAH2eAABlEssAZQB9ngA + AZRLLAGUAfZ3AAEaAU1LLAGaeAABGgFNSywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABlEssAZQB9ngA + AZRLLAGUAfZ4AAGUSywBlAH2eAABlEssAZQB9nYAARoBdQFNSiwBlHgAARoBdQFNSiwBlHgAARoBdQFN + SiwBlHgAARoBdQFNSiwBlG4AARoJdQFNSSwBlHEAARoJdQFNSSwBlHEAARoJdQFNSSwBlHEAARoJdQFN + SSwBlHAAARoBTQ8sARq0AAEaAU0PLAEatAABGgFNDywBGrQAARoBTQ8sARq0AAEaECwBG7QAARoQLAEb + tAABGhAsARu0AAEaECwBG7QAARoPLAEatQABGg8sARq1AAEaDywBGrUAARoPLAEatQABGg0sARq3AAEa + DSwBGrcAARoNLAEatwABGg0sARq5AAGaCCwBGrwAAZoILAEavAABmggsARq8AAGaCCwBGjAAAeyMAAj2 + vgAI9r4ACPa+AAj2LwABEgETARECEgHs/wD/AP8AFQACRAQRARIB7P8A/wD/ABIAARQBRAFFBhEB7P8A + /wD/ABEAChEBEwHs/wD/AEsAAhQB68AAAfQIEQFtAfMBEQHs/wD/AEgAARQBFQMRARQB678ACREBFQER + Aev/AP8ASAABQwFFBREB674AAfQIEQJDAev/AP8ASAABQwFFAUMFEQEVAey+AAH0BhECRAHr/wD/AEgA + ChEBQwHsvgAB9AURAev/AIMAAfQDQwFtwAALEQHrwAAB9AIRAW3/AIQABREBbb8AAfQLEQHs/wD/AEcA + AUQBRQFEBREBbb4AAfQHEQFDAUQBQwHsqQABQwEPAQABEf8AmQABEQJEBxEB674AAfQGEQFEAW6oAAEV + AQ8CAAERAg//AJgACxEB674AAfQEEQJDAeulAAEUAhACAAJDAW0BmAEU0gAB9AMRAW3AAAwRAey/AAH0 + AkMB66UAARIBEAH0AgABFQEUAXMDmQFzAQ/QAAH0AREBQwQRAW2/AAJDCREB7KoAARUBEQEPuQAB6gER + AfQBAAEUARABSgFzBpkBQ9AAARECRQYRAW2+AAH0AUMGEQJEAeynAAEUAhECAAERtgABbQIRAfQBAAET + AUMBbQEcBJkCHAKZAesBD88AAREBRAFDCBEB670AAfQBFQFDBBECRAHspQABEwFDAwABQwEUAeoBD7MA + AesBQwHzAgABEgERAesGmQHrARUCEwGZAZgBEc8AARULEQHsvgAB9AIVAhEBFAHspAABEgFDAfQCAAEV + ARIBcwKZARSxAAHrAUMB8wEAAeoBEAFtARwBFAEcBpkBFQEHAb0B6gFzAZkBbdAAARQKEQHsqwABFBQA + AfQBFAHsowABbQIVAfQBAAEUAUMBbQEcBJkBcwEPsAAB6wHyAesBFAHrAQcCvQHqARwGmQEUAZMBGgET + ARwBmQEAARDQAAEUCREB7KgAARMCFQEAARC3AAHrARUB9AIAARMBFAHrAZgDmQKYApkBQ7AAAesBDwH0 + AQABGwMaAeoB9AYAARwBEgETARQDAAEU0AAB9AETARQFEQJEAeymAAESARQB9AIAAkO1AAHrARQB8wIA + AhIBcwWZAXMCEgFzAZkBbbAAAewBEAHyBQABEwHzCwACFNMAAfQBEwEUAxECRAHtpAAB6gEUAfQBAAEV + AUMBSgEcAXMBD7EAAW0BFQEUAfMBAAHqAUMBEwESAZgFmQGYARUBkwHtARQBmQEcARCwAAHsAhQB8wEA + ARMBFQcUAfQCAAETARTDAAL2EwAB9AQSAeyhAAH2AesCFAH0AQACFAHrAZgDmQEVAfavAAHrAQ8B8gEA + AW0BFAHsARoBvAETARwFmQEcARMCGgFDApkBbbMAAewCFAH0BwAB6gIUwgAC9AESARMBDwH0twAB9AHr + ARMB8wH0AfYBEwESAXMGmQHrAQ+vAAHtARABFAESARwEGgEUApkDAAEIAZkBFAFuAe0BbQEAAvT/AIEA + A/QB6gETAvQBQwEPtAAC9AHrARMB8wH0ARMBQwFKAXMEmQEcAnMBmQGYARGwAAHsAfIGAAETAfME9AIA + ARwB6wEAAvQBEwES/wB/AAL0AesCEgL0ARUBFAHrARQB9LAAAfYB9AHsAhIB8gH0AeoBEQHqARwFmQEc + ARQBbQEUAXMBmQHqAfSwAAHsAfIF9AEUARMEEgL0AQAC9AIS/wB/AAL0AesBEgHzAvQBFAESAXMCmQFz + AQ+wAAHrARQB8gL0AW0B6gHtAW4B6wGYBZkBbQFuAb0BkwEUAZkBHAEPsQAB7AYSBQAB6wESAfQB6gES + /wB+AAP0AesBEgHzAfQBFAFDAeoBcwWZAUOwAAHrAfEB7AHqAesBkwEaAb0BkwHqAZkFCAFzAW0BBwLs + AQgBAAEQvwABbf8AfgAC9AHsAuoB8gH0ARIBFAHrARwDmQIcAZgBmQHrAfSvAAHtAREB8wEAARsDGgEH + ARQB9AUAAQgB7AHrAeoBAAL0Aer/AP8APQAC9AHsAeoB8gL0AhMBcwGYBJkBHAHqARIBbQGYARwBEbAA + Ae0B8Qb0ARQB8gX0AgAD9AFtAer/AP8APQAB9AHtAW0B8QH0AeoBFQFtARUBHAaZARIB7AG8ARIBcwGZ + AeoB9LAAAe0CbQERAQ8BEghtAfMB9AHrAm3/AP8APwAB6wHwAfMBbQETAewBBwG9AW0BcwGZBAgBmQEU + AZMBGgFtAXIBCAEcAQ+zAAHtAW0B9AgAAesBbf8A/wBCAAHrAQ8B6gGSARoDGwHrAZIBCAQAAQgBHAHq + AW0B6wEcAQAB8wHr/wD/AP8AAwAB9wFDAfAFAAESAfEF8wIAAe8B6wPzAev/AP8A/wAFAAH3AesB8QTz + ARQBbQXrAfID8wPr/wD/AP8ACAAB9wXrBgAB7AEQAuv/AP8A/wAYAAHs/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8AEAAE8wH0/wD/AP8AFAAB8wHxAc8BrgKNAfcB9P8A/wD/ABIA + AfEBtALbAa4CegKTAfMB9P8A/wD/AA8AAfABzwPbAc8CegF1AZMBjQG1/wD/AEsAAfIF8wH0vAABzwS0 + AewBegF0A5MB7wH0/wD/AEgAAfIB8QK0Aa4CkwGNAfcB87oAAfAD2wG0Ac8BjQOTAXUBegGTAbX/AP8A + RwAB8AHPAbQC2wG0AnoBdQGTAbUB87kAAc8D2wG0BI0BegF1ApMB7/8AhAAD8QHzvgABzwK0AtsBkQJ6 + ApMBjQHvuQABzwHVArQB7QKTAY0B7QGTAo4BjQG2/wCCAAHyAfABzwGuAY0B9wLzuwAB8AW0AY0BdQOT + AXUBmQHzuAABrgLtAZMBdAGTAe0BdQGTAa4BggGPAYgBtv8AgQAB8AG0AdUB2wGuAXoBdQKTAfO6AAHP + A9sBtAGuAY0BkwGNAZMCegGTAe+4AAEHAXUCegF1AY0BkwF1AY4CggKIAbb/AIAAAbwBzwPbAbQCegF1 + AZMB9wHzuQABzwLbAdUBtAHtAZMCjQF0ApMBjgHvkgAB8xMaEwABkwJ6ApMBegGTAY0BjwGIAYIBjgHx + vQAE8QHzvQABzwS0AY0BegF1A5MB9wHzuAABzwK0AZICkwHtApMCjQKIAbaSAAGUE00TAAEHAZMBdQGN + AXQBegGTAYgBjwGIAYIBtrwAAfEBGQG0Aa4DkwHxAfO6AAG8AdUC2wG0Ac8BjQOTAXUBegGTAbW4AAGu + ApMBdAF1ApMBdQGTAoIBjwGIAbaSAAGUE00UAAG8AZMBjQJ6AZMBiAGPAYgBjQHwuwAB8AG0AtsBtAJ6 + AXUBkwGvAfO5AAHPA9sBtAGuA40CdQGTARwB77gAAQcBkwJ6AZMBjQJ1AY0EiAG1kgABlBNNFQABBwGu + A5MBggGOAbwB8LsAAbwCtALbAc8CegKTAewB77kAAc8B1QK0AZICkwGNAe0BkwKOAY0BtrgAAfQBjQJ1 + ApMBegGTAYIBjwGIAYIBjgHxkgABlBNNFgAFvAHxvQAFtAGNAXUDkwF0AZMB87gAAa4B9wGSA5MBjQKT + Aa4BggKIAbaSAAEbE70TAAEHApMBjQF1AXoBkwGIAY8BiAGNAfGTAAGUE03YAAEJA9sBtAHPAY0BkwHt + AZMCegGTAe+4AAG8AZMBdQF6AXUB7QGTAXUBjgKCAogBtpIAAZQTTRQAAQcCjQF1AXoBkwGCAYgBjgHy + lAABlBNN2AABzwPbAbQB7QGTAa4BjQF1ApMBjgHvuQABkwJ6AZMB7QF6AZMBjQGPAYgBggGOAfKSAAGU + E00VAAG8AQcEjQHwAfGVAAGUE03YAAHPArQBtQEcAZMB7QKTAo0CiAG2uQABvAGTAXUB7QGTAXoBkwGC + AY8BiAGCAbaTAAGUE00XAAO8AfGXAAGUE03YAAG8ARwCkwF1ApMBdQGTAoIBjwGIAba6AAG8AZMBjQJ6 + AZMBiAGPAYgBrwHykwABlBNNsgABlBNN2QABkwJ6AZMBjQJ1AY0DiAGxAfK7AAG8Aa4DkwGCAY4B8AHy + lAABlBNNsgABlBNN2AAB9AGNAXoBdQKTAXoBkwGCAY8BiAGCAba9AALwAvEB8AHylgABlBNNsgABlBNN + 2QABvAGTAXQBjQF1AXoBkwGIAY8BiAGvAfP/AFoAAZQTTbIAAZQTTdoAAbwCjQJ6AZMBggGIAY4B8/8A + WwABlBNNsgABlBNN2wAC8AEaAe0BjQGvAfIB8/8AXAABlBNNsgABlBNN3gAC8QHz/wBeAAGUE02yAAGU + E03/AP8AQAABlBNNsAABGgEAAZQTTQEAAr3/AP8APQABlBNNrwABGgHjAZQB4xNNAZoBFwFNAb3/AP8A + PAABlBNNrgABGgHjGk0Bvf8A/wA7AAGUE02tAAEaAeMcTQG9/wD/ADoAAZQTTa0AAZQdTQEX/wD/ADoA + AZQTTa0AAfQBFhtNARcBG/8A/wA3AAG9AZoBAAGUE00BAAKaqwAB9AEWDE0BGgHjDE0BG/8A/wA3AAG9 + AeMBTQGUAeMTTQGUARcBTQGUqwAB9AEWCE0BGgIbAQAB8wEbAeMJTQEb/wD/ADcAAb0B4xtNrAAB9AEW + Bk0BGgYAAfMB4wdNARv/AP8AOAABlBxNAZSsAAH0ARYFTQgAAfMB4wVNARv/AP8AOQAB9AEWG00B860A + AfQF8wkABvP/AP8AOwAB9AEWCk0BGgPzAeMKTQHz/wD/AP8AAfQBFgdNARoB8wQAAfQB8wHjB00B8/8A + /wD/AAIAAfQBFgZNCAAB4wZNAfP/AP8A/wAEAAH2ARYETQEaCAAB9AHjBE0B8/8A/wD/AAYAAfYE9AoA + BfT/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP4AAU0B9CwAARsBLAF1lQABTQH0LAABGwEsAXWVAAFN + AfQsAAEbASwBdZUAAU0B9CwAARsBLAF1kgABdQYsAfYnAAEbBSwBlJAAAXUGLAH2JwABGwUsAZSQAAF1 + BiwB9icAARsFLAGUkAABdQYsAfYnAAEbBSwBlI8AAXUILAH2JAAB8wksAZSNAAF1CCwB9iQAAfMJLAGU + jQABdQgsAfYkAAHzCSwBlI0AAXUILAH2JAAB8wksAZSMAAF1CiwkAAEbCSwBlIwAAXUKLCQAARsJLAGU + jAABdQosJAABGwksAZSMAAF1CiwkAAEbCSwBlIwAAXUKLCMAAfQLLAGaiwABdQosIwAB9AssAZqLAAF1 + CiwjAAH0CywBmosAAXUKLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMA + AfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9Ass + AZqKAAF1CywjAAH0CywBmooAAZQBTQosIwAB9AssAZqKAAGUAU0KLCMAAfQLLAGaigABlAFNCiwjAAH0 + CywBmooAAZQBTQosIwAB9AssAZqLAAF1CiwjAAH0AU0JLAFNARqLAAF1CiwjAAH0AU0JLAFNARqLAAF1 + CiwjAAH0AU0JLAFNARqLAAF1CiwjAAH0AU0JLAFNARqLAAGUAU0ILAFNJAAB9AFNBywBTQEajAABlAFN + CCwBTSQAAfQBTQcsAU0BGowAAZQBTQgsAU0kAAH0AU0HLAFNARqMAAGUAU0ILAFNJAAB9AFNBywBTQEa + jQABlAFNBiwBTSYAAfQBTQUsAU0Bmo4AAZQBTQYsAU0mAAH0AU0FLAFNAZqOAAGUAU0GLAFNJgAB9AFN + BSwBTQGajgABlAFNBiwBTSYAAfQBTQUsAU0Bmo8AAZQGdSgAAfQFdQGakAABlAZ1KAAB9AV1AZqQAAGU + BnUoAAH0BXUBmpAAAZQGdSgAAfQFdQGa/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/QAB9jf0jgAB9jf0 + jgAB9jf0jgAB9jf0jAAB9gH0AU03LAF1iwAB9gH0AU03LAF1iwAB9gH0AU03LAF1iwAB9gH0AU03LAF1 + iQAB9gHzAU06LAF1iAAB9gHzAU06LAF1iAAB9gHzAU06LAF1iAAB9gHzAU06LAF1hwAB9AF1PSwBmoYA + AfQBdT0sAZqGAAH0AXU9LAGahgAB9AF1PSwBmoUAAfQBdT0sAU0BGoUAAfQBdT0sAU0BGoUAAfQBdT0s + AU0BGoUAAfQBdT0sAU0BGoQAAfQBdT0sAU0BGoUAAfQBdT0sAU0BGoUAAfQBdT0sAU0BGoUAAfQBdT0s + AU0BGoUAAXUGLDh1ARqGAAF1Biw4dQEahgABdQYsOHUBGoYAAXUGLDh1ARqFAAH0AXUFLAF1vgAB9AF1 + BSwBdb4AAfQBdQUsAXW+AAH0AXUFLAF1vgABdQUsAXW/AAF1BSwBdb8AAXUFLAF1vwABdQUsAXW+AAH0 + AXUFLAH0vgAB9AF1BSwB9L4AAfQBdQUsAfS+AAH0AXUFLAH0vgABdQUsAXW/AAF1BSwBdb8AAXUFLAF1 + vwABdQUsAXW/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1 + BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwjGgEbnAABdQUs + IxoBG5wAAXUFLCMaARucAAF1BSwjGgEbmwAB8wF1KCwBTQ0aAfONAAHzAXUoLAFNDRoB840AAfMBdSgs + AU0NGgHzjQAB8wF1KCwBTQ0aAfONAAF1NywBdQIaAfOKAAF1NywBdQIaAfOKAAF1NywBdQIaAfOKAAF1 + NywBdQIaAfOKAAF1OiwBdQEaAfOIAAF1OiwBdQEaAfOIAAF1OiwBdQEaAfOIAAF1OiwBdQEaAfOIAAF1 + PCwBdQEaAfOGAAF1PCwBdQEaAfOGAAF1PCwBdQEaAfOGAAF1PCwBdQEaAfOGAAF1PiwBdQHzhQABdT4s + AXUB84UAAXU+LAF1AfOFAAF1PiwBdQHzhQABdT8sAXUB84QAAXU/LAF1AfOEAAF1PywBdQHzhAABdT8s + AXUB84QAAXVALAGahAABdUAsAZqEAAF1QCwBmoQAAXVALAGahAABdUAsAXUB84MAAXVALAF1AfODAAF1 + QCwBdQHzgwABdUAsAXUB84IAARsBTUEsAZqCAAEbAU1BLAGaggABGwFNQSwBmoIAARsBTUEsAZqCAAF1 + QiwBdQHzgQABdUIsAXUB84EAAXVCLAF1AfOBAAF1QiwBdQHzgQABdUMsAZqBAAF1QywBmoEAAXVDLAGa + gQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1 + QywBmoEAAXVDLAGagQABdUMsAXUBG4AAAXVDLAF1ARuAAAF1QywBdQEbgAABdUMsAXUBG4AAAXVELAGa + gAABdUQsAZqAAAF1RCwBmoAAAXVELAGafwABGgFNRCwBmn8AARoBTUQsAZp/AAEaAU1ELAGafwABGgFN + RCwBmn8AAZRFLAGafwABlEUsAZp/AAGURSwBmn8AAZRFLAGafwABlEUsAXUBG34AAZRFLAF1ARt+AAGU + RSwBdQEbfgABlEUsAXUBG34AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGU + RiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAF1 + ARt9AAGURiwBdQEbfQABlEYsAXUBG30AAZRGLAF1ARt9AAGURywBmn0AAZRHLAGafQABlEcsAZp9AAGU + RywBmnwAARoBTUcsAZp8AAEaAU1HLAGafAABGgFNRywBmnwAARoBTUcsAZp8AAGUSCwBmnwAAZRILAGa + fAABlEgsAZp8AAGUSCwBmnwAAZRILAFNARp7AAGUSCwBTQEaewABlEgsAU0BGnsAAZRILAFNARp7AAGU + SSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGa + ewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBTQEaegABlEksAU0BGnoAAZRJLAFN + ARp6AAGUSSwBTQEaegABlEosAZp6AAGUSiwBmnoAAZRKLAGaegABlEosAZp5AAEaAU1KLAGaeQABGgFN + SiwBmnkAARoBTUosAZp5AAEaAU1KLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGU + SywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGa + eQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGU + SywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeAABGgFNSywBmngAARoBTUssAZp4AAEa + AU1LLAGaeAABGgFNSywBmngAAZRLLAGUAfZ4AAGUSywBlAH2eAABlEssAZQB9ngAAZRLLAGUAfZ3AAEa + AU1LLAGaeAABGgFNSywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABlEssAZQB9ngAAZRLLAGUAfZ4AAGU + SywBlAH2eAABlEssAZQB9nYAARoBdQFNSiwBlHgAARoBdQFNSiwBlHgAARoBdQFNSiwBlHgAARoBdQFN + SiwBlG4AARoJdQFNECwUTSUsAZRxAAEaCXUBTUksAZRxAAEaCXUBTUksAZRxAAEaCXUBTUksAZRwAAEa + AU0PLAEaCgABFhNNlgABGgFNDywBGgoAARYTTZYAARoBTQ8sARoLAAEWEk2WAAEaAU0PLAEatAABGhAs + ARsKAAEWE02WAAEaECwBGwoAARYTTZYAARoQLAEbCwABFhJNlgABGhAsARu0AAEaDywBGgsAARYTTZYA + ARoPLAEaCwABFhNNlgABGg8sARoMAAEWEk2WAAEaDywBGrUAARoNLAEaDQABFhNNlgABGg0sARoNAAEW + E02WAAEaDSwBGg4AARYSTZYAARoNLAEauQABmggsARoQAAEWE02YAAGaCCwBGhAAARYTTZgAAZoILAEa + DgABlAIWARcSTQMWlQABmggsARq9AAj2EQABFhNNmQAI9hEAARYTTZkACPYNAAGUAeMBFxdNARcB4wEW + lAAI9tcAARYTTbIAARYTTa0AAZQBFxtNARcBFv8AcwABFhNNsgABFhNNrgABFhtNARf/AHQAARYTTbAA + AZQB4wEXE00BAALjrAABFhlNARf/AHUAARYTTa8AAZQBFxVNAeMCTQHjrAABFglNBQAB4whNARf/AHYA + ARYTTa4AAZQBFxpNAeOsAAEWBk0JAAEXBU0BF/8AdwABFhNNrQABlAEXHE0B46wAARYFTQkAARcETQEX + /wB4AAEWE02tAAGUHU0BF/8A/wA3AAGUARcBAAEWE00CFwHjqwABlBtNARf/AP8ANwABlAEXAU0CFxZN + AeOrAAGUC00B9gEAAeMLTQEX/wD/ADcAAZQBFxtNAeOrAAEWCE0GAAHjCE0BF/8A/wA3AAGUHk0B46sA + ARYGTQgAARcGTQEX/wD/ADgAAZQeTQHjrAABFgVNCQABFwRNARf/AP8AOgABlAEXG00B4/8A/wD9AAGU + ARcKTQUXCk0B4/8A/wD/AAGUARcITQEXBQAB4whNAeP/AP8A/wACAAGUARcGTQEXAfYGAAEXBk0B4/8A + /wD/AAQAAZQGFwgAAeMFFwHj/wD/AP8A/wD/AP8A/wD/AJQAAfQEEQFt/wD/AP8AFQABQwFEBREBbf8A + /wD/ABIAAfQBQwFFBxEBbf8A/wD/ABAAARMKEQFt/wD/AEoAAfMCEQHqwQALEQHs/wD/AEgAAfMFEQFt + AfS+AAESChEB6/8A/wBIAAFDAUQBQwURAW2+AAHqARIIEQEVAZL/AP8ARwABEQFFAUQGEQFtAfS9AAH0 + AeoBEgQRAUMBRAHs/wCDAAT0wAALEQFtqgAB9BMAAfQB6gESAxEBRAH3/wCCAAHyAxEB6gH0vwAB6gsR + AeymAAP0AW0B9BQAAfQDbQGS/wCCAAHyBREB6gL0vgAB6goRAeykAAL0AesC6gHzAREB9P8AmgABEQJE + BREBbQL0vQACbQYRAkQB7KIAAvQB6wHqAQAC9AEVARQBEP8AmgABEQJEBxEBbQH0vQAB9AFtBRECRAH3 + nwAD9AHrAW0B8wL0ARQB6gFzAZkBFAHz1AAD8wH0wAABbQoRAW0B9KcAAfQD8xIAAfQB6wFtAxEBRAH3 + ngAB9AHzAewCbQHyAfQCFAHrARwDmQFzAQ/TAAHyAxEB6gHzAfS+AAH0CxEB7KUAAfQB8wPrAQ8UAAH0 + A+sB950AAfQB8wHsAesBAAH0AfMBEgETAXMBmAKZApgBmQGYAUPSAAH0AREBQwQRAeoB8wH0vQAB6wFt + CREB7KMAAvMB7AHrA/MBQwHzsgAB9ALzAe0B6wHxAvMC6gFzBJkBHAHsAXMBHAGZAW0B89EAAfEBRAFF + BhEBbQHzAfS9AAFtBhECRAHsoAAD8wHsAesB8gHzAhQBbQFyARCxAAH0Ae0C6wHxAfMB6gEUARUBcwaZ + ARIBbQHrARMBmAEcARDRAAHrAUMBRAgRAW0B9KgAAvMTAAHsAesEEQJEAe+eAALzAewC6wHyAfMCEwFz + AZgCmQEUsAAB9AHtAvQB8wFtAeoB7QEHARMBHAWZARwBFAIaARQBHAEIAe0B89AAAfQLEQHspgAC8wHs + AQ8B8hMAAfQB7AHrAhEBFQHvnQAC8wHtAesB8QLzARIB6gFzBZkBcgHzrwAB7wHwAfMC7QGTARoCvQET + AZkGCAETAhwB7AEIAQAB8wHr0QAB7AoRAW0B86IAAfMC8gLsAfIBEQEPFQAB9ALsAe+bAAHzAvIB7QHs + AfEB8wESARQBbQEcA5kBHAJzAZkBmAERsAAB6wEPAfMBAAHzARsB8gEbARMB9AYAAe8C7AEAAfMB8gHs + 0wAB7AoRAeygAAHzAfIB7QLsAfIB8wEUARMBFQHysQAB8wHyAe0C7AHxAfMBEgEUAXIBHASZAZgBbQIS + AXMBmQFKAfKvAAHvAewB8AXyARQB8AXyAwAC8gLs1QAC7AURAkQBEwHvngAB8wHyAe0B7AEAAvMBEwHq + AXMBmQFzAQ+wAAHzAfcB7AHwAfIB8wRtAZgFmQFzARIBBwEcARQBmQEcARCxAAHvDOwB8QLyAuzCAAPy + FAAC7AQRAUQBB5wAAfMC8gHtAewB8QHyAfMBEgFtAXMDmQGYARWwAAHrAbwB8gESARQB7AGTARoBkwES + ARwECAGZAXMB6gKTARQCCAEQvgAB7QLswQAC8gEAAe0B7AEPAfEUAAH0AuwBEQEUAe+bAAHzAfIBkgLs + AfAB8gESARMB6wEcApkBmAEcApkB6wHxrwAB7wEVAesB7QG8AxsB8AETAZkEAAIIARIBbQL3AQAB8gEP + /wCBAAHyAfEB7QHsAQAC8gEUARAWAAH0Ae0B75oAAfMB8QH3AewB9AHyAfEC6gFzAZgDmQGYAXMB6wFz + AZgBHAERsAAB7wG8BQAB8gEUAbwE8QIAAQgB9wEAAfIB8QHtAez/AH8AAfIB8QLtAfAB8QHyARIBbQFz + ARSxAAHzAfEB9wHtAfAB8QHyAesBFQFzBpkB6wHqAe0BEgFzAZkB6gHxsAAB7wG8BPEBFAHsBe0E8QEA + Au3/AH4AAfIB8QEAAfcB7QHwAfECEwHrARwCmQFzAfGwAALrAbwB8QFtARIB7AEHAesBcwaZARIBkgG9 + AewBbQGZAQcBD7EAAe8F7QYAAfcD7f8AfwAB8gHxAfcB7QEAAfIB8QESAeoBcwGYBJkBmAFDsAAB6wEH + AvcBBwEaAr0B7AFtBggBcwHrAe0BEwHvAQgBAAEP/wD/AD8AAfIB8AH3Ae0BvAHxAfIB6gFtAXMDmQGY + AnMBHAGZAW0B8K8AAQcBFQHzAgAB8wEbAfMBbQFDAfQFAAHwAe8BkgHtA/AB7f8A/wA8AAHyAfABAAEH + AZIBvAHwAeoBEQFtARwFmQHrAm0BSgGYARwBEbAAAQcBvAXwARQBDwG8AgAB8QLwAgAB8QHwA5L/AP8A + PQAB6wHsAfQB8gHxAm0B7QEUARwGmQEVAZMBGgETAXMBmQETAfCwAAEHCJICAAHvApIC8AH3AZL/AP8A + QAAB6wHvAfAC6wGTARoBvQESAXMBvAQbAZkBFAEcAZMBFAG8ARsBBwEPvgAB7wH3/wD/AEIAAesB7AH3 + AbwBGwPzARIBBwUAAfEBBwFtAe8B9wEAAfABvAH3/wD/AP8AAwABBwK8BQABEgEHBbwCAAG8AQAB8AG8 + Avf/AP8A/wAFAAG8AfcFvAHvBvcEvAL3/wD/AP8ACQABBwTvBwAE7/8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wDYAAHxAfABGwHyAfP/AP8A/wAUAAIZAbQBrgJ1AZMB8/8A/wD/ABIAAQkD2wG0AnoBdQGT + AfL/AP8A/wAQAAEJBLQB7AF6AXUDkwHz/wD/AP8ADwABtAHbAdUBtAHPAY0DkwF0AXoBGv8A/wD/AA8A + A9sBtAGuA40BdQF6AXQBkwHy/wD/AP8ADgAB2wHVAbQB7QKTAY0B7QKTAo4Btv8A/wD/AA4AAbUB9wEc + ApMB7QKTAo0CiAG2/wD/AP8ADgABkwF1AXoBdQHtAZMBdQGOAoIBiAGxAfP/AP8A/wAOAAEbAnoBkwHt + AXoBkwGNAY8BiAGCAbb/AP8A/wAQAAF0AXUB7QGTAXoBkwGCAY8BiAGwAfP/AP8A/wAQAAHxAZMBjQJ6 + AZMBiAGPAY4B8/8A/wD/ABIAAfIB8AOTAa8B8gHz/wD/AP8AFQAE8/8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wB9AAFNAfQsAAEbASwBdZUAAU0B9CwAARsBLAF1lQABTQH0 + LAABGwEsAXWVAAFNAfQsAAEbASwBdZIAAXUGLAH2JwABGwUsAZSQAAF1BiwB9icAARsFLAGUkAABdQYs + AfYnAAEbBSwBlJAAAXUGLAH2JwABGwUsAZSPAAF1CCwB9iQAAfMJLAGUjQABdQgsAfYkAAHzCSwBlI0A + AXUILAH2JAAB8wksAZSNAAF1CCwB9iQAAfMJLAGUjAABdQosJAABGwksAZSMAAF1CiwkAAEbCSwBlIwA + AXUKLCQAARsJLAGUjAABdQosJAABGwksAZSMAAF1CiwjAAH0CywBmosAAXUKLCMAAfQLLAGaiwABdQos + IwAB9AssAZqLAAF1CiwjAAH0CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0 + CywBmooAAXULLCMAAfQLLAGaigABdQssIwAB9AssAZqKAAF1CywjAAH0CywBmooAAXULLCMAAfQLLAGa + igABdQssIwAB9AssAZqKAAGUAU0KLCMAAfQLLAGaigABlAFNCiwjAAH0CywBmooAAZQBTQosIwAB9Ass + AZqKAAGUAU0KLCMAAfQLLAGaiwABdQosIwAB9AFNCSwBTQEaiwABdQosIwAB9AFNCSwBTQEaiwABdQos + IwAB9AFNCSwBTQEaiwABdQosIwAB9AFNCSwBTQEaiwABlAFNCCwBTSQAAfQBTQcsAU0BGowAAZQBTQgs + AU0kAAH0AU0HLAFNARqMAAGUAU0ILAFNJAAB9AFNBywBTQEajAABlAFNCCwBTSQAAfQBTQcsAU0BGo0A + AZQBTQYsAU0mAAH0AU0FLAFNAZqOAAGUAU0GLAFNJgAB9AFNBSwBTQGajgABlAFNBiwBTSYAAfQBTQUs + AU0Bmo4AAZQBTQYsAU0mAAH0AU0FLAFNAZqPAAGUBnUoAAH0BXUBmpAAAZQGdSgAAfQFdQGakAABlAZ1 + KAAB9AV1AZqQAAGUBnUoAAH0BXUBmv8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP0AAfY39I4AAfY39I4A + AfY39I4AAfY39IwAAfYB9AFNNywBdYsAAfYB9AFNNywBdYsAAfYB9AFNNywBdYsAAfYB9AFNNywBdYkA + AfYB8wFNOiwBdYgAAfYB8wFNOiwBdYgAAfYB8wFNOiwBdYgAAfYB8wFNOiwBdYcAAfQBdT0sAZqGAAH0 + AXU9LAGahgAB9AF1PSwBmoYAAfQBdT0sAZqFAAH0AXU9LAFNARqFAAH0AXU9LAFNARqFAAH0AXU9LAFN + ARqFAAH0AXU9LAFNARqEAAH0AXU9LAFNARqFAAH0AXU9LAFNARqFAAH0AXU9LAFNARqFAAH0AXU9LAFN + ARqFAAF1Biw4dQEahgABdQYsOHUBGoYAAXUGLDh1ARqGAAF1Biw4dQEahQAB9AF1BSwBdb4AAfQBdQUs + AXW+AAH0AXUFLAF1vgAB9AF1BSwBdb4AAXUFLAF1vwABdQUsAXW/AAF1BSwBdb8AAXUFLAF1vgAB9AF1 + BSwB9L4AAfQBdQUsAfS+AAH0AXUFLAH0vgAB9AF1BSwB9L4AAXUFLAF1vwABdQUsAXW/AAF1BSwBdb8A + AXUFLAF1vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUs + AfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsAfS/AAF1BSwB9L8AAXUFLAH0vwABdQUsIxoBG5wAAXUFLCMa + ARucAAF1BSwjGgEbnAABdQUsIxoBG5sAAfMBdSgsAU0NGgHzjQAB8wF1KCwBTQ0aAfONAAHzAXUoLAFN + DRoB840AAfMBdSgsAU0NGgHzjQABdTcsAXUCGgHzigABdTcsAXUCGgHzigABdTcsAXUCGgHzigABdTcs + AXUCGgHzigABdTosAXUBGgHziAABdTosAXUBGgHziAABdTosAXUBGgHziAABdTosAXUBGgHziAABdTws + AXUBGgHzhgABdTwsAXUBGgHzhgABdTwsAXUBGgHzhgABdTwsAXUBGgHzhgABdT4sAXUB84UAAXU+LAF1 + AfOFAAF1PiwBdQHzhQABdT4sAXUB84UAAXU/LAF1AfOEAAF1PywBdQHzhAABdT8sAXUB84QAAXU/LAF1 + AfOEAAF1QCwBmoQAAXVALAGahAABdUAsAZqEAAF1QCwBmoQAAXVALAF1AfODAAF1QCwBdQHzgwABdUAs + AXUB84MAAXVALAF1AfOCAAEbAU1BLAGaggABGwFNQSwBmoIAARsBTUEsAZqCAAEbAU1BLAGaggABdUIs + AXUB84EAAXVCLAF1AfOBAAF1QiwBdQHzgQABdUIsAXUB84EAAXVDLAGagQABdUMsAZqBAAF1QywBmoEA + AXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMsAZqBAAF1QywBmoEAAXVDLAGagQABdUMs + AZqBAAF1QywBmoEAAXVDLAF1ARuAAAF1QywBdQEbgAABdUMsAXUBG4AAAXVDLAF1ARuAAAF1RCwBmoAA + AXVELAGagAABdUQsAZqAAAF1RCwBmn8AARoBTUQsAZp/AAEaAU1ELAGafwABGgFNRCwBmn8AARoBTUQs + AZp/AAGURSwBmn8AAZRFLAGafwABlEUsAZp/AAGURSwBmn8AAZRFLAF1ARt+AAGURSwBdQEbfgABlEUs + AXUBG34AAZRFLAF1ARt+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYs + AZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBmn4AAZRGLAGafgABlEYsAZp+AAGURiwBdQEb + fQABlEYsAXUBG30AAZRGLAF1ARt9AAGURiwBdQEbfQABlEcsAZp9AAGURywBmn0AAZRHLAGafQABlEcs + AZp8AAEaAU1HLAGafAABGgFNRywBmnwAARoBTUcsAZp8AAEaAU1HLAGafAABlEgsAZp8AAGUSCwBmnwA + AZRILAGafAABlEgsAZp8AAGUSCwBTQEaewABlEgsAU0BGnsAAZRILAFNARp7AAGUSCwBTQEaewABlEks + AZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAZp7AAGUSSwBmnsA + AZRJLAGaewABlEksAZp7AAGUSSwBmnsAAZRJLAGaewABlEksAU0BGnoAAZRJLAFNARp6AAGUSSwBTQEa + egABlEksAU0BGnoAAZRKLAGaegABlEosAZp6AAGUSiwBmnoAAZRKLAGaeQABGgFNSiwBmnkAARoBTUos + AZp5AAEaAU1KLAGaeQABGgFNSiwBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEss + AZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkA + AZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmnkAAZRLLAGaeQABlEss + AZp5AAGUSywBmnkAAZRLLAGaeQABlEssAZp5AAGUSywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABGgFN + SywBmngAARoBTUssAZp4AAGUSywBlAH2eAABlEssAZQB9ngAAZRLLAGUAfZ4AAGUSywBlAH2dwABGgFN + SywBmngAARoBTUssAZp4AAEaAU1LLAGaeAABGgFNSywBmngAAZRLLAGUAfZ4AAGUSywBlAH2eAABlEss + AZQB9ngAAZRLLAGUAfZ2AAEaAXUBTUosAZR4AAEaAXUBTUosAZR4AAEaAXUBTUosAZR4AAEaAXUBTUos + AZRuAAEaCXUBTUksAZRxAAEaCXUBTUksAZRxAAEaCXUBTUksAZRxAAEaCXUBTTQsA0wETQ4sAZRwAAEa + AU0PLAEatAABGgFNDywBGrQAARoBTQ8sARq0AAEaAU0PLAEatAABGhAsARu0AAEaECwBG7QAARoQLAEb + tAABGhAsARu0AAEaDywBGrUAARoPLAEatQABGg8sARq1AAEaDywBGgsAAZQTFpYAARoNLAEatwABGg0s + ARq3AAEaDSwBGrcAARoNLAEaDQABFhNNmAABmggsARq8AAGaCCwBGrwAAZoILAEavAABmggsARoQAAEW + E02ZAAj2vgAI9r4ACPa+AAj2EQABFhNN/wD/AGUAAfQBzwGNAe0B75wAARYTTf8A/wBAAAGUE+MQAAG0 + AtsBjQF1AZQBkwEHmgABFhNN/wD/AEAAARYTTQ8AAbQD2wGuA3oBkwEHmQABFhNN/wD/AEAAARYTTQ4A + As8BtALbAewCegGTAY0BkwEHmAABFhNN/wD/AEAAARYTTQ4AAdUC2wG0Ac8BjQF1AZMBjQF1AXoBGpgA + ARYTTf8A/wBAAAEWE00OAATbAa4DjQN6AZMBB5cAARYTTf8AeAABlBQXsgABFhNNDQABtALbAdUBzwKT + Aa4BjQF1AZMBjQGuAbWXAAEWE03/AHgAARYUTRIAAfQCrgG1nAABFhNNDQABrgHPAa4BjQF0AZMBjQF0 + AZMBrgGCAY8BiAG2lwABFhNN/wB4AAEWFE0QAAH0AbQB1QG0AZMBegGTAe+aAAEWE00OAAN6AXUBjQGT + AXUBjgKCAY8BiAG2lwABFhNN/wB4AAEWFE0PAAHPAbQC2wG0AZMCegF1Ae0BtZgAARYTTQ0AAfYBkwJ6 + AZMBjQF6AZMBjQGPAogBt5gAARYTTf8AeAABFhRNDwABzwG0AtsBtAGTAXoBdQHtAY0BB5gAARYTTQ4A + AY0BegF1AY0BdAF6AZMBiAGPAYgBggG2mAABFhNNsQABFhRNsQABFhRNDgABzwLbAbQCzwF1AXQBjQGT + AXoBkwHvlwABFhNNDgAB9AGNAXQBjQF6AXUBkwGIAY8BiAG2mQABFhNNsQABFhRNsQABFhRNDgABtAPb + AbQBrgKNAZMCegF1AQeXAAEWE00PAAH0Aa4BjQJ6AZMCiAG2lwABFgFNAfYBFhNNAQABTQEXrgABFhRN + sQABFhRNDgAD2wG0AY0BkwKNAnUBkwGNAe+XAAEWE00RAAH0Aa4CjQG1mAABlBpNARetAAEWFE0TAAH0 + AYwBtZsAARYUTQ4AAc8BtAHPAe0BdQGTAe0BkwGuAY0BiAGPAbeXAAEWE02tAAGUHE0BF6wAARYUTRAA + AfQBzwK0AY0BdQGTAY0BtZgAARYUTQ4AAZMBdAJ6AZMBjQF6AZMBjQGCAo8BtpcAARYTTawAAZQeTQHj + qwABFhRNDwAB9AHPA9sB7AN6AZMBtZcAARYUTQ4AAY0CegF1AY0BkwF1AY4CiAGCAYgBtpcAARYTTawA + AZQBFxxNARcB46sAARYUTQ8AAa4BtAPbAewCegF0AY0BrgG1lgABFhRNDgABrgF0AXoBkwHsAXoBdAGN + Ao8BiAGCAbWUAAEWAU0B9AEWE00BAAEXqwABlAEXGk0BFwHjrAABFhRNDgAB9AO0Ac8BtAGNAXoBkwGN + AZMBdQEHlgABFhRNDwABjQF0ApMBegF0AY0CjwGIAbWUAAEWGU0BF6sAAZQBFwpNBOMBFwlNARcB460A + ARYUTQ4AAc8E2wGuAY0BkwGNAXUCegGTAbWVAAEWFE0PAAH0Ao0BdAF6AZMBjQGPAYgBtpQAAZQbTQEX + qwABlAEXCE0B4wQAARYBFwhNAeOuAAEWFE0OAAHPA9sBtAGNAZMBrgGTAXoBdQGTAY0BtZUAARYUTREA + AfQBjQL3Ao0BtZQAAZQdTQEXqwABlAEXBk0B4wYAARYBFwZNAeOvAAEWFE0OAAHPArQBrgGTAXQB7AGT + A40CiAG2lQABFhRNrAABlB1NARcBFqsAAZQG4wH2BwABFgbjsAABFhRNDgABrgKTAXoBdQKTAXUBkwGM + AYgBjwGIAbaTAAEWAfMBFhRNAfYBF6oAAZQBFxtNARcBFv8AcwABFhRNDgABjQF1AnoBkwGNAXoBkwGN + AYgBggGIAY4BB5IAARYZTQEXAfapAAGUARcLTQTjARcJTQEXARb/AHQAARYUTQ8AAZMBegF1Ae0BkwF6 + AZMBiAGPAYgBggG2kgABlBtNARcB9qkAAZQBFwhNAeMBFgQAARYBFwdNARcBFv8AdQABFhRNDwABjQKT + AY0BegF1AY4BiAGPAYgBjQEHkQABlB1NAReqAAGUARcHTQcAARYBFwZNARb/AHYAARYUTRAAA40CdQGO + AogBjgG2kgABlB1NARcBFqoAAZQBFgEXBE0BFggAARcFTQEW/wB0AAH2ARYBGwEWFE0BAAEXDwABrwH3 + AZMBmQGTAq8BB5MAAZoBFxtNARcBFq0AAZQEFgH2CAAGFv8AdQABFhlNAReqAAGaARcLTQMWARcKTQEX + ARb/AP8ANwABFhtNAReqAAGaARcITQIWAwABlAEWARcHTQEXARb/AP8ANwABFh1NAReqAAGaARcHTQcA + AZQBFwZNARb/AP8ANwABvQEXHU0BFwGUqgABmgEXBU0BFggAARcFTQEW/wD/ADkAAb0B4xtNARcBlKwA + AZoFlAkABpT/AP8AOwABvQEXC00BFgKUARcKTQEXAZT/AP8A/gABvQEXCE0BFgGUAwAClAEXB00BFwGU + /wD/AP8AAQABvQHjB00HAAHjB00BlP8A/wD/AAMAAb0BFwVNARYHAAGUARcFTQGU/wD/AGAABfOfAAG9 + BZQJAAaU/wD/AGAAAfEEEQHqAfIB8/8A/wD/ABIAAfQBEQFDBREB6gHyAfP/AP8A/wAQAAH0AUMBRQFD + BhEBbQHz/wD/AEwAAfIB88AAAfQBEQFDCBEBbQHz/wD/AEkAAfIB8AERARIB8gHzvgAB9AsRAW0B8/8A + /wBHAAHwBREBEgHyAfO9AAHsCxEB7P8A/wBGAAH0ARECRAURAeoB870AAe0B7AcRAkMB7P8A/wBGAAH0 + ARECRAYRAeoB8QHzqAAB8RQAAe0B7AURAkQBB/8AgwAC8QHyvwAB9AsRAW0B86QAAvEBAAGSAfAVAAGS + AewDEQFEAez/AIIAAfEBvAIRARIB8r8AAewLEQHsogAB8QHwAfcB7QEAAfEBQxYAAfQEkgEH/wCBAAH0 + AREBQwMRARIB8AHyvgAB7QoRAeygAAHxAQAB7wGSAvAB8gESAW0B8P8AnAABvAJEBREB6gHwAfK9AAH3 + Ae0GEQJEAeydAAHxAfABAAHvAQAB8QHwARMB6gFzAZgBmQEV/wCbAAH0AREBQwFEBxEB6gHypgAD8BUA + AfcB7QQRAkQB7JsAAfEB8AL3AQAB8QHwAeoBbQFzBJkB6wHw1wAC8AHxwAABkgoRAeoB8qMAAfABAAHv + AvcBvBYAAe0EEQETAbyZAAHxAQABBwH3AbwB8AHxAW0B6wEcA5kCHAGZARwBQ9UAAfABBwIRARMB8AHx + vgAB9AsRAeyhAAHwAQAB7wEAAvAB8QEUFwAE7wG8lwAB8QG8AQABBwEAAfEB8AESAeoBcwEcBJkBcwLr + AXMBmQFtAbzTAAH0AUMBRAQRARIBvAHxvQAB7wGSCREB6gHynQAB8AG8AQAB7wEAAvABEgFtAnMBvLEA + AfEB7wH3AfQB8QHwAesB6gESARwFmQEcARMBHAHsARMBmQEcARDTAAH0AUMBRQFDBREBEgG8AfG9AAGS + BhEBQwFEARIBvJsAAfABAAEHAe8BAALwAW0B6wFzApkBmAEVsAAB8QHvAQcBvAHwAuwCkwESARwFmQFz + ARMBGgEHARUBmAEbAe/TAAH0AREBRAgRAeoB8aQAAbwYAAHvAZIFEQFEAeyaAAHwAQABBwEAAfABvAHw + AesBcwEcBZkB6wG8rwABvAEHAu8BvAHxAhoB8gESAQgF8QHwAeoB7AFtAe8BGwEAAbzTAAH0CxEB6gHx + owABBwIAArwWAAHvAZIDEQESAbyXAAHxAbwBAAG8AQAB8AG8Am0BcwGYA5kBcwHrAXMCHAERsAAB6wHv + AwAB9AHzAQABEgH0BgABvAEHAe8BAAK8Ae/UAAH3CxEB7KMAArwB8QHrARQYAAPvAfCWAAHxAQABvAHv + AQAC8AESAeoBcwWZAXMB6gFuAeoBcwGZAeqwAAG8Ae8GBwEVAfQDAAG8AQcDAAG8AQAC79YAAfcIEQFD + AREB7JwAAfAEAAK8AW0BcwEcAZkBcwEHsAAB8QHvAfQB8AG8AfAB7AHtAusBmAWZAW0B7AEaAe0BSgGZ + AbwBB7EAAbwG7wQAAQcB7wIHAQABB9oAAQcB9wYRAkQB7JwAAbwCAALwAewBcwGYA5kBmAEVsAAB6wH3 + AQcB7wHsAZMBGgG9ARwBbQG8BRsBcwFtARwB6wEHARsBAAEQvgABBwHv3gABBwH3BBEBRAHqAfCcAAK8 + AfACcwOZARwBcwGYAZkBbbAAAfABFAH3AQAB9APzAfEBvAYAAfEBBwG8AQcCAAIH/wCHAAG8AfAYAAEH + AfcBEQESAQcB8JYAAfAEAAG8AQcB6wFzARwEmQFzAW0B6wFtAZgBHAEHsAAB8AEHBQABvAYHBQABBwEA + AQf/AIUAArwB8QFzARwBvBkAAQcB8JYAAfAB9AHwAgAC8AHtARQBcwaZARIB7QGTARIBcwGZARKxAAHw + AQABvAIHAQABvAYHAQADBwEAAQf/AIUAAbwB8AJzA5kB67EAAfAB9gK8AfABHAGTARoBbQFzAZkB8QMb + AZkBFAGTARoB6gG8ARsBvAEHsgAB8AIHCQABvAIH/wCFAAG8AfABcwEcBZkBHAEHsAABvAH0AfABvAHx + AfMC9ALwARsEAAHzAbwB6wHxAbwDAAEH/wD/AEQAArwB8QIcA5kBcwJtAXMBmQFtsAAB8QHvAfQOAAHw + /wD/AEgAAfABvAHqAXMBmASZAZgBEgLsARIBmAEcsQAB8QEAAbwDAAG8Ae8JAAHv/wD/AEUAAvAB7wGT + ARMBHAGZAxsBmQEcARQCGgEVARwBG7MAAfEDAAHwAbwHAAHvAQABvP8A/wBFAAHyAfMC9AHwAfIBGwMA + AfMB8gHwAuwBvAHywQABvP8A/wBUAALw/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wAvAAFCAU0BPgcA + AT4DAAEoAwABGAEDAgABpAEEAgABAQEAAQEFAAEQAdABARUAA///AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A + /wD/AP8A/wD/AP8ApgBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQAK/wHnBf8BjxL/AZ8E/wH+AT8R/wH+ + AX8E/wH4Ev8B+QX/AeMI/wEACv8BAAT/Af4BAxH/AfwBAwT/AfgBDxH/AfABDwT/AeABPxH/AcABPwT/ + AYAI/wEACf8B/gEAAX8D/wH4AQAR/wH4AQEE/wHgAQMR/wHgAQcE/wGAAQ8R/wGAAR8D/wH+AQABPwf/ + AQAJ/wH8AQABfwP/AfgBABH/AfABAQT/AeABAxH/AcABBwT/AYABDxH/AQABHwP/Af4BAAE/B/8BAAn/ + AfwBAAF/A/8B8AEAAX8Q/wHwAQEE/wHAAQER/wHAAQcE/wEAAQcR/wEAAR8D/wH8AQABHwf/AQAJ/wH4 + AQABfwP/AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/AQAJ/wH4 + AQABfwP/AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/AQAJ/wH4 + AQABfwP/AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/AQAJ/wH8 + AQABfwP/AfABAAF/EP8B8AEBBP8BwAEBEf8BwAEHBP8BAAEHEf8BAAEfA/8B/AEAAR8H/wEACf8B/AEA + AX8D/wH4AQAR/wHwAQEE/wHgAQMR/wHAAQcE/wGAAQ8R/wEAAR8D/wH+AQABPwf/AQAJ/wH+AQAE/wH8 + AQER/wH4AQME/wHwAQcR/wHgAQ8E/wHAAR8R/wGAAT8E/wEAAX8H/wEACv8BAQT/Af4BAxH/AfwBBwT/ + AfgBDxH/AfABHwT/AeABPxH/AcABfwT/AYAI/wEAY/8BAGP/AQBj/wEAY/8BAAr/AYAGAAF/EP8B/gYA + AQER/wH4BgABBxH/AeAGAAEfB/8BAAn/Af4HAAE/EP8B+AcAEf8B4AYAAQMR/wGABgABDwf/AQAJ/wH4 + BwABHxD/AeAHAAF/EP8BgAYAAQEQ/wH+BwABBwf/AQAJ/wHwBwABDxD/AcAHAAE/EP8IABD/AfwHAAED + B/8BAAn/AeAHAAEPEP8BgAcAAT8P/wH+CAAQ/wH4BwABAwf/AQAJ/wHABwABHxD/CAABfw//AfwHAAEB + EP8B8AcAAQcH/wEACf8BwAcAAT8Q/wgAEP8B/AcAAQMQ/wHwBwABDwf/AQAJ/wGAAX8W/wH+AQEX/wH4 + AQcX/wHgAR8O/wEACf8BgBf/Af4BAxf/AfgBDxf/AeABPw7/AQAJ/wEAF/8B/AEDF/8B8AEPF/8BwAE/ + Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8BARf/AfwBBxf/AfABHxf/AcABfw7/AQAJ/wEB + F/8B/AEHF/8B8AEfF/8BwAF/Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8FAAE/Ev8B/AUA + E/8B8AQAAQMT/wHABAABDwr/AQAI/wH+BwAR/wH4BgABAxH/AeAGAAEPEf8BgAYAAT8I/wEACP8B/gcA + AR8Q/wH4BwABfxD/AeAGAAEBEf8BgAYAAQcI/wEACP8B/gcAAQcQ/wH4BwABHxD/AeAHAAF/EP8BgAYA + AQEI/wEACP8B/gcAAQEQ/wH4BwABBxD/AeAHAAEfEP8BgAcAAX8H/wEACP8B/ggAEP8B+AcAAQMQ/wHg + BwABDxD/AYAHAAE/B/8BAAj/Af4IAAF/D/8B+AcAAQEQ/wHgBwABBxD/AYAHAAEfB/8BAAj/Af4IAAF/ + D/8B+AcAAQEQ/wHgBwABBxD/AYAHAAEfB/8BAAj/Af4IAAE/D/8B+AgAEP8B4AcAAQMQ/wGABwABDwf/ + AQAI/wH8CAABPw//AfAIABD/AcAHAAEDEP8IAAEPB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHABwABARD/ + CAABBwf/AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgAAQcH/wEACP8B/AgAAR8P/wHwCAABfw// + AcAHAAEBEP8IAAEHB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHABwABARD/CAABBwf/AQAI/wH8CAABDw// + AfAIAAE/D/8BwAgAEP8IAAEDB/8BAAj/AfwIAAEPD/8B8AgAAT8P/wHACAAQ/wgAAQMH/wEACP8B+AgA + AQ8P/wHgCAABPw//AYAIAA//Af4IAAEDB/8BAAj/AfgIAAEPD/8B4AgAAT8P/wGACAAP/wH+CAABAwf/ + AQAI/wH4CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABBw//AeAIAAEfD/8BgAgA + AX8O/wH+CAABAQf/AQAI/wH4CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABBw// + AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABAw//AeAIAAEPD/8BgAgAAT8O/wH+CQAH/wEA + CP8B+AgAAQMP/wHgCAABDw//AYAIAAE/Dv8B/gkAB/8BAAj/AfAIAAEDD/8BwAgAAQ8P/wkAAT8O/wH8 + CQAH/wEACP8B8AgAAQMP/wHACAABDw//CQABPw7/AfwJAAf/AQAI/wHwCAABAQ//AcAIAAEHD/8JAAEf + Dv8B/AkAAX8G/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/AfwJAAF/Bv8BAAj/AfAIAAEBD/8BwAgA + AQcP/wkAAR8O/wH8CQABfwb/AQAI/wHwCAABAQ//AcAIAAEHD/8JAAEfDv8B/AkAAX8G/wEACP8B8AkA + D/8BwAgAAQMP/wkAAQ8O/wH8CQABPwb/AQAI/wHwCQAP/wHACAABAw//CQABDw7/AfwJAAE/Bv8BAAj/ + AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkA + AT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkA + AQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8B4AkAD/8BgAgA + AQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHA + CQAP/wkAAQMO/wH8CQABDw7/AfAJAAE/Bv8BAAj/AcAJAA//CQABAw7/AfwJAAEPDv8B8AkAAT8G/wEA + CP8BgAgAAQEO/wH+CQABBw7/AfgJAAEfDv8B4AkAAX8G/wEACP8BgAgAAQEO/wH+CQABBw7/AfgJAAEf + Dv8B4AkAAX8G/wEAB/8B/gkAAQcO/wH4CQABHw7/AeAJAAF/Dv8BgAgAAQEH/wEABv8B+AoAAT8N/wHg + CgAO/wGACQABAw3/Af4KAAEPB/8BAAb/AfABAAEDFv8BwAEAAQ8W/wIAAT8V/wH8AgAQ/wEABv8B8AEA + AQMW/wHAAQABDxb/AgABPxX/AfwCABD/AQAG/wHwAQABBxb/AcABAAEfFv8CAAF/Ff8B/AEAAQEQ/wEA + Bv8B8AEAAR8W/wHAAQABfxb/AQABARb/AfwBAAEHEP8BAAb/AfwBABf/AfABAxf/AcABDxf/AQABPxD/ + AQAG/wH+AQEX/wH4AQcX/wHgAR8X/wGAAX8Q/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/ + AQBj/wEAY/8BAGP/AQBU/wGAAQABAwz/AQBU/wGAAQABAwz/AQBU/wGAAQABAwz/AQBU/wGAAQABAwL/ + AY8J/wEAVP8BgAEAAQMB/wH8AQEJ/wEAO/8B4AEAAQEW/wGAAQABAwH/AfgBAAn/AQA7/wHgAQABARb/ + AYABAAEDAf8B+AEAAX8I/wEAO/8B4AEAAQEC/wGAE/8BgAEAAQMB/wHwAQABfwj/AQA7/wHgAQABAQL/ + AQABfxL/AYABAAEDAf8B8AEAAT8I/wEAO/8B4AEAAQEB/wH+AQABPxL/AYABAAEDAf8B8AEAAT8I/wEA + Iv8B+AIAAX8V/wHgAQABAQH/AfwBAAEfEv8BgAEAAQMB/wHwAQABPwj/AQAi/wH4AgABfwH/AcABHxL/ + AeABAAEBAf8B/AEAAQ8S/wGAAQABAwH/AfABAAE/CP8BACL/AfgCAAF/Af8BgAEPEv8B4AEAAQEB/wH8 + AQABDxL/AYABAAEDAf8B8AEAAT8I/wEAIv8B+AIAAX8B/wGAAQcS/wHgAQABAQH/AfwBAAEPEv8BgAEA + AQMB/wH4AQABfwj/AQAO/wH8AR8S/wH4AgABfwH/AQABBxL/AeABAAEBAf8B/AEAAQ8S/wGAAQABAwH/ + AfgBAAF/CP8BAA7/AfABBxL/AfgCAAF/Af8BAAEDEv8B4AEAAQEB/wH8AQABDxL/AYABAAEDAf8B/AEA + Cf8BAAn/AfwCAAEfAf8B4AEDEv8B+AIAAX8B/wEAAQMS/wHgAQABAQH/AfwBAAEPEf8B/AIAAQIB/wH+ + AQEJ/wEACf8B/AIAAR8B/wHgAQES/wH4AgABfwH/AQABAxL/AeABAAEBAf8B/gEAAR8R/wH8AwABfwv/ + AQAJ/wH8AgABHwH/AcABABL/AfgCAAF/Af8BAAEDEv8B4AEAAQEC/wEAAT8R/wH4AwABPwv/AQAJ/wH8 + AgABHwH/AcABABL/AfgCAAF/Af8BAAEDEv8B4AEAAQEC/wGAAX8R/wHwAwABHwv/AQAJ/wH8AgABHwH/ + AcABABL/AfgCAAF/Af8BgAEHEv8B4AEAAQEC/wGAEv8B4AMAAQ8L/wEACf8B/AIAAR8B/wHAAQAS/wH4 + AgABfwH/AYABBxL/AYACAAE/FP8B8AMAAR8L/wEACf8B/AIAAR8B/wHAAQAS/wH4AgABfwH/AcABDxL/ + AwABHxT/AfgDAAE/C/8BAAn/AfwCAAEfAf8BwAEAEv8B+AIAAX8B/wHgAR8R/wH+AwABDxT/AfwBAAE4 + AQABfwv/AQAJ/wH8AgABHwH/AcABARL/AfgCAAF/Af8B8AF/Ef8B/AMAAQcU/wH+AQAB/gEADP8BAAn/ + AfwCAAEfAf8B4AEBEv8B+AIAAX8U/wH4AwABBxX/AQAB/gEBDP8BAAn/AfwCAAEfAf8B8AEDEv8B4AIA + AR8U/wH4AwABBxX/AYEB/wEDDP8BAAn/AfwCAAEfAf8B/AEPEv8BgAIAAQ8U/wH8AwABDyT/AQAJ/wH8 + AgABHxX/AwABBxT/Af4DAAEfJP8BAAn/AfwCAAEfFP8B/gMAAQMV/wEAAT8BAAE/JP8BAAn/AfwCAAEf + FP8B/gMAAQEV/wGAAX8BgAF/JP8BAAn/AfQCAAEHFP8B/gMAAQEV/wHAAX8BgCX/AQAJ/wHgAgABAxX/ + AwABAz3/AQAJ/wHAAgABARX/AYACAAEHPf8BAAn/AYADABX/AcABDwGAAQ89/wEACf8EABX/AeABHwHA + AR89/wEACf8EABX/AfABHwHgAT89/wEACf8BgAMAVv8BAAn/AcACAAEBVv8BAAn/AeABAwHgAQNW/wEA + Cf8B8AEHAfABB1b/AQAJ/wH4AQ8B8AEPVv8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQAK/wHnBf8BjxL/AZ8E/wH+ + AT8R/wH+AX8E/wH4Ev8B+QX/AeMI/wEACv8BAAT/Af4BAxH/AfwBAwT/AfgBDxH/AfABDwT/AeABPxH/ + AcABPwT/AYAI/wEACf8B/gEAAX8D/wH4AQAR/wH4AQEE/wHgAQMR/wHgAQcE/wGAAQ8R/wGAAR8D/wH+ + AQABPwf/AQAJ/wH8AQABfwP/AfgBABH/AfABAQT/AeABAxH/AcABBwT/AYABDxH/AQABHwP/Af4BAAE/ + B/8BAAn/AfwBAAF/A/8B8AEAAX8Q/wHwAQEE/wHAAQER/wHAAQcE/wEAAQcR/wEAAR8D/wH8AQABHwf/ + AQAJ/wH4AQABfwP/AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/ + AQAJ/wH4AQABfwP/AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/ + AQAJ/wH4AQABfwP/AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/ + AQAJ/wH8AQABfwP/AfABAAF/EP8B8AEBBP8BwAEBEf8BwAEHBP8BAAEHEf8BAAEfA/8B/AEAAR8H/wEA + Cf8B/AEAAX8D/wH4AQAR/wHwAQEE/wHgAQMR/wHAAQcE/wGAAQ8R/wEAAR8D/wH+AQABPwf/AQAJ/wH+ + AQAE/wH8AQER/wH4AQME/wHwAQcR/wHgAQ8E/wHAAR8R/wGAAT8E/wEAAX8H/wEACv8BAQT/Af4BAxH/ + AfwBBwT/AfgBDxH/AfABHwT/AeABPxH/AcABfwT/AYAI/wEAY/8BAGP/AQBj/wEAY/8BAAr/AYAGAAF/ + EP8B/gYAAQER/wH4BgABBxH/AeAGAAEfB/8BAAn/Af4HAAE/EP8B+AcAEf8B4AYAAQMR/wGABgABDwf/ + AQAJ/wH4BwABHxD/AeAHAAF/EP8BgAYAAQEQ/wH+BwABBwf/AQAJ/wHwBwABDxD/AcAHAAE/EP8IABD/ + AfwHAAEDB/8BAAn/AeAHAAEPEP8BgAcAAT8P/wH+CAAQ/wH4BwABAwf/AQAJ/wHABwABHxD/CAABfw// + AfwHAAEBEP8B8AcAAQcH/wEACf8BwAcAAT8Q/wgAEP8B/AcAAQMQ/wHwBwABDwf/AQAJ/wGAAX8W/wH+ + AQEX/wH4AQcX/wHgAR8O/wEACf8BgBf/Af4BAxf/AfgBDxf/AeABPw7/AQAJ/wEAF/8B/AEDF/8B8AEP + F/8BwAE/Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8BARf/AfwBBxf/AfABHxf/AcABfw7/ + AQAJ/wEBF/8B/AEHF/8B8AEfF/8BwAF/Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8FAAE/ + Ev8B/AUAE/8B8AQAAQMT/wHABAABDwr/AQAI/wH+BwAR/wH4BgABAxH/AeAGAAEPEf8BgAYAAT8I/wEA + CP8B/gcAAR8Q/wH4BwABfxD/AeAGAAEBEf8BgAYAAQcI/wEACP8B/gcAAQcQ/wH4BwABHxD/AeAHAAF/ + EP8BgAYAAQEI/wEACP8B/gcAAQEQ/wH4BwABBxD/AeAHAAEfEP8BgAcAAX8H/wEACP8B/ggAEP8B+AcA + AQMQ/wHgBwABDxD/AYAHAAE/B/8BAAj/Af4IAAF/D/8B+AcAAQEQ/wHgBwABBxD/AYAHAAEfB/8BAAj/ + Af4IAAF/D/8B+AcAAQEQ/wHgBwABBxD/AYAHAAEfB/8BAAj/Af4IAAE/D/8B+AgAEP8B4AcAAQMQ/wGA + BwABDwf/AQAI/wH8CAABPw//AfAIABD/AcAHAAEDEP8IAAEPB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHA + BwABARD/CAABBwf/AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgAAQcH/wEACP8B/AgAAR8P/wHw + CAABfw//AcAHAAEBEP8IAAEHB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHABwABARD/CAABBwf/AQAI/wH8 + CAABDw//AfAIAAE/D/8BwAgAEP8IAAEDB/8BAAj/AfwIAAEPD/8B8AgAAT8P/wHACAAQ/wgAAQMH/wEA + CP8B+AgAAQ8P/wHgCAABPw//AYAIAA//Af4IAAEDB/8BAAj/AfgIAAEPD/8B4AgAAT8P/wGACAAP/wH+ + CAABAwf/AQAI/wH4CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABBw//AeAIAAEf + D/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4 + CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABAw//AeAIAAEPD/8BgAgAAT8O/wH+ + CQAH/wEACP8B+AgAAQMP/wHgCAABDw//AYAIAAE/Dv8B/gkAB/8BAAj/AfAIAAEDD/8BwAgAAQ8P/wkA + AT8O/wH8CQAH/wEACP8B8AgAAQMP/wHACAABDw//CQABPw7/AfwJAAf/AQAI/wHwCAABAQ//AcAIAAEH + D/8JAAEfDv8B/AkAAX8G/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/AfwJAAF/Bv8BAAj/AfAIAAEB + D/8BwAgAAQcP/wkAAR8O/wH8CQABfwb/AQAI/wHwCAABAQ//AcAIAAEHD/8JAAEfDv8B/AkAAX8G/wEA + CP8B8AkAD/8BwAgAAQMP/wkAAQ8O/wH8CQABPwb/AQAI/wHwCQAP/wHACAABAw//CQABDw7/AfwJAAE/ + Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEP + Dv8B+AkAAT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAED + Dv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8B4AkA + D/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/ + AQAI/wHACQAP/wkAAQMO/wH8CQABDw7/AfAJAAE/Bv8BAAj/AcAJAA//CQABAw7/AfwJAAEPDv8B8AkA + AT8G/wEACP8BgAgAAQEO/wH+CQABBw7/AfgJAAEfDv8B4AkAAX8G/wEACP8BgAgAAQEO/wH+CQABBw7/ + AfgJAAEfDv8B4AkAAX8G/wEAB/8B/gkAAQcO/wH4CQABHw7/AeAJAAF/Dv8BgAgAAQEH/wEABv8B+AoA + AT8N/wHgCgAO/wGACQABAw3/Af4KAAEPB/8BAAb/AfABAAEDBP8B/AEfEP8BwAEAAQ8W/wIAAT8V/wH8 + AgAD/wHjDP8BAAb/AfABAAEDBP8B/AEPEP8BwAEAAQ8W/wIAAT8V/wH8AgAD/wGDDP8BAAb/AfABAAEH + BP8B+AEDEP8BwAEAAR8W/wIAAX8C/wH5Ev8B/AEAAQEC/wH8AQEM/wEABv8B8AEAAR8E/wH4AQAQ/wHA + AQABfxb/AQABAQP/AckS/wH8AQABBwL/AfABAQz/AQAG/wH8AQAF/wH4AQABfw//AfABAxf/AcABDwP/ + AUgT/wEAAT8C/wHAAQEM/wEABv8B/gEBBf8B+QEAAT8P/wH4AQcX/wHgAR8C/wH9AUAT/wGAAX8B/wH+ + AgAM/wEADf8B/AEAAT8s/wHnAQABfxX/AfgBBwEDDP8BAA7/ASABPxT/AfgBfxb/AZwBAAF/F/8Bzwz/ + AQAO/wHIAX8U/wHCAX8V/wH+AWABAAF/JP8BAA7/AeAV/wEYAT8V/wHxAYABAAE/JP8BACP/AfwBQAE/ + Ff8B5gIAAT8k/wEADP8BPxb/AeEBAAEfFf8B8AEBAYEB3yT/AQAL/wH4Ad8W/wGMAQABHxX/AucB9wG/ + JP8BAAv/AecBHxX/Af4BIAEAAQ8V/wHzAeQB/iX/AQAL/wGYAQ8V/wH4AYABAAEPFf8B+AEHAZsl/wEA + Cv8B/AEgAQ8V/wHyAgABDxf/Ae8l/wEACv8B8QGAAQcV/wHwAQEB8AHvPf8BAAr/AcQBAAEHFf8C+QH/ + AZ89/wEACf8B/gEQAQABBxX/AfwBYAEOAX89/wEACf8B/AHAAQABAxb/AQcB8T7/AQAJ/wH8AQABMAEb + Vv8BAAn/AfwBfAF+AXNW/wEACf8B/gE8AQcBz1b/AQAK/wGAAfIBP1b/AQAL/wH9V/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAFn/AQcJ/wEAWP8B/AEBCf8BAFj/AfgBAAn/AQBA/wHh + F/8B+AEAAX8I/wEAQP8BgAF/Ev8CAAEPAf8B8AEAAT8I/wEAQP8BAAE/Ev8CAAEPAf8B8AEAAT8I/wEA + P/8B/gEAAR8S/wIAAQ8B/wHwAQABPwj/AQAn/wHwAT8W/wH+AQABDxL/AgABDwH/AfABAAE/CP8BACf/ + AeABDxL/AcABAAEDAf8B/AEAAQ8S/wIAAQ8B/wHwAQABPwj/AQAn/wHAAQcS/wGAAQABAwH/AfwBAAEP + Ev8CAAEPAf8B8AEAAT8I/wEAD/8BPxf/AYABBxL/AYABAAEDAf8B/AEAAQ8S/wIAAQ8B/wH4AQABPwj/ + AQAO/wH4AQcX/wEAAQMS/wGAAQABAwH/AfwBAAEPEv8CAAEPAf8B+AEAAX8I/wEADv8B8AEDF/8BAAED + Ev8BgAEAAQMB/wH8AQABDxL/AgABDwH/AfwBAAn/AQAO/wHgAQES/wHgAQABAQL/AQABAxL/AYABAAED + Af8B/AEAAQ8S/wIAAQ8B/wH+AQEJ/wEADv8B4AEAEv8B4AEAAQEC/wEAAQMS/wGAAQABAwH/AfwBAAEf + Ev8CAAEPAv8Bhwn/AQAO/wHAAQAS/wHgAQABAQL/AQABAxL/AYABAAEDAf8B/gEAAR8S/wIAAQ8M/wEA + Dv8BwAEAEv8B4AEAAQEC/wEAAQMS/wGAAQABAwL/AQABPxL/AgABDwz/AQAO/wHAAQAS/wHgAQABAQL/ + AYABAxL/AYABAAEDAv8BwAF/Ev8CAAEPDP8BAAn/AfgCAAF/Af8BwAEAEv8B4AEAAQEC/wGAAQcS/wGA + AQABAxb/AgABDwz/AQAJ/wH4AgABfwH/AcABABL/AeABAAEBAv8BwAEHEv8BgAEAAQMV/wH9AgABCwz/ + AQAJ/wH4AgABfwH/AcABABL/AeABAAEBAv8B4AEfEv8BgAEAAQMV/wH4AgABAQz/AQAJ/wH4AgABfwH/ + AcABABL/AeABAAEBAv8B+AE/Ev8BgAEAAQMV/wHwAwAM/wEACf8B+AIAAX8B/wHgAQES/wHgAQABARb/ + AYABAAEDFf8B4AMAAX8L/wEACf8B+AIAAX8B/wHwAQMS/wHgAQABARb/AYABAAEDFf8BwAMAAT8L/wEA + Cf8B+AIAAX8B/wH4AQcS/wHgAQABARX/Af4BgAEAAQIV/wHAAwABPwv/AQAJ/wH4AgABfwL/AT8S/wHg + AQABARX/AfwDAAF/FP8B4AMAAX8L/wEACf8B+AIAAX8V/wHgAQABARX/AfgDAAE/FP8B8AMADP8BAAn/ + AfgCAAF/Ff8B4AEAAQEV/wHwAwABHxT/AfgBAAHwAQEM/wEACf8B+AIAAX8V/wHgAQABARX/AeADAAEP + FP8B/AEBAfgBAwz/AQAJ/wH4AgABfxX/AaABAAEBFf8B4AMAAQ8U/wH+AQMB/AEHDP8BAAn/AfgCAAF/ + Ff8DAAE/FP8B8AMAAR8V/wEHAfwBDwz/AQAJ/wH4AgABfxT/Af4DAAEfFP8B+AMAAT8k/wEACf8B+AIA + AX8U/wH8AwABDxT/AfwBAAE4AQABfyT/AQAJ/wH4AgABfxT/AfgDAAEHFP8B/gEAAf4BACX/AQAJ/wH4 + AgABfxT/AfgDAAEHFf8BAAH+AQEl/wEACf8BwAIAAQ8U/wH4AwABBxX/AYEB/wEDJf8BAAn/AYACAAEH + FP8B/AMAAQ89/wEACf8DAAEDFP8B/gEAAQwBAAEfPf8BAAj/Af4DAAEBFf8BAAE/AQABPz3/AQAI/wH+ + AwABARX/AYABfwGAAX89/wEACP8B/gMAAQEV/wHAAX8BgD7/AQAJ/wMAAQNW/wEACf8BgAEDAQABB1b/ + AQAJ/wHAAQ8BwAEPVv8BAAn/AeABHwHgAR9W/wEACf8B8AEfAeABP1b/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEACv8B5wX/AY8S/wGfBP8B/gE/Ef8B/gF/ + BP8B+BL/AfkF/wHjCP8BAAr/AQAE/wH+AQMR/wH8AQME/wH4AQ8R/wHwAQ8E/wHgAT8R/wHAAT8E/wGA + CP8BAAn/Af4BAAF/A/8B+AEAEf8B+AEBBP8B4AEDEf8B4AEHBP8BgAEPEf8BgAEfA/8B/gEAAT8H/wEA + Cf8B/AEAAX8D/wH4AQAR/wHwAQEE/wHgAQMR/wHAAQcE/wGAAQ8R/wEAAR8D/wH+AQABPwf/AQAJ/wH8 + AQABfwP/AfABAAF/EP8B8AEBBP8BwAEBEf8BwAEHBP8BAAEHEf8BAAEfA/8B/AEAAR8H/wEACf8B+AEA + AX8D/wHwAQABfxD/AeABAQT/AcABARH/AYABBwT/AQABBxD/Af4BAAEfA/8B/AEAAR8H/wEACf8B+AEA + AX8D/wHwAQABfxD/AeABAQT/AcABARH/AYABBwT/AQABBxD/Af4BAAEfA/8B/AEAAR8H/wEACf8B+AEA + AX8D/wHwAQABfxD/AeABAQT/AcABARH/AYABBwT/AQABBxD/Af4BAAEfA/8B/AEAAR8H/wEACf8B/AEA + AX8D/wHwAQABfxD/AfABAQT/AcABARH/AcABBwT/AQABBxH/AQABHwP/AfwBAAEfB/8BAAn/AfwBAAF/ + A/8B+AEAEf8B8AEBBP8B4AEDEf8BwAEHBP8BgAEPEf8BAAEfA/8B/gEAAT8H/wEACf8B/gEABP8B/AEB + Ef8B+AEDBP8B8AEHEf8B4AEPBP8BwAEfEf8BgAE/BP8BAAF/B/8BAAr/AQEE/wH+AQMR/wH8AQcE/wH4 + AQ8R/wHwAR8E/wHgAT8R/wHAAX8E/wGACP8BAGP/AQBj/wEAY/8BAGP/AQAK/wGABgABfxD/Af4GAAEB + Ef8B+AYAAQcR/wHgBgABHwf/AQAJ/wH+BwABPxD/AfgHABH/AeAGAAEDEf8BgAYAAQ8H/wEACf8B+AcA + AR8Q/wHgBwABfxD/AYAGAAEBEP8B/gcAAQcH/wEACf8B8AcAAQ8Q/wHABwABPxD/CAAQ/wH8BwABAwf/ + AQAJ/wHgBwABDxD/AYAHAAE/D/8B/ggAEP8B+AcAAQMH/wEACf8BwAcAAR8Q/wgAAX8P/wH8BwABARD/ + AfAHAAEHB/8BAAn/AcAHAAE/EP8IABD/AfwHAAEDEP8B8AcAAQ8H/wEACf8BgAF/Fv8B/gEBF/8B+AEH + F/8B4AEfDv8BAAn/AYAX/wH+AQMX/wH4AQ8X/wHgAT8O/wEACf8BABf/AfwBAxf/AfABDxf/AcABPw7/ + AQAJ/wEBF/8B/AEHF/8B8AEfF/8BwAF/Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8BARf/ + AfwBBxf/AfABHxf/AcABfw7/AQAJ/wEBF/8B/AEHF/8B8AEfF/8BwAF/Dv8BAAn/BQABPxL/AfwFABP/ + AfAEAAEDE/8BwAQAAQ8K/wEACP8B/gcAEf8B+AYAAQMR/wHgBgABDxH/AYAGAAE/CP8BAAj/Af4HAAEf + EP8B+AcAAX8Q/wHgBgABARH/AYAGAAEHCP8BAAj/Af4HAAEHEP8B+AcAAR8Q/wHgBwABfxD/AYAGAAEB + CP8BAAj/Af4HAAEBEP8B+AcAAQcQ/wHgBwABHxD/AYAHAAF/B/8BAAj/Af4IABD/AfgHAAEDEP8B4AcA + AQ8Q/wGABwABPwf/AQAI/wH+CAABfw//AfgHAAEBEP8B4AcAAQcQ/wGABwABHwf/AQAI/wH+CAABfw// + AfgHAAEBEP8B4AcAAQcQ/wGABwABHwf/AQAI/wH+CAABPw//AfgIABD/AeAHAAEDEP8BgAcAAQ8H/wEA + CP8B/AgAAT8P/wHwCAAQ/wHABwABAxD/CAABDwf/AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgA + AQcH/wEACP8B/AgAAR8P/wHwCAABfw//AcAHAAEBEP8IAAEHB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHA + BwABARD/CAABBwf/AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgAAQcH/wEACP8B/AgAAQ8P/wHw + CAABPw//AcAIABD/CAABAwf/AQAI/wH8CAABDw//AfAIAAE/D/8BwAgAEP8IAAEDB/8BAAj/AfgIAAEP + D/8B4AgAAT8P/wGACAAP/wH+CAABAwf/AQAI/wH4CAABDw//AeAIAAE/D/8BgAgAD/8B/ggAAQMH/wEA + CP8B+AgAAQcP/wHgCAABHw//AYAIAAF/Dv8B/ggAAQEH/wEACP8B+AgAAQcP/wHgCAABHw//AYAIAAF/ + Dv8B/ggAAQEH/wEACP8B+AgAAQcP/wHgCAABHw//AYAIAAF/Dv8B/ggAAQEH/wEACP8B+AgAAQcP/wHg + CAABHw//AYAIAAF/Dv8B/ggAAQEH/wEACP8B+AgAAQMP/wHgCAABDw//AYAIAAE/Dv8B/gkAB/8BAAj/ + AfgIAAEDD/8B4AgAAQ8P/wGACAABPw7/Af4JAAf/AQAI/wHwCAABAw//AcAIAAEPD/8JAAE/Dv8B/AkA + B/8BAAj/AfAIAAEDD/8BwAgAAQ8P/wkAAT8O/wH8CQAH/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/ + AfwJAAF/Bv8BAAj/AfAIAAEBD/8BwAgAAQcP/wkAAR8O/wH8CQABfwb/AQAI/wHwCAABAQ//AcAIAAEH + D/8JAAEfDv8B/AkAAX8G/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/AfwJAAF/Bv8BAAj/AfAJAA// + AcAIAAEDD/8JAAEPDv8B/AkAAT8G/wEACP8B8AkAD/8BwAgAAQMP/wkAAQ8O/wH8CQABPwb/AQAI/wHg + CQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/ + Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEP + Dv8B+AkAAT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAED + Dv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8BwAkA + D/8JAAEDDv8B/AkAAQ8O/wHwCQABPwb/AQAI/wHACQAP/wkAAQMO/wH8CQABDw7/AfAJAAE/Bv8BAAj/ + AYAIAAEBDv8B/gkAAQcO/wH4CQABHw7/AeAJAAF/Bv8BAAj/AYAIAAEBDv8B/gkAAQcO/wH4CQABHw7/ + AeAJAAF/Bv8BAAf/Af4JAAEHDv8B+AkAAR8O/wHgCQABfw7/AYAIAAEBB/8BAAb/AfgKAAE/Df8B4AoA + Dv8BgAkAAQMN/wH+CgABDwf/AQAG/wHwAQABAxb/AcABAAEPFv8CAAE/Ff8B/AIAEP8BAAb/AfABAAED + Fv8BwAEAAQ8W/wIAAT8V/wH8AgAQ/wEABv8B8AEAAQcW/wHAAQABHxb/AgABfxX/AfwBAAEBEP8BAAb/ + AfABAAEfFv8BwAEAAX8W/wEAAQEW/wH8AQABBxD/AQAG/wH8AQAX/wHwAQMX/wHAAQ8X/wEAAT8F/wHf + Cv8BAAb/Af4BARf/AfgBBxf/AeABHxf/AYABfwX/AQMK/wEAWP8BAAr/AQBX/wH+AQABfwn/AQBX/wH+ + AQABHwn/AQA//wHxF/8B/gEAAQ8J/wEAP/8BwAF/F/8BAAEPCf8BAD//AcABPxf/AQABDwn/AQA//wHA + AQ8X/wHAAQ8J/wEAP/8BwAEDF/8B8AEfCf8BACb/AfgBPxf/AcABAxf/AfwBPwn/AQAm/wH4AR8X/wHA + AQEi/wEAJv8B8AEHF/8B4AEBFf8BLwz/AQAm/wHwAQEX/wH4AQMU/wH8AccM/wEAJv8B8AEAF/8B/AED + FP8B4wEHDP8BAA3/Af4BDxf/AfABAAF/F/8BDxT/AYwBAwz/AQAN/wH8AQMX/wH4AQABfxT/AeMW/wH+ + ASABAwz/AQAN/wH8AQAX/wH8AQABfxT/ARsW/wHwAYABAQz/AQAN/wH8AQABPxb/Af4BAAF/E/8B/AHh + Fv8BxgEAAQEM/wEADf8B/AEAAR8X/wGAFP8B8QGBFv8BEAEAAQEM/wEADf8B/gEAAR8U/wH9Av8B4xT/ + AYQBABb/AgABAgz/AQAO/wEAAR8U/wHiFv8B/gEwAQAW/wEQAT8BDgz/AQAO/wEAAR8U/wGMFv8B+AHA + AQAW/wEfAT8B+Qz/AQAO/wHAAR8T/wH+ASABfxX/AcICAAF/Ff8BhAEAAc8M/wEAC/8B/gF/Af8B8AE/ + E/8B4AGAAT8V/wGIAgABfxX/AfAB/gE/DP8BAAv/AfABPxb/AYABAAE/Ff8BgAEHAQIBfyT/AQAL/wGA + AT8V/wH8AgABPxX/Ac8BwAHIAX8k/wEACv8B/gEAAR8V/wHgAgABHxX/AeABAAEhJf8BAAr/AfgBAAEf + Ff8B4AIAAR8V/wHwAR8BByX/AQAK/wHAAQABHxX/AeACAAFfF/8B3yX/AQAK/wIAAQ8V/wHiAQMB4QEf + Pf8BAAn/AfwCAAEPFf8B8AEAARgBPz3/AQAJ/wH4AgABBxX/AfgCAD7/AQAJ/wH4AgABBxb/AR8B5z7/ + AQAJ/wH4AQAB8AEnVv8BAAn/AvgBDAEPVv8BAAn/AfwCAAEfVv8BAAr/AQMB8Ff/AQAL/wH7V/8BAGP/ + AQBj/wEAY/8BAGP/AQBj/wEAWf8Bgwn/AQBY/wH+AQEJ/wEAWP8B/AEAAX8I/wEAWP8B+AEAAX8I/wEA + QP8BwAF/Fv8B+AEAAT8I/wEAQP8BAAE/Fv8B8AEAAT8I/wEAP/8B/gEAAR8W/wHwAQABPwj/AQAn/wH4 + AX8W/wH+AQABHxb/AfABAAE/CP8BACf/AeABHxb/AfwBAAEPFv8B8AEAAT8I/wEAJ/8BwAEPFv8B/AEA + AQ8W/wHwAQABPwj/AQAn/wGAAQcW/wH8AQABDxH/AfwCAAE/Af8B+AEAAT8I/wEADv8B/gEPF/8BgAED + Fv8B/AEAAQ8R/wH8AgABPwH/AfgBAAF/CP8BAA7/AfgBAxf/AQABAxb/AfwBAAEPEf8B/AIAAT8B/wH8 + AQABfwj/AQAO/wHwAQEX/wEAAQMW/wH8AQABDxH/AfwCAAE/Af8B/gEACf8BAA7/AeABARf/AQABAxb/ + AfwBAAEPEf8B/AIAAT8C/wEDCf8BAA7/AeABABf/AQABAxL/AgABDwH/Af4BAAEfEf8B/AIAAT8M/wEA + Dv8BwAEAF/8BAAEDEv8CAAEPAv8BAAE/Ef8B/AIAAT8M/wEADv8BwAEAF/8BgAEDEv8CAAEPAv8BgAF/ + Ef8B/AIAAT8M/wEADv8BwAEAF/8BgAEHEv8CAAEPAv8B4RL/AfwCAAE/DP8BAA7/AcABABf/AcABBxL/ + AgABDxX/AfwCAAE/DP8BAA7/AeABABf/AeABDxL/AgABDxX/AfwCAAE/DP8BAA7/AcABARf/AfABPxL/ + AgABDxX/AfwCAAE/DP8BAA7/AeABASv/AgABDxX/AfwCAAE/DP8BAA7/AfABAyv/AgABDxX/AfwCAAE/ + DP8BAA7/AfgBByv/AgABDxX/AfwCAAE/DP8BAA//AR8r/wIAAQ8V/wH8AgABPwz/AQA7/wIAAQ8V/wH0 + AgABJwz/AQA7/wIAAQ8V/wHgAgABAwz/AQA7/wIAAQ8V/wHAAgABAQz/AQA7/wIAAQ8V/wGAAwAM/wEA + O/8CAAEPFf8BgAMADP8BADv/AgABDxX/AYADAAz/AQA6/wH5AgABCRX/AcACAAEBDP8BADr/AfADABX/ + AeABAAGAAQMM/wEAOv8B4AMAFf8B8AEHAeABBwz/AQA6/wHgAwABfxT/AfgBDwHwAQ8M/wEAOv8B4AMA + AX8U/wH8AQ8B+AEfDP8BADr/AfADACX/AQA6/wH4AQAB8AEBJf8BADr/AfwBAwH8AQMl/wEAOv8B/gED + AfwBByX/AQA7/wEHAf4BDyX/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQAK/wHnBf8BjxL/AZ8E/wH+AT8R/wH+AX8E/wH4 + Ev8B+QX/AeMI/wEACv8BAAT/Af4BAxH/AfwBAwT/AfgBDxH/AfABDwT/AeABPxH/AcABPwT/AYAI/wEA + Cf8B/gEAAX8D/wH4AQAR/wH4AQEE/wHgAQMR/wHgAQcE/wGAAQ8R/wGAAR8D/wH+AQABPwf/AQAJ/wH8 + AQABfwP/AfgBABH/AfABAQT/AeABAxH/AcABBwT/AYABDxH/AQABHwP/Af4BAAE/B/8BAAn/AfwBAAF/ + A/8B8AEAAX8Q/wHwAQEE/wHAAQER/wHAAQcE/wEAAQcR/wEAAR8D/wH8AQABHwf/AQAJ/wH4AQABfwP/ + AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/AQAJ/wH4AQABfwP/ + AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/AQAJ/wH4AQABfwP/ + AfABAAF/EP8B4AEBBP8BwAEBEf8BgAEHBP8BAAEHEP8B/gEAAR8D/wH8AQABHwf/AQAJ/wH8AQABfwP/ + AfABAAF/EP8B8AEBBP8BwAEBEf8BwAEHBP8BAAEHEf8BAAEfA/8B/AEAAR8H/wEACf8B/AEAAX8D/wH4 + AQAR/wHwAQEE/wHgAQMR/wHAAQcE/wGAAQ8R/wEAAR8D/wH+AQABPwf/AQAJ/wH+AQAE/wH8AQER/wH4 + AQME/wHwAQcR/wHgAQ8E/wHAAR8R/wGAAT8E/wEAAX8H/wEACv8BAQT/Af4BAxH/AfwBBwT/AfgBDxH/ + AfABHwT/AeABPxH/AcABfwT/AYAI/wEAY/8BAGP/AQBj/wEAY/8BAAr/AYAGAAF/EP8B/gYAAQER/wH4 + BgABBxH/AeAGAAEfB/8BAAn/Af4HAAE/EP8B+AcAEf8B4AYAAQMR/wGABgABDwf/AQAJ/wH4BwABHxD/ + AeAHAAF/EP8BgAYAAQEQ/wH+BwABBwf/AQAJ/wHwBwABDxD/AcAHAAE/EP8IABD/AfwHAAEDB/8BAAn/ + AeAHAAEPEP8BgAcAAT8P/wH+CAAQ/wH4BwABAwf/AQAJ/wHABwABHxD/CAABfw//AfwHAAEBEP8B8AcA + AQcH/wEACf8BwAcAAT8Q/wgAEP8B/AcAAQMQ/wHwBwABDwf/AQAJ/wGAAX8W/wH+AQEX/wH4AQcX/wHg + AR8O/wEACf8BgBf/Af4BAxf/AfgBDxf/AeABPw7/AQAJ/wEAF/8B/AEDF/8B8AEPF/8BwAE/Dv8BAAn/ + AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8BARf/AfwBBxf/AfABHxf/AcABfw7/AQAJ/wEBF/8B/AEH + F/8B8AEfF/8BwAF/Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8FAAE/Ev8B/AUAE/8B8AQA + AQMT/wHABAABDwr/AQAI/wH+BwAR/wH4BgABAxH/AeAGAAEPEf8BgAYAAT8I/wEACP8B/gcAAR8Q/wH4 + BwABfxD/AeAGAAEBEf8BgAYAAQcI/wEACP8B/gcAAQcQ/wH4BwABHxD/AeAHAAF/EP8BgAYAAQEI/wEA + CP8B/gcAAQEQ/wH4BwABBxD/AeAHAAEfEP8BgAcAAX8H/wEACP8B/ggAEP8B+AcAAQMQ/wHgBwABDxD/ + AYAHAAE/B/8BAAj/Af4IAAF/D/8B+AcAAQEQ/wHgBwABBxD/AYAHAAEfB/8BAAj/Af4IAAF/D/8B+AcA + AQEQ/wHgBwABBxD/AYAHAAEfB/8BAAj/Af4IAAE/D/8B+AgAEP8B4AcAAQMQ/wGABwABDwf/AQAI/wH8 + CAABPw//AfAIABD/AcAHAAEDEP8IAAEPB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHABwABARD/CAABBwf/ + AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgAAQcH/wEACP8B/AgAAR8P/wHwCAABfw//AcAHAAEB + EP8IAAEHB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHABwABARD/CAABBwf/AQAI/wH8CAABDw//AfAIAAE/ + D/8BwAgAEP8IAAEDB/8BAAj/AfwIAAEPD/8B8AgAAT8P/wHACAAQ/wgAAQMH/wEACP8B+AgAAQ8P/wHg + CAABPw//AYAIAA//Af4IAAEDB/8BAAj/AfgIAAEPD/8B4AgAAT8P/wGACAAP/wH+CAABAwf/AQAI/wH4 + CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+ + CAABAQf/AQAI/wH4CAABBw//AeAIAAEfD/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABBw//AeAIAAEf + D/8BgAgAAX8O/wH+CAABAQf/AQAI/wH4CAABAw//AeAIAAEPD/8BgAgAAT8O/wH+CQAH/wEACP8B+AgA + AQMP/wHgCAABDw//AYAIAAE/Dv8B/gkAB/8BAAj/AfAIAAEDD/8BwAgAAQ8P/wkAAT8O/wH8CQAH/wEA + CP8B8AgAAQMP/wHACAABDw//CQABPw7/AfwJAAf/AQAI/wHwCAABAQ//AcAIAAEHD/8JAAEfDv8B/AkA + AX8G/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/AfwJAAF/Bv8BAAj/AfAIAAEBD/8BwAgAAQcP/wkA + AR8O/wH8CQABfwb/AQAI/wHwCAABAQ//AcAIAAEHD/8JAAEfDv8B/AkAAX8G/wEACP8B8AkAD/8BwAgA + AQMP/wkAAQ8O/wH8CQABPwb/AQAI/wHwCQAP/wHACAABAw//CQABDw7/AfwJAAE/Bv8BAAj/AeAJAA// + AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEA + CP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4 + CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+ + CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHACQAP/wkA + AQMO/wH8CQABDw7/AfAJAAE/Bv8BAAj/AcAJAA//CQABAw7/AfwJAAEPDv8B8AkAAT8G/wEACP8BgAgA + AQEO/wH+CQABBw7/AfgJAAEfDv8B4AkAAX8G/wEACP8BgAgAAQEO/wH+CQABBw7/AfgJAAEfDv8B4AkA + AX8G/wEAB/8B/gkAAQcO/wH4CQABHw7/AeAJAAF/Dv8BgAgAAQEH/wEABv8B+AoAAT8N/wHgCgAO/wGA + CQABAw3/Af4KAAEPB/8BAAb/AfABAAEDAf8CAAEPEv8BwAEAAQ8B/AIAAT8S/wIAAT8B+AIAEv8B/AIA + EP8BAAb/AfABAAEDAf8CAAEPEv8BwAEAAQ8B/AIAAT8S/wIAAT8B+AIAEv8B/AIAEP8BAAb/AfABAAEH + Af8CAAEPEv8BwAEAAR8B/AIAAT8S/wIAAX8B+AIAEv8B/AEAAQEQ/wEABv8B8AEAAR8B/wIAAQ8S/wHA + AQABfwH8AgABPxL/AQABAQH/AfgCABL/AfwBAAEHEP8BAAb/AfwBAAL/AgABDxL/AfABAwH/AfwCAAE/ + Ev8BwAEPAf8BwAIAAR8S/wEAAT8Q/wEABv8B/gEBAv8CAAEPEv8B+AEHAf8B/AIAAT8S/wHgAR8B/wMA + AQcS/wGAAX8Q/wEACv8CAAEPFf8B/AIAAT8U/wH+AwABAyT/AQAK/wIAAQ8V/wH8AgABPxX/AwABByT/ + AQAK/wIAAQ8V/wHwAgABJxX/AYACAAEPJP8BAAr/AgABDxX/AeACAAEDFf8BwAEPAYABHyT/AQAK/wIA + AQ8V/wHAAgABARX/AeABPwHgAT8k/wEACv8CAAEPFf8BgAMAFf8B8AE/AeABfyT/AQAK/wIAAQ8V/wGA + AwA9/wEACf8B+QIAAQEV/wHAAgABAT3/AQAJ/wHwAwAV/wHgAQABgAEDPf8BAAn/AeADAAF/FP8B8AEH + AeABBz3/AQAJ/wHAAwABPxT/AfgBDwHwAQ89/wEACf8BwAMAAT8U/wH8AQ8B+AEfPf8BAAn/AeADAAF/ + Vf8BAAn/AfADAFb/AQAJ/wH4AQAB+AEBVv8BAAn/AfwBAAH8AQNW/wEACf8B/gEDAfwBB1b/AQBj/wEA + WP8BgQr/AQBY/wGAAX8J/wEAWP8BAAEfCf8BAFj/AQABDwn/AQA//wHwGP8BgAEHCf8BAD//AeABHxf/ + AYABBwn/AQA//wHgAQ8X/wHAAQMJ/wEAP/8B4AEDF/8B4AEHCf8BACb/Af4BHxf/AeABARX/Ab8B/wH4 + AQcJ/wEAJv8B/AEPF/8B4AEAFP8B/AEfAf8B/gEPCf8BACb/AfgBAxf/AfABABT/AfABDwz/AQAm/wH4 + AQAX/wH4AQAU/wHCAQ8M/wEAJv8B+AEAAX8W/wH8AQAT/wH+AQABBwz/AQAO/wGHF/8B+AEAAT8U/wGH + Af8B/gEBE/8B+AEAAQcM/wEADv8BARf/AfgBAAE/E/8B/gEHAv8BgxP/AeEBAAEHDP8BAA3/Af4BAAF/ + Fv8B/AEAAT8T/wH4AQMW/wIAAQMM/wEADf8B/gEAAR8X/wEAAT8T/wHAAQMV/wH+AgABAwz/AQAN/wH+ + AQABDxT/AfMC/wGAAT8T/wEAAQMV/wH8AgABAQz/AQAN/wH+AQABDxT/AcEC/wHAAX8S/wH8AQABARX/ + AfwCAAEJDP8BAA7/AQABBxP/Af4BAQL/AfAT/wHgAQABARX/Af4BIAF+ASMM/wEADv8BgAEHE/8B+AEA + Fv8BgAIAFf8B/gEAAQMBhwz/AQAO/wHAAQcT/wHhAQAW/wMAFv8BgAEAAR8M/wEAC/8B+AL/AfABDxP/ + AgAW/wMAF/8B/AF/DP8BAAv/AcgBfwH/AfgBHxL/AfwCAAF/Ff8BAAEeAQQl/wEAC/8BCAF/Af8B/gE/ + Ev8B8AIAAX8V/wGfAQEBkCX/AQAK/wH8AQABfxX/AcACAAE/Ff8BwAEAARMl/wEACv8B5AEAAT8V/wHA + AgABPxX/AeABfgEfJf8BAAr/AYQBAAE/Ff8BwAIAAb89/wEACf8B/gIAAR8V/wHGAQcBwAE/Pf8BAAn/ + AfICAAEfFf8B4AEGATABfz3/AQAJ/wHwAgABDxX/AfABBgEDPv8BAAn/AfACAAEPF/8Bzz7/AQAJ/wHw + AQMB4AGPVv8BAAn/AfEB8AEaAR9W/wEACf8B+AIAAX9W/wEACf8B/gEPAeFX/wEAY/8BAGP/AQBj/wEA + Wf8Bgwn/AQBY/wH+AQEJ/wEAWP8B/AEACf8BAFj/AfgBAAF/CP8BAFj/AfgBAAF/CP8BAFj/AfgBAAE/ + CP8BAFj/AfgBAAE/CP8BAFj/AfgBAAE/CP8BAFj/AfgBAAE/CP8BAFj/AfgBAAF/CP8BAFj/AfwBAAF/ + CP8BAFj/AfwBAAn/AQBY/wH+AQEJ/wEAWf8Bhwn/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEACv8B5wX/AY8S/wGfBP8B/gE/Ef8B/gF/ + BP8B+BL/AfkF/wHjCP8BAAr/AQAE/wH+AQMR/wH8AQME/wH4AQ8R/wHwAQ8E/wHgAT8R/wHAAT8E/wGA + CP8BAAn/Af4BAAF/A/8B+AEAEf8B+AEBBP8B4AEDEf8B4AEHBP8BgAEPEf8BgAEfA/8B/gEAAT8H/wEA + Cf8B/AEAAX8D/wH4AQAR/wHwAQEE/wHgAQMR/wHAAQcE/wGAAQ8R/wEAAR8D/wH+AQABPwf/AQAJ/wH8 + AQABfwP/AfABAAF/EP8B8AEBBP8BwAEBEf8BwAEHBP8BAAEHEf8BAAEfA/8B/AEAAR8H/wEACf8B+AEA + AX8D/wHwAQABfxD/AeABAQT/AcABARH/AYABBwT/AQABBxD/Af4BAAEfA/8B/AEAAR8H/wEACf8B+AEA + AX8D/wHwAQABfxD/AeABAQT/AcABARH/AYABBwT/AQABBxD/Af4BAAEfA/8B/AEAAR8H/wEACf8B+AEA + AX8D/wHwAQABfxD/AeABAQT/AcABARH/AYABBwT/AQABBxD/Af4BAAEfA/8B/AEAAR8H/wEACf8B/AEA + AX8D/wHwAQABfxD/AfABAQT/AcABARH/AcABBwT/AQABBxH/AQABHwP/AfwBAAEfB/8BAAn/AfwBAAF/ + A/8B+AEAEf8B8AEBBP8B4AEDEf8BwAEHBP8BgAEPEf8BAAEfA/8B/gEAAT8H/wEACf8B/gEABP8B/AEB + Ef8B+AEDBP8B8AEHEf8B4AEPBP8BwAEfEf8BgAE/BP8BAAF/B/8BAAr/AQEE/wH+AQMR/wH8AQcE/wH4 + AQ8R/wHwAR8E/wHgAT8R/wHAAX8E/wGACP8BAGP/AQBj/wEAY/8BAGP/AQAK/wGABgABfxD/Af4GAAEB + Ef8B+AYAAQcR/wHgBgABHwf/AQAJ/wH+BwABPxD/AfgHABH/AeAGAAEDEf8BgAYAAQ8H/wEACf8B+AcA + AR8Q/wHgBwABfxD/AYAGAAEBEP8B/gcAAQcH/wEACf8B8AcAAQ8Q/wHABwABPxD/CAAQ/wH8BwABAwf/ + AQAJ/wHgBwABDxD/AYAHAAE/D/8B/ggAEP8B+AcAAQMH/wEACf8BwAcAAR8Q/wgAAX8P/wH8BwABARD/ + AfAHAAEHB/8BAAn/AcAHAAE/EP8IABD/AfwHAAEDEP8B8AcAAQ8H/wEACf8BgAF/Fv8B/gEBF/8B+AEH + F/8B4AEfDv8BAAn/AYAX/wH+AQMX/wH4AQ8X/wHgAT8O/wEACf8BABf/AfwBAxf/AfABDxf/AcABPw7/ + AQAJ/wEBF/8B/AEHF/8B8AEfF/8BwAF/Dv8BAAn/AQEX/wH8AQcX/wHwAR8X/wHAAX8O/wEACf8BARf/ + AfwBBxf/AfABHxf/AcABfw7/AQAJ/wEBF/8B/AEHF/8B8AEfF/8BwAF/Dv8BAAn/BQABPxL/AfwFABP/ + AfAEAAEDE/8BwAQAAQ8K/wEACP8B/gcAEf8B+AYAAQMR/wHgBgABDxH/AYAGAAE/CP8BAAj/Af4HAAEf + EP8B+AcAAX8Q/wHgBgABARH/AYAGAAEHCP8BAAj/Af4HAAEHEP8B+AcAAR8Q/wHgBwABfxD/AYAGAAEB + CP8BAAj/Af4HAAEBEP8B+AcAAQcQ/wHgBwABHxD/AYAHAAF/B/8BAAj/Af4IABD/AfgHAAEDEP8B4AcA + AQ8Q/wGABwABPwf/AQAI/wH+CAABfw//AfgHAAEBEP8B4AcAAQcQ/wGABwABHwf/AQAI/wH+CAABfw// + AfgHAAEBEP8B4AcAAQcQ/wGABwABHwf/AQAI/wH+CAABPw//AfgIABD/AeAHAAEDEP8BgAcAAQ8H/wEA + CP8B/AgAAT8P/wHwCAAQ/wHABwABAxD/CAABDwf/AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgA + AQcH/wEACP8B/AgAAR8P/wHwCAABfw//AcAHAAEBEP8IAAEHB/8BAAj/AfwIAAEfD/8B8AgAAX8P/wHA + BwABARD/CAABBwf/AQAI/wH8CAABHw//AfAIAAF/D/8BwAcAAQEQ/wgAAQcH/wEACP8B/AgAAQ8P/wHw + CAABPw//AcAIABD/CAABAwf/AQAI/wH8CAABDw//AfAIAAE/D/8BwAgAEP8IAAEDB/8BAAj/AfgIAAEP + D/8B4AgAAT8P/wGACAAP/wH+CAABAwf/AQAI/wH4CAABDw//AeAIAAE/D/8BgAgAD/8B/ggAAQMH/wEA + CP8B+AgAAQcP/wHgCAABHw//AYAIAAF/Dv8B/ggAAQEH/wEACP8B+AgAAQcP/wHgCAABHw//AYAIAAF/ + Dv8B/ggAAQEH/wEACP8B+AgAAQcP/wHgCAABHw//AYAIAAF/Dv8B/ggAAQEH/wEACP8B+AgAAQcP/wHg + CAABHw//AYAIAAF/Dv8B/ggAAQEH/wEACP8B+AgAAQMP/wHgCAABDw//AYAIAAE/Dv8B/gkAB/8BAAj/ + AfgIAAEDD/8B4AgAAQ8P/wGACAABPw7/Af4JAAf/AQAI/wHwCAABAw//AcAIAAEPD/8JAAE/Dv8B/AkA + B/8BAAj/AfAIAAEDD/8BwAgAAQ8P/wkAAT8O/wH8CQAH/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/ + AfwJAAF/Bv8BAAj/AfAIAAEBD/8BwAgAAQcP/wkAAR8O/wH8CQABfwb/AQAI/wHwCAABAQ//AcAIAAEH + D/8JAAEfDv8B/AkAAX8G/wEACP8B8AgAAQEP/wHACAABBw//CQABHw7/AfwJAAF/Bv8BAAj/AfAJAA// + AcAIAAEDD/8JAAEPDv8B/AkAAT8G/wEACP8B8AkAD/8BwAgAAQMP/wkAAQ8O/wH8CQABPwb/AQAI/wHg + CQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/ + Bv8BAAj/AeAJAA//AYAIAAEDDv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEP + Dv8B+AkAAT8G/wEACP8B4AkAD/8BgAgAAQMO/wH+CQABDw7/AfgJAAE/Bv8BAAj/AeAJAA//AYAIAAED + Dv8B/gkAAQ8O/wH4CQABPwb/AQAI/wHgCQAP/wGACAABAw7/Af4JAAEPDv8B+AkAAT8G/wEACP8BwAkA + D/8JAAEDDv8B/AkAAQ8O/wHwCQABPwb/AQAI/wHACQAP/wkAAQMO/wH8CQABDw7/AfAJAAE/Bv8BAAj/ + AYAIAAEBDv8B/gkAAQcO/wH4CQABHw7/AeAJAAF/Bv8BAAj/AYAIAAEBDv8B/gkAAQcO/wH4CQABHw7/ + AeAJAAF/Bv8BAAf/Af4JAAEHDv8B+AkAAR8O/wHgCQABfw7/AYAIAAEBB/8BAAb/AfgKAAE/Df8B4AoA + Dv8BgAkAAQMN/wH+CgABDwf/AQAG/wHwAQABAxb/AcABAAEPFv8CAAE/Ff8B/AIAEP8BAAb/AfABAAED + Fv8BwAEAAQ8W/wIAAT8V/wH8AgAQ/wEABv8B8AEAAQcW/wHAAQABHxb/AgABfxX/AfwBAAEBAf8BwAEA + AQMM/wEABv8B8AEAAR8W/wHAAQABfxb/AQABARb/AfwBAAEHAf8BwAEAAQMM/wEABv8B/AEAF/8B8AED + F/8BwAEPF/8BAAE/Af8BwAEAAQMM/wEABv8B/gEBF/8B+AEHF/8B4AEfF/8BgAF/Af8BwAEAAQMM/wEA + QP8BgxP/AcABAAEDDP8BADv/AfACAAL/AQAT/wHAAQABAwz/AQA7/wHwAgAB/wH+AQABfxL/AcABAAED + DP8BADv/AfACAAH/AfwBAAE/Ev8BwAEAAQMM/wEAO/8B8AIAAf8B/AEAAT8S/wHAAQABAwz/AQA7/wHw + AgAB/wH8AQABHxL/AcABAAEDDP8BACL/AfgCAAE/Ff8B8AIAAf8B+AEAAR8S/wHAAQABAwz/AQAi/wH4 + AgABPwH/AfAT/wHwAgAB/wH4AQABHxL/AcABAAEDDP8BACL/AfgCAAE/Af8BwAE/Ev8B8AIAAf8B/AEA + AR8S/wHAAQABAwz/AQAi/wH4AgABPwH/AYABDxL/AfACAAH/AfgBAAE/Ev8BwAEAAQMM/wEAIv8B+AIA + AT8B/wGAAQ8S/wHwAgAB/wH8AQABPxL/AcABAAEDDP8BAAn/Af4CAAEPFf8B+AIAAT8B/wEAAQcS/wHw + AgAB/wH8AQABfxL/AcABAAEDDP8BAAn/Af4CAAEPFf8B+AIAAT8B/wEAAQcS/wHwAgAB/wH+AQAS/wH+ + AgABAgF/C/8BAAn/Af4CAAEPFf8B+AIAAT8B/wEAAQcS/wHwAgAC/wGDEv8B/AMAAT8L/wEACf8B/gIA + AQ8B/wH+AT8S/wH4AgABPwH/AQABBxL/AfACABX/AfgDAAEfC/8BAAn/Af4CAAEPAf8B8AEHEv8B+AIA + AT8B/wEAAQcS/wHwAgAV/wHwAwABDwv/AQAJ/wH+AgABDwH/AeABAxL/AfgCAAE/Af8BAAEHEv8B8AIA + Ff8B8AMAAQ8L/wEACf8B/gIAAQ8B/wHgAQES/wH4AgABPwH/AQABBxL/AYACAAG/FP8B+AMAAR8L/wEA + Cf8B/gIAAQ8B/wHAAQES/wH4AgABPwH/AYABDxL/AwABHxT/AfwDAAE/C/8BAAn/Af4CAAEPAf8BwAEA + Ev8B+AIAAT8B/wGAAR8R/wH+AwABDxT/Af4BAAE8AQABfwv/AQAJ/wH+AgABDwH/AcABABL/AfgCAAE/ + Af8B4AE/Ef8B/AMAAQcV/wEAAX4BAAz/AQAJ/wH+AgABDwH/AcABABL/AfgCAAE/FP8B/AMAAQMV/wGA + AX8BAQz/AQAJ/wH+AgABDwH/AcABABL/AeACAAEPFP8B/AMAAQck/wEACf8B/gIAAQ8B/wHAAQAS/wHA + AgABAxT/Af4DAAEPJP8BAAn/Af4CAAEPAf8B4AEBEv8BgAIAAQEV/wEAAQ8BAAEfJP8BAAn/Af4CAAEP + Af8B4AEBEv8DAAEBFf8BgAE/AYABPyT/AQAJ/wH+AgABDwH/AfABAxL/BAAV/wHAAT8BwAF/JP8BAAn/ + AfACAAELAf8B+AEHEv8DAAEBFf8B8AE/AcAl/wEACf8B8AIAAQEV/wGAAgABAz3/AQAJ/wHgAwAV/wHA + AQMBgAEHPf8BAAn/AcADAAF/FP8B4AEPAeABDz3/AQAJ/wGAAwABPxT/AfABDwHwAR89/wEACf8BwAMA + AX8U/wH4AR8B8AE/Pf8BAAn/AeADAFb/AQAJ/wHwAQAB4AEBVv8BAAn/AfgBAwH4AQNW/wEACf8B/AED + AfgBB0v/AeAK/wEACf8B/gEHAfwBD0v/AcABPwn/AQBY/wGAAQ8J/wEAWP8BgAEHCf8BAD//Af4Bfxf/ + AYABAwn/AQA//wH4AR8X/wGAAQEJ/wEAP/8B8AEHF/8BwAEBCf8BAD//AeABAxf/AeABAQn/AQA//wHg + AQAV/wF/Af8B+AEBCf8BACf/AY8X/wHgAQABfxP/AfkBPwH/Af4BAwn/AQAm/wH+AQcX/wHwAQABfxP/ + AeEBPwL/AQMJ/wEAJv8B/AEBF/8B+AEAAX8T/wGgAR8M/wEAJv8B/AEAAX8W/wH8AQABfxL/AfwBoAEf + DP8BACb/AfgBAAE/FP8BHwL/AQABfxL/AfABgAEPDP8BAA7/AeMX/wH8AQABHxP/Af0BDwL/AcABfxL/ + AdABAAEPDP8BAA7/AYAX/wH8AQABHxP/AfUBDwL/AeAS/wH+AVABAAEHDP8BAA7/AQABPxb/Af4BAAEP + E/8BlAEHFf8B/AIAAQcM/wEADv8BAAEPF/8BgAEPEv8B/gGQAQcV/wH4AgABBwz/AQAO/wEAAQcU/wG/ + Av8BwAEfEv8B+gGAAQMV/wH4AgABFwz/AQAO/wEAAQMU/wGzAv8B8AEfEv8BygEAAQMV/wH8AeQB/AFH + DP8BAA7/AYABAxT/AYMC/wH8AT8S/wFIAQABAxX/AfwBAAHnAU8M/wEADv8BwAEDE/8B3gEBFf8B/gIA + AQEW/wEBAeEBfwz/AQAO/wHgAQMT/wHYAQEV/wH+AgABBRf/AfkN/wEADv8B+AEDE/8BwAEBFf8B/gEg + AX4BGSX/AQAL/wH5Av8B/gEHEv8B7wIAFv8BPgEDAesl/wEAC/8BwAP/AZ8S/wGMAgAW/wGiAQIBLyX/ + AQAL/wEAFv8BgAIAAX8V/wHjAf4BPyX/AQAK/wH8AQABfxX/AYABDwEHAX89/wEACv8B4AEAAX8V/wGP + Af8B3z7/AQAK/wGAAQABfxX/AdcBPwHvPv8BAAn/Af4CAAF/Ff8B9wE/Aa8+/wEACf8B/gEDAYAY/wG/ + Pv8BAAv/AfNX/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Y/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEAY/8BAGP/AQBj/wEA + Cw== + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/GroupBoxEX.Designer.cs b/JinYuan.ControlLib/GroupBoxEX.Designer.cs new file mode 100644 index 0000000..f3d8f9e --- /dev/null +++ b/JinYuan.ControlLib/GroupBoxEX.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class GroupBoxEX + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/GroupBoxEX.cs b/JinYuan.ControlLib/GroupBoxEX.cs new file mode 100644 index 0000000..a3c0550 --- /dev/null +++ b/JinYuan.ControlLib/GroupBoxEX.cs @@ -0,0 +1,40 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class GroupBoxEX : GroupBox + { + + private Color mBorderColor = Color.FromArgb(1, 146, 235); + + [Browsable(true), Description("边框颜色"), Category("自定义分组")] + public Color BorderColor + { + get { return mBorderColor; } + set { mBorderColor = value; } + } + + + public GroupBoxEX() + { + InitializeComponent(); + } + + // 重写 + protected override void OnPaint(PaintEventArgs e) + { + var vSize = e.Graphics.MeasureString(this.Text, this.Font); + + e.Graphics.Clear(this.BackColor); + e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), 10, 1); + Pen vPen = new Pen(this.mBorderColor); // 用属性颜色来画边框颜色 + e.Graphics.DrawLine(vPen, 1, vSize.Height / 2, 8, vSize.Height / 2); + e.Graphics.DrawLine(vPen, vSize.Width + 8, vSize.Height / 2, this.Width - 2, vSize.Height / 2); + e.Graphics.DrawLine(vPen, 1, vSize.Height / 2, 1, this.Height - 2); + e.Graphics.DrawLine(vPen, 1, this.Height - 2, this.Width - 2, this.Height - 2); + e.Graphics.DrawLine(vPen, this.Width - 2, vSize.Height / 2, this.Width - 2, this.Height - 2); + } + } +} diff --git a/JinYuan.ControlLib/JinYuan.ControlLib.csproj b/JinYuan.ControlLib/JinYuan.ControlLib.csproj new file mode 100644 index 0000000..d620a27 --- /dev/null +++ b/JinYuan.ControlLib/JinYuan.ControlLib.csproj @@ -0,0 +1,718 @@ + + + + + Debug + AnyCPU + {1BB7ED33-D2CB-4CDD-AB39-F7F9AE948CA2} + Library + Properties + JinYuan.ControlLib + JinYuan.ControlLib + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + + + + ..\packages\SeeSharpTools.JY.GUI.1.4.4.533\lib\net40\SeeSharpTools.JY.GUI.dll + + + ..\packages\AntdUI.1.8.4\lib\net48\AntdUI.dll + + + False + Lib\HML.ComplexityPropertys.dll + + + False + ..\Libs\HML.dll + + + + + + + + + + + + + + + + + + + + + + + UserControl + + + ArrTotalQty.cs + + + Component + + + CheckBoxExt.cs + + + Component + + + CircleProgramBar.cs + + + UserControl + + + ControlBase.cs + + + Component + + + CustomComboBox.cs + + + Component + + + Component + + + CustomGroupBox.cs + + + Component + + + CustomRichTextBox.cs + + + + + + + + + + UserControl + + + UCDataGridView.cs + + + UserControl + + + UCDataGridViewRow.cs + + + UserControl + + + UCDataGridViewTreeRow.cs + + + UserControl + + + DialPlate.cs + + + Component + + + FlatComboBox.cs + + + Form + + + FrmBase.cs + + + Form + + + FrmTransparent.cs + + + Form + + + FrmWaiting.cs + + + Component + + + GroupBoxEX.cs + + + Component + + + LightweightGridPanel.cs + + + Component + + + ListViewEx.cs + + + + LogListBox.cs + + + UserControl + + + LongTitle.cs + + + UserControl + + + LongTitleStyle2.cs + + + + UserControl + + + StatusExt.cs + + + UserControl + + + TButton.cs + + + UserControl + + + TitleButton.cs + + + + SidebarNavigation.cs + + + UserControl + + + UCCheckBox.cs + + + + + UserControl + + + NaviButton2.cs + + + UserControl + + + NaviButton.cs + + + UserControl + + + NumKeyboard.cs + + + Component + + + PanelEnhanced.cs + + + Component + + + PanelExt.cs + + + + True + True + Resources.resx + + + Component + + + + UserControl + + + UserControl + + + UserControl + + + SimpleLed.cs + + + UserControl + + + TextSet2.cs + + + UserControl + + + TextSet.cs + + + UserControl + + + Title.cs + + + UserControl + + + FanShapedSchedule.cs + + + UserControl + + + ProcessEllipse.cs + + + UserControl + + + TitleTime.cs + + + UserControl + + + Toggle.cs + + + UserControl + + + TotalQty.cs + + + UserControl + + + CPK.cs + + + UserControl + + + UCBlower.cs + + + UserControl + + + UCControlBase.cs + + + UserControl + + + UCElectricityMeterH.cs + + + UserControl + + + UCElectricityMeterV.cs + + + UserControl + + + UCFengSu.cs + + + + Component + + + + + Component + + + + + + UserControl + + + UCLed.cs + + + UserControl + + + UCLedAvatar.cs + + + UserControl + + + ucPanel_400_200.cs + + + UserControl + + + ucPanel_900_450.cs + + + + + UserControl + + + UCRollText.cs + + + UserControl + + + UCSplitLine_H.cs + + + UserControl + + + UCSplitLine_V.cs + + + UserControl + + + UpDownLabel.cs + + + + Component + + + Component + + + Wave.cs + + + UserControl + + + WaveProcess.cs + + + UserControl + + + WithBgBox.cs + + + + + ArrTotalQty.cs + Designer + + + UCDataGridView.cs + + + UCDataGridViewRow.cs + + + UCDataGridViewTreeRow.cs + + + DialPlate.cs + + + FrmBase.cs + + + FrmTransparent.cs + + + FrmWaiting.cs + + + LongTitle.cs + + + LongTitleStyle2.cs + + + StatusExt.cs + + + TButton.cs + + + TitleButton.cs + + + NaviButton2.cs + + + NaviButton.cs + + + NumKeyboard.cs + + + ProcessEllipse.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + UCVScrollbar.cs + + + SidebarNavigation.cs + + + SimpleLed.cs + + + TextSet2.cs + + + TextSet.cs + + + Title.cs + + + TitleTime.cs + + + Toggle.cs + + + TotalQty.cs + + + CPK.cs + + + UCBlower.cs + + + UCCheckBox.cs + + + UCElectricityMeterH.cs + + + UCElectricityMeterV.cs + + + UCFengSu.cs + + + ucPanel_400_200.cs + + + ucPanel_900_450.cs + + + UCSplitLine_H.cs + + + UCSplitLine_V.cs + + + UpDownLabel.cs + + + WaveProcess.cs + + + WithBgBox.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {4c0bcb84-5cd7-4846-8363-c4c10d46e391} + JinYuan.Models + + + + + + + + + + + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/LightweightGridPanel.Designer.cs b/JinYuan.ControlLib/LightweightGridPanel.Designer.cs new file mode 100644 index 0000000..5b2c1c2 --- /dev/null +++ b/JinYuan.ControlLib/LightweightGridPanel.Designer.cs @@ -0,0 +1,37 @@ +namespace JinYuan.ControlLib +{ + partial class LightweightGridPanel + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + //this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/LightweightGridPanel.cs b/JinYuan.ControlLib/LightweightGridPanel.cs new file mode 100644 index 0000000..1778f2d --- /dev/null +++ b/JinYuan.ControlLib/LightweightGridPanel.cs @@ -0,0 +1,150 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class LightweightGridPanel : Panel + { + public int Rows { get; set; } + public int Columns { get; set; } + public int CellSize { get; set; } + public int HeaderHeight { get; set; } + public int RowHeaderWidth { get; set; } + public int BorderWidth { get; set; } = 1; + + private bool _styleSet = false; + + public LightweightGridPanel(int rows, int cols, int cellSize, int headerHeight, int rowHeaderWidth) + { + Rows = rows; + Columns = cols; + CellSize = cellSize; + HeaderHeight = headerHeight; + RowHeaderWidth = rowHeaderWidth; + + DoubleBuffered = true; + SetControlStyles(); + UpdateStyles(); + + CalculateAndSetSize(); + + BackColor = Color.FromArgb(28, 40, 55); + BorderStyle = BorderStyle.FixedSingle; + } + + /// + /// 尺寸计算 + /// + private void CalculateAndSetSize() + { + // 总宽度 = 行号列宽度 + 列数*单元格尺寸 + (列数+1)*边框宽度 + int totalWidth = RowHeaderWidth + (Columns * CellSize) + (Columns + 1) * BorderWidth; + // 总高度 = 表头高度 + 行数*单元格尺寸 + (行数+1)*边框宽度 + int totalHeight = HeaderHeight + (Rows * CellSize) + (Rows + 1) * BorderWidth; + + // 关键:设置最小/最大尺寸,同时允许手动调整(避免固定死导致适配问题) + MinimumSize = new Size(totalWidth, totalHeight); + Size = MinimumSize; + MaximumSize = new Size(totalWidth + 100, totalHeight + 100); // 留余量 + } + + private void SetControlStyles() + { + if (_styleSet) return; + + // 仅保留必要的双缓冲样式,关闭ResizeRedraw + SetStyle(ControlStyles.OptimizedDoubleBuffer | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.UserPaint, true); + SetStyle(ControlStyles.ResizeRedraw, false); + + _styleSet = true; + } + + /// + /// 控件位置/尺寸计算,确保在可视区域内 + /// + public void AddControl(Control ctrl, int row, int col) + { + if (ctrl == null) return; + + int x = 0, y = 0; + int ctrlWidth = 0, ctrlHeight = 0; + + // 左上角角落(行\列) + if (row == 0 && col == 0) + { + x = BorderWidth; + y = BorderWidth; + ctrlWidth = RowHeaderWidth - BorderWidth * 2; + ctrlHeight = HeaderHeight - BorderWidth * 2; + } + // 表头列(列号) + else if (row == 0) + { + x = RowHeaderWidth + (col - 1) * (CellSize + BorderWidth) + BorderWidth; + y = BorderWidth; + ctrlWidth = CellSize - BorderWidth * 2; + ctrlHeight = HeaderHeight - BorderWidth * 2; + } + // 行号列 + else if (col == 0) + { + x = BorderWidth; + y = HeaderHeight + (row - 1) * (CellSize + BorderWidth) + BorderWidth; + ctrlWidth = RowHeaderWidth - BorderWidth * 2; + ctrlHeight = CellSize - BorderWidth * 2; + } + // 电池控件(数据区) + else + { + x = RowHeaderWidth + (col - 1) * CellSize + (col) * BorderWidth; + y = HeaderHeight + (row - 1) * CellSize + (row) * BorderWidth; + ctrlWidth = CellSize - BorderWidth * 2; + ctrlHeight = CellSize - BorderWidth * 2; + } + + // 强制设置控件尺寸(避免尺寸为0) + ctrl.Size = new Size(Math.Max(10, ctrlWidth), Math.Max(10, ctrlHeight)); + ctrl.Location = new Point(x, y); + ctrl.Margin = new Padding(0); + ctrl.Padding = new Padding(0); + ctrl.Dock = DockStyle.None; + ctrl.Visible = true; + + // 确保子控件在最上层绘制 + ctrl.BringToFront(); + Controls.Add(ctrl); + } + + + // 重写SetStyle,直接调用基类 + protected new void SetStyle(ControlStyles flags, bool value) + { + base.SetStyle(flags, value); + } + + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + + // 确保控件重新布局 + if (Controls.Count > 0) + { + Invalidate(); // 触发重绘 + } + } + + // 添加网格线抗锯齿 + protected override void OnPaint(PaintEventArgs e) + { + e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + base.OnPaint(e); + } + } + + +} \ No newline at end of file diff --git a/JinYuan.ControlLib/ListViewEx.Designer.cs b/JinYuan.ControlLib/ListViewEx.Designer.cs new file mode 100644 index 0000000..69c392a --- /dev/null +++ b/JinYuan.ControlLib/ListViewEx.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class ListViewEx + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/ListViewEx.cs b/JinYuan.ControlLib/ListViewEx.cs new file mode 100644 index 0000000..bce6cbb --- /dev/null +++ b/JinYuan.ControlLib/ListViewEx.cs @@ -0,0 +1,75 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class ListViewEx : ListView + { + + StringFormat sf = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center };//字体水平位置居左,垂直居中 + + public ListViewEx() + { + InitializeComponent(); + this.OwnerDraw = true; + } + + public ListViewEx(IContainer container) + { + container.Add(this); + + InitializeComponent(); + } + + + private Brush bgColor = Brushes.DodgerBlue; + [CategoryAttribute("自定义")] + [DescriptionAttribute("背景颜色")] + public Brush BgColor + { + set + { + bgColor = value; + } + get + { + return bgColor; + } + } + + private Brush fontColor = Brushes.White; + [CategoryAttribute("自定义")] + [DescriptionAttribute("字体颜色")] + public Brush FontColor + { + set + { + fontColor = value; + } + get + { + return fontColor; + } + } + + + protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) + { + //e.DrawBackground(); + e.Graphics.FillRectangle(BgColor, e.Bounds); //设置背景颜色 + Font font = new Font("微软雅黑", 12, FontStyle.Bold); //设置字体大小 + e.Graphics.DrawString(e.Header.Text, font, FontColor, e.Bounds, sf); //设置字体颜色 + } + + protected override void OnDrawItem(DrawListViewItemEventArgs e) + { + e.DrawDefault = true; //采用系统默认方式绘制项 + } + + protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e) + { + e.DrawDefault = true; //采用系统默认方式绘制项 + } + } +} diff --git a/JinYuan.ControlLib/LogListBox.Designer.cs b/JinYuan.ControlLib/LogListBox.Designer.cs new file mode 100644 index 0000000..814dc44 --- /dev/null +++ b/JinYuan.ControlLib/LogListBox.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class LogListBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/LogListBox.cs b/JinYuan.ControlLib/LogListBox.cs new file mode 100644 index 0000000..624a6ec --- /dev/null +++ b/JinYuan.ControlLib/LogListBox.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + class LogItem + { + public String info; + public int index; + public Color color; + } + + public partial class LogListBox : ListBox + { + + private int m_nMaxLength = 1000; + [CategoryAttribute("自定义")] + [DescriptionAttribute("日志最大显示条数")] + public int MaxLength + { + set + { + m_nMaxLength = value; + } + get + { + return m_nMaxLength; + } + } + Dictionary m_dicItems = new Dictionary(); + + public LogListBox() + { + InitializeComponent(); + this.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable; + } + + public LogListBox(IContainer container) + { + container.Add(this); + + InitializeComponent(); + } + + protected override void OnDrawItem(DrawItemEventArgs e) + { + e.DrawBackground(); + e.DrawFocusRectangle(); + // 确保listbox中有日志且该日志被记录在字典中 + if (e.Index >= 0 && m_dicItems.Keys.Contains(e.Index)) + { + e.Graphics.DrawString(m_dicItems[e.Index].info, Font, new SolidBrush(m_dicItems[e.Index].color), e.Bounds); + } + } + + protected override void OnMeasureItem(MeasureItemEventArgs e) + { + base.OnMeasureItem(e); + e.ItemHeight = 16; + } + public void AddLog(String log, Color color) + { + ModefyItems(); + LogItem item = new LogItem(); + String showLog = String.Format("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss"), log); + item.info = showLog; + item.color = color; + + item.index = Items.Add(log); + if (!m_dicItems.Keys.Contains(item.index)) + m_dicItems.Add(item.index, item); + SelectedIndex = item.index; + } + + public void Clear() + { + Items.Clear(); + m_dicItems.Clear(); + } + + private void ModefyItems() + { + if (Items.Count >= m_nMaxLength) + { + Items.RemoveAt(0); + for (int n = 0; n < m_dicItems.Count - 1; n++) + { + if (m_dicItems.Keys.Contains(n) && m_dicItems.Keys.Contains(n + 1)) + { + m_dicItems[n].info = m_dicItems[n + 1].info; + m_dicItems[n].color = m_dicItems[n + 1].color; + } + } + + m_dicItems.Remove(m_dicItems.Count - 1); + } + } + } +} diff --git a/JinYuan.ControlLib/LongTitle.Designer.cs b/JinYuan.ControlLib/LongTitle.Designer.cs new file mode 100644 index 0000000..67a60cb --- /dev/null +++ b/JinYuan.ControlLib/LongTitle.Designer.cs @@ -0,0 +1,68 @@ +namespace JinYuan.ControlLib +{ + partial class LongTitle + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 16F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(35, 0); + this.lbl_Title.Margin = new System.Windows.Forms.Padding(50, 0, 0, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(205, 52); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "标题名称"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // LongTitle + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 19F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.标题_03左; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "LongTitle"; + this.Size = new System.Drawing.Size(543, 52); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/LongTitle.cs b/JinYuan.ControlLib/LongTitle.cs new file mode 100644 index 0000000..413921e --- /dev/null +++ b/JinYuan.ControlLib/LongTitle.cs @@ -0,0 +1,67 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class LongTitle : UserControl + { + public LongTitle() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private bool isRight = true; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮是否为右边")] + public bool IsRight + { + get { return isRight; } + set + { + isRight = value; + UpdataImage(); + } + } + + + private string titleName = "标题名称"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示标题名称")] + + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + } + } + + /// + ///统一更新背景 + /// + private void UpdataImage() + { + if (this.isRight) + { + lbl_Title.Dock = DockStyle.Right; + this.BackgroundImage = Properties.Resources.标题_03右; + } + else + { + lbl_Title.Dock = DockStyle.Left; + this.BackgroundImage = Properties.Resources.标题_03左; + } + } + } +} diff --git a/JinYuan.ControlLib/LongTitle.resx b/JinYuan.ControlLib/LongTitle.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/LongTitle.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/LongTitleStyle2.Designer.cs b/JinYuan.ControlLib/LongTitleStyle2.Designer.cs new file mode 100644 index 0000000..8d6b6c4 --- /dev/null +++ b/JinYuan.ControlLib/LongTitleStyle2.Designer.cs @@ -0,0 +1,68 @@ +namespace JinYuan.ControlLib +{ + partial class LongTitleStyle2 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LongTitleStyle2)); + this.lbl_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(233, 41); + this.lbl_Title.TabIndex = 1; + this.lbl_Title.Text = "标题名称"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // + // LongTitleStyle2 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage"))); + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Name = "LongTitleStyle2"; + this.Size = new System.Drawing.Size(233, 41); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/LongTitleStyle2.cs b/JinYuan.ControlLib/LongTitleStyle2.cs new file mode 100644 index 0000000..22f2ecf --- /dev/null +++ b/JinYuan.ControlLib/LongTitleStyle2.cs @@ -0,0 +1,38 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class LongTitleStyle2 : UserControl + { + public LongTitleStyle2() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + } + + + + private string titleName = "标题名称"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示标题名称")] + + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + } + } + } +} diff --git a/JinYuan.ControlLib/LongTitleStyle2.resx b/JinYuan.ControlLib/LongTitleStyle2.resx new file mode 100644 index 0000000..93d6c5e --- /dev/null +++ b/JinYuan.ControlLib/LongTitleStyle2.resx @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Models/CPKModel.cs b/JinYuan.ControlLib/Models/CPKModel.cs new file mode 100644 index 0000000..69ef269 --- /dev/null +++ b/JinYuan.ControlLib/Models/CPKModel.cs @@ -0,0 +1,134 @@ +namespace JinYuan.ControlLib.Models +{ + //子组大小:这个与计算内的CPK值又非常打的关系,即是分组的样本个数,数据的分组在此处需要说明的是,必须 + //是根据实际情况来填写,比如每次抽样为5个,那么子组大小为5个,我们不能随心所欲的任意填写这个值,否则 + //将没有实际意义。 + //上规格:用户录入的上规格值 + //目标值:用户输入的目标值,即期望达到的中心值 + //下规格:用户输入的下规格值 + + + public class CPKModel + { + /// + /// 总样本数 。参与分析的数据的个数 + /// + public int TotalNumber { get; set; } + /// + /// 图表类型 .说明进行分析的控制图的类型,此处为XR控制图 + /// + public string ChartType { get; set; } + /// + /// 平均值 所有样本数据的平均值 + /// + public double MeanVlaue { get; set; } + /// + /// 最大值 所有样本的最大值 + /// + public double MaxValue { get; set; } + /// + /// 最小值 + /// + public double MinValue { get; set; } + + /// + /// 正的3倍标准差线 + /// + public double Pos3Sigma { get; set; } + /// + /// 负的3倍标准差线 + /// + public double Neg3Sigma { get; set; } + /// + /// 组内标准差值 + /// + public double GroupSTDEV { get; set; } + /// + /// 整体标准差值 + /// + public double WholeSTDEV { get; set; } + + /// + /// 组内CPK值 工序能力指数,与规格值及上述标准差值相关联 + /// + public double GroupCPK { get; set; } + /// + /// 整体CPK值 工序能力指数,与规格值及上述标准差值相关联 + /// + public double WholeCPK { get; set; } + + /// + /// 组内CP值 Cp值是衡量过程满足产品品质标准的成都,也叫制程精密度,Cp值越大,表示过程变异越小,过程能力越差 + /// + public double GroupCP { get; set; } + /// + /// 整体CP值 Cp值是衡量过程满足产品品质标准的成都,也叫制程精密度,Cp值越大,表示过程变异越小,过程能力越差 + /// + public double WholeCP { get; set; } + + /// + /// 组内CPL值 相对应于下规格的工序能力值; + /// + public double GroupCPL { get; set; } + /// + /// 整体CPL值 相对应于下规格的工序能力值; + /// + public double WholeCPL { get; set; } + + /// + /// 组内CPU值 相对应于上规格的工序能力值; + /// + public double GroupCPU { get; set; } + /// + /// 整体CPU值 相对应于上规格的工序能力值; + /// + public double WholeCPU { get; set; } + + /// + /// 组内PPM + public double GroupPPM_LSL { get; set; } + /// + /// 整体PPM + public double WholePPM_LSL { get; set; } + + /// + /// 实际检测PPM + public double MeasuredPPM_LSL { get; set; } + + /// + /// 组内PPM + public double GroupPPM_USL { get; set; } + /// + /// 整体PPM + public double WholePPM_USL { get; set; } + /// + /// 实际检测PPM + public double MeasuredPPM_USL { get; set; } + /// + /// 组内PPM Total值,预测的总的不合格品数 + /// + public double GroupPPM_Total { get; set; } + /// + /// 整体PPM + public double WholePPM_Total { get; set; } + + /// + /// 实际检测PPM + public double MeasuredPPM_Total { get; set; } + + /// + /// 制程准确度,值越小越好 + /// + public double CA { get; set; } + + + } +} diff --git a/JinYuan.ControlLib/NaviButton.Designer.cs b/JinYuan.ControlLib/NaviButton.Designer.cs new file mode 100644 index 0000000..53a777c --- /dev/null +++ b/JinYuan.ControlLib/NaviButton.Designer.cs @@ -0,0 +1,66 @@ +namespace JinYuan.ControlLib +{ + partial class NaviButton + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold); + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(129, 43); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "导航按钮"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.lbl_Title.Click += new System.EventHandler(this.lbl_Title_Click); + // + // NaviButton + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.LeftUnSelected; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Name = "NaviButton"; + this.Size = new System.Drawing.Size(129, 43); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/NaviButton.cs b/JinYuan.ControlLib/NaviButton.cs new file mode 100644 index 0000000..9d3b8ef --- /dev/null +++ b/JinYuan.ControlLib/NaviButton.cs @@ -0,0 +1,90 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [DefaultEvent("Click")]//增加特性事件 + public partial class NaviButton : UserControl + { + public NaviButton() + { + InitializeComponent(); + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private bool isSelected = false; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮是否选中")] + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + UpdataImage(); + } + } + + + private bool isLeft = true; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮是否为左边")] + public bool IsLeft + { + get { return isLeft; } + set + { + isLeft = value; + UpdataImage(); + } + } + + private string titleName = "导航按钮"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮文本内容")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + } + } + + + /// + ///统一更新背景 + /// + private void UpdataImage() + { + if (this.isLeft) + { + this.BackgroundImage = isSelected ? Properties.Resources.LeftSelected : Properties.Resources.LeftUnSelected; + } + else + { + this.BackgroundImage = isSelected ? Properties.Resources.RightSelected : Properties.Resources.RightUnSelected; + } + } + + [Browsable(true)]//是否可见 + [Category("自定义事件")] //类别 + [Description("设置或显示导航按钮文本内容")] + public new EventHandler Click; + + private void lbl_Title_Click(object sender, EventArgs e) + { + this.Click?.Invoke(this, e); + } + } +} diff --git a/JinYuan.ControlLib/NaviButton.resx b/JinYuan.ControlLib/NaviButton.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/NaviButton.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/NaviButton2.Designer.cs b/JinYuan.ControlLib/NaviButton2.Designer.cs new file mode 100644 index 0000000..2a261c7 --- /dev/null +++ b/JinYuan.ControlLib/NaviButton2.Designer.cs @@ -0,0 +1,65 @@ +namespace JinYuan.ControlLib +{ + partial class NaviButton2 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new AntdUI.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("Cambria", 10.5F); + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(129, 43); + this.lbl_Title.TabIndex = 1; + this.lbl_Title.Text = "Data Monitor"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // NaviButton2 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Control; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.RightUnSelected2; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Name = "NaviButton2"; + this.Size = new System.Drawing.Size(129, 43); + this.ResumeLayout(false); + + } + + #endregion + + private AntdUI.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/NaviButton2.cs b/JinYuan.ControlLib/NaviButton2.cs new file mode 100644 index 0000000..69a565e --- /dev/null +++ b/JinYuan.ControlLib/NaviButton2.cs @@ -0,0 +1,315 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + + [DefaultEvent("Click")] // 增加特性事件 + public partial class NaviButton2 : UserControl + { + public NaviButton2() + { + InitializeComponent(); + + // 设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + // 绑定 Resize 事件 + this.Resize += NaviButton2_Resize; + + // 绑定 Label 的点击事件 + this.lbl_Title.Click += lbl_Title_Click; + + + } + + private bool isSelected = false; + [Browsable(true)] // 是否可见 + [Category("自定义属性")] // 类别 + [Description("设置或显示导航按钮是否选中")] + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + UpdataImage(); + this.Invalidate(); // 刷新控件 + } + } + + private bool isLeft = true; + [Browsable(true)] // 是否可见 + [Category("自定义属性")] // 类别 + [Description("设置或显示导航按钮是否为左边")] + public bool IsLeft + { + get { return isLeft; } + set + { + isLeft = value; + UpdataImage(); + this.Invalidate(); // 刷新控件 + } + } + + private string titleName = "导航按钮"; + [Browsable(true)] // 是否可见 + [Category("自定义属性")] // 类别 + [Description("设置或显示导航按钮文本内容")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + this.lbl_Title.AutoSize = false; // 禁用 AutoSize + this.lbl_Title.Size = new Size(this.Width - 10, this.Height - 10); // 设置 Label 的大小 + this.Invalidate(); // 刷新控件 + } + } + + + + private bool titleTextMultiLine = true; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或显示导航按钮文本是否支持多行显示")] + public bool TitleTextMultiLine + { + get { return titleTextMultiLine; } + set + { + titleTextMultiLine = value; + this.lbl_Title.AutoSize = false; // 禁用 AutoSize + this.lbl_Title.TextMultiLine = titleTextMultiLine; // 设置多行显示 + this.Invalidate(); // 刷新控件 + } + } + + private Color titleForeColor = Color.Black; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或显示导航按钮文本的字体颜色")] + public Color TitleForeColor + { + get { return titleForeColor; } + set + { + titleForeColor = value; + this.lbl_Title.ForeColor = titleForeColor; + this.Invalidate(); // 刷新控件 + } + } + + + private Font titleFont = new Font("Cambria", 10.5f, FontStyle.Bold); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或显示导航按钮文本的字体样式")] + public Font TitleFont + { + get { return titleFont; } + set + { + titleFont = value; + this.lbl_Title.Font = titleFont; + this.Invalidate(); // 刷新控件 + } + } + + /// + /// 统一更新背景 + /// + private void UpdataImage() + { + if (this.isLeft) + { + this.BackgroundImage = isSelected ? Properties.Resources.LeftSelected3 : Properties.Resources.LeftUnSelected3; + } + else + { + this.BackgroundImage = isSelected ? Properties.Resources.RightSelected3 : Properties.Resources.RightUnSelected3; + } + } + + [Browsable(true)] // 是否可见 + [Category("自定义事件")] // 类别 + [Description("设置或显示导航按钮文本内容")] + public new event EventHandler Click; + + private void lbl_Title_Click(object sender, EventArgs e) + { + // 触发 Click 事件 + this.Click?.Invoke(this, e); + } + + + + private void NaviButton2_Resize(object sender, EventArgs e) + { + // 调整 Label 的大小和位置 + this.lbl_Title.Size = new Size(this.Width - 10, this.Height - 10); + this.lbl_Title.Location = new Point(5, 5); // 根据需要调整位置 + this.Invalidate(); // 刷新控件 + } + } + + //[DefaultEvent("Click")] // 增加特性事件 + //public partial class NaviButton2 : UserControl + //{ + // public NaviButton2() + // { + // InitializeComponent(); + // // 设置控件样式,去除缓冲 + // this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + // this.SetStyle(ControlStyles.DoubleBuffer, true); + // this.SetStyle(ControlStyles.ResizeRedraw, true); + // this.SetStyle(ControlStyles.Selectable, true); + // this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + // // 绑定 Resize 事件 + // this.Resize += NaviButton2_Resize; + // } + + // private bool isSelected = false; + // [Browsable(true)] // 是否可见 + // [Category("自定义属性")] // 类别 + // [Description("设置或显示导航按钮是否选中")] + // public bool IsSelected + // { + // get { return isSelected; } + // set + // { + // isSelected = value; + // UpdataImage(); + // } + // } + + // private bool isLeft = true; + // [Browsable(true)] // 是否可见 + // [Category("自定义属性")] // 类别 + // [Description("设置或显示导航按钮是否为左边")] + // public bool IsLeft + // { + // get { return isLeft; } + // set + // { + // isLeft = value; + // UpdataImage(); + // } + // } + + // private string titleName = "导航按钮"; + // [Browsable(true)] // 是否可见 + // [Category("自定义属性")] // 类别 + // [Description("设置或显示导航按钮文本内容")] + // public string TitleName + // { + // get { return titleName; } + // set + // { + // titleName = value; + // this.lbl_Title.Text = titleName; + // this.lbl_Title.AutoSize = false; // 禁用 AutoSize + // this.lbl_Title.Size = new Size(this.Width - 10, this.Height - 10); // 设置 Label 的大小 + // } + // } + + // private float titleFontSize = 12f; + // [Browsable(true)] + // [Category("自定义属性")] + // [Description("设置或显示导航按钮文本的字体大小")] + // public float TitleFontSize + // { + // get { return titleFontSize; } + // set + // { + // titleFontSize = value; + // this.lbl_Title.Font = new Font(this.lbl_Title.Font.FontFamily, titleFontSize, this.lbl_Title.Font.Style); + // } + // } + + // private bool textMultiLine = true; + // [Browsable(true)] + // [Category("自定义属性")] + // [Description("设置或显示导航按钮文本是否换行")] + // public bool TextMultiLine + // { + // get { return textMultiLine; } + // set + // { + // textMultiLine = value; + // this.lbl_Title.AutoSize = false; // 禁用 AutoSize + // this.lbl_Title.TextMultiLine = textMultiLine; + // } + // } + + // private Color titleForeColor = Color.Black; + // [Browsable(true)] + // [Category("自定义属性")] + // [Description("设置或显示导航按钮文本的字体颜色")] + // public Color TitleForeColor + // { + // get { return titleForeColor; } + // set + // { + // titleForeColor = value; + // this.lbl_Title.ForeColor = titleForeColor; + // } + // } + + // private FontStyle titleFontStyle = FontStyle.Regular; + // [Browsable(true)] + // [Category("自定义属性")] + // [Description("设置或显示导航按钮文本的字体样式")] + // public FontStyle TitleFontStyle + // { + // get { return titleFontStyle; } + // set + // { + // titleFontStyle = value; + // this.lbl_Title.Font = new Font(this.lbl_Title.Font.FontFamily, this.lbl_Title.Font.Size, titleFontStyle); + // } + // } + + // /// + // /// 统一更新背景 + // /// + // private void UpdataImage() + // { + // if (this.isLeft) + // { + // this.BackgroundImage = isSelected ? Properties.Resources.LeftSelected3 : Properties.Resources.LeftUnSelected3; + // } + // else + // { + // this.BackgroundImage = isSelected ? Properties.Resources.RightSelected3 : Properties.Resources.RightUnSelected3; + // } + // } + + // [Browsable(true)] // 是否可见 + // [Category("自定义事件")] // 类别 + // [Description("设置或显示导航按钮文本内容")] + // public new EventHandler Click; + + // private void lbl_Title_Click(object sender, EventArgs e) + // { + // this.Click?.Invoke(this, e); + // } + + // private void NaviButton2_Resize(object sender, EventArgs e) + // { + // // 调整 Label 的大小和位置 + // this.lbl_Title.Size = new Size(this.Width - 10, this.Height - 10); + // this.lbl_Title.Location = new Point(5, 5); // 根据需要调整位置 + // } + //} +} diff --git a/JinYuan.ControlLib/NaviButton2.resx b/JinYuan.ControlLib/NaviButton2.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/NaviButton2.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/NumKeyboard.Designer.cs b/JinYuan.ControlLib/NumKeyboard.Designer.cs new file mode 100644 index 0000000..a595c57 --- /dev/null +++ b/JinYuan.ControlLib/NumKeyboard.Designer.cs @@ -0,0 +1,426 @@ +namespace JinYuan.ControlLib +{ + partial class NumKeyboard + { + /// + /// ±ØÐèµÄÉè¼ÆÆ÷±äÁ¿¡£ + /// + private System.ComponentModel.IContainer components = null; + + /// + /// ÇåÀíËùÓÐÕýÔÚʹÓõÄ×ÊԴ¡£ + /// + /// Èç¹ûӦÊͷÅÍйÜ×ÊԴ£¬Ϊ true£»·ñÔòΪ false¡£ + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region ×é¼þÉè¼ÆÆ÷Éú³ɵĴúÂë + + /// + /// Éè¼ÆÆ÷֧³ÖËùÐèµķ½·¨ - ²»ҪÐ޸Ä + /// ʹÓôúÂë±༭Æ÷Ð޸Ĵ˷½·¨µÄÄÚÈݡ£ + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.btn_Enter = new System.Windows.Forms.Button(); + this.button14 = new System.Windows.Forms.Button(); + this.button13 = new System.Windows.Forms.Button(); + this.btn_Esc = new System.Windows.Forms.Button(); + this.button11 = new System.Windows.Forms.Button(); + this.button10 = new System.Windows.Forms.Button(); + this.button9 = new System.Windows.Forms.Button(); + this.btn_Del = new System.Windows.Forms.Button(); + this.button7 = new System.Windows.Forms.Button(); + this.button6 = new System.Windows.Forms.Button(); + this.button5 = new System.Windows.Forms.Button(); + this.btn_Minus = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.lbl_Result = new System.Windows.Forms.Label(); + this.lbl_Max = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.lbl_Min = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.button1 = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 4; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.Controls.Add(this.btn_Enter, 2, 5); + this.tableLayoutPanel1.Controls.Add(this.button14, 1, 5); + this.tableLayoutPanel1.Controls.Add(this.button13, 0, 5); + this.tableLayoutPanel1.Controls.Add(this.btn_Esc, 3, 4); + this.tableLayoutPanel1.Controls.Add(this.button11, 2, 4); + this.tableLayoutPanel1.Controls.Add(this.button10, 1, 4); + this.tableLayoutPanel1.Controls.Add(this.button9, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.btn_Del, 3, 3); + this.tableLayoutPanel1.Controls.Add(this.button7, 2, 3); + this.tableLayoutPanel1.Controls.Add(this.button6, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.button5, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.btn_Minus, 3, 2); + this.tableLayoutPanel1.Controls.Add(this.button3, 2, 2); + this.tableLayoutPanel1.Controls.Add(this.button2, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.lbl_Result, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.lbl_Max, 3, 0); + this.tableLayoutPanel1.Controls.Add(this.label3, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Min, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.button1, 0, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 6; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(320, 276); + this.tableLayoutPanel1.TabIndex = 0; + // + // btn_Enter + // + this.tableLayoutPanel1.SetColumnSpan(this.btn_Enter, 2); + this.btn_Enter.Dock = System.Windows.Forms.DockStyle.Fill; + this.btn_Enter.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Enter.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Enter.ForeColor = System.Drawing.Color.White; + this.btn_Enter.Location = new System.Drawing.Point(166, 236); + this.btn_Enter.Margin = new System.Windows.Forms.Padding(6); + this.btn_Enter.Name = "btn_Enter"; + this.btn_Enter.Size = new System.Drawing.Size(148, 34); + this.btn_Enter.TabIndex = 19; + this.btn_Enter.Text = "Enter"; + this.btn_Enter.UseVisualStyleBackColor = true; + this.btn_Enter.Click += new System.EventHandler(this.btn_Enter_Click); + // + // button14 + // + this.button14.Dock = System.Windows.Forms.DockStyle.Fill; + this.button14.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button14.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button14.ForeColor = System.Drawing.Color.White; + this.button14.Location = new System.Drawing.Point(86, 236); + this.button14.Margin = new System.Windows.Forms.Padding(6); + this.button14.Name = "button14"; + this.button14.Size = new System.Drawing.Size(68, 34); + this.button14.TabIndex = 18; + this.button14.Text = "0"; + this.button14.UseVisualStyleBackColor = true; + this.button14.Click += new System.EventHandler(this.btn_Common_Click); + // + // button13 + // + this.button13.Dock = System.Windows.Forms.DockStyle.Fill; + this.button13.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button13.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button13.ForeColor = System.Drawing.Color.White; + this.button13.Location = new System.Drawing.Point(6, 236); + this.button13.Margin = new System.Windows.Forms.Padding(6); + this.button13.Name = "button13"; + this.button13.Size = new System.Drawing.Size(68, 34); + this.button13.TabIndex = 17; + this.button13.Text = "."; + this.button13.UseVisualStyleBackColor = true; + this.button13.Click += new System.EventHandler(this.btn_Common_Click); + // + // btn_Esc + // + this.btn_Esc.Dock = System.Windows.Forms.DockStyle.Fill; + this.btn_Esc.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Esc.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Esc.ForeColor = System.Drawing.Color.White; + this.btn_Esc.Location = new System.Drawing.Point(246, 190); + this.btn_Esc.Margin = new System.Windows.Forms.Padding(6); + this.btn_Esc.Name = "btn_Esc"; + this.btn_Esc.Size = new System.Drawing.Size(68, 34); + this.btn_Esc.TabIndex = 16; + this.btn_Esc.Text = "ESC"; + this.btn_Esc.UseVisualStyleBackColor = true; + this.btn_Esc.Click += new System.EventHandler(this.btn_Esc_Click); + // + // button11 + // + this.button11.Dock = System.Windows.Forms.DockStyle.Fill; + this.button11.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button11.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button11.ForeColor = System.Drawing.Color.White; + this.button11.Location = new System.Drawing.Point(166, 190); + this.button11.Margin = new System.Windows.Forms.Padding(6); + this.button11.Name = "button11"; + this.button11.Size = new System.Drawing.Size(68, 34); + this.button11.TabIndex = 15; + this.button11.Text = "3"; + this.button11.UseVisualStyleBackColor = true; + this.button11.Click += new System.EventHandler(this.btn_Common_Click); + // + // button10 + // + this.button10.Dock = System.Windows.Forms.DockStyle.Fill; + this.button10.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button10.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button10.ForeColor = System.Drawing.Color.White; + this.button10.Location = new System.Drawing.Point(86, 190); + this.button10.Margin = new System.Windows.Forms.Padding(6); + this.button10.Name = "button10"; + this.button10.Size = new System.Drawing.Size(68, 34); + this.button10.TabIndex = 14; + this.button10.Text = "2"; + this.button10.UseVisualStyleBackColor = true; + this.button10.Click += new System.EventHandler(this.btn_Common_Click); + // + // button9 + // + this.button9.Dock = System.Windows.Forms.DockStyle.Fill; + this.button9.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button9.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button9.ForeColor = System.Drawing.Color.White; + this.button9.Location = new System.Drawing.Point(6, 190); + this.button9.Margin = new System.Windows.Forms.Padding(6); + this.button9.Name = "button9"; + this.button9.Size = new System.Drawing.Size(68, 34); + this.button9.TabIndex = 13; + this.button9.Text = "1"; + this.button9.UseVisualStyleBackColor = true; + this.button9.Click += new System.EventHandler(this.btn_Common_Click); + // + // btn_Del + // + this.btn_Del.Dock = System.Windows.Forms.DockStyle.Fill; + this.btn_Del.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Del.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Del.ForeColor = System.Drawing.Color.White; + this.btn_Del.Location = new System.Drawing.Point(246, 144); + this.btn_Del.Margin = new System.Windows.Forms.Padding(6); + this.btn_Del.Name = "btn_Del"; + this.btn_Del.Size = new System.Drawing.Size(68, 34); + this.btn_Del.TabIndex = 12; + this.btn_Del.Text = "DEL"; + this.btn_Del.UseVisualStyleBackColor = true; + this.btn_Del.Click += new System.EventHandler(this.btn_Del_Click); + // + // button7 + // + this.button7.Dock = System.Windows.Forms.DockStyle.Fill; + this.button7.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button7.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button7.ForeColor = System.Drawing.Color.White; + this.button7.Location = new System.Drawing.Point(166, 144); + this.button7.Margin = new System.Windows.Forms.Padding(6); + this.button7.Name = "button7"; + this.button7.Size = new System.Drawing.Size(68, 34); + this.button7.TabIndex = 11; + this.button7.Text = "6"; + this.button7.UseVisualStyleBackColor = true; + this.button7.Click += new System.EventHandler(this.btn_Common_Click); + // + // button6 + // + this.button6.Dock = System.Windows.Forms.DockStyle.Fill; + this.button6.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button6.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button6.ForeColor = System.Drawing.Color.White; + this.button6.Location = new System.Drawing.Point(86, 144); + this.button6.Margin = new System.Windows.Forms.Padding(6); + this.button6.Name = "button6"; + this.button6.Size = new System.Drawing.Size(68, 34); + this.button6.TabIndex = 10; + this.button6.Text = "5"; + this.button6.UseVisualStyleBackColor = true; + this.button6.Click += new System.EventHandler(this.btn_Common_Click); + // + // button5 + // + this.button5.Dock = System.Windows.Forms.DockStyle.Fill; + this.button5.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button5.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button5.ForeColor = System.Drawing.Color.White; + this.button5.Location = new System.Drawing.Point(6, 144); + this.button5.Margin = new System.Windows.Forms.Padding(6); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(68, 34); + this.button5.TabIndex = 9; + this.button5.Text = "4"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.btn_Common_Click); + // + // btn_Minus + // + this.btn_Minus.Dock = System.Windows.Forms.DockStyle.Fill; + this.btn_Minus.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Minus.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Minus.ForeColor = System.Drawing.Color.White; + this.btn_Minus.Location = new System.Drawing.Point(246, 98); + this.btn_Minus.Margin = new System.Windows.Forms.Padding(6); + this.btn_Minus.Name = "btn_Minus"; + this.btn_Minus.Size = new System.Drawing.Size(68, 34); + this.btn_Minus.TabIndex = 8; + this.btn_Minus.Text = "-"; + this.btn_Minus.UseVisualStyleBackColor = true; + this.btn_Minus.Click += new System.EventHandler(this.btn_Minus_Click); + // + // button3 + // + this.button3.Dock = System.Windows.Forms.DockStyle.Fill; + this.button3.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button3.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button3.ForeColor = System.Drawing.Color.White; + this.button3.Location = new System.Drawing.Point(166, 98); + this.button3.Margin = new System.Windows.Forms.Padding(6); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(68, 34); + this.button3.TabIndex = 7; + this.button3.Text = "9"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.btn_Common_Click); + // + // button2 + // + this.button2.Dock = System.Windows.Forms.DockStyle.Fill; + this.button2.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(64))))); + this.button2.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(27)))), ((int)(((byte)(78))))); + this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button2.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button2.ForeColor = System.Drawing.Color.White; + this.button2.Location = new System.Drawing.Point(86, 98); + this.button2.Margin = new System.Windows.Forms.Padding(6); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(68, 34); + this.button2.TabIndex = 6; + this.button2.Text = "8"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.btn_Common_Click); + // + // lbl_Result + // + this.lbl_Result.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.tableLayoutPanel1.SetColumnSpan(this.lbl_Result, 4); + this.lbl_Result.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Result.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.5F, System.Drawing.FontStyle.Bold); + this.lbl_Result.ForeColor = System.Drawing.Color.White; + this.lbl_Result.Location = new System.Drawing.Point(3, 46); + this.lbl_Result.Name = "lbl_Result"; + this.lbl_Result.Size = new System.Drawing.Size(314, 46); + this.lbl_Result.TabIndex = 4; + this.lbl_Result.Text = "0"; + this.lbl_Result.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.lbl_Result.MouseDown += new System.Windows.Forms.MouseEventHandler(this.lbl_Result_MouseDown); + this.lbl_Result.MouseMove += new System.Windows.Forms.MouseEventHandler(this.lbl_Result_MouseMove); + // + // lbl_Max + // + this.lbl_Max.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Max.Font = new System.Drawing.Font("΢ÈíÑźÚ", 11.5F, System.Drawing.FontStyle.Bold); + this.lbl_Max.ForeColor = System.Drawing.Color.White; + this.lbl_Max.Location = new System.Drawing.Point(243, 0); + this.lbl_Max.Name = "lbl_Max"; + this.lbl_Max.Size = new System.Drawing.Size(74, 46); + this.lbl_Max.TabIndex = 3; + this.lbl_Max.Text = "0"; + this.lbl_Max.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // label3 + // + this.label3.Dock = System.Windows.Forms.DockStyle.Fill; + this.label3.Font = new System.Drawing.Font("΢ÈíÑźÚ", 11.5F, System.Drawing.FontStyle.Bold); + this.label3.ForeColor = System.Drawing.Color.White; + this.label3.Location = new System.Drawing.Point(163, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(74, 46); + this.label3.TabIndex = 2; + this.label3.Text = "Max£º"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lbl_Min + // + this.lbl_Min.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Min.Font = new System.Drawing.Font("΢ÈíÑźÚ", 11.5F, System.Drawing.FontStyle.Bold); + this.lbl_Min.ForeColor = System.Drawing.Color.White; + this.lbl_Min.Location = new System.Drawing.Point(83, 0); + this.lbl_Min.Name = "lbl_Min"; + this.lbl_Min.Size = new System.Drawing.Size(74, 46); + this.lbl_Min.TabIndex = 1; + this.lbl_Min.Text = "0"; + this.lbl_Min.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // label1 + // + this.label1.Dock = System.Windows.Forms.DockStyle.Fill; + this.label1.Font = new System.Drawing.Font("΢ÈíÑźÚ", 11.5F, System.Drawing.FontStyle.Bold); + this.label1.ForeColor = System.Drawing.Color.White; + this.label1.Location = new System.Drawing.Point(3, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(74, 46); + this.label1.TabIndex = 0; + this.label1.Text = "Min£º"; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // button1 + // + this.button1.Dock = System.Windows.Forms.DockStyle.Fill; + this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button1.Font = new System.Drawing.Font("΢ÈíÑźÚ", 12.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button1.ForeColor = System.Drawing.Color.White; + this.button1.Location = new System.Drawing.Point(6, 98); + this.button1.Margin = new System.Windows.Forms.Padding(6); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(68, 34); + this.button1.TabIndex = 5; + this.button1.Text = "7"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.btn_Common_Click); + // + // NumKeyboard + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(27)))), ((int)(((byte)(78))))); + this.Controls.Add(this.tableLayoutPanel1); + this.Font = new System.Drawing.Font("΢ÈíÑźÚ", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "NumKeyboard"; + this.Size = new System.Drawing.Size(320, 276); + this.tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Button btn_Enter; + private System.Windows.Forms.Button button14; + private System.Windows.Forms.Button button13; + private System.Windows.Forms.Button btn_Esc; + private System.Windows.Forms.Button button11; + private System.Windows.Forms.Button button10; + private System.Windows.Forms.Button button9; + private System.Windows.Forms.Button btn_Del; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.Button button5; + private System.Windows.Forms.Button btn_Minus; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Label lbl_Result; + private System.Windows.Forms.Label lbl_Max; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label lbl_Min; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button button1; + } +} diff --git a/JinYuan.ControlLib/NumKeyboard.cs b/JinYuan.ControlLib/NumKeyboard.cs new file mode 100644 index 0000000..d9dd2ad --- /dev/null +++ b/JinYuan.ControlLib/NumKeyboard.cs @@ -0,0 +1,207 @@ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class NumKeyboard : UserControl + { + public NumKeyboard() + { + InitializeComponent(); + } + + [Browsable(false)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("×îÖյĽá¹ûֵ")] + public string ResultValue + { + get { return this.lbl_Result.Text; } + } + + private string initialValue; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("³õʼֵ")] + public string InitialValue + { + get { return initialValue; } + set + { + initialValue = value; + this.lbl_Result.Text = value; + } + } + + private float minValue = 0.0f; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖõÄ×îСֵ")] + public float MinValue + { + get { return minValue; } + set + { + minValue = value; + this.lbl_Min.Text = value.ToString(); + } + } + + + private float maxValue = 0.0f; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖõÄ×î´óֵ")] + public float MaxValue + { + get { return maxValue; } + set + { + maxValue = value; + this.lbl_Max.Text = value.ToString(); + } + } + + [Browsable(false)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("¹ØÁª¿ؼþ")] + public Control RelateControl { get; set; } + + [Browsable(true)] + [Category("×Զ¨Òåʼþ")] + [Description("Enter°´ÏÂʼþ")] + public event EventHandler EnterClick; + + + [Browsable(true)] + [Category("×Զ¨Òåʼþ")] + [Description("ESC°´ÏÂʼþ")] + public event EventHandler ESCClick; + + private void btn_Enter_Click(object sender, EventArgs e) + { + string temp = this.lbl_Result.Text; + + if (float.TryParse(temp, out float value)) + { + if (value >= this.minValue && value <= this.maxValue) + { + EnterClick?.Invoke(this, e); + } + else + { + return; + } + } + else + { + return; + } + + } + + private void btn_Esc_Click(object sender, EventArgs e) + { + ESCClick?.Invoke(this, e); + } + + private void btn_Common_Click(object sender, EventArgs e) + { + if (sender is Button button) + { + if (button.Text == ".") + { + //´¦ÀíСÊýµã + if (this.lbl_Result.Text.Contains('.')) + { + return; + } + else + { + this.lbl_Result.Text += button.Text; + } + } + else + { + string temp = this.lbl_Result.Text + button.Text; + + if (float.TryParse(temp, out float value)) + { + if (value >= this.minValue && value <= this.maxValue) + { + this.lbl_Result.Text = temp; + } + else + { + return; + } + } + else + { + return; + } + } + } + } + + private void btn_Del_Click(object sender, EventArgs e) + { + if (this.lbl_Result.Text.Length == 0) return; + + this.lbl_Result.Text = this.lbl_Result.Text.Substring(0, this.lbl_Result.Text.Length - 1); + } + + private void btn_Minus_Click(object sender, EventArgs e) + { + string temp = this.lbl_Result.Text; + + if (temp.StartsWith("-")) + { + temp = temp.Remove(0, 1); + } + else + { + temp = temp.Insert(0, "-"); + } + + if (float.TryParse(temp, out float value)) + { + if (value >= this.minValue && value <= this.maxValue) + { + this.lbl_Result.Text = temp; + } + else + { + return; + } + } + else + { + return; + } + } + + + #region Îޱ߿òÍ϶¯ + + private Point mPoint; + private void lbl_Result_MouseDown(object sender, MouseEventArgs e) + { + mPoint = new Point(e.X, e.Y); + } + + private void lbl_Result_MouseMove(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + this.Location = new Point(this.Location.X + e.X - mPoint.X, this.Location.Y + e.Y - mPoint.Y); + } + } + + #endregion + + } +} diff --git a/JinYuan.ControlLib/NumKeyboard.resx b/JinYuan.ControlLib/NumKeyboard.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/NumKeyboard.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/PanelEnhanced.Designer.cs b/JinYuan.ControlLib/PanelEnhanced.Designer.cs new file mode 100644 index 0000000..481de60 --- /dev/null +++ b/JinYuan.ControlLib/PanelEnhanced.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class PanelEnhanced + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/PanelEnhanced.cs b/JinYuan.ControlLib/PanelEnhanced.cs new file mode 100644 index 0000000..0227741 --- /dev/null +++ b/JinYuan.ControlLib/PanelEnhanced.cs @@ -0,0 +1,55 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class PanelEnhanced : Panel + { + public PanelEnhanced() + { + InitializeComponent(); + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + protected override void OnPaintBackground(PaintEventArgs e) + { + //重载基类得背景擦除方法 + + //解决窗体刷新,放大和闪烁 + + return; + } + + protected override void OnPaint(PaintEventArgs e) + { + //使用双缓冲 + this.DoubleBuffered = true; + + if (this.BackgroundImage != null) + { + e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + + e.Graphics.DrawImage(this.BackgroundImage, new Rectangle + (0, 0, this.Width, this.Height), 0, 0, this.BackgroundImage.Width, this.BackgroundImage.Height, GraphicsUnit.Pixel); + } + base.OnPaint(e); + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + } +} diff --git a/JinYuan.ControlLib/PanelExt.Designer.cs b/JinYuan.ControlLib/PanelExt.Designer.cs new file mode 100644 index 0000000..e1b645c --- /dev/null +++ b/JinYuan.ControlLib/PanelExt.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class PanelExt + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/PanelExt.cs b/JinYuan.ControlLib/PanelExt.cs new file mode 100644 index 0000000..9184dc6 --- /dev/null +++ b/JinYuan.ControlLib/PanelExt.cs @@ -0,0 +1,134 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class PanelExt : Panel + { + public PanelExt() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private int topGap; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示上边间隔距离")] + public int TopGap + { + get { return topGap; } + set + { + topGap = value; + this.Invalidate();//点击后立即生效 + } + } + + private int bottomGap; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示下边间隔距离")] + public int BottomGap + { + get { return bottomGap; } + set + { + bottomGap = value; + this.Invalidate();//点击后立即生效 + } + } + + private int leftGap; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示左边间隔距离")] + public int LeftGap + { + get { return leftGap; } + set + { + leftGap = value; + this.Invalidate();//点击后立即生效 + } + } + + private int rightGap; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示右边间隔距离")] + public int RightGap + { + get { return rightGap; } + set + { + rightGap = value; + this.Invalidate();//点击后立即生效 + } + } + + private int bordeWidth = 2; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示边框的宽度")] + public int BordeWidth + { + get { return bordeWidth; } + set + { + bordeWidth = value; + this.Invalidate();//点击后立即生效 + } + } + + private Color bordeColor = Color.FromArgb(35, 255, 253); + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示边框的颜色")] + public Color BordeColor + { + get { return bordeColor; } + set + { + bordeColor = value; + this.Invalidate();//点击后立即生效 + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + //准备画布 + Graphics graphics = e.Graphics; + //准备笔 + Pen pen = new Pen(bordeColor, bordeWidth); + //准备矩形参数 + float x = leftGap + bordeWidth * 0.5f; + float y = topGap + bordeWidth * 0.5f; + float width = this.Width - leftGap - rightGap - bordeWidth; + float height = this.Height - topGap - bottomGap - bordeWidth; + + //绘制矩形 + graphics.DrawRectangle(pen, x, y, width, height); + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + } +} diff --git a/JinYuan.ControlLib/ProcessEllipse.Designer.cs b/JinYuan.ControlLib/ProcessEllipse.Designer.cs new file mode 100644 index 0000000..f0307d2 --- /dev/null +++ b/JinYuan.ControlLib/ProcessEllipse.Designer.cs @@ -0,0 +1,45 @@ +namespace JinYuan.ControlLib +{ + partial class ProcessEllipse + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + //protected override void Dispose(bool disposing) + //{ + // if (disposing && (components != null)) + // { + // components.Dispose(); + // } + // base.Dispose(disposing); + //} + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // ProcessEllipse + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(28)))), ((int)(((byte)(68))))); + this.Name = "ProcessEllipse"; + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/ProcessEllipse.cs b/JinYuan.ControlLib/ProcessEllipse.cs new file mode 100644 index 0000000..a4e0b3d --- /dev/null +++ b/JinYuan.ControlLib/ProcessEllipse.cs @@ -0,0 +1,736 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class ProcessEllipse : UserControl + { + private bool _isRefreshPending = false; + private SolidBrush _backEllipseBrush; + private SolidBrush _coreEllipseBrush; + private SolidBrush _valueBrush; + private SolidBrush _foreColorBrush; + private Pen _coreEllipsePen; + private Pen _valueArcPen; + + public ProcessEllipse() + { + InitializeComponent(); + SetStyle(ControlStyles.AllPaintingInWmPaint | + ControlStyles.DoubleBuffer | + ControlStyles.ResizeRedraw | + ControlStyles.Selectable | + ControlStyles.SupportsTransparentBackColor | + ControlStyles.UserPaint | + ControlStyles.OptimizedDoubleBuffer, true); + UpdateStyles(); + + ForeColor = Color.White; + Font = new Font("Arial Unicode MS", 20); + + InitDrawingObjects(); + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + [Description("值改变事件"), Category("自定义")] + public event EventHandler ValueChanged; + + #region 私有字段 + private Color m_backEllipseColor = Color.FromArgb(22, 160, 133); + private Color m_coreEllipseColor = Color.FromArgb(180, 180, 180); + private Color m_valueColor = Color.FromArgb(255, 77, 59); + private bool m_isShowCoreEllipseBorder = true; + private ShowType m_showType = ShowType.PPM; + private ValueType m_valueType = ValueType.Percent; + private ValueFloatOrInt m_valueFloatOrInt = ValueFloatOrInt.Int; + private int m_valueWidth = 30; + private int m_valueMargin = 5; + private int m_maxValue = 100; + private int m_intValue = 0; + private float m_floatValue = 0.00f; + private Font m_font = new Font("Arial Unicode MS", 20); + Color m_foreColor = Color.White; + private ShowStyleType m_showStyleType = ShowStyleType.Ring; + #endregion + + + #region 公共属性 + + /// + /// 圆背景色 + /// + [Description("圆背景色"), Category("自定义")] + public Color BackEllipseColor + { + get { return m_backEllipseColor; } + set + { + m_backEllipseColor = value; + //ControlRefreshExtension.RefreshWithMonitor(this); + + if (m_backEllipseColor == value) return; // 判重:值不变不刷新 + m_backEllipseColor = value; + _backEllipseBrush?.Dispose(); + _backEllipseBrush = new SolidBrush(value); + ScheduleRefresh(); // 延迟刷新 + } + } + + + /// + /// 内圆颜色,ShowType=Ring 有效 + /// + [Description("内圆颜色,ShowType=Ring 有效"), Category("自定义")] + public Color CoreEllipseColor + { + get { return m_coreEllipseColor; } + set + { + m_coreEllipseColor = value; + if (m_coreEllipseColor == value) return; + m_coreEllipseColor = value; + _coreEllipseBrush?.Dispose(); + _coreEllipseBrush = new SolidBrush(value); + ScheduleRefresh(); + } + } + + + + [Description("值圆颜色"), Category("自定义")] + public Color ValueColor + { + get { return m_valueColor; } + set + { + if (m_valueColor == value) return; + m_valueColor = value; + _valueBrush?.Dispose(); + _valueBrush = new SolidBrush(value); + _coreEllipsePen?.Dispose(); + _coreEllipsePen = new Pen(value, 2); + _valueArcPen?.Dispose(); + _valueArcPen = new Pen(value, m_valueWidth - m_valueMargin * 2); + ScheduleRefresh(); + } + } + + /// + /// 内圆是否显示边框,ShowType=Ring 有效 + /// + [Description("内圆是否显示边框,ShowType=Ring 有效"), Category("自定义")] + public bool IsShowCoreEllipseBorder + { + get { return m_isShowCoreEllipseBorder; } + set + { + if (m_isShowCoreEllipseBorder == value) return; + m_isShowCoreEllipseBorder = value; + ScheduleRefresh(); + } + } + + /// + /// 值文字类型 + /// + [Description("显示类型"), Category("自定义")] + public ShowType ShowType + { + get { return m_showType; } + set + { + if (m_showType == value) return; + m_showType = value; + UpdataMaxValue(); + ScheduleRefresh(); + } + } + + + /// + /// 值文字类型 + /// + [Description("值文字类型,Percent-百分比;Absolute-数值"), Category("自定义")] + public ValueType ValueType + { + get { return m_valueType; } + set + { + if (m_valueType == value) return; + m_valueType = value; + ScheduleRefresh(); + } + } + + + /// + /// 值文字类型 + /// + [Description("值类型"), Category("自定义")] + public ValueFloatOrInt ValueFloatOrInt + { + get { return m_valueFloatOrInt; } + set + { + if (m_valueFloatOrInt == value) return; + m_valueFloatOrInt = value; + ScheduleRefresh(); + } + } + + + /// + /// 外圆值宽度 + /// + [Description("外圆值宽度,ShowType=Ring 有效"), Category("自定义")] + public int ValueWidth + { + get { return m_valueWidth; } + set + { + if (value <= 0 || value > Math.Min(this.Width, this.Height) || m_valueWidth == value) + return; + m_valueWidth = value; + _valueArcPen?.Dispose(); + _valueArcPen = new Pen(m_valueColor, value - m_valueMargin * 2); + ScheduleRefresh(); + } + } + + /// + /// 外圆值间距 + /// + [Description("外圆值间距"), Category("自定义")] + public int ValueMargin + { + get { return m_valueMargin; } + set + { + if (value < 0 || m_valueMargin >= m_valueWidth || m_valueMargin == value) + return; + m_valueMargin = value; + _valueArcPen?.Dispose(); + _valueArcPen = new Pen(m_valueColor, m_valueWidth - value * 2); + ScheduleRefresh(); + } + } + + /// + /// 最大值 + /// + [Description("最大值"), Category("自定义")] + public int MaxValue + { + get { return m_maxValue; } + set + { + if (m_maxValue == value) return; + m_maxValue = value; + ScheduleRefresh(); + } + } + + /// + /// 当前值 + /// + [Description("当前值整数,ValueFloatOrInt=Int 有效"), Category("自定义")] + public int IntValue + { + get { return m_intValue; } + set + { + if (m_maxValue < value || value < 0 || m_intValue == value) + return; + m_intValue = value; + ValueChanged?.Invoke(this, null); // 简化事件调用 + ScheduleRefresh(); + } + } + + /// + /// 当前值 + /// + [Description("当前值浮点数,ValueFloatOrInt=Float 有效"), Category("自定义")] + public float FloatValue + { + get { return m_floatValue; } + set + { + if (m_maxValue < value || value < 0 || Math.Abs(m_floatValue - value) < 0.001f) + return; + m_floatValue = value; + ValueChanged?.Invoke(this, null); + ScheduleRefresh(); + } + } + + [Description("文字字体"), Category("自定义")] + public override Font Font + { + get + { + return m_font; + } + set + { + if (m_font == value) return; + m_font?.Dispose(); // 释放旧字体 + m_font = value; + ScheduleRefresh(); + } + } + + [Description("文字颜色"), Category("自定义")] + public override Color ForeColor + { + get + { + return m_foreColor; + } + set + { + if (m_foreColor == value) return; + m_foreColor = value; + _foreColorBrush?.Dispose(); + _foreColorBrush = new SolidBrush(value); + ScheduleRefresh(); + } + } + + + [Description("显示样式"), Category("自定义")] + public ShowStyleType ShowStyleType + { + get { return m_showStyleType; } + set + { + if (m_showStyleType == value) return; + m_showStyleType = value; + ScheduleRefresh(); + } + } + + #endregion + + ///// + ///// 更新最大值 + ///// + //private void UpdataMaxValue() + //{ + // switch (m_showType) + // { + // case ShowType.PPM: + // this.m_maxValue = 100; + // break; + // case ShowType.稼动率: + // this.m_maxValue = 100; + // break; + // } + + //} + + + //protected override void OnPaint(PaintEventArgs e) + //{ + // base.OnPaint(e); + + // var g = e.Graphics; + // g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿 + // g.InterpolationMode = InterpolationMode.HighQualityBicubic; + // g.CompositingQuality = CompositingQuality.HighQuality; + + // int intWidth = Math.Min(this.Size.Width, this.Size.Height); + // //底圆 + // g.FillEllipse(new SolidBrush(m_backEllipseColor), new Rectangle(new Point(0, 0), new Size(intWidth, intWidth))); + // if (m_showStyleType == ShowStyleType.Ring) + // { + // //中心圆 + // int intCore = intWidth - m_valueWidth * 2; + // g.FillEllipse(new SolidBrush(m_coreEllipseColor), new Rectangle(new Point(m_valueWidth, m_valueWidth), new Size(intCore, intCore))); + // //中心圆边框 + // if (m_isShowCoreEllipseBorder) + // { + // g.DrawEllipse(new Pen(m_valueColor, 2), new Rectangle(new Point(m_valueWidth + 1, m_valueWidth + 1), new Size(intCore - 1, intCore - 1))); + // } + // if (m_valueFloatOrInt == ValueFloatOrInt.Int) + // { + // if (m_intValue >= 0 && m_maxValue > 0) + // { + // int fltPercent = (int)m_intValue / (int)m_maxValue; + // if (fltPercent > 1) + // { + // fltPercent = 1; + // } + + // g.DrawArc(new Pen(m_valueColor, m_valueWidth - m_valueMargin * 2), new RectangleF(new Point(m_valueWidth / 2 + m_valueMargin / 4, m_valueWidth / 2 + m_valueMargin / 4), new SizeF(intWidth - m_valueWidth - m_valueMargin / 2 + (m_valueMargin == 0 ? 0 : 1), intWidth - m_valueWidth - m_valueMargin / 2 + (m_valueMargin == 0 ? 0 : 1))), -90, fltPercent * 360); + + // string strValueText = m_valueType == ValueType.Percent ? fltPercent.ToString("0%") : m_intValue.ToString(); + // System.Drawing.SizeF _txtSize = g.MeasureString(strValueText, this.Font); + // g.DrawString(strValueText, this.Font, new SolidBrush(this.ForeColor), new PointF((intWidth - _txtSize.Width) / 2 + 1, (intWidth - _txtSize.Height) / 2 + 1)); + // } + // } + // else + // { + // if (m_floatValue >= 0 && m_maxValue > 0) + // { + // float fltPercent = (float)m_floatValue / (float)m_maxValue; + // if (fltPercent > 1f) + // { + // fltPercent = 1f; + // } + + // g.DrawArc(new Pen(m_valueColor, m_valueWidth - m_valueMargin * 2), new RectangleF(new Point(m_valueWidth / 2 + m_valueMargin / 4, m_valueWidth / 2 + m_valueMargin / 4), new SizeF(intWidth - m_valueWidth - m_valueMargin / 2 + (m_valueMargin == 0 ? 0 : 1), intWidth - m_valueWidth - m_valueMargin / 2 + (m_valueMargin == 0 ? 0 : 1))), -90, fltPercent * 360); + // string strValueText = m_valueType == ValueType.Percent ? fltPercent.ToString("0%") : m_floatValue.ToString("f2"); + // System.Drawing.SizeF _txtSize = g.MeasureString(strValueText, this.Font); + // g.DrawString(strValueText, this.Font, new SolidBrush(this.ForeColor), new PointF((intWidth - _txtSize.Width) / 2 + 1, (intWidth - _txtSize.Height) / 2 + 1)); + // } + // } + + // } + // else + // { + // if (m_valueFloatOrInt == ValueFloatOrInt.Int) + // { + // if (m_intValue >= 0 && m_maxValue > 0) + // { + // int fltPercent = (int)m_intValue / (int)m_maxValue; + // if (fltPercent > 1) + // { + // fltPercent = 1; + // } + + // g.FillPie(new SolidBrush(m_valueColor), new Rectangle(m_valueMargin, m_valueMargin, intWidth - m_valueMargin * 2, intWidth - m_valueMargin * 2), -90, fltPercent * 360); + + // string strValueText = m_valueType == ValueType.Percent ? fltPercent.ToString("0%") : m_intValue.ToString(); + // System.Drawing.SizeF _txtSize = g.MeasureString(strValueText, this.Font); + // g.DrawString(strValueText, this.Font, new SolidBrush(this.ForeColor), new PointF((intWidth - _txtSize.Width) / 2 + 1, (intWidth - _txtSize.Height) / 2 + 1)); + // } + // } + // else + // { + // if (m_floatValue >= 0 && m_maxValue > 0) + // { + // float fltPercent = (float)m_floatValue / (float)m_maxValue; + // if (fltPercent > 1f) + // { + // fltPercent = 1f; + // } + + // g.FillPie(new SolidBrush(m_valueColor), new Rectangle(m_valueMargin, m_valueMargin, intWidth - m_valueMargin * 2, intWidth - m_valueMargin * 2), -90, fltPercent * 360); + // string strValueText = m_valueType == ValueType.Percent ? fltPercent.ToString("0%") : m_floatValue.ToString("f2"); + // System.Drawing.SizeF _txtSize = g.MeasureString(strValueText, this.Font); + // g.DrawString(strValueText, this.Font, new SolidBrush(this.ForeColor), new PointF((intWidth - _txtSize.Width) / 2 + 1, (intWidth - _txtSize.Height) / 2 + 1)); + // } + // } + + // } + + #region 核心优化方法 + /// + /// 初始化绘图对象 + /// + private void InitDrawingObjects() + { + _backEllipseBrush = new SolidBrush(m_backEllipseColor); + _coreEllipseBrush = new SolidBrush(m_coreEllipseColor); + _valueBrush = new SolidBrush(m_valueColor); + _foreColorBrush = new SolidBrush(m_foreColor); + _coreEllipsePen = new Pen(m_valueColor, 2); + _valueArcPen = new Pen(m_valueColor, m_valueWidth - m_valueMargin * 2); + } + + /// + /// 延迟刷新 + /// + private void ScheduleRefresh() + { + if (_isRefreshPending) return; + _isRefreshPending = true; + + // 先判断控件句柄是否已创建 + if (!this.IsHandleCreated) + { + // 句柄未创建时: + // 1. 注册句柄创建完成的事件,创建后再刷新 + this.HandleCreated += ProcessEllipse_HandleCreated; + // 2. 直接调用Invalidate(句柄未创建时Invalidate无副作用) + this.Invalidate(); + _isRefreshPending = false; + return; + } + + // 句柄已创建时,使用BeginInvoke延迟刷新 + try + { + this.BeginInvoke(new Action(() => + { + // 双重校验:避免跨线程/句柄释放导致的异常 + if (this.IsDisposed || !this.IsHandleCreated) + { + _isRefreshPending = false; + return; + } + + this.Invalidate(); + _isRefreshPending = false; + })); + } + catch (ObjectDisposedException) + { + // 控件已释放时,重置标识 + _isRefreshPending = false; + } + } + + /// + /// 句柄创建完成后触发的刷新逻辑 + /// + private void ProcessEllipse_HandleCreated(object sender, EventArgs e) + { + // 取消事件注册,避免重复触发 + this.HandleCreated -= ProcessEllipse_HandleCreated; + // 句柄创建完成后,执行一次刷新 + if (!_isRefreshPending) + { + this.Invalidate(); + } + } + + /// + /// 更新最大值 + /// + private void UpdataMaxValue() + { + switch (m_showType) + { + case ShowType.PPM: + case ShowType.稼动率: + m_maxValue = 100; + break; + } + } + #endregion + + #region 重写OnPaint(复用绘图对象 + 优化逻辑) + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + var g = e.Graphics; + // 优化绘图质量(只设置一次,避免重复赋值) + g.SmoothingMode = SmoothingMode.AntiAlias; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.CompositingQuality = CompositingQuality.HighQuality; + g.Clear(BackColor); // 统一清背景,减少闪烁 + + int intWidth = Math.Min(Size.Width, Size.Height); + if (intWidth == 0) return; // 避免除以0 + + // 绘制底圆(复用画刷) + g.FillEllipse(_backEllipseBrush, new Rectangle(0, 0, intWidth, intWidth)); + + if (m_showStyleType == ShowStyleType.Ring) + { + // 绘制中心圆(复用画刷) + int intCore = intWidth - m_valueWidth * 2; + g.FillEllipse(_coreEllipseBrush, new Rectangle(m_valueWidth, m_valueWidth, intCore, intCore)); + + // 绘制中心圆边框(复用画笔) + if (m_isShowCoreEllipseBorder) + { + g.DrawEllipse(_coreEllipsePen, new Rectangle(m_valueWidth + 1, m_valueWidth + 1, intCore - 1, intCore - 1)); + } + + // 绘制数值圆弧/文字 + DrawValueContent(g, intWidth); + } + else + { + // 绘制扇形样式 + DrawSectorContent(g, intWidth); + } + } + + /// + /// 绘制圆环样式的数值内容(复用逻辑) + /// + private void DrawValueContent(Graphics g, int intWidth) + { + float percent = 0f; + string strValueText = string.Empty; + + if (m_valueFloatOrInt == ValueFloatOrInt.Int) + { + if (m_intValue >= 0 && m_maxValue > 0) + { + percent = (float)m_intValue / m_maxValue; + percent = Math.Min(percent, 1f); + strValueText = m_valueType == ValueType.Percent ? percent.ToString("0%") : m_intValue.ToString(); + } + } + else + { + if (m_floatValue >= 0 && m_maxValue > 0) + { + percent = m_floatValue / m_maxValue; + percent = Math.Min(percent, 1f); + strValueText = m_valueType == ValueType.Percent ? percent.ToString("0%") : m_floatValue.ToString("f2"); + } + } + + // 绘制圆弧(复用画笔) + if (percent > 0) + { + var arcRect = new RectangleF( + m_valueWidth / 2 + m_valueMargin / 4, + m_valueWidth / 2 + m_valueMargin / 4, + intWidth - m_valueWidth - m_valueMargin / 2 + (m_valueMargin == 0 ? 0 : 1), + intWidth - m_valueWidth - m_valueMargin / 2 + (m_valueMargin == 0 ? 0 : 1)); + g.DrawArc(_valueArcPen, arcRect, -90, percent * 360); + } + + // 绘制文字(复用画刷) + if (!string.IsNullOrEmpty(strValueText)) + { + var txtSize = g.MeasureString(strValueText, Font); + g.DrawString(strValueText, Font, _foreColorBrush, + (intWidth - txtSize.Width) / 2 + 1, + (intWidth - txtSize.Height) / 2 + 1); + } + } + + /// + /// 绘制扇形样式的数值内容(复用逻辑) + /// + private void DrawSectorContent(Graphics g, int intWidth) + { + float percent = 0f; + string strValueText = string.Empty; + + if (m_valueFloatOrInt == ValueFloatOrInt.Int) + { + if (m_intValue >= 0 && m_maxValue > 0) + { + percent = (float)m_intValue / m_maxValue; + percent = Math.Min(percent, 1f); + strValueText = m_valueType == ValueType.Percent ? percent.ToString("0%") : m_intValue.ToString(); + } + } + else + { + if (m_floatValue >= 0 && m_maxValue > 0) + { + percent = m_floatValue / m_maxValue; + percent = Math.Min(percent, 1f); + strValueText = m_valueType == ValueType.Percent ? percent.ToString("0%") : m_floatValue.ToString("f2"); + } + } + + // 绘制扇形(复用画刷) + if (percent > 0) + { + var pieRect = new Rectangle(m_valueMargin, m_valueMargin, + intWidth - m_valueMargin * 2, intWidth - m_valueMargin * 2); + g.FillPie(_valueBrush, pieRect, -90, percent * 360); + } + + // 绘制文字(复用画刷) + if (!string.IsNullOrEmpty(strValueText)) + { + var txtSize = g.MeasureString(strValueText, Font); + g.DrawString(strValueText, Font, _foreColorBrush, + (intWidth - txtSize.Width) / 2 + 1, + (intWidth - txtSize.Height) / 2 + 1); + } + } + #endregion + + #region 释放资源(避免内存泄漏) + protected override void Dispose(bool disposing) + { + if (disposing) + { + // 释放缓存的绘图对象 + _backEllipseBrush?.Dispose(); + _coreEllipseBrush?.Dispose(); + _valueBrush?.Dispose(); + _foreColorBrush?.Dispose(); + _coreEllipsePen?.Dispose(); + _valueArcPen?.Dispose(); + m_font?.Dispose(); // 释放字体 + components?.Dispose(); + } + base.Dispose(disposing); + } + #endregion + + } + + + public enum ShowType + { + /// + /// PPM + /// + PPM, + /// + /// 数值 + /// + 稼动率, + /// + /// + /// + 生产数 + } + + + public enum ValueType + { + /// + /// 百分比 + /// + Percent, + /// + /// 数值 + /// + Absolute + } + + public enum ValueFloatOrInt + { + /// + /// 整数 + /// + Int, + /// + /// 浮点数 + /// + Float + } + + public enum ShowStyleType + { + /// + /// 圆环 + /// + Ring, + /// + /// 扇形 + /// + Sector + } +} diff --git a/JinYuan.ControlLib/ProcessEllipse.resx b/JinYuan.ControlLib/ProcessEllipse.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/ProcessEllipse.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Properties/AssemblyInfo.cs b/JinYuan.ControlLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..870604b --- /dev/null +++ b/JinYuan.ControlLib/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.ControlLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.ControlLib")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("1bb7ed33-d2cb-4cdd-ab39-f7f9ae948ca2")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.ControlLib/Properties/Resources.Designer.cs b/JinYuan.ControlLib/Properties/Resources.Designer.cs new file mode 100644 index 0000000..9787750 --- /dev/null +++ b/JinYuan.ControlLib/Properties/Resources.Designer.cs @@ -0,0 +1,433 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace JinYuan.ControlLib.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("JinYuan.ControlLib.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap _2bg { + get { + object obj = ResourceManager.GetObject("2bg", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap _4 { + get { + object obj = ResourceManager.GetObject("4", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap _6 { + get { + object obj = ResourceManager.GetObject("6", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap _61 { + get { + object obj = ResourceManager.GetObject("61", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap bg2 { + get { + object obj = ResourceManager.GetObject("bg2", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap big_arrow { + get { + object obj = ResourceManager.GetObject("big_arrow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap big_arrow_l { + get { + object obj = ResourceManager.GetObject("big_arrow_l", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap big_box { + get { + object obj = ResourceManager.GetObject("big_box", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap big_box_l { + get { + object obj = ResourceManager.GetObject("big_box_l", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap big_box_s { + get { + object obj = ResourceManager.GetObject("big_box_s", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap big_box_super { + get { + object obj = ResourceManager.GetObject("big_box_super", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap caret_down { + get { + object obj = ResourceManager.GetObject("caret_down", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap caret_right { + get { + object obj = ResourceManager.GetObject("caret_right", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Green { + get { + object obj = ResourceManager.GetObject("Green", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap LeftSelected { + get { + object obj = ResourceManager.GetObject("LeftSelected", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap LeftSelected3 { + get { + object obj = ResourceManager.GetObject("LeftSelected3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap LeftUnSelected { + get { + object obj = ResourceManager.GetObject("LeftUnSelected", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap LeftUnSelected2 { + get { + object obj = ResourceManager.GetObject("LeftUnSelected2", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap LeftUnSelected3 { + get { + object obj = ResourceManager.GetObject("LeftUnSelected3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap loading { + get { + object obj = ResourceManager.GetObject("loading", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Red { + get { + object obj = ResourceManager.GetObject("Red", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap RightSelected { + get { + object obj = ResourceManager.GetObject("RightSelected", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap RightSelected3 { + get { + object obj = ResourceManager.GetObject("RightSelected3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap RightUnSelected { + get { + object obj = ResourceManager.GetObject("RightUnSelected", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap RightUnSelected2 { + get { + object obj = ResourceManager.GetObject("RightUnSelected2", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap RightUnSelected3 { + get { + object obj = ResourceManager.GetObject("RightUnSelected3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Title { + get { + object obj = ResourceManager.GetObject("Title", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap TotalQty { + get { + object obj = ResourceManager.GetObject("TotalQty", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 开机时间 { + get { + object obj = ResourceManager.GetObject("开机时间", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 数字指标 { + get { + object obj = ResourceManager.GetObject("数字指标", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 星球地球科技蓝色转动动图压缩86_9 { + get { + object obj = ResourceManager.GetObject("星球地球科技蓝色转动动图压缩86.9", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 标题_03右 { + get { + object obj = ResourceManager.GetObject("标题_03右", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 标题_03左 { + get { + object obj = ResourceManager.GetObject("标题_03左", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 标题_04 { + get { + object obj = ResourceManager.GetObject("标题_04", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 组_178_拷贝 { + get { + object obj = ResourceManager.GetObject("组 178 拷贝", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 蓝色 { + get { + object obj = ResourceManager.GetObject("蓝色", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 运行时间 { + get { + object obj = ResourceManager.GetObject("运行时间", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JinYuan.ControlLib/Properties/Resources.resx b/JinYuan.ControlLib/Properties/Resources.resx new file mode 100644 index 0000000..e8df2ca --- /dev/null +++ b/JinYuan.ControlLib/Properties/Resources.resx @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\2bg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\6.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\61.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\bg2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\big_arrow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\big_arrow_l.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\big_box.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\big_box_l.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\big_box_s.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\big_box_super.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\caret-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\caret-right.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Green.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LeftSelected.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LeftSelected3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LeftUnSelected.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LeftUnSelected2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LeftUnSelected3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\loading.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Red.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\RightSelected.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\RightSelected3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\RightUnSelected.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\常规按钮.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\RightUnSelected3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Title.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\TotalQty.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\开机时间.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\数字指标.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\星球地球科技蓝色转动动图压缩86.9.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\标题_03右.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\标题_03.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\标题_04.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\组 178 拷贝.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\蓝色.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\运行时间.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Resources/2bg.png b/JinYuan.ControlLib/Resources/2bg.png new file mode 100644 index 0000000..56b8ae0 Binary files /dev/null and b/JinYuan.ControlLib/Resources/2bg.png differ diff --git a/JinYuan.ControlLib/Resources/4.png b/JinYuan.ControlLib/Resources/4.png new file mode 100644 index 0000000..5d6c438 Binary files /dev/null and b/JinYuan.ControlLib/Resources/4.png differ diff --git a/JinYuan.ControlLib/Resources/6.png b/JinYuan.ControlLib/Resources/6.png new file mode 100644 index 0000000..c9c4858 Binary files /dev/null and b/JinYuan.ControlLib/Resources/6.png differ diff --git a/JinYuan.ControlLib/Resources/61.png b/JinYuan.ControlLib/Resources/61.png new file mode 100644 index 0000000..c9c4858 Binary files /dev/null and b/JinYuan.ControlLib/Resources/61.png differ diff --git a/JinYuan.ControlLib/Resources/Green.png b/JinYuan.ControlLib/Resources/Green.png new file mode 100644 index 0000000..783d0fb Binary files /dev/null and b/JinYuan.ControlLib/Resources/Green.png differ diff --git a/JinYuan.ControlLib/Resources/LeftSelected.png b/JinYuan.ControlLib/Resources/LeftSelected.png new file mode 100644 index 0000000..09cfb6d Binary files /dev/null and b/JinYuan.ControlLib/Resources/LeftSelected.png differ diff --git a/JinYuan.ControlLib/Resources/LeftSelected3.png b/JinYuan.ControlLib/Resources/LeftSelected3.png new file mode 100644 index 0000000..561b10b Binary files /dev/null and b/JinYuan.ControlLib/Resources/LeftSelected3.png differ diff --git a/JinYuan.ControlLib/Resources/LeftUnSelected.png b/JinYuan.ControlLib/Resources/LeftUnSelected.png new file mode 100644 index 0000000..b024137 Binary files /dev/null and b/JinYuan.ControlLib/Resources/LeftUnSelected.png differ diff --git a/JinYuan.ControlLib/Resources/LeftUnSelected2.png b/JinYuan.ControlLib/Resources/LeftUnSelected2.png new file mode 100644 index 0000000..e08c43d Binary files /dev/null and b/JinYuan.ControlLib/Resources/LeftUnSelected2.png differ diff --git a/JinYuan.ControlLib/Resources/LeftUnSelected3.png b/JinYuan.ControlLib/Resources/LeftUnSelected3.png new file mode 100644 index 0000000..93d36e8 Binary files /dev/null and b/JinYuan.ControlLib/Resources/LeftUnSelected3.png differ diff --git a/JinYuan.ControlLib/Resources/Red.png b/JinYuan.ControlLib/Resources/Red.png new file mode 100644 index 0000000..6fc76cd Binary files /dev/null and b/JinYuan.ControlLib/Resources/Red.png differ diff --git a/JinYuan.ControlLib/Resources/RightSelected.png b/JinYuan.ControlLib/Resources/RightSelected.png new file mode 100644 index 0000000..819cf76 Binary files /dev/null and b/JinYuan.ControlLib/Resources/RightSelected.png differ diff --git a/JinYuan.ControlLib/Resources/RightSelected3.png b/JinYuan.ControlLib/Resources/RightSelected3.png new file mode 100644 index 0000000..5de3c7d Binary files /dev/null and b/JinYuan.ControlLib/Resources/RightSelected3.png differ diff --git a/JinYuan.ControlLib/Resources/RightUnSelected.png b/JinYuan.ControlLib/Resources/RightUnSelected.png new file mode 100644 index 0000000..9196206 Binary files /dev/null and b/JinYuan.ControlLib/Resources/RightUnSelected.png differ diff --git a/JinYuan.ControlLib/Resources/RightUnSelected3.png b/JinYuan.ControlLib/Resources/RightUnSelected3.png new file mode 100644 index 0000000..16e61bb Binary files /dev/null and b/JinYuan.ControlLib/Resources/RightUnSelected3.png differ diff --git a/JinYuan.ControlLib/Resources/Title.png b/JinYuan.ControlLib/Resources/Title.png new file mode 100644 index 0000000..38a87f7 Binary files /dev/null and b/JinYuan.ControlLib/Resources/Title.png differ diff --git a/JinYuan.ControlLib/Resources/TotalQty.png b/JinYuan.ControlLib/Resources/TotalQty.png new file mode 100644 index 0000000..45e6493 Binary files /dev/null and b/JinYuan.ControlLib/Resources/TotalQty.png differ diff --git a/JinYuan.ControlLib/Resources/bg2.png b/JinYuan.ControlLib/Resources/bg2.png new file mode 100644 index 0000000..4210157 Binary files /dev/null and b/JinYuan.ControlLib/Resources/bg2.png differ diff --git a/JinYuan.ControlLib/Resources/big_arrow.png b/JinYuan.ControlLib/Resources/big_arrow.png new file mode 100644 index 0000000..b97d348 Binary files /dev/null and b/JinYuan.ControlLib/Resources/big_arrow.png differ diff --git a/JinYuan.ControlLib/Resources/big_arrow_l.png b/JinYuan.ControlLib/Resources/big_arrow_l.png new file mode 100644 index 0000000..fab7f74 Binary files /dev/null and b/JinYuan.ControlLib/Resources/big_arrow_l.png differ diff --git a/JinYuan.ControlLib/Resources/big_box.png b/JinYuan.ControlLib/Resources/big_box.png new file mode 100644 index 0000000..c803f2d Binary files /dev/null and b/JinYuan.ControlLib/Resources/big_box.png differ diff --git a/JinYuan.ControlLib/Resources/big_box_l.png b/JinYuan.ControlLib/Resources/big_box_l.png new file mode 100644 index 0000000..a8c8097 Binary files /dev/null and b/JinYuan.ControlLib/Resources/big_box_l.png differ diff --git a/JinYuan.ControlLib/Resources/big_box_s.png b/JinYuan.ControlLib/Resources/big_box_s.png new file mode 100644 index 0000000..d9cb1ac Binary files /dev/null and b/JinYuan.ControlLib/Resources/big_box_s.png differ diff --git a/JinYuan.ControlLib/Resources/big_box_super.png b/JinYuan.ControlLib/Resources/big_box_super.png new file mode 100644 index 0000000..d9bcfa5 Binary files /dev/null and b/JinYuan.ControlLib/Resources/big_box_super.png differ diff --git a/JinYuan.ControlLib/Resources/caret-down.png b/JinYuan.ControlLib/Resources/caret-down.png new file mode 100644 index 0000000..d45d9ca Binary files /dev/null and b/JinYuan.ControlLib/Resources/caret-down.png differ diff --git a/JinYuan.ControlLib/Resources/caret-right.png b/JinYuan.ControlLib/Resources/caret-right.png new file mode 100644 index 0000000..90ff769 Binary files /dev/null and b/JinYuan.ControlLib/Resources/caret-right.png differ diff --git a/JinYuan.ControlLib/Resources/loading.gif b/JinYuan.ControlLib/Resources/loading.gif new file mode 100644 index 0000000..42c22fe Binary files /dev/null and b/JinYuan.ControlLib/Resources/loading.gif differ diff --git a/JinYuan.ControlLib/Resources/常规按钮.png b/JinYuan.ControlLib/Resources/常规按钮.png new file mode 100644 index 0000000..7304ff0 Binary files /dev/null and b/JinYuan.ControlLib/Resources/常规按钮.png differ diff --git a/JinYuan.ControlLib/Resources/开机时间.png b/JinYuan.ControlLib/Resources/开机时间.png new file mode 100644 index 0000000..6accedc Binary files /dev/null and b/JinYuan.ControlLib/Resources/开机时间.png differ diff --git a/JinYuan.ControlLib/Resources/数字指标.png b/JinYuan.ControlLib/Resources/数字指标.png new file mode 100644 index 0000000..7095056 Binary files /dev/null and b/JinYuan.ControlLib/Resources/数字指标.png differ diff --git a/JinYuan.ControlLib/Resources/星球地球科技蓝色转动动图压缩86.9.gif b/JinYuan.ControlLib/Resources/星球地球科技蓝色转动动图压缩86.9.gif new file mode 100644 index 0000000..f913149 Binary files /dev/null and b/JinYuan.ControlLib/Resources/星球地球科技蓝色转动动图压缩86.9.gif differ diff --git a/JinYuan.ControlLib/Resources/标题_03.png b/JinYuan.ControlLib/Resources/标题_03.png new file mode 100644 index 0000000..a3ec442 Binary files /dev/null and b/JinYuan.ControlLib/Resources/标题_03.png differ diff --git a/JinYuan.ControlLib/Resources/标题_03右.png b/JinYuan.ControlLib/Resources/标题_03右.png new file mode 100644 index 0000000..487bff7 Binary files /dev/null and b/JinYuan.ControlLib/Resources/标题_03右.png differ diff --git a/JinYuan.ControlLib/Resources/标题_04.png b/JinYuan.ControlLib/Resources/标题_04.png new file mode 100644 index 0000000..1da05f1 Binary files /dev/null and b/JinYuan.ControlLib/Resources/标题_04.png differ diff --git a/JinYuan.ControlLib/Resources/组 178 拷贝.png b/JinYuan.ControlLib/Resources/组 178 拷贝.png new file mode 100644 index 0000000..08ce660 Binary files /dev/null and b/JinYuan.ControlLib/Resources/组 178 拷贝.png differ diff --git a/JinYuan.ControlLib/Resources/蓝色.png b/JinYuan.ControlLib/Resources/蓝色.png new file mode 100644 index 0000000..17a67a4 Binary files /dev/null and b/JinYuan.ControlLib/Resources/蓝色.png differ diff --git a/JinYuan.ControlLib/Resources/运行时间.png b/JinYuan.ControlLib/Resources/运行时间.png new file mode 100644 index 0000000..630649a Binary files /dev/null and b/JinYuan.ControlLib/Resources/运行时间.png differ diff --git a/JinYuan.ControlLib/ScrollBar/ScrollbarComponent.cs b/JinYuan.ControlLib/ScrollBar/ScrollbarComponent.cs new file mode 100644 index 0000000..494b82e --- /dev/null +++ b/JinYuan.ControlLib/ScrollBar/ScrollbarComponent.cs @@ -0,0 +1,829 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.ScrollBar +{ + [ProvideProperty("UserCustomScrollbar", typeof(Control))] + public class ScrollbarComponent : Component, IExtenderProvider + { + public ScrollbarComponent() + { + + } + + public ScrollbarComponent(IContainer container) + { + container.Add(this); + } + + Dictionary m_controlCache = new Dictionary(); + public bool CanExtend(object extendee) + { + if (extendee is ScrollableControl) + { + ScrollableControl control = (ScrollableControl)extendee; + if (control.AutoScroll == true) + { + return true; + } + } + else if (extendee is TreeView) + { + TreeView control = (TreeView)extendee; + if (control.Scrollable) + { + return true; + } + } + else if (extendee is TextBox) + { + TextBox control = (TextBox)extendee; + if (control.Multiline && control.ScrollBars != ScrollBars.None) + { + return true; + } + } + else if (extendee is RichTextBox) + { + return true; + } + else if (extendee is ListBox) + { + return true; + } + //else if (extendee is ListView) + //{ + // return true; + //} + else if (extendee is DataGridView) + { + return true; + } + return false; + } + + [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)] + public bool GetUserCustomScrollbar(Control control) + { + if (m_controlCache.ContainsKey(control)) + return m_controlCache[control]; + return true; + } + + public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar) + { + m_controlCache[control] = blnUserCustomScrollbar; + if (!blnUserCustomScrollbar) + return; + + if (control is TreeView) + { + TreeView tv = (TreeView)control; + //tv.MouseWheel += tv_MouseWheel; + //tv.AfterSelect += tv_AfterSelect; + tv.AfterExpand += tv_AfterExpand; + tv.AfterCollapse += tv_AfterCollapse; + } + else if (control is TextBox) + { + TextBox txt = (TextBox)control; + //txt.MouseWheel += txt_MouseWheel; + txt.TextChanged += txt_TextChanged; + txt.KeyDown += txt_KeyDown; + } + else if (control is RichTextBox) + { + RichTextBox txt = (RichTextBox)control; + //txt.MouseWheel += txt_MouseWheel; + txt.TextChanged += txt_TextChanged; + txt.KeyDown += txt_KeyDown; + } + else if (control is ListBox) + { + ListBox lb = (ListBox)control; + lb.DataSourceChanged += Lb_DataSourceChanged; + lb.SelectedIndexChanged += Lb_SelectedIndexChanged; + } + //else if (control is ListView) + //{ + // ListView lv = (ListView)control; + + //} + else if (control is DataGridView) + { + DataGridView dgv = (DataGridView)control; + dgv.DataSourceChanged += dgv_DataSourceChanged; + dgv.RowsAdded += dgv_RowsAdded; + dgv.RowsRemoved += dgv_RowsRemoved; + dgv.Scroll += dgv_Scroll; + } + + control.VisibleChanged += control_VisibleChanged; + control.SizeChanged += control_SizeChanged; + control.LocationChanged += control_LocationChanged; + control.Disposed += control_Disposed; + control.MouseWheel += Control_MouseWheel; + control_SizeChanged(control, null); + } + + void dgv_Scroll(object sender, ScrollEventArgs e) + { + if (e.NewValue == e.OldValue) + return; + DataGridView dgv = (DataGridView)sender; + if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) + { + if (m_lstHCache.ContainsKey(dgv)) + { + m_lstHCache[dgv].Value = e.NewValue; + } + } + else if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) + { + if (m_lstVCache.ContainsKey(dgv)) + { + m_lstVCache[dgv].Value = e.NewValue; + } + } + } + + void dgv_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e) + { + Control control = sender as Control; + control_SizeChanged(control, null); + } + + void dgv_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) + { + Control control = sender as Control; + control_SizeChanged(control, null); + } + + void dgv_DataSourceChanged(object sender, EventArgs e) + { + Control control = sender as Control; + control_SizeChanged(control, null); + } + + private void Lb_SelectedIndexChanged(object sender, EventArgs e) + { + Control c = sender as Control; + SetVMaxNum(c); + } + + private void Lb_DataSourceChanged(object sender, EventArgs e) + { + Control c = sender as Control; + control_SizeChanged(c, null); + } + + private void Control_MouseWheel(object sender, MouseEventArgs e) + { + Control c = (Control)sender; + if (m_lstVCache.ContainsKey(c)) + { + if (e.Delta > 5) + { + ControlHelper.ScrollUp(c.Handle); + } + else if (e.Delta < -5) + { + ControlHelper.ScrollDown(c.Handle); + } + + SetVMaxNum(c); + } + else if (m_lstHCache.ContainsKey(c)) + { + if (e.Delta > 5) + { + ControlHelper.ScrollLeft(c.Handle); + } + else if (e.Delta < -5) + { + ControlHelper.ScrollRight(c.Handle); + } + + SetHMaxNum(c); + } + } + + void control_Disposed(object sender, EventArgs e) + { + Control control = (Control)sender; + if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) + { + m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); + m_lstVCache.Remove(control); + } + } + + void control_LocationChanged(object sender, EventArgs e) + { + ResetScrollLocation(sender); + } + + void control_SizeChanged(object sender, EventArgs e) + { + if (ControlHelper.IsDesignMode()) + { + return; + } + else + { + var control = sender as Control; + + bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; + bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; + if (control is TextBox) + { + var txt = (TextBox)control; + if (txt.ScrollBars == ScrollBars.Both) + { + blnHasVScrollbar = true; + blnHasHScrollbar = true; + } + else if (txt.ScrollBars == ScrollBars.Vertical) + { + blnHasVScrollbar = true; + blnHasHScrollbar = false; + } + else if (txt.ScrollBars == ScrollBars.Horizontal) + { + blnHasVScrollbar = false; + blnHasHScrollbar = true; + } + else + { + blnHasVScrollbar = false; + blnHasHScrollbar = false; + } + } + else if (control is DataGridView) + { + var dgv = (DataGridView)control; + if (dgv.ScrollBars == ScrollBars.Both || dgv.ScrollBars == ScrollBars.Vertical) + { + int _height = dgv.RowTemplate.Height * dgv.Rows.Count; + if (dgv.ColumnHeadersVisible) + { + _height += dgv.ColumnHeadersHeight; + } + blnHasVScrollbar = _height > dgv.Height; + } + if (dgv.ScrollBars == ScrollBars.Both || dgv.ScrollBars == ScrollBars.Horizontal) + { + int _width = 0; + foreach (DataGridViewColumn com in dgv.Columns) + { + _width += com.Width; + } + if (dgv.RowHeadersVisible) + { + _width += dgv.RowHeadersWidth; + } + blnHasHScrollbar = _width > dgv.Width; + } + } + else if (control is ListView) + { + if (!((ListView)control).Scrollable) + { + blnHasVScrollbar = false; + blnHasHScrollbar = false; + } + } + if (blnHasVScrollbar) + { + if (!m_lstVCache.ContainsKey(control)) + { + if (control.Parent != null) + { + UCVScrollbar barV = new UCVScrollbar(); + barV.SmallChange = 5; + barV.Width = SystemInformation.VerticalScrollBarWidth + 1; + barV.Scroll += barV_Scroll; + m_lstVCache[control] = barV; + if (blnHasHScrollbar) + { + barV.Height = control.Height - barV.Width; + } + else + { + barV.Height = control.Height; + } + SetVMaxNum(control); + barV.Location = new System.Drawing.Point(control.Right - barV.Width, control.Top); + control.Parent.Controls.Add(barV); + int intControlIndex = control.Parent.Controls.GetChildIndex(control); + control.Parent.Controls.SetChildIndex(barV, intControlIndex); + } + } + else + { + if (blnHasHScrollbar) + { + m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width; + } + else + { + m_lstVCache[control].Height = control.Height; + } + SetVMaxNum(control); + } + } + else + { + if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) + { + m_lstVCache[control].Visible = false; + } + } + + if (blnHasHScrollbar) + { + if (!m_lstHCache.ContainsKey(control)) + { + if (control.Parent != null) + { + UCHScrollbar barH = new UCHScrollbar(); + barH.Height = SystemInformation.HorizontalScrollBarHeight + 1; + barH.SmallChange = 5; + + barH.Scroll += barH_Scroll; + m_lstHCache[control] = barH; + if (blnHasHScrollbar) + { + barH.Width = control.Width - barH.Height; + } + else + { + barH.Width = control.Width; + } + SetHMaxNum(control); + barH.Location = new System.Drawing.Point(control.Left, control.Bottom - barH.Height); + control.Parent.Controls.Add(barH); + int intControlIndex = control.Parent.Controls.GetChildIndex(control); + control.Parent.Controls.SetChildIndex(barH, intControlIndex); + } + } + else + { + if (blnHasHScrollbar) + { + m_lstHCache[control].Width = control.Width - m_lstHCache[control].Height; + } + else + { + m_lstHCache[control].Width = control.Width; + } + SetHMaxNum(control); + } + } + else + { + if (m_lstHCache.ContainsKey(control)) + { + if (m_lstHCache[control].Visible && m_lstHCache[control].Parent != null) + { + m_lstHCache[control].Visible = false; + } + } + } + } + ResetScrollLocation(sender); + } + + + private void SetVMaxNum(Control control) + { + if (!m_lstVCache.ContainsKey(control)) + return; + var intoV = ControlHelper.GetVScrollBarInfo(control.Handle); + UCVScrollbar barV = m_lstVCache[control]; + if (control is ScrollableControl) + { + barV.Maximum = intoV.ScrollMax; + barV.Visible = intoV.ScrollMax > 0 && intoV.nMax > 0 && intoV.nPage > 0; + barV.Value = intoV.nPos; + barV.BringToFront(); + // barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum; + // barV.Value = (control as ScrollableControl).VerticalScroll.Value; + } + else if (control is TreeView) + { + var tv = control as TreeView; + barV.Maximum = intoV.ScrollMax * tv.ItemHeight; + barV.Visible = intoV.ScrollMax > 0 && intoV.nMax > 0 && intoV.nPage > 0; + barV.Value = intoV.nPos * tv.ItemHeight; + barV.BringToFront(); + + //barV.Maximum = GetTreeNodeMaxY(control as TreeView) - control.Height; + //barV.Value = (control as TreeView).AutoScrollOffset.Y; + } + else if (control is TextBox) + { + TextBox txt = (TextBox)control; + barV.Maximum = intoV.ScrollMax * txt.PreferredHeight; + if (txt.ScrollBars == ScrollBars.Both || txt.ScrollBars == ScrollBars.Vertical) + { + barV.Visible = true; + } + else + { + barV.Visible = false; + } + barV.Value = intoV.nPos * txt.PreferredHeight; + barV.BringToFront(); + } + else if (control is RichTextBox) + { + bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; + barV.Maximum = intoV.ScrollMax; + barV.Visible = blnHasVScrollbar; + barV.Value = intoV.nPos; + barV.BringToFront(); + } + else if (control is ListBox) + { + var lb = control as ListBox; + if (intoV.ScrollMax <= 1) + { + var v = lb.ItemHeight * lb.Items.Count - lb.Height; + if (v > 0) + barV.Maximum = v; + else + barV.Maximum = intoV.ScrollMax * lb.ItemHeight; + } + else + { + barV.Maximum = intoV.ScrollMax * lb.ItemHeight; + } + barV.Visible = intoV.ScrollMax > 0 && intoV.nMax > 0 && intoV.nPage > 0; + barV.Value = intoV.nPos * lb.ItemHeight; + barV.BringToFront(); + } + else if (control is ListView) + { + barV.Maximum = intoV.ScrollMax; + barV.Visible = intoV.ScrollMax > 0 && intoV.nMax > 0 && intoV.nPage > 0; + barV.Value = intoV.nPos; + barV.BringToFront(); + } + else if (control is DataGridView) + { + bool blnHasVScrollbar = false; + var dgv = (DataGridView)control; + if (dgv.ScrollBars == ScrollBars.Both || dgv.ScrollBars == ScrollBars.Vertical) + { + int _height = dgv.RowTemplate.Height * dgv.Rows.Count; + if (dgv.ColumnHeadersVisible) + { + _height += dgv.ColumnHeadersHeight; + } + blnHasVScrollbar = _height > dgv.Height; + } + barV.Maximum = dgv.Rows.Count; + barV.Visible = blnHasVScrollbar; + barV.Value = dgv.FirstDisplayedScrollingRowIndex; ; + barV.BringToFront(); + } + } + private void SetHMaxNum(Control control) + { + if (!m_lstHCache.ContainsKey(control)) + return; + var intoH = ControlHelper.GetHScrollBarInfo(control.Handle); + UCHScrollbar barH = m_lstHCache[control]; + if (control is ScrollableControl) + { + barH.Maximum = intoH.ScrollMax; + barH.Visible = intoH.ScrollMax > 0 && intoH.nMax > 0 && intoH.nPage > 0; + barH.Value = intoH.nPos; + barH.BringToFront(); + + //barH.Maximum = (control as ScrollableControl).HorizontalScroll.Maximum; + //barH.Value = (control as ScrollableControl).HorizontalScroll.Value; + } + else if (control is TreeView) + { + var tv = control as TreeView; + barH.Maximum = intoH.ScrollMax; + barH.Visible = intoH.ScrollMax > 0 && intoH.nMax > 0 && intoH.nPage > 0; + barH.Value = intoH.nPos; + barH.BringToFront(); + //barH.Maximum = GetTreeNodeMaxX(control as TreeView); + //barH.Value = (control as TreeView).AutoScrollOffset.X; + } + else if (control is TextBox) + { + TextBox txt = (TextBox)control; + barH.Maximum = intoH.ScrollMax; + + if (txt.ScrollBars == ScrollBars.Both || txt.ScrollBars == ScrollBars.Horizontal) + { + barH.Visible = true; + } + else + { + barH.Visible = false; + } + + barH.Value = intoH.nPos; + barH.BringToFront(); + } + else if (control is RichTextBox) + { + bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; + + barH.Maximum = intoH.ScrollMax; + barH.Visible = blnHasHScrollbar; + barH.Value = intoH.nPos; + barH.BringToFront(); + } + else if (control is ListBox) + { + var lb = control as ListBox; + barH.Maximum = intoH.ScrollMax * lb.ItemHeight; + barH.Visible = intoH.ScrollMax > 0 && intoH.nMax > 0 && intoH.nPage > 0; + barH.Value = intoH.nPos * lb.ItemHeight; + barH.BringToFront(); + } + else if (control is ListView) + { + barH.Maximum = intoH.ScrollMax; + barH.Visible = intoH.ScrollMax > 0 && intoH.nMax > 0 && intoH.nPage > 0; + barH.Value = intoH.nPos; + barH.BringToFront(); + } + else if (control is DataGridView) + { + bool blnHasHScrollbar = false; + var dgv = (DataGridView)control; + int _width = 0; + if (dgv.ScrollBars == ScrollBars.Both || dgv.ScrollBars == ScrollBars.Horizontal) + { + foreach (DataGridViewColumn com in dgv.Columns) + { + _width += com.Width; + } + if (dgv.RowHeadersVisible) + { + _width += dgv.RowHeadersWidth; + } + blnHasHScrollbar = _width > dgv.Width; + } + if (blnHasHScrollbar) + barH.Maximum = _width - dgv.Width; + barH.Visible = blnHasHScrollbar; + barH.Value = dgv.FirstDisplayedScrollingColumnHiddenWidth; + barH.BringToFront(); + } + } + /// + /// Resets the v scroll location. + /// + /// The sender. + private void ResetScrollLocation(object sender) + { + Control control = (Control)sender; + bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; + bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; + if (control is TextBox) + { + var txt = (TextBox)control; + if (txt.ScrollBars == ScrollBars.Both) + { + blnHasVScrollbar = true; + blnHasHScrollbar = true; + } + else if (txt.ScrollBars == ScrollBars.Vertical) + { + blnHasVScrollbar = true; + blnHasHScrollbar = false; + } + else if (txt.ScrollBars == ScrollBars.Horizontal) + { + blnHasVScrollbar = false; + blnHasHScrollbar = true; + } + else + { + blnHasVScrollbar = false; + blnHasHScrollbar = false; + } + } + else if (control is DataGridView) + { + var dgv = (DataGridView)control; + if (dgv.ScrollBars == ScrollBars.Both || dgv.ScrollBars == ScrollBars.Vertical) + { + int _height = dgv.RowTemplate.Height * dgv.Rows.Count; + if (dgv.ColumnHeadersVisible) + { + _height += dgv.ColumnHeadersHeight; + } + blnHasVScrollbar = _height > dgv.Height; + } + if (dgv.ScrollBars == ScrollBars.Both || dgv.ScrollBars == ScrollBars.Horizontal) + { + int _width = 0; + foreach (DataGridViewColumn com in dgv.Columns) + { + _width += com.Width; + } + if (dgv.RowHeadersVisible) + { + _width += dgv.RowHeadersWidth; + } + blnHasHScrollbar = _width > dgv.Width; + } + } + else if (control is ListView) + { + if (!((ListView)control).Scrollable) + { + blnHasVScrollbar = false; + blnHasHScrollbar = false; + } + } + if (control.Visible) + { + if (m_lstVCache.ContainsKey(control)) + { + m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width, control.Top); + if (blnHasHScrollbar) + { + m_lstVCache[control].Height = control.Height - m_lstHCache[control].Height; + } + else + { + m_lstVCache[control].Height = control.Height; + } + SetVMaxNum(control); + } + + if (m_lstHCache.ContainsKey(control)) + { + m_lstHCache[control].Location = new System.Drawing.Point(control.Left, control.Bottom - m_lstHCache[control].Height); + //if (blnHasVScrollbar) + //{ + // m_lstHCache[control].Width = control.Width - m_lstVCache[control].Width; + //} + //else + //{ + m_lstHCache[control].Width = control.Width; + //} + SetHMaxNum(control); + } + } + } + + /// + /// Handles the VisibleChanged event of the control control. + /// + /// The source of the event. + /// The instance containing the event data. + void control_VisibleChanged(object sender, EventArgs e) + { + Control control = (Control)sender; + + if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) + { + m_lstVCache[control].Visible = control.Visible; + } + + if (m_lstHCache.ContainsKey(control) && m_lstHCache[control].Parent != null) + { + m_lstHCache[control].Visible = control.Visible; + } + if (control.Visible) + { + control_SizeChanged(control, null); + } + } + + private const int HSCROLL = 0x100000; + private const int VSCROLL = 0x200000; + private const int STYLE = -16; + + private Dictionary m_lstVCache = new Dictionary(); + private Dictionary m_lstHCache = new Dictionary(); + + void barV_Scroll(object sender, EventArgs e) + { + UCVScrollbar bar = (UCVScrollbar)sender; + if (m_lstVCache.ContainsValue(bar)) + { + Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key; + + //ControlHelper.SetVScrollValue(c.Handle, bar.Value); + if (c is ScrollableControl) + { + (c as ScrollableControl).AutoScrollPosition = new Point((c as ScrollableControl).AutoScrollPosition.X, bar.Value); + } + else if (c is TreeView) + { + ControlHelper.SetVScrollValue(c.Handle, bar.Value / ((c as TreeView).ItemHeight)); + } + else if (c is TextBox) + { + ControlHelper.SetVScrollValue(c.Handle, bar.Value / ((c as TextBox).PreferredHeight)); + } + else if (c is RichTextBox) + { + ControlHelper.SetVScrollValue(c.Handle, bar.Value); + } + else if (c is ListBox) + { + ControlHelper.SetVScrollValue(c.Handle, bar.Value / ((c as ListBox).ItemHeight)); + } + else if (c is ListView) + { + ControlHelper.SetVScrollValue(c.Handle, bar.Value); + } + else if (c is DataGridView) + { + var dgv = (DataGridView)c; + if (bar.Value > 0) + dgv.FirstDisplayedScrollingRowIndex = bar.Value - 1; + } + } + } + + void barH_Scroll(object sender, EventArgs e) + { + UCHScrollbar bar = (UCHScrollbar)sender; + if (m_lstHCache.ContainsValue(bar)) + { + Control c = m_lstHCache.FirstOrDefault(p => p.Value == bar).Key; + if (c is ScrollableControl) + { + (c as ScrollableControl).AutoScrollPosition = new Point(bar.Value, (c as ScrollableControl).AutoScrollPosition.Y); + } + else if (c is TreeView) + { + ControlHelper.SetHScrollValue(c.Handle, bar.Value); + //TreeView tv = (c as TreeView); + //SetTreeViewVScrollLocation(tv, tv.Nodes, bar.Value); + } + else if (c is TextBox) + { + ControlHelper.SetHScrollValue(c.Handle, bar.Value); + //TextBox txt = (c as TextBox); + //SetTextBoxVScrollLocation(txt, bar.Value); + } + else if (c is RichTextBox) + { + ControlHelper.SetHScrollValue(c.Handle, bar.Value); + } + else if (c is ListBox) + { + ControlHelper.SetHScrollValue(c.Handle, bar.Value); + } + else if (c is ListView) + { + ControlHelper.SetHScrollValue(c.Handle, bar.Value); + } + else if (c is DataGridView) + { + var dgv = (DataGridView)c; + dgv.HorizontalScrollingOffset = bar.Value; + } + } + } + + #region Treeview处理 English:Treeview\u5904\u7406 + void tv_AfterCollapse(object sender, TreeViewEventArgs e) + { + control_SizeChanged(sender as Control, null); + } + + void tv_AfterExpand(object sender, TreeViewEventArgs e) + { + control_SizeChanged(sender as Control, null); + } + + #endregion + + #region TextBox处理 English:TextBox Processing + + void txt_TextChanged(object sender, EventArgs e) + { + Control txt = sender as Control; + control_SizeChanged(txt, null); + } + + void txt_KeyDown(object sender, KeyEventArgs e) + { + Control txt = sender as Control; + control_SizeChanged(txt, null); + } + #endregion + } +} diff --git a/JinYuan.ControlLib/ScrollBar/ScrollbarControlDesigner.cs b/JinYuan.ControlLib/ScrollBar/ScrollbarControlDesigner.cs new file mode 100644 index 0000000..cb4e1af --- /dev/null +++ b/JinYuan.ControlLib/ScrollBar/ScrollbarControlDesigner.cs @@ -0,0 +1,39 @@ +using System.ComponentModel; +using System.Windows.Forms.Design; + +namespace JinYuan.ControlLib.ScrollBar +{ + /// + /// Class ScrollbarControlDesigner. + /// Implements the + /// + /// + internal class ScrollbarControlDesigner : System.Windows.Forms.Design.ControlDesigner + { + /// + /// 获取指示组件的移动功能的选择规则。 + /// + /// The selection rules. + public override SelectionRules SelectionRules + { + get + { + SelectionRules selectionRules = base.SelectionRules; + PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(this.Component)["AutoSize"]; + if (propDescriptor != null) + { + bool autoSize = (bool)propDescriptor.GetValue(this.Component); + if (autoSize) + { + selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable | SelectionRules.TopSizeable; + } + else + { + selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable; + } + } + return selectionRules; + } + } + } +} diff --git a/JinYuan.ControlLib/ScrollBar/UCHScrollbar.cs b/JinYuan.ControlLib/ScrollBar/UCHScrollbar.cs new file mode 100644 index 0000000..0b37e4b --- /dev/null +++ b/JinYuan.ControlLib/ScrollBar/UCHScrollbar.cs @@ -0,0 +1,519 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.ScrollBar +{ + [Designer(typeof(ScrollbarControlDesigner))] + [DefaultEvent("Scroll")] + public class UCHScrollbar : UCControlBase + { + #region 属性 English:attribute + /// + /// The mo large change + /// + protected int moLargeChange = 10; + /// + /// The mo small change + /// + protected int moSmallChange = 1; + /// + /// The mo minimum + /// + protected int moMinimum = 0; + /// + /// The mo maximum + /// + protected int moMaximum = 100; + /// + /// The mo value + /// + protected int moValue = 0; + /// + /// The n click point + /// + private int nClickPoint; + /// + /// The mo thumb top + /// + protected int moThumbLeft = 0; + /// + /// The mo automatic size + /// + protected bool moAutoSize = false; + /// + /// The mo thumb down + /// + private bool moThumbMouseDown = false; + /// + /// The mo thumb dragging + /// + private bool moThumbMouseDragging = false; + /// + /// Occurs when [scroll]. + /// + public new event EventHandler Scroll = null; + /// + /// Occurs when [value changed]. + /// + public event EventHandler ValueChanged = null; + + /// + /// The BTN height + /// + private int btnWidth = 18; + /// + /// The m int thumb minimum height + /// + private int m_intThumbMinWidth = 15; + + /// + /// Gets or sets the height of the BTN. + /// + /// The height of the BTN. + public int BtnWidth + { + get { return btnWidth; } + set { btnWidth = value; } + } + /// + /// Gets or sets the large change. + /// + /// The large change. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")] + public int LargeChange + { + get { return moLargeChange; } + set + { + moLargeChange = value; + Invalidate(); + } + } + + /// + /// Gets or sets the small change. + /// + /// The small change. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")] + public int SmallChange + { + get { return moSmallChange; } + set + { + moSmallChange = value; + Invalidate(); + } + } + + /// + /// Gets or sets the minimum. + /// + /// The minimum. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")] + public int Minimum + { + get { return moMinimum; } + set + { + moMinimum = value; + Invalidate(); + } + } + + /// + /// Gets or sets the maximum. + /// + /// The maximum. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")] + public int Maximum + { + get { return moMaximum; } + set + { + moMaximum = value; + Invalidate(); + } + } + + /// + /// Gets or sets the value. + /// + /// The value. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")] + public int Value + { + get { return moValue; } + set + { + moValue = value; + if (moValue > moMaximum) + moValue = moMaximum; + int nTrackWidth = (this.Width - btnWidth * 2); + float fThumbWidth = nTrackWidth - Maximum; + //float fThumbWidth = ((float)LargeChange / (float)Maximum) * nTrackWidth; + int nThumbWidth = (int)fThumbWidth; + + if (nThumbWidth > nTrackWidth) + { + nThumbWidth = nTrackWidth; + fThumbWidth = nTrackWidth; + } + if (nThumbWidth < m_intThumbMinWidth) + { + nThumbWidth = m_intThumbMinWidth; + fThumbWidth = m_intThumbMinWidth; + } + + //figure out value + int nPixelRange = nTrackWidth - nThumbWidth; + int nRealRange = (Maximum - Minimum) - LargeChange; + float fPerc = 0.0f; + if (nRealRange != 0) + { + fPerc = (float)moValue / (float)nRealRange; + + } + + float fLeft = fPerc * nPixelRange; + moThumbLeft = (int)fLeft; + + + Invalidate(); + } + } + + /// + /// Gets or sets a value indicating whether [automatic size]. + /// + /// true if [automatic size]; otherwise, false. + public override bool AutoSize + { + get + { + return base.AutoSize; + } + set + { + base.AutoSize = value; + if (base.AutoSize) + { + this.Width = 15; + } + } + } + + /// + /// The thumb color + /// + private Color thumbColor = Color.FromArgb(1, 146, 235); + + /// + /// Gets or sets the color of the thumb. + /// + /// The color of the thumb. + public Color ThumbColor + { + get { return thumbColor; } + set { thumbColor = value; } + } + #endregion + + public UCHScrollbar() + { + InitializeComponent(); + ConerRadius = 2; + FillColor = Color.FromArgb(6, 30, 78); + IsShowRect = false; + IsRadius = true; + + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + + + + } + + + #region 静止闪烁 + protected override void WndProc(ref Message m) + { + if (m.Msg == 0x0014) // 禁掉清除背景消息 + return; + base.WndProc(ref m); + } + #endregion + + /// + /// Initializes the component. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + + this.MinimumSize = new System.Drawing.Size(0, 10); + this.Name = "UCHScrollbar"; + this.Size = new System.Drawing.Size(150, 18); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseDown); + this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseMove); + this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseUp); + this.ResumeLayout(false); + + } + + #region 鼠标事件 English:Mouse event + /// + /// Handles the MouseDown event of the CustomScrollbar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e) + { + if (Maximum <= 0) + { + return; + } + Point ptPoint = this.PointToClient(Cursor.Position); + int nTrackWidth = (this.Width - btnWidth * 2); + float fThumbWidth = nTrackWidth - Maximum; + //float fThumbWidth = ((float)LargeChange / (float)Maximum) * nTrackWidth; + int nThumbWidth = (int)fThumbWidth; + + if (nThumbWidth > nTrackWidth) + { + nThumbWidth = nTrackWidth; + fThumbWidth = nTrackWidth; + } + if (nThumbWidth < m_intThumbMinWidth) + { + nThumbWidth = m_intThumbMinWidth; + fThumbWidth = m_intThumbMinWidth; + } + + int nLeft = moThumbLeft; + nLeft += btnWidth; + + + Rectangle thumbrect = new Rectangle(new Point(nLeft, 1), new Size(nThumbWidth, this.Height - 2)); + //滑块 + if (thumbrect.Contains(ptPoint)) + { + //hit the thumb + nClickPoint = (ptPoint.X - nLeft); + this.moThumbMouseDown = true; + } + else + { + //左按钮 + Rectangle leftarrowrect = new Rectangle(new Point(0, 1), new Size(btnWidth, this.Height)); + if (leftarrowrect.Contains(ptPoint)) + { + int nRealRange = (Maximum - Minimum) - LargeChange; + int nPixelRange = (nTrackWidth - nThumbWidth); + if (nRealRange > 0) + { + if (nPixelRange > 0) + { + if ((moThumbLeft - SmallChange) < 0) + moThumbLeft = 0; + else + moThumbLeft -= SmallChange; + + //figure out value + float fPerc = (float)moThumbLeft / (float)nPixelRange; + float fValue = fPerc * (Maximum - LargeChange); + + moValue = (int)fValue; + + if (ValueChanged != null) + ValueChanged(this, new EventArgs()); + + if (Scroll != null) + Scroll(this, new EventArgs()); + + Invalidate(); + } + } + } + else + { + Rectangle rightarrowrect = new Rectangle(new Point(btnWidth + nTrackWidth, 1), new Size(btnWidth, this.Height)); + if (rightarrowrect.Contains(ptPoint)) + { + int nRealRange = (Maximum - Minimum) - LargeChange; + int nPixelRange = (nTrackWidth - nThumbWidth); + if (nRealRange > 0) + { + if (nPixelRange > 0) + { + if ((moThumbLeft + SmallChange) > nPixelRange) + moThumbLeft = nPixelRange; + else + moThumbLeft += SmallChange; + + //figure out value + float fPerc = (float)moThumbLeft / (float)nPixelRange; + float fValue = fPerc * (Maximum - LargeChange); + + moValue = (int)fValue; + + if (ValueChanged != null) + ValueChanged(this, new EventArgs()); + + if (Scroll != null) + Scroll(this, new EventArgs()); + + Invalidate(); + } + } + } + } + } + } + + /// + /// Handles the MouseUp event of the CustomScrollbar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e) + { + this.moThumbMouseDown = false; + this.moThumbMouseDragging = false; + Application.DoEvents(); + } + + /// + /// Moves the thumb. + /// + /// The y. + private void MoveThumb(int x) + { + int nRealRange = Maximum - Minimum; + int nTrackWidth = (this.Width - btnWidth * 2); + // float fThumbWidth = ((float)LargeChange / (float)Maximum) * nTrackWidth; + float fThumbWidth = nTrackWidth - Maximum; + int nThumbWidth = (int)fThumbWidth; + + if (nThumbWidth > nTrackWidth) + { + nThumbWidth = nTrackWidth; + fThumbWidth = nTrackWidth; + } + if (nThumbWidth < m_intThumbMinWidth) + { + nThumbWidth = m_intThumbMinWidth; + fThumbWidth = m_intThumbMinWidth; + } + + int nSpot = nClickPoint; + + int nPixelRange = (nTrackWidth - nThumbWidth); + if (moThumbMouseDown && nRealRange > 0) + { + if (nPixelRange > 0) + { + int nNewThumbLeft = x - (btnWidth + nSpot); + + if (nNewThumbLeft < 0) + { + moThumbLeft = nNewThumbLeft = 0; + } + else if (nNewThumbLeft > nPixelRange) + { + moThumbLeft = nNewThumbLeft = nPixelRange; + } + else + { + moThumbLeft = x - (btnWidth + nSpot); + } + + + float fPerc = (float)moThumbLeft / (float)nPixelRange; + float fValue = fPerc * (Maximum - (nNewThumbLeft == nPixelRange ? 0 : LargeChange)); + //float fValue = fPerc * (Maximum - LargeChange); + if (Math.Abs(moValue - fValue) < 1) + { + return; + } + moValue = (int)fValue; + Invalidate(); + + try + { + Application.DoEvents(); + } + catch { } + } + } + } + + /// + /// Handles the MouseMove event of the CustomScrollbar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e) + { + if (!moThumbMouseDown) + return; + + if (moThumbMouseDown == true) + { + this.moThumbMouseDragging = true; + } + + if (this.moThumbMouseDragging) + { + MoveThumb(e.X); + } + + if (ValueChanged != null) + ValueChanged(this, new EventArgs()); + + if (Scroll != null) + Scroll(this, new EventArgs()); + } + #endregion + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + e.Graphics.SetGDIHigh(); + if (Maximum > 0) + { + //draw thumb + int nTrackWidth = (this.Width - btnWidth * 2); + //float fThumbWidth = ((float)LargeChange / (float)Maximum) * nTrackWidth; + float fThumbWidth = nTrackWidth - Maximum; + int nThumbWidth = (int)fThumbWidth; + + if (nThumbWidth > nTrackWidth) + { + nThumbWidth = nTrackWidth; + fThumbWidth = nTrackWidth; + } + if (nThumbWidth < m_intThumbMinWidth) + { + nThumbWidth = m_intThumbMinWidth; + fThumbWidth = m_intThumbMinWidth; + } + int nLeft = moThumbLeft; + nLeft += btnWidth; + if (nLeft + nThumbWidth > this.Width - btnWidth) + nLeft = this.Width - btnWidth - nThumbWidth; + e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(nLeft, 1, nThumbWidth, this.Height - 3).CreateRoundedRectanglePath(this.ConerRadius)); + } + ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(btnWidth - Math.Min(5, this.Height / 2), this.Height / 2), Math.Min(5, this.Height / 2), GraphDirection.Leftward); + ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width - (btnWidth - Math.Min(5, this.Height / 2)), this.Height / 2), Math.Min(5, this.Height / 2), GraphDirection.Rightward); + + } + } + +} diff --git a/JinYuan.ControlLib/ScrollBar/UCVScrollbar.cs b/JinYuan.ControlLib/ScrollBar/UCVScrollbar.cs new file mode 100644 index 0000000..f3950c4 --- /dev/null +++ b/JinYuan.ControlLib/ScrollBar/UCVScrollbar.cs @@ -0,0 +1,539 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 2019-09-19 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(»ÆÕý»Ô) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub£ºhttps://github.com/kwwwvagaa/NetWinformControl +// gitee£ºhttps://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.ScrollBar +{ + + /// + /// Class UCVScrollbar. + /// Implements the + /// + /// + [Designer(typeof(ScrollbarControlDesigner))] + [DefaultEvent("Scroll")] + public class UCVScrollbar : UCControlBase + { + /// + /// The mo large change + /// + protected int moLargeChange = 10; + /// + /// The mo small change + /// + protected int moSmallChange = 5; + /// + /// The mo minimum + /// + protected int moMinimum = 0; + /// + /// The mo maximum + /// + protected int moMaximum = 100; + /// + /// The mo value + /// + protected int moValue = 0; + /// + /// The n click point + /// + private int nClickPoint; + /// + /// The mo thumb top + /// + protected int moThumbTop = 0; + /// + /// The mo automatic size + /// + protected bool moAutoSize = false; + /// + /// The mo thumb down + /// + private bool moThumbMouseDown = false; + /// + /// The mo thumb dragging + /// + private bool moThumbMouseDragging = false; + /// + /// Occurs when [scroll]. + /// + public new event EventHandler Scroll = null; + /// + /// Occurs when [value changed]. + /// + public event EventHandler ValueChanged = null; + + /// + /// The BTN height + /// + private int btnHeight = 18; + /// + /// The m int thumb minimum height + /// + private int m_intThumbMinHeight = 30; + + /// + /// Gets or sets the height of the BTN. + /// + /// The height of the BTN. + public int BtnHeight + { + get { return btnHeight; } + set { btnHeight = value; } + } + /// + /// Gets or sets the large change. + /// + /// The large change. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("×Զ¨Òå"), Description("LargeChange")] + public int LargeChange + { + get { return moLargeChange; } + set + { + moLargeChange = value; + Invalidate(); + } + } + + /// + /// Gets or sets the small change. + /// + /// The small change. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("×Զ¨Òå"), Description("SmallChange")] + public int SmallChange + { + get { return moSmallChange; } + set + { + moSmallChange = value; + Invalidate(); + } + } + + /// + /// Gets or sets the minimum. + /// + /// The minimum. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("×Զ¨Òå"), Description("Minimum")] + public int Minimum + { + get { return moMinimum; } + set + { + moMinimum = value; + Invalidate(); + } + } + + /// + /// Gets or sets the maximum. + /// + /// The maximum. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("×Զ¨Òå"), Description("Maximum")] + public int Maximum + { + get { return moMaximum; } + set + { + moMaximum = value; + Invalidate(); + } + } + + /// + /// Gets or sets the value. + /// + /// The value. + [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("×Զ¨Òå"), Description("Value")] + public int Value + { + get { return moValue; } + set + { + moValue = value; + + int nTrackHeight = (this.Height - btnHeight * 2); + //float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; + float fThumbHeight = nTrackHeight - Maximum; + int nThumbHeight = (int)fThumbHeight; + + if (nThumbHeight > nTrackHeight) + { + nThumbHeight = nTrackHeight; + fThumbHeight = nTrackHeight; + } + if (nThumbHeight < m_intThumbMinHeight) + { + nThumbHeight = m_intThumbMinHeight; + fThumbHeight = m_intThumbMinHeight; + } + + //figure out value + int nPixelRange = nTrackHeight - nThumbHeight; + int nRealRange = (Maximum - Minimum) - LargeChange; + float fPerc = 0.0f; + if (nRealRange != 0) + { + fPerc = (float)moValue / (float)nRealRange; + + } + + float fTop = fPerc * nPixelRange; + moThumbTop = (int)fTop; + + + Invalidate(); + } + } + + /// + /// Gets or sets a value indicating whether [automatic size]. + /// + /// true if [automatic size]; otherwise, false. + public override bool AutoSize + { + get + { + return base.AutoSize; + } + set + { + base.AutoSize = value; + if (base.AutoSize) + { + this.Width = 15; + } + } + } + + /// + /// The thumb color + /// + private Color thumbColor = Color.FromArgb(1, 146, 235); + + /// + /// Gets or sets the color of the thumb. + /// + /// The color of the thumb. + public Color ThumbColor + { + get { return thumbColor; } + set { thumbColor = value; } + } + + /// + /// Initializes a new instance of the class. + /// + public UCVScrollbar() + { + InitializeComponent(); + ConerRadius = 2; + FillColor = Color.FromArgb(6, 30, 78); + IsShowRect = false; + IsRadius = true; + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + } + + + #region ¾²ֹÉÁ˸ + protected override void WndProc(ref Message m) + { + if (m.Msg == 0x0014) // ½ûµôÇå³ý±³¾°ÏûϢ + return; + base.WndProc(ref m); + } + #endregion + + /// + /// Initializes the component. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // UCVScrollbar + // + this.MinimumSize = new System.Drawing.Size(10, 0); + this.Name = "UCVScrollbar"; + this.Size = new System.Drawing.Size(18, 150); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseDown); + this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseMove); + this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseUp); + this.ResumeLayout(false); + + } + + + /// + /// Òý·¢ ʼþ¡£ + /// + /// °üº¬Ê¼þÊý¾ݵÄ ¡£ + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + e.Graphics.SetGDIHigh(); + if (Maximum > 0) + { + //draw thumb + int nTrackHeight = (this.Height - btnHeight * 2); + //float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; + float fThumbHeight = nTrackHeight - Maximum; + int nThumbHeight = (int)fThumbHeight; + + if (nThumbHeight > nTrackHeight) + { + nThumbHeight = nTrackHeight; + fThumbHeight = nTrackHeight; + } + if (nThumbHeight < m_intThumbMinHeight) + { + nThumbHeight = m_intThumbMinHeight; + fThumbHeight = m_intThumbMinHeight; + } + int nTop = moThumbTop; + nTop += btnHeight; + if (nTop + nThumbHeight > this.Height - btnHeight) + nTop = this.Height - btnHeight - nThumbHeight; + e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(1, nTop, this.Width - 3, nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius)); + } + ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, btnHeight - Math.Min(5, this.Width / 2)), Math.Min(5, this.Width / 2), GraphDirection.Upward); + ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, this.Height - (btnHeight - Math.Min(5, this.Width / 2))), Math.Min(5, this.Width / 2), GraphDirection.Downward); + + } + + /// + /// Handles the MouseDown event of the CustomScrollbar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e) + { + if (Maximum <= 0) + return; + Point ptPoint = this.PointToClient(Cursor.Position); + int nTrackHeight = (this.Height - btnHeight * 2); + //float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; + float fThumbHeight = nTrackHeight - Maximum; + int nThumbHeight = (int)fThumbHeight; + + if (nThumbHeight > nTrackHeight) + { + nThumbHeight = nTrackHeight; + fThumbHeight = nTrackHeight; + } + if (nThumbHeight < m_intThumbMinHeight) + { + nThumbHeight = m_intThumbMinHeight; + fThumbHeight = m_intThumbMinHeight; + } + + int nTop = moThumbTop; + nTop += btnHeight; + + + Rectangle thumbrect = new Rectangle(new Point(1, nTop), new Size(this.Width - 2, nThumbHeight)); + if (thumbrect.Contains(ptPoint)) + { + + //hit the thumb + nClickPoint = (ptPoint.Y - nTop); + //MessageBox.Show(Convert.ToString((ptPoint.Y - nTop))); + this.moThumbMouseDown = true; + } + else + { + Rectangle uparrowrect = new Rectangle(new Point(1, 0), new Size(this.Width, btnHeight)); + if (uparrowrect.Contains(ptPoint)) + { + + int nRealRange = (Maximum - Minimum) - LargeChange; + int nPixelRange = (nTrackHeight - nThumbHeight); + if (nRealRange > 0) + { + if (nPixelRange > 0) + { + if ((moThumbTop - SmallChange) < 0) + moThumbTop = 0; + else + moThumbTop -= SmallChange; + + //figure out value + float fPerc = (float)moThumbTop / (float)nPixelRange; + float fValue = fPerc * (Maximum - LargeChange); + + moValue = (int)fValue; + + if (ValueChanged != null) + ValueChanged(this, new EventArgs()); + + if (Scroll != null) + Scroll(this, new EventArgs()); + + Invalidate(); + } + } + } + else + { + Rectangle downarrowrect = new Rectangle(new Point(1, btnHeight + nTrackHeight), new Size(this.Width, btnHeight)); + if (downarrowrect.Contains(ptPoint)) + { + int nRealRange = (Maximum - Minimum) - LargeChange; + int nPixelRange = (nTrackHeight - nThumbHeight); + if (nRealRange > 0) + { + if (nPixelRange > 0) + { + if ((moThumbTop + SmallChange) > nPixelRange) + moThumbTop = nPixelRange; + else + moThumbTop += SmallChange; + + //figure out value + float fPerc = (float)moThumbTop / (float)nPixelRange; + float fValue = fPerc * (Maximum - LargeChange); + + moValue = (int)fValue; + + if (ValueChanged != null) + ValueChanged(this, new EventArgs()); + + if (Scroll != null) + Scroll(this, new EventArgs()); + + Invalidate(); + } + } + } + } + } + + } + + /// + /// Handles the MouseUp event of the CustomScrollbar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e) + { + this.moThumbMouseDown = false; + this.moThumbMouseDragging = false; + } + + /// + /// Moves the thumb. + /// + /// The y. + private void MoveThumb(int y) + { + int nRealRange = Maximum - Minimum; + int nTrackHeight = (this.Height - btnHeight * 2); + //float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; + float fThumbHeight = nTrackHeight - Maximum; + int nThumbHeight = (int)fThumbHeight; + + if (nThumbHeight > nTrackHeight) + { + nThumbHeight = nTrackHeight; + fThumbHeight = nTrackHeight; + } + if (nThumbHeight < m_intThumbMinHeight) + { + nThumbHeight = m_intThumbMinHeight; + fThumbHeight = m_intThumbMinHeight; + } + + int nSpot = nClickPoint; + + int nPixelRange = (nTrackHeight - nThumbHeight); + if (moThumbMouseDown && nRealRange > 0) + { + if (nPixelRange > 0) + { + int nNewThumbTop = y - (btnHeight + nSpot); + + if (nNewThumbTop < 0) + { + moThumbTop = nNewThumbTop = 0; + } + else if (nNewThumbTop > nPixelRange) + { + moThumbTop = nNewThumbTop = nPixelRange; + } + else + { + moThumbTop = y - (btnHeight + nSpot); + } + + + float fPerc = (float)moThumbTop / (float)nPixelRange; + float fValue = fPerc * (Maximum - (nNewThumbTop == nPixelRange ? 0 : LargeChange)); + if (Math.Abs(moValue - fValue) < 1) + { + return; + } + moValue = (int)fValue; + Invalidate(); + + try + { + Application.DoEvents(); + } + catch { } + } + } + } + + /// + /// Handles the MouseMove event of the CustomScrollbar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e) + { + if (!moThumbMouseDown) + return; + + if (moThumbMouseDown == true) + { + this.moThumbMouseDragging = true; + } + + if (this.moThumbMouseDragging) + { + MoveThumb(e.Y); + } + + if (ValueChanged != null) + ValueChanged(this, new EventArgs()); + + if (Scroll != null) + Scroll(this, new EventArgs()); + } + + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/ScrollBar/UCVScrollbar.resx b/JinYuan.ControlLib/ScrollBar/UCVScrollbar.resx new file mode 100644 index 0000000..d58980a --- /dev/null +++ b/JinYuan.ControlLib/ScrollBar/UCVScrollbar.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/SidebarNavigation.Designer.cs b/JinYuan.ControlLib/SidebarNavigation.Designer.cs new file mode 100644 index 0000000..55fe051 --- /dev/null +++ b/JinYuan.ControlLib/SidebarNavigation.Designer.cs @@ -0,0 +1,48 @@ +namespace JinYuan.ControlLib +{ + partial class SidebarNavigation + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + + if (disposing&& (components != null)) + { + toolTip.Dispose(); + if (components != null) + { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // SidebarNavigation + // + this.Name = "SidebarNavigation"; + this.Size = new System.Drawing.Size(51, 823); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/SidebarNavigation.cs b/JinYuan.ControlLib/SidebarNavigation.cs new file mode 100644 index 0000000..bada6f2 --- /dev/null +++ b/JinYuan.ControlLib/SidebarNavigation.cs @@ -0,0 +1,1133 @@ +using AntdUI; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using System.Xml.Linq; + +namespace JinYuan.ControlLib +{ + + public enum NavigationItemType + { + Normal, // 普通项 + Settings, // 设置项 + UserManagement // 用户管理项 + } + + public enum Position + { + Top, + Bottom + } + + public class SidebarNavigationItem + { + public string Text { get; set; } + public string Tag { get; set; } + public string IconSvg { get; set; } + public Func CreatePageControl { get; set; } + public NavigationItemType ItemType { get; set; } = NavigationItemType.Normal; + public Position Position { get; set; } = Position.Top; + public bool IsSettings { get; set; } + } + + public partial class SidebarNavigation : UserControl + { + private List items = new List(); + private Dictionary buttonCache = new Dictionary(); + private Color lightBackgroundColor = Color.FromArgb(240, 240, 240); + private Color darkBackgroundColor = Color.FromArgb(33, 33, 33); + private Color lightSelectedColor = Color.FromArgb(0, 122, 204); + private Color darkSelectedColor = Color.FromArgb(0, 122, 204); + private AntdUI.Button selectedButton; + private bool isReordering = false; + private Font buttonFont = new Font("Microsoft YaHei UI", 10F); + private ToolTip toolTip = new ToolTip(); // 添加 ToolTip 控件 + + public Size IconSize { get; set; } = new Size(42, 42); + public event EventHandler ItemSelected; + + public class ButtonInfo + { + public SidebarNavigationItem Item { get; set; } + public AntdUI.Button Button { get; set; } + } + + private bool showText = false; + public bool ShowText + { + get => showText; + set + { + if (showText != value) + { + showText = value; + UpdateButtonsLayout(); + } + } + } + + public SidebarNavigation() + { + InitializeComponent(); + + SetStyle(ControlStyles.OptimizedDoubleBuffer | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.UserPaint, true); + + this.BackColor = AntdUI.Config.IsDark ? darkBackgroundColor : lightBackgroundColor; + this.Width = 50; + this.Padding = new Padding(0); + this.Margin = new Padding(0); + this.AutoScroll = false; + + // 配置 ToolTip + toolTip.AutoPopDelay = 5000; + toolTip.InitialDelay = 500; + toolTip.ReshowDelay = 500; + toolTip.ShowAlways = true; + } + + public void UpdateVisibility(Func visibilityPredicate) + { + this.SuspendLayout(); + try + { + // 保存当前选中按钮的Tag + string selectedTag = null; + if (selectedButton?.Tag is ButtonInfo selectedInfo) + { + selectedTag = selectedInfo.Item.Tag; + } + + // 缓存现有按钮的状态 + foreach (Control control in this.Controls) + { + if (control is AntdUI.Button button && button.Tag is ButtonInfo info) + { + buttonCache[info.Item.Tag] = info; + } + } + + // 清除现有控件 + this.Controls.Clear(); + + // 重新添加符合条件的按钮 + var topButtons = items.Where(i => i.Position == Position.Top && visibilityPredicate(i)) + .OrderBy(i => items.IndexOf(i)); + + var bottomButtons = items.Where(i => i.Position == Position.Bottom && visibilityPredicate(i)) + .OrderBy(i => items.IndexOf(i)); + + // 添加顶部按钮 + foreach (var item in topButtons.Reverse()) + { + CreateOrRestoreButton(item); + } + + // 添加底部按钮 + foreach (var item in bottomButtons) + { + CreateOrRestoreButton(item); + } + + // 恢复选中状态 + if (selectedTag != null) + { + foreach (Control control in this.Controls) + { + if (control is AntdUI.Button button && + button.Tag is ButtonInfo info && + info.Item.Tag == selectedTag) + { + SetSelectedButton(button); + break; + } + } + } + } + finally + { + this.ResumeLayout(); + } + } + + private void CreateOrRestoreButton(SidebarNavigationItem item) + { + if (buttonCache.TryGetValue(item.Tag, out ButtonInfo cachedInfo)) + { + AntdUI.Button btn = new AntdUI.Button + { + Text = showText ? item.Text : "", + TextMultiLine = true, + AutoEllipsis = true, + BackColor = cachedInfo.Button.BackColor, + ForeColor = AntdUI.Config.IsDark ? Color.White : Color.Black, + Width = this.Width, + Height = this.Width + 5, + Dock = item.Position == Position.Bottom ? DockStyle.Bottom : DockStyle.Top, + Font = buttonFont, + IconPosition = TAlignMini.Top, + Radius = 3, + BorderWidth = 1, + WaveSize = 1, + IconSvg = item.IconSvg, + IconRatio = 0.8f, + Margin = new Padding(0), + Padding = new Padding(0), + RespondRealAreas = true, + Type = cachedInfo.Button.Type, + Ghost = false + }; + + // 设置工具提示 + toolTip.SetToolTip(btn, item.Text); + + btn.Click += NavigationButton_Click; + + var buttonInfo = new ButtonInfo + { + Item = item, + Button = btn + }; + btn.Tag = buttonInfo; + + this.Controls.Add(btn); + } + else + { + CreateNavigationButton(item); + } + } + + private void CreateNavigationButton(SidebarNavigationItem item) + { + AntdUI.Button btn = new AntdUI.Button + { + Text = showText ? item.Text : "", + TextMultiLine = true, + AutoEllipsis = true, + BackColor = Color.Transparent, + ForeColor = AntdUI.Config.IsDark ? Color.White : Color.Black, + Width = this.Width, + Height = this.Width + 5, + Dock = item.Position == Position.Bottom ? DockStyle.Bottom : DockStyle.Top, + Font = buttonFont, + IconPosition = TAlignMini.Top, + Radius = 3, + BorderWidth = 1, + WaveSize = 1, + IconSvg = item.IconSvg, + IconRatio = 0.8f, + Margin = new Padding(0), + Padding = new Padding(0), + RespondRealAreas = true, + Type = TTypeMini.Primary, + Ghost = false + }; + + // 设置工具提示 + toolTip.SetToolTip(btn, item.Text); + + btn.Click += NavigationButton_Click; + + var buttonInfo = new ButtonInfo + { + Item = item, + Button = btn + }; + btn.Tag = buttonInfo; + + this.Controls.Add(btn); + + if (selectedButton != null && + selectedButton.Tag is ButtonInfo selectedInfo && + selectedInfo.Item.Tag == item.Tag) + { + SetSelectedButton(btn); + } + } + + private void UpdateButtonsLayout() + { + this.SuspendLayout(); + foreach (Control control in this.Controls) + { + if (control is AntdUI.Button button) + { + button.Height = this.Width; + if (button.Tag is ButtonInfo buttonInfo) + { + button.Text = showText ? buttonInfo.Item.Text : ""; + } + } + } + this.PerformLayout(); + this.ResumeLayout(); + } + + private void SetSelectedButton(AntdUI.Button button) + { + if (selectedButton != null) + { + selectedButton.BackColor = Color.Transparent; + selectedButton.Type = TTypeMini.Default; + selectedButton.Invalidate(); + } + selectedButton = button; + if (button != null) + { + button.BackColor = AntdUI.Config.IsDark ? darkSelectedColor : lightSelectedColor; + button.Type = TTypeMini.Primary; + button.Invalidate(); + } + } + + public void UpdateTheme(bool isDark) + { + this.SuspendLayout(); + this.BackColor = isDark ? darkBackgroundColor : lightBackgroundColor; + + foreach (Control control in this.Controls) + { + if (control is AntdUI.Button button) + { + if (button == selectedButton) + { + button.BackColor = isDark ? darkSelectedColor : lightSelectedColor; + button.Type = TTypeMini.Primary; + } + else + { + button.BackColor = Color.Transparent; + button.Type = TTypeMini.Default; + } + button.ForeColor = isDark ? Color.White : Color.Black; + } + } + + this.ResumeLayout(); + } + + public void AddItem(SidebarNavigationItem item) + { + this.SuspendLayout(); + items.Add(item); + CreateNavigationButton(item); + ReorderButtons(); + this.ResumeLayout(); + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + foreach (Control control in this.Controls) + { + if (control is AntdUI.Button button) + { + button.Width = this.Width; + button.Height = this.Width; + } + } + } + + private void ReorderButtons() + { + if (isReordering) return; + + try + { + isReordering = true; + this.SuspendLayout(); + + var visibleTopItems = items.Where(i => i.Position == Position.Top && + this.Controls.Cast() + .Any(c => c is AntdUI.Button b && + b.Tag is ButtonInfo bi && + bi.Item == i)) + .OrderBy(i => items.IndexOf(i)); + + var visibleBottomItems = items.Where(i => i.Position == Position.Bottom && + this.Controls.Cast() + .Any(c => c is AntdUI.Button b && + b.Tag is ButtonInfo bi && + bi.Item == i)) + .OrderBy(i => items.IndexOf(i)); + + this.Controls.Clear(); + + foreach (var item in visibleTopItems.Reverse()) + { + CreateOrRestoreButton(item); + } + + foreach (var item in visibleBottomItems) + { + CreateOrRestoreButton(item); + } + } + finally + { + this.ResumeLayout(); + isReordering = false; + } + } + + private string ResizeSvgIcon(string svgContent, Size targetSize) + { + try + { + XDocument doc = XDocument.Parse(svgContent); + XElement svg = doc.Root; + + if (svg.Attribute("width") != null && svg.Attribute("height") != null) + { + svg.SetAttributeValue("width", targetSize.Width); + svg.SetAttributeValue("height", targetSize.Height); + } + + if (svg.Attribute("viewBox") == null) + { + svg.SetAttributeValue("viewBox", $"0 0 {targetSize.Width} {targetSize.Height}"); + } + + return doc.ToString(); + } + catch (Exception) + { + return svgContent; + } + } + + private void NavigationButton_Click(object sender, EventArgs e) + { + if (sender is AntdUI.Button clickedButton && clickedButton.Tag is ButtonInfo info) + { + SetSelectedButton(clickedButton); + ItemSelected?.Invoke(this, info.Item); + } + } + + public void UpdateButtonText(string tag, string text) + { + foreach (Control control in this.Controls) + { + if (control is AntdUI.Button button && + button.Tag is ButtonInfo buttonInfo && + buttonInfo.Item.Tag == tag) + { + buttonInfo.Item.Text = text; + button.Text = showText ? text : ""; + toolTip.SetToolTip(button, text); // 更新工具提示 + break; + } + } + } + + public void ClearItems() + { + this.SuspendLayout(); + try + { + items.Clear(); + buttonCache.Clear(); // 清除按钮缓存 + this.Controls.Clear(); + selectedButton = null; + } + finally + { + this.ResumeLayout(); + } + this.Invalidate(); + } + + public IEnumerable GetItems() + { + return items; + } + + + } + //// 1. 首先定义导航项类型的枚举 + //public enum NavigationItemType + //{ + // Normal, // 普通项 + // Settings, // 设置项 + // UserManagement // 用户管理项 + //} + + //public enum Position + //{ + // Top, + // Bottom + //} + + //public class SidebarNavigationItem + //{ + // public string Text { get; set; } + // public string Tag { get; set; } + // public string IconSvg { get; set; } + // public Func CreatePageControl { get; set; } + // public NavigationItemType ItemType { get; set; } = NavigationItemType.Normal; // 默认为普通项 + // public Position Position { get; set; } = Position.Top; + + // public bool IsSettings { get; set; } // 保留原有属性以保持兼容性 + + //} + + //public partial class SidebarNavigation : UserControl + //{ + // private List items = new List(); + // private Color lightBackgroundColor = Color.FromArgb(240, 240, 240); + // private Color darkBackgroundColor = Color.FromArgb(33, 33, 33); + // private Color lightSelectedColor = Color.FromArgb(0, 122, 204); + // private Color darkSelectedColor = Color.FromArgb(0, 122, 204); + // private AntdUI.Button selectedButton; + // private bool isReordering = false; + // private Font buttonFont = new Font("Microsoft YaHei UI", 10F); + + // public Size IconSize { get; set; } = new Size(42,42); + + // public event EventHandler ItemSelected; + + // public class ButtonInfo + // { + // public SidebarNavigationItem Item { get; set; } + // public AntdUI.Button Button { get; set; } + // } + + // private bool showText = false; + // public bool ShowText + // { + // get => showText; + // set + // { + // if (showText != value) + // { + // showText = value; + // UpdateButtonsLayout(); + // } + // } + // } + + // public SidebarNavigation() + // { + // InitializeComponent(); + + // SetStyle(ControlStyles.OptimizedDoubleBuffer | + // ControlStyles.AllPaintingInWmPaint | + // ControlStyles.UserPaint, true); + + // this.BackColor = AntdUI.Config.IsDark ? darkBackgroundColor : lightBackgroundColor; + // this.Width = 50; + // this.Padding = new Padding(0);// 移除控件的内边距 + // this.Margin = new Padding(0);// 移除控件的外边距 + // this.AutoScroll = false;// 禁用自动滚动以避免出现滚动条 + // } + + // public void UpdateVisibility(Func visibilityPredicate) + // { + // this.SuspendLayout(); + // try + // { + // // 先从 Controls 集合中移除所有按钮 + // this.Controls.Clear(); + + // // 重新添加符合条件的按钮 + // var topButtons = items.Where(i => i.Position == Position.Top && visibilityPredicate(i)) + // .OrderBy(i => items.IndexOf(i)); + + // var bottomButtons = items.Where(i => i.Position == Position.Bottom && visibilityPredicate(i)) + // .OrderBy(i => items.IndexOf(i)); + + // // 添加顶部按钮 + // foreach (var item in topButtons.Reverse()) + // { + // CreateNavigationButton(item); + // } + + // // 添加底部按钮 + // foreach (var item in bottomButtons) + // { + // CreateNavigationButton(item); + // } + // } + // finally + // { + // this.ResumeLayout(); + // } + // } + + + // private void CreateNavigationButton(SidebarNavigationItem item) + // { + // AntdUI.Button btn = new AntdUI.Button + // { + // Text = showText ? item.Text : "", + // // 启用多行文本 + // TextMultiLine = true, + // // 允许文本超出时自动处理 + // AutoEllipsis = true, + // BackColor = Color.Transparent, + // ForeColor = AntdUI.Config.IsDark ? Color.White : Color.Black, + // Width = this.Width, + // Height = this.Width + 5, + // Dock = item.Position == Position.Bottom ? DockStyle.Bottom : DockStyle.Top, + // Font = buttonFont, + // IconPosition = TAlignMini.Top, + // Radius = 3, + // BorderWidth = 1, + // WaveSize = 1, + // IconSvg = item.IconSvg, + // // Increase icon ratio to make icons larger relative to button size + // IconRatio = 0.8f, + // Margin = new Padding(0), + // Padding = new Padding(0), + // RespondRealAreas = true, + // Type = TTypeMini.Primary, + // Ghost = false + // }; + + // btn.Click += NavigationButton_Click; + + // var buttonInfo = new ButtonInfo + // { + // Item = item, + // Button = btn + // }; + // btn.Tag = buttonInfo; + + // this.Controls.Add(btn); + + // // 如果是当前选中的按钮,恢复选中状态 + // if (selectedButton != null && + // selectedButton.Tag is ButtonInfo selectedInfo && + // selectedInfo.Item.Tag == item.Tag) + // { + // SetSelectedButton(btn); + // } + // } + + // private void UpdateButtonsLayout() + // { + // this.SuspendLayout(); + // foreach (Control control in this.Controls) + // { + // if (control is AntdUI.Button button) + // { + // button.Height = this.Width; + // if (button.Tag is ButtonInfo buttonInfo) + // { + // button.Text = showText ? buttonInfo.Item.Text : ""; + // } + // } + // } + // this.PerformLayout(); + // this.ResumeLayout(); + // } + + // private void SetSelectedButton(AntdUI.Button button) + // { + // if (selectedButton != null) + // { + // selectedButton.BackColor = Color.Transparent; + // selectedButton.Type = TTypeMini.Default; + // selectedButton.Invalidate(); + // } + // selectedButton = button; + // if (button != null) + // { + // button.BackColor = AntdUI.Config.IsDark ? darkSelectedColor : lightSelectedColor; + // button.Type = TTypeMini.Primary; + // button.Invalidate(); + // } + // } + + + + // public void UpdateTheme(bool isDark) + // { + // this.SuspendLayout(); + // this.BackColor = isDark ? darkBackgroundColor : lightBackgroundColor; + + // foreach (Control control in this.Controls) + // { + // if (control is AntdUI.Button button) + // { + // if (button == selectedButton) + // { + // button.BackColor = isDark ? darkSelectedColor : lightSelectedColor; + // button.Type = TTypeMini.Primary; + // } + // else + // { + // button.BackColor = Color.Transparent; + // button.Type = TTypeMini.Default; + // } + // button.ForeColor = isDark ? Color.White : Color.Black; + // } + // } + + // this.ResumeLayout(); + // } + + + + // public void AddItem(SidebarNavigationItem item) + // { + // this.SuspendLayout(); + // items.Add(item); + // CreateNavigationButton(item); + // ReorderButtons(); + // this.ResumeLayout(); + // } + + + // protected override void OnResize(EventArgs e) + // { + // base.OnResize(e); + // foreach (Control control in this.Controls) + // { + // if (control is AntdUI.Button button) + // { + // button.Width = this.Width; + // button.Height = this.Width; + // } + // } + // } + + // private void ReorderButtons() + // { + // if (isReordering) return; + + // try + // { + // isReordering = true; + // this.SuspendLayout(); + + // // 获取当前所有可见的按钮 + // var visibleTopItems = items.Where(i => i.Position == Position.Top && + // this.Controls.Cast() + // .Any(c => c is AntdUI.Button b && + // b.Tag is ButtonInfo bi && + // bi.Item == i)) + // .OrderBy(i => items.IndexOf(i)); + + // var visibleBottomItems = items.Where(i => i.Position == Position.Bottom && + // this.Controls.Cast() + // .Any(c => c is AntdUI.Button b && + // b.Tag is ButtonInfo bi && + // bi.Item == i)) + // .OrderBy(i => items.IndexOf(i)); + + // this.Controls.Clear(); + + // // 重新添加顶部按钮 + // foreach (var item in visibleTopItems.Reverse()) + // { + // CreateNavigationButton(item); + // } + + // // 重新添加底部按钮 + // foreach (var item in visibleBottomItems) + // { + // CreateNavigationButton(item); + // } + // } + // finally + // { + // this.ResumeLayout(); + // isReordering = false; + // } + // } + + // private string ResizeSvgIcon(string svgContent, Size targetSize) + // { + // try + // { + // XDocument doc = XDocument.Parse(svgContent); + // XElement svg = doc.Root; + + // if (svg.Attribute("width") != null && svg.Attribute("height") != null) + // { + // svg.SetAttributeValue("width", targetSize.Width); + // svg.SetAttributeValue("height", targetSize.Height); + // } + + // if (svg.Attribute("viewBox") == null) + // { + // svg.SetAttributeValue("viewBox", $"0 0 {targetSize.Width} {targetSize.Height}"); + // } + + // return doc.ToString(); + // } + // catch (Exception) + // { + // return svgContent; + // } + // } + + // private void NavigationButton_Click(object sender, EventArgs e) + // { + // if (sender is AntdUI.Button clickedButton && clickedButton.Tag is ButtonInfo info) + // { + // SetSelectedButton(clickedButton); + // ItemSelected?.Invoke(this, info.Item); + // } + // } + + // // 更新按钮文本的方法 + // public void UpdateButtonText(string tag, string text) + // { + // foreach (Control control in this.Controls) + // { + // if (control is AntdUI.Button button && + // button.Tag is ButtonInfo buttonInfo && + // buttonInfo.Item.Tag == tag) + // { + // buttonInfo.Item.Text = text; + // button.Text = showText ? text : ""; + // break; + // } + // } + // } + + + + + // public void ClearItems() + // { + // this.SuspendLayout(); + // try + // { + // items.Clear(); + // this.Controls.Clear(); + // selectedButton = null; + // } + // finally + // { + // this.ResumeLayout(); + // } + // this.Invalidate(); + // } + + // public IEnumerable GetItems() + // { + // return items; + // } + + + + //} +} + +#region 最早期的 +//public enum Position +//{ +// Top, +// Bottom +//} + +//public class SidebarNavigationItem +//{ +// public string Text { get; set; } +// public string Tag { get; set; } +// public string IconSvg { get; set; } +// public Func CreatePageControl { get; set; } +// public bool IsSettings { get; set; } +// public Position Position { get; set; } = Position.Top; +//} + +//public partial class SidebarNavigation : UserControl +//{ +// private List items = new List(); +// private Color lightBackgroundColor = Color.FromArgb(240, 240, 240); +// private Color darkBackgroundColor = Color.FromArgb(33, 33, 33); +// private Color lightSelectedColor = Color.FromArgb(0, 150, 136); +// private Color darkSelectedColor = Color.FromArgb(0, 200, 186); +// private int buttonHeight = 40; +// private AntdUI.Button selectedButton; +// private ToolTip toolTip; +// private bool isReordering = false; + +// public Size IconSize { get; set; } = new Size(200, 200); + +// public event EventHandler ItemSelected; + +// public SidebarNavigation() +// { +// InitializeComponent(); + +// SetStyle(ControlStyles.OptimizedDoubleBuffer | +// ControlStyles.AllPaintingInWmPaint | +// ControlStyles.UserPaint, true); + +// this.BackColor = AntdUI.Config.IsDark ? darkBackgroundColor : lightBackgroundColor; +// this.Width = 50; +// this.AutoScroll = true; + +// toolTip = new ToolTip +// { +// AutoPopDelay = 5000, +// InitialDelay = 500, +// ReshowDelay = 500, +// ShowAlways = true +// }; +// } + +// public void AddItem(SidebarNavigationItem item) +// { +// this.SuspendLayout(); +// items.Add(item); +// CreateNavigationButton(item); +// ReorderButtons(); +// this.ResumeLayout(); +// } + +// public void ClearItems() +// { +// this.SuspendLayout(); +// try +// { +// items.Clear(); +// for (int i = this.Controls.Count - 1; i >= 0; i--) +// { +// if (this.Controls[i] is AntdUI.Button button) +// { +// button.Click -= NavigationButton_Click; +// this.Controls.RemoveAt(i); +// button.Dispose(); +// } +// } +// selectedButton = null; +// ReorderButtons(); +// } +// finally +// { +// this.ResumeLayout(); +// } +// this.Invalidate(); +// } + +// private void CreateNavigationButton(SidebarNavigationItem item) +// { +// string resizedSvg = ResizeSvgIcon(item.IconSvg, IconSize); + +// AntdUI.Button btn = new AntdUI.Button +// { +// Text = "", +// Tag = item, +// Dock = item.Position == Position.Bottom ? DockStyle.Bottom : DockStyle.Top, +// Height = buttonHeight, +// IconSvg = resizedSvg, +// BackColor = this.BackColor, +// ForeColor = AntdUI.Config.IsDark ? Color.White : Color.Black, +// Radius = 0, +// BorderWidth = 0 +// }; +// btn.Click += NavigationButton_Click; + +// toolTip.SetToolTip(btn, item.Text); + +// this.Controls.Add(btn); +// } + +// private string ResizeSvgIcon(string svgContent, Size targetSize) +// { +// try +// { +// XDocument doc = XDocument.Parse(svgContent); +// XElement svg = doc.Root; + +// if (svg.Attribute("width") != null && svg.Attribute("height") != null) +// { +// svg.SetAttributeValue("width", targetSize.Width); +// svg.SetAttributeValue("height", targetSize.Height); +// } + +// if (svg.Attribute("viewBox") == null) +// { +// svg.SetAttributeValue("viewBox", $"0 0 {targetSize.Width} {targetSize.Height}"); +// } + +// return doc.ToString(); +// } +// catch (Exception) +// { +// return svgContent; +// } +// } + + +// /// +// /// 图标按钮排序 +// /// +// private void ReorderButtons() +// { +// if (isReordering) return; + +// try +// { +// isReordering = true; +// this.SuspendLayout(); + +// var buttonDict = this.Controls.OfType() +// .Where(b => b.Tag is SidebarNavigationItem) +// .ToDictionary(b => ((SidebarNavigationItem)b.Tag).Tag); + +// this.Controls.Clear(); + +// // 分别获取顶部和底部的项目 +// var topItems = items.Where(i => i.Position == Position.Top) +// .OrderBy(i => items.IndexOf(i)); +// var bottomItems = items.Where(i => i.Position == Position.Bottom) +// .OrderBy(i => items.IndexOf(i)); + +// // 添加顶部按钮(反序添加以保证正确顺序) +// foreach (var item in topItems.Reverse()) +// { +// if (buttonDict.TryGetValue(item.Tag, out var button)) +// { +// button.Dock = DockStyle.Top; +// this.Controls.Add(button); +// } +// } + +// // 添加底部按钮(正序添加以保证正确顺序) +// foreach (var item in bottomItems) +// { +// if (buttonDict.TryGetValue(item.Tag, out var button)) +// { +// button.Dock = DockStyle.Bottom; +// this.Controls.Add(button); +// } +// } +// } +// finally +// { +// this.ResumeLayout(); +// isReordering = false; +// } +// } + + +// public void UpdateIconSize(Size newSize) +// { +// this.IconSize = newSize; +// foreach (Control control in this.Controls) +// { +// if (control is AntdUI.Button button && button.Tag is SidebarNavigationItem item) +// { +// string resizedSvg = ResizeSvgIcon(item.IconSvg, newSize); +// button.IconSvg = resizedSvg; +// } +// } +// this.Invalidate(); +// } + +// private void NavigationButton_Click(object sender, EventArgs e) +// { +// if (sender is AntdUI.Button clickedButton && clickedButton.Tag is SidebarNavigationItem item) +// { +// SetSelectedButton(clickedButton); +// ItemSelected?.Invoke(this, item); +// } +// } + +// private void SetSelectedButton(AntdUI.Button button) +// { +// if (selectedButton != null) +// { +// selectedButton.BackColor = this.BackColor; +// } +// selectedButton = button; +// selectedButton.BackColor = AntdUI.Config.IsDark ? darkSelectedColor : lightSelectedColor; +// } + +// public void UpdateTheme(bool isDark) +// { +// this.SuspendLayout(); +// this.BackColor = isDark ? darkBackgroundColor : lightBackgroundColor; +// foreach (Control control in this.Controls) +// { +// if (control is AntdUI.Button button) +// { +// button.BackColor = this.BackColor; +// button.ForeColor = isDark ? Color.White : Color.Black; +// } +// } +// if (selectedButton != null) +// { +// selectedButton.BackColor = isDark ? darkSelectedColor : lightSelectedColor; +// } +// toolTip.BackColor = isDark ? Color.FromArgb(64, 64, 64) : Color.White; +// toolTip.ForeColor = isDark ? Color.White : Color.Black; +// this.ResumeLayout(); +// } + +// public void UpdateItemToolTip(AntdUI.Button button, string translatedText) +// { +// if (button.InvokeRequired) +// { +// button.Invoke(new Action(() => toolTip.SetToolTip(button, translatedText))); +// } +// else +// { +// toolTip.SetToolTip(button, translatedText); +// } +// } + +// protected override void OnControlAdded(ControlEventArgs e) +// { +// base.OnControlAdded(e); +// ReorderButtons(); +// } + +// protected override void OnResize(EventArgs e) +// { +// base.OnResize(e); +// this.SuspendLayout(); +// foreach (Control control in this.Controls) +// { +// if (control is AntdUI.Button button) +// { +// button.Width = this.Width; +// } +// } +// this.ResumeLayout(); +// } + +// public void SelectFirstItem() +// { +// if (this.Controls.Count > 0 && this.Controls[0] is AntdUI.Button firstButton) +// { +// SetSelectedButton(firstButton); +// if (firstButton.Tag is SidebarNavigationItem item) +// { +// ItemSelected?.Invoke(this, item); +// } +// } +// } + +// public IEnumerable GetItems() +// { +// return items; +// } + +// public void UpdateVisibility(Func visibilityPredicate) +// { +// this.SuspendLayout(); +// foreach (Control control in this.Controls) +// { +// if (control is AntdUI.Button button && button.Tag is SidebarNavigationItem item) +// { +// button.Visible = visibilityPredicate(item); +// } +// } +// this.ResumeLayout(); +// } +//} +#endregion + diff --git a/JinYuan.ControlLib/SidebarNavigation.resx b/JinYuan.ControlLib/SidebarNavigation.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/SidebarNavigation.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/SimpleLed.Designer.cs b/JinYuan.ControlLib/SimpleLed.Designer.cs new file mode 100644 index 0000000..e3a4464 --- /dev/null +++ b/JinYuan.ControlLib/SimpleLed.Designer.cs @@ -0,0 +1,50 @@ +namespace JinYuan.ControlLib +{ + partial class SimpleLed + { + /// + /// ±ØÐèµÄÉè¼ÆÆ÷±äÁ¿¡£ + /// + private System.ComponentModel.IContainer components = null; + + /// + /// ÇåÀíËùÓÐÕýÔÚʹÓõÄ×ÊԴ¡£ + /// + /// Èç¹ûӦÊͷÅÍйÜ×ÊԴ£¬Ϊ true£»·ñÔòΪ false¡£ + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region ×é¼þÉè¼ÆÆ÷Éú³ɵĴúÂë + + /// + /// Éè¼ÆÆ÷֧³ÖËùÐèµķ½·¨ - ²»ҪÐ޸Ä + /// ʹÓôúÂë±༭Æ÷Ð޸Ĵ˷½·¨µÄÄÚÈݡ£ + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // SimpleLed + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.Green; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("΢ÈíÑźÚ", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Name = "SimpleLed"; + this.Size = new System.Drawing.Size(18, 17); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/SimpleLed.cs b/JinYuan.ControlLib/SimpleLed.cs new file mode 100644 index 0000000..166dc4d --- /dev/null +++ b/JinYuan.ControlLib/SimpleLed.cs @@ -0,0 +1,40 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class SimpleLed : UserControl + { + public SimpleLed() + { + InitializeComponent(); + + //ÉèÖÿؼþÑùʽ + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private bool state = true; + + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡָʾµƵÄ״̬")] + public bool State + { + get { return state; } + set + { + state = value; + this.BackgroundImage = state ? Properties.Resources.Green : Properties.Resources.Red; + } + } + + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡָʾµư󶨵ıäÁ¿Ãû³Æ")] + public string BindVarName { get; set; } + } +} diff --git a/JinYuan.ControlLib/SimpleLed.resx b/JinYuan.ControlLib/SimpleLed.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/SimpleLed.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/StatusExt.Designer.cs b/JinYuan.ControlLib/StatusExt.Designer.cs new file mode 100644 index 0000000..3e4cc4f --- /dev/null +++ b/JinYuan.ControlLib/StatusExt.Designer.cs @@ -0,0 +1,42 @@ +//namespace JinYuan.ControlLib +//{ +// public class BatteryControl +// { +// /// +// /// 必需的设计器变量。 +// /// +// private System.ComponentModel.IContainer components = null; + +// /// +// /// 清理所有正在使用的资源。 +// /// +// /// 如果应释放托管资源,为 true;否则为 false。 +// protected override void Dispose(bool disposing) +// { +// if (disposing && (components != null)) +// { +// components.Dispose(); +// } + +// base.Dispose(disposing); +// } + +// #region 组件设计器生成的代码 + +// /// +// /// 设计器支持所需的方法 - 不要修改 +// /// 使用代码编辑器修改此方法的内容。 +// /// +// private void InitializeComponent() +// { +// components = new System.ComponentModel.Container(); + +// SuspendLayout(); +// Name = "BatteryControl"; +// Size = new System.Drawing.Size(28, 28); +// ResumeLayout(false); +// } + +// #endregion +// } +//} diff --git a/JinYuan.ControlLib/StatusExt.cs b/JinYuan.ControlLib/StatusExt.cs new file mode 100644 index 0000000..3061450 --- /dev/null +++ b/JinYuan.ControlLib/StatusExt.cs @@ -0,0 +1,193 @@ +using JinYuan.Models; +using SeeSharpTools.JY.GUI; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public enum BatteryStatus + { + Init, // 初始化-浅灰 + PackNG, // 装箱NG-红色 + Replacing, // 替换中-天蓝色 + Normal // 正常-绿色 + } + + public class BatteryControl : LED + { + // 位置信息 + public string Grade { get; set; } // 等级(对应Tab页) + public int Layer { get; set; } // 层 + public int Row { get; set; } // 行 + public int Col { get; set; } // 列 + public string Container { get; set; }// 容器编号 + public string Barcode { get; set; } // 电池条码 + public BatteryStatus Status { get; set; } = BatteryStatus.Init; + + private readonly Size _squareSize = new Size(25, 25); + public Size BatterySquareSize => _squareSize; + + public BatteryControl(BatteryStatus status) + : this("", 0, 0, 0, "") + { + UpdateStatus(status); + } + + // 构造函数:初始化工业风样式 + public BatteryControl(string grade, int layer, int row, int col, string container, BatteryStatus status = BatteryStatus.Init) + { + // 基础位置信息 + this.Grade = grade; + this.Layer = layer; + this.Row = row; + this.Col = col; + this.Container = container; + + // 核心样式配置 + this.Size = _squareSize; + this.MinimumSize = _squareSize; + this.MaximumSize = _squareSize; + this.BorderStyle = BorderStyle.None; + this.BackColor = Color.FromArgb(24, 24, 24); + this.Margin = new Padding(2); + + // LED控件核心配置 + this.Style = LedStyle.Circular; + this.Interacton = InteractionStyle.Indicator; + this.BlinkOn = false; + this.BlinkInterval = 500; + + // 初始化LED基础颜色 + this.OffColor = Color.Gray; // 默认关闭颜色(Init状态) + this.OnColor = Color.LimeGreen;// 默认开启颜色(Normal状态) + this.Value = false; // 默认关闭(Init状态) + + // 双缓冲优化,防止闪烁 + this.DoubleBuffered = true; + this.SetStyle(ControlStyles.OptimizedDoubleBuffer | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.UserPaint, true); + ResizeRedraw = false; // 禁止调整大小重绘 + + // 默认状态 + UpdateStatus(status); + + // 点击事件 + Click += (s, e) => OnBatteryClicked?.Invoke(this); + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + // 强制保持正方形 + if (this.Size != _squareSize) + { + this.Size = _squareSize; + } + } + + // 更新状态方法,确保颜色立即生效 + public void UpdateStatus(BatteryStatus status) + { + // 防止跨线程调用问题 + if (this.InvokeRequired) + { + this.Invoke(new Action(UpdateStatus), status); + return; + } + + this.Status = status; + switch (status) + { + case BatteryStatus.Normal: + this.Value = true; // 必须设为true才能显示OnColor + this.OnColor = Color.LimeGreen; + this.OffColor = Color.Transparent; + break; + case BatteryStatus.PackNG: + this.Value = true; // 必须设为true才能显示OnColor + this.OnColor = Color.Red; + this.OffColor = Color.Transparent; + break; + case BatteryStatus.Init: + this.Value = false; // 设为false显示OffColor + this.OffColor = Color.Gray; + this.OnColor = Color.Transparent; + this.Barcode = null; + break; + case BatteryStatus.Replacing: + this.Value = true; // 必须设为true才能显示OnColor + this.OnColor = Color.SkyBlue; + this.OffColor = Color.Transparent; + break; + } + + // 强制刷新控件,确保颜色立即更新 + this.Invalidate(); + //this.Update(); + //this.Refresh(); + } + + /// + /// 绑定数据(线程安全+状态更新) + /// + public void BindData(string barcode, BatteryStatus status, string container = null) + { + if (InvokeRequired) + { + BeginInvoke(new Action(BindData), barcode, status, container); + return; + } + + Barcode = barcode; + if (!string.IsNullOrEmpty(container)) + { + Container = container; + } + + // 仅状态变化时更新 + if (Status != status) + { + UpdateStatus(status); + } + } + + /// + /// 清理控件(重置为初始状态) + /// + public void Clear() + { + BindData(null, BatteryStatus.Init, Container); + } + + // 选中事件回调 + public event Action OnBatteryClicked; + + // 重写OnPaint方法,确保绘制生效 + protected override void OnPaint(PaintEventArgs e) + { + // 启用双缓冲和高质量绘制 + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + e.Graphics.CompositingQuality = CompositingQuality.HighQuality; + base.OnPaint(e); + } + + private void InitializeComponent() + { + this.SuspendLayout(); + // + // BatteryControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); + this.Name = "BatteryControl"; + this.Size = new System.Drawing.Size(40, 40); + this.ResumeLayout(false); + + } + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/StatusExt.resx b/JinYuan.ControlLib/StatusExt.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/StatusExt.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/TButton.Designer.cs b/JinYuan.ControlLib/TButton.Designer.cs new file mode 100644 index 0000000..bf6696a --- /dev/null +++ b/JinYuan.ControlLib/TButton.Designer.cs @@ -0,0 +1,67 @@ +namespace JinYuan.ControlLib +{ + partial class TButton + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold); + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(118, 36); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "标题按钮"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.lbl_Title.Click += new System.EventHandler(this.lbl_Title_Click); + // + // TButton + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(28)))), ((int)(((byte)(68))))); + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.Title; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Name = "TButton"; + this.Size = new System.Drawing.Size(207, 41); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/TButton.cs b/JinYuan.ControlLib/TButton.cs new file mode 100644 index 0000000..6c4f860 --- /dev/null +++ b/JinYuan.ControlLib/TButton.cs @@ -0,0 +1,47 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class TButton : UserControl + { + public TButton() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private string titleName = "标题名称"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示标题名称")] + + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + } + } + + [Browsable(true)]//是否可见 + [Category("自定义事件")] //类别 + [Description("设置或显示按钮文本内容")] + public new EventHandler Click; + + private void lbl_Title_Click(object sender, EventArgs e) + { + this.Click?.Invoke(this, e); + } + + } +} diff --git a/JinYuan.ControlLib/TButton.resx b/JinYuan.ControlLib/TButton.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/TButton.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/TextSet.Designer.cs b/JinYuan.ControlLib/TextSet.Designer.cs new file mode 100644 index 0000000..859a443 --- /dev/null +++ b/JinYuan.ControlLib/TextSet.Designer.cs @@ -0,0 +1,108 @@ +namespace JinYuan.ControlLib +{ + partial class TextSet + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.MainTableLayoutControl = new System.Windows.Forms.TableLayoutPanel(); + this.lbl_Unit = new System.Windows.Forms.Label(); + this.lbl_Value = new System.Windows.Forms.Label(); + this.MainTableLayoutControl.SuspendLayout(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Location = new System.Drawing.Point(4, 5); + this.lbl_Title.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(94, 20); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "参数名称设置"; + // + // MainTableLayoutControl + // + this.MainTableLayoutControl.ColumnCount = 3; + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 30F)); + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.MainTableLayoutControl.Controls.Add(this.lbl_Unit, 2, 0); + this.MainTableLayoutControl.Controls.Add(this.lbl_Value, 1, 0); + this.MainTableLayoutControl.Controls.Add(this.lbl_Title, 0, 0); + this.MainTableLayoutControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.MainTableLayoutControl.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.MainTableLayoutControl.Location = new System.Drawing.Point(0, 0); + this.MainTableLayoutControl.Margin = new System.Windows.Forms.Padding(1); + this.MainTableLayoutControl.Name = "MainTableLayoutControl"; + this.MainTableLayoutControl.RowCount = 1; + this.MainTableLayoutControl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.MainTableLayoutControl.Size = new System.Drawing.Size(204, 30); + this.MainTableLayoutControl.TabIndex = 1; + // + // lbl_Unit + // + this.lbl_Unit.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Unit.Location = new System.Drawing.Point(167, 5); + this.lbl_Unit.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Unit.Name = "lbl_Unit"; + this.lbl_Unit.Size = new System.Drawing.Size(33, 20); + this.lbl_Unit.TabIndex = 2; + this.lbl_Unit.Text = "℃"; + // + // lbl_Value + // + this.lbl_Value.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Value.Location = new System.Drawing.Point(106, 5); + this.lbl_Value.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Value.Name = "lbl_Value"; + this.lbl_Value.Size = new System.Drawing.Size(53, 20); + this.lbl_Value.TabIndex = 1; + this.lbl_Value.Text = "0.0"; + // + // TextSet + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.MainTableLayoutControl); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "TextSet"; + this.Size = new System.Drawing.Size(204, 30); + this.MainTableLayoutControl.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + private System.Windows.Forms.TableLayoutPanel MainTableLayoutControl; + private System.Windows.Forms.Label lbl_Unit; + private System.Windows.Forms.Label lbl_Value; + } +} diff --git a/JinYuan.ControlLib/TextSet.cs b/JinYuan.ControlLib/TextSet.cs new file mode 100644 index 0000000..000fc2c --- /dev/null +++ b/JinYuan.ControlLib/TextSet.cs @@ -0,0 +1,112 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [DefaultEvent("ControlDoubleClick")] + public partial class TextSet : UserControl + { + public TextSet() + { + InitializeComponent(); + } + + + //private int titleScale = 50; + //[Browsable(true)] + //[Category("自定义属性")] + //[Description("设置或获取标题所占比例")] + //public int TitleScale + //{ + // get { return titleScale; } + // set + // { + // titleScale = value; + + // this.MainTableLayoutControl.ColumnStyles[0] = new ColumnStyle(SizeType.Percent, titleScale); + // } + //} + + + //private int valueScale = 30; + //[Browsable(true)] + //[Category("自定义属性")] + //[Description("设置或获取数据所占比例")] + //public int ValueScale + //{ + // get { return valueScale; } + // set + // { + // valueScale = value; + + // this.MainTableLayoutControl.ColumnStyles[1] = new ColumnStyle(SizeType.Percent, valueScale); + // } + //} + + private string titleName = "参数名称设置"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取参数名称")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + + this.lbl_Title.Text = titleName; + } + } + + + private string currentValue = "0.0"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取当前数值")] + public string CurrentValue + { + get { return currentValue; } + set + { + currentValue = value; + + this.lbl_Value.Text = currentValue; + } + } + + + private string unit = "℃"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取当前单位")] + public string Unit + { + get { return unit; } + set + { + unit = value; + + this.lbl_Unit.Text = unit; + } + } + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取绑定变量名称")] + public string BindVarName { get; set; } + + [Browsable(true)] + [Category("自定义事件")] + [Description("控件双击事件")] + public event EventHandler ControlDoubleClick; + + private void lbl_Value_DoubleClick(object sender, EventArgs e) + { + if (ControlDoubleClick != null) + { + ControlDoubleClick(this, e); + } + } + } +} diff --git a/JinYuan.ControlLib/TextSet.resx b/JinYuan.ControlLib/TextSet.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/TextSet.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/TextSet2.Designer.cs b/JinYuan.ControlLib/TextSet2.Designer.cs new file mode 100644 index 0000000..2580a7f --- /dev/null +++ b/JinYuan.ControlLib/TextSet2.Designer.cs @@ -0,0 +1,95 @@ +namespace JinYuan.ControlLib +{ + partial class TextSet2 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.MainTableLayoutControl = new System.Windows.Forms.TableLayoutPanel(); + this.lbl_Value = new System.Windows.Forms.Label(); + this.MainTableLayoutControl.SuspendLayout(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Location = new System.Drawing.Point(4, 5); + this.lbl_Title.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(107, 20); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "参数名称设置"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // MainTableLayoutControl + // + this.MainTableLayoutControl.ColumnCount = 2; + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 60.73298F)); + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 39.26702F)); + this.MainTableLayoutControl.Controls.Add(this.lbl_Value, 1, 0); + this.MainTableLayoutControl.Controls.Add(this.lbl_Title, 0, 0); + this.MainTableLayoutControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.MainTableLayoutControl.Location = new System.Drawing.Point(0, 0); + this.MainTableLayoutControl.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.MainTableLayoutControl.Name = "MainTableLayoutControl"; + this.MainTableLayoutControl.RowCount = 1; + this.MainTableLayoutControl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.MainTableLayoutControl.Size = new System.Drawing.Size(191, 30); + this.MainTableLayoutControl.TabIndex = 1; + // + // lbl_Value + // + this.lbl_Value.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Value.Location = new System.Drawing.Point(119, 5); + this.lbl_Value.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.lbl_Value.Name = "lbl_Value"; + this.lbl_Value.Size = new System.Drawing.Size(68, 20); + this.lbl_Value.TabIndex = 1; + this.lbl_Value.Text = "0.0"; + this.lbl_Value.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // TextSet2 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.MainTableLayoutControl); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "TextSet2"; + this.Size = new System.Drawing.Size(191, 30); + this.MainTableLayoutControl.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + private System.Windows.Forms.TableLayoutPanel MainTableLayoutControl; + private System.Windows.Forms.Label lbl_Value; + } +} diff --git a/JinYuan.ControlLib/TextSet2.cs b/JinYuan.ControlLib/TextSet2.cs new file mode 100644 index 0000000..dee5637 --- /dev/null +++ b/JinYuan.ControlLib/TextSet2.cs @@ -0,0 +1,99 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [DefaultEvent("ControlDoubleClick")] + public partial class TextSet2 : UserControl + { + public TextSet2() + { + InitializeComponent(); + } + + + //private int titleScale = 50; + //[Browsable(true)] + //[Category("自定义属性")] + //[Description("设置或获取标题所占比例")] + //public int TitleScale + //{ + // get { return titleScale; } + // set + // { + // titleScale = value; + + // this.MainTableLayoutControl.ColumnStyles[0] = new ColumnStyle(SizeType.Percent, titleScale); + // } + //} + + + //private int valueScale = 30; + //[Browsable(true)] + //[Category("自定义属性")] + //[Description("设置或获取数据所占比例")] + //public int ValueScale + //{ + // get { return valueScale; } + // set + // { + // valueScale = value; + + // this.MainTableLayoutControl.ColumnStyles[1] = new ColumnStyle(SizeType.Percent, valueScale); + // } + //} + + private string titleName = "参数名称设置"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取参数名称")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + + this.lbl_Title.Text = titleName; + } + } + + + private string currentValue = "0.0"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取当前数值")] + public string CurrentValue + { + get { return currentValue; } + set + { + currentValue = value; + + this.lbl_Value.Text = currentValue; + } + } + + + + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取绑定变量名称")] + public string BindVarName { get; set; } + + [Browsable(true)] + [Category("自定义事件")] + [Description("控件双击事件")] + public event EventHandler ControlDoubleClick; + + private void lbl_Value_DoubleClick(object sender, EventArgs e) + { + if (ControlDoubleClick != null) + { + ControlDoubleClick(this, e); + } + } + } +} diff --git a/JinYuan.ControlLib/TextSet2.resx b/JinYuan.ControlLib/TextSet2.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/TextSet2.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Title.Designer.cs b/JinYuan.ControlLib/Title.Designer.cs new file mode 100644 index 0000000..58f20bd --- /dev/null +++ b/JinYuan.ControlLib/Title.Designer.cs @@ -0,0 +1,66 @@ +namespace JinYuan.ControlLib +{ + partial class Title + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold); + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(118, 36); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "标题名称"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // Title + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(28)))), ((int)(((byte)(68))))); + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.Title; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Name = "Title"; + this.Size = new System.Drawing.Size(118, 36); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/Title.cs b/JinYuan.ControlLib/Title.cs new file mode 100644 index 0000000..a4145c3 --- /dev/null +++ b/JinYuan.ControlLib/Title.cs @@ -0,0 +1,36 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class Title : UserControl + { + public Title() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private string titleName = "标题名称"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示标题名称")] + + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + } + } + + } +} diff --git a/JinYuan.ControlLib/Title.resx b/JinYuan.ControlLib/Title.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/Title.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/TitleButton.Designer.cs b/JinYuan.ControlLib/TitleButton.Designer.cs new file mode 100644 index 0000000..b01fa81 --- /dev/null +++ b/JinYuan.ControlLib/TitleButton.Designer.cs @@ -0,0 +1,66 @@ +namespace JinYuan.ControlLib +{ + partial class TitleButton + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.btn_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // btn_Title + // + this.btn_Title.BackColor = System.Drawing.Color.Transparent; + this.btn_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.btn_Title.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold); + this.btn_Title.ForeColor = System.Drawing.Color.White; + this.btn_Title.Location = new System.Drawing.Point(0, 0); + this.btn_Title.Name = "btn_Title"; + this.btn_Title.Size = new System.Drawing.Size(129, 43); + this.btn_Title.TabIndex = 0; + this.btn_Title.Text = "菜单按钮"; + this.btn_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.btn_Title.Click += new System.EventHandler(this.lbl_Title_Click); + // + // TitleButton + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.Title; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.btn_Title); + this.DoubleBuffered = true; + this.Name = "TitleButton"; + this.Size = new System.Drawing.Size(129, 43); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label btn_Title; + } +} diff --git a/JinYuan.ControlLib/TitleButton.cs b/JinYuan.ControlLib/TitleButton.cs new file mode 100644 index 0000000..dc70f82 --- /dev/null +++ b/JinYuan.ControlLib/TitleButton.cs @@ -0,0 +1,90 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [DefaultEvent("Click")]//增加特性事件 + public partial class TitleButton : UserControl + { + public TitleButton() + { + InitializeComponent(); + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private bool isSelected = false; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮是否选中")] + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + UpdataImage(); + } + } + + + private bool isLeft = true; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮是否为左边")] + public bool IsLeft + { + get { return isLeft; } + set + { + isLeft = value; + UpdataImage(); + } + } + + private string titleName = "导航按钮"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示导航按钮文本内容")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.btn_Title.Text = titleName; + } + } + + + /// + ///统一更新背景 + /// + private void UpdataImage() + { + if (this.isLeft) + { + this.BackgroundImage = isSelected ? Properties.Resources.LeftSelected : Properties.Resources.LeftUnSelected; + } + else + { + this.BackgroundImage = isSelected ? Properties.Resources.RightSelected : Properties.Resources.RightUnSelected; + } + } + + [Browsable(true)]//是否可见 + [Category("自定义事件")] //类别 + [Description("设置或显示导航按钮文本内容")] + public new EventHandler Click; + + private void lbl_Title_Click(object sender, EventArgs e) + { + this.Click?.Invoke(this, e); + } + } +} diff --git a/JinYuan.ControlLib/TitleButton.resx b/JinYuan.ControlLib/TitleButton.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/TitleButton.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/TitleTime.Designer.cs b/JinYuan.ControlLib/TitleTime.Designer.cs new file mode 100644 index 0000000..18125f9 --- /dev/null +++ b/JinYuan.ControlLib/TitleTime.Designer.cs @@ -0,0 +1,98 @@ +namespace JinYuan.ControlLib +{ + partial class TitleTime + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lb_TitleName = new System.Windows.Forms.Label(); + this.lbl_Title = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // lb_TitleName + // + this.lb_TitleName.Dock = System.Windows.Forms.DockStyle.Fill; + this.lb_TitleName.ForeColor = System.Drawing.Color.White; + this.lb_TitleName.Location = new System.Drawing.Point(22, 0); + this.lb_TitleName.Name = "lb_TitleName"; + this.lb_TitleName.Size = new System.Drawing.Size(108, 30); + this.lb_TitleName.TabIndex = 0; + this.lb_TitleName.Text = "label1"; + this.lb_TitleName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // lbl_Title + // + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(136, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(169, 30); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "label1"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 3; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 19F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 39.44637F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 60.55363F)); + this.tableLayoutPanel1.Controls.Add(this.lb_TitleName, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lbl_Title, 2, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(308, 30); + this.tableLayoutPanel1.TabIndex = 1; + // + // TitleTime + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources._61; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.tableLayoutPanel1); + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "TitleTime"; + this.Size = new System.Drawing.Size(308, 30); + this.tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Label lb_TitleName; + private System.Windows.Forms.Label lbl_Title; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + } +} diff --git a/JinYuan.ControlLib/TitleTime.cs b/JinYuan.ControlLib/TitleTime.cs new file mode 100644 index 0000000..54aaab4 --- /dev/null +++ b/JinYuan.ControlLib/TitleTime.cs @@ -0,0 +1,246 @@ +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Text; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + //public partial class TitleTime : UserControl + //{ + // public TitleTime() + // { + // InitializeComponent(); + // //设置控件样式,去除缓冲 + // this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + // this.SetStyle(ControlStyles.DoubleBuffer, true); + // this.SetStyle(ControlStyles.ResizeRedraw, true); + // this.SetStyle(ControlStyles.Selectable, true); + // this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + // } + + // private string ttfFelePath = ""; + + // private string ttfPath = ""; + // [Browsable(true)]//是否可见 + // [Category("自定义属性")] //类别/Assts/Fonts/zaozigongfangjinzhuti.ttf + // [Description("设置字体路径")] + // public string TtfPath + // { + // get { return ttfPath; } + // set + // { + // ttfPath = value; + // if (ttfPath != "") + // { + // ttfFelePath = System.Windows.Forms.Application.StartupPath + $"{ttfPath}"; + // this.Invalidate(); + // } + + // } + // } + + // private string titleName = "标题名称"; + // [Browsable(true)]//是否可见 + // [Category("自定义属性")] //类别 + // [Description("设置或显示标题名称")] + // public string TitleName + // { + // get { return titleName; } + // set + // { + // titleName = value; + // if (ttfFelePath != "") + // { + // string fontPath = ttfFelePath; + // LoadFont(fontPath, 24); + // } + // this.lb_TitleName.Text = titleName; + // } + // } + + + // private Color titleNameForColor = Color.FromArgb(255, 77, 59); + // [Browsable(true)] + // [Category("自定义属性")] + // [Description("设置或获取标题名称字体颜色")] + // public Color TitleNameForColor + // { + // get { return titleNameForColor; } + // set + // { + // titleNameForColor = value; + // this.lb_TitleName.ForeColor = titleNameForColor; + // } + // } + + // private string title = "控件内容"; + // [Browsable(true)]//是否可见 + // [Category("自定义属性")] //类别 + // [Description("设置或显示内容")] + // public string Title + // { + // get { return title; } + // set + // { + // title = value; + // if (ttfFelePath != "") + // { + // string fontPath = ttfFelePath; + // LoadFont(fontPath, 24); + // } + // this.lbl_Title.Text = title; + // } + // } + + + + + // public void LoadFont(string path, float size) + // { + // //int fontId = AddFontResource(path); + // PrivateFontCollection fontCollection = new PrivateFontCollection(); + // fontCollection.AddFontFile(path); + // Font myFont = new Font(fontCollection.Families[0].Name, 9F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134))); + // //Font font = new Font(fontCollection.Families[0], size); + // this.lbl_Title.Font = myFont; + // //RemoveFontResource(path); + // //return font; + // } + + // // 辅助方法 + // private class FontLoader + // { + // //[DllImport("gdi32.dll", EntryPoint = "AddFontResourceW", SetLastError = true)] + // //public static extern int AddFontResource([In][MarshalAs(UnmanagedType.LPWStr)] string lpFileName); + + // //[DllImport("gdi32.dll", EntryPoint = "RemoveFontResourceW", SetLastError = true)] + // //public static extern int RemoveFontResource([In][MarshalAs(UnmanagedType.LPWStr)] string lpFileName); + + // public Font LoadFont(string path, float size) + // { + // //int fontId = AddFontResource(path); + // PrivateFontCollection fontCollection = new PrivateFontCollection(); + // fontCollection.AddFontFile(path); + // //Font myFont = new Font(font.Families[0].Name, 9F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134))); + // Font font = new Font(fontCollection.Families[0], size); + // //RemoveFontResource(path); + // return font; + // } + // } + + + + //} + + + public partial class TitleTime : UserControl + { + public TitleTime() + { + InitializeComponent(); + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + private string ttfFelePath = ""; + + private string ttfPath = ""; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置字体路径")] + public string TtfPath + { + get { return ttfPath; } + set + { + ttfPath = value; + if (ttfPath != "") + { + ttfFelePath = System.Windows.Forms.Application.StartupPath + $"{ttfPath}"; + this.Invalidate(); + } + } + } + + private float titleFontSize = 24f; // 默认字体大小 + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取标题字体大小")] + public float TitleFontSize + { + get { return titleFontSize; } + set + { + titleFontSize = value; + if (ttfFelePath != "") + { + LoadFont(ttfFelePath, titleFontSize); + } + this.Invalidate(); // 强制重绘控件 + } + } + + private string titleName = "标题名称"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或显示标题名称")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + if (ttfFelePath != "") + { + LoadFont(ttfFelePath, TitleFontSize); + } + this.lb_TitleName.Text = titleName; + } + } + + private Color titleNameForColor = Color.FromArgb(255, 77, 59); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取标题名称字体颜色")] + public Color TitleNameForColor + { + get { return titleNameForColor; } + set + { + titleNameForColor = value; + this.lb_TitleName.ForeColor = titleNameForColor; + } + } + + private string title = "控件内容"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或显示内容")] + public string Title + { + get { return title; } + set + { + title = value; + if (ttfFelePath != "") + { + LoadFont(ttfFelePath, TitleFontSize); + } + this.lbl_Title.Text = title; + } + } + + public void LoadFont(string path, float size) + { + PrivateFontCollection fontCollection = new PrivateFontCollection(); + fontCollection.AddFontFile(path); + Font myFont = new Font(fontCollection.Families[0].Name, size, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134))); + this.lbl_Title.Font = myFont; + this.lb_TitleName.Font = myFont; // 如果需要标题名称也使用相同的字体 + } + } +} diff --git a/JinYuan.ControlLib/TitleTime.resx b/JinYuan.ControlLib/TitleTime.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/TitleTime.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/Toggle.Designer.cs b/JinYuan.ControlLib/Toggle.Designer.cs new file mode 100644 index 0000000..1d47d30 --- /dev/null +++ b/JinYuan.ControlLib/Toggle.Designer.cs @@ -0,0 +1,45 @@ +namespace JinYuan.ControlLib +{ + partial class Toggle + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // Toggle + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "Toggle"; + this.Size = new System.Drawing.Size(95, 42); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/Toggle.cs b/JinYuan.ControlLib/Toggle.cs new file mode 100644 index 0000000..484eef4 --- /dev/null +++ b/JinYuan.ControlLib/Toggle.cs @@ -0,0 +1,338 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public enum ControlType + { + /// + /// 椭圆 + /// + Ellipse, + /// + /// 矩形 + /// + Rectangle, + /// + /// 直线 + /// + Line + + } + + [DefaultEvent("CheckedChanged")] + public partial class Toggle : UserControl + { + public Toggle() + { + InitializeComponent(); + + //设置控件样式 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + this.MouseDown += Toggle_MouseDown; + } + + private void Toggle_MouseDown(object sender, MouseEventArgs e) + { + IsChecked = !IsChecked; + + CheckedChanged?.Invoke(this, e); + } + + private ControlType controlType = ControlType.Ellipse; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件的样式")] + public ControlType ControlType + { + get { return controlType; } + set + { + controlType = value; + + this.Invalidate(); + } + } + + + private Color trueColor = Color.FromArgb(73, 119, 232); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件选中的颜色")] + public Color TrueColor + { + get { return trueColor; } + set + { + trueColor = value; + + this.Invalidate(); + } + } + + + private Color falseColor = Color.FromArgb(180, 180, 180); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件未选中的颜色")] + public Color FalseColor + { + get { return falseColor; } + set + { + falseColor = value; + + this.Invalidate(); + } + } + + + private bool isChecked = false; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件是否选中")] + public bool IsChecked + { + get { return isChecked; } + set + { + isChecked = value; + this.Invalidate(); + } + } + + + + + private string trueText = string.Empty; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件选中的文本")] + public string TrueText + { + get { return trueText; } + set + { + trueText = value; + this.Invalidate(); + } + } + + private string falseText = string.Empty; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件未选中的文本")] + public string FalseText + { + get { return falseText; } + set + { + falseText = value; + this.Invalidate(); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + Graphics graphics = e.Graphics; + + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + + //获取填充颜色 + Color fillColor = isChecked ? trueColor : falseColor; + + //创建路径 + GraphicsPath path = new GraphicsPath(); + + //文本 + string text = isChecked ? trueText : falseText; + + //文件尺寸 + SizeF size = graphics.MeasureString(text, this.Font); + + //间隙 + int gap = 2; + + //小圆宽度 + int border = 2; + + switch (controlType) + { + case ControlType.Ellipse: + + float r = (this.Height - 2) * 0.5f; + + //添加直线 + path.AddLine(new Point(this.Height / 2, 1), new Point(this.Width - this.Height / 2, 1)); + //添加圆弧 + path.AddArc(new RectangleF(this.Width - 2 * r - 1, 1, 2 * r, 2 * r), -90, 180); + //添加直线 + path.AddLine(new PointF(this.Width - r - 1, this.Height - 1), new Point(this.Height / 2, this.Height - 1)); + //添加圆弧 + path.AddArc(new RectangleF(1, 1, 2 * r, 2 * r), 90, 180); + + graphics.FillPath(new SolidBrush(fillColor), path); + + //大圆半径 + float radius = (this.Height - 2 * (1 + gap)) * 0.5f; + + //如果选中如何绘制 + if (isChecked) + { + graphics.FillEllipse(Brushes.White, new RectangleF(this.Width - 2 * radius - gap - 1, gap + 1, 2 * radius, 2 * radius)); + + //如果文本为空,则画小圆,否则,写文字 + if (string.IsNullOrEmpty(text)) + { + graphics.DrawEllipse(new Pen(Color.White, border), new RectangleF(this.Height * 0.5f - radius * 0.5f, this.Height * 0.5f - radius * 0.5f, radius, radius)); + } + else + { + graphics.DrawString(text, this.Font, Brushes.White, new PointF(this.Height * 0.5f - size.Height * 0.5f, this.Height * 0.5f - size.Height * 0.5f)); + } + } + else + { + graphics.FillEllipse(Brushes.White, new RectangleF(gap + 1, gap + 1, 2 * radius, 2 * radius)); + + //如果文本为空,则画小圆,否则,写文字 + if (string.IsNullOrEmpty(text)) + { + graphics.DrawEllipse(new Pen(Color.White, border), new RectangleF(this.Width - (1.5f * radius + 1), this.Height * 0.5f - radius * 0.5f, radius, radius)); + } + else + { + graphics.DrawString(text, this.Font, Brushes.White, new PointF(this.Width - (this.Height * 0.5f - size.Height * 0.5f) - size.Width, this.Height * 0.5f - size.Height * 0.5f)); + } + } + break; + case ControlType.Rectangle: + + int intRadius = 3; + + //添加圆弧1 + path.AddArc(new RectangleF(1, 1, intRadius * 2, intRadius * 2), 180, 90); + //添加圆弧2 + path.AddArc(new RectangleF(this.Width - 2 * intRadius - 1, 1, intRadius * 2, intRadius * 2), 270, 90); + //添加圆弧3 + path.AddArc(new RectangleF(this.Width - 2 * intRadius - 1, this.Height - 2 * intRadius - 1, intRadius * 2, intRadius * 2), 0, 90); + //添加圆弧4 + path.AddArc(new RectangleF(1, this.Height - 2 * intRadius - 1, intRadius * 2, intRadius * 2), 90, 90); + + graphics.FillPath(new SolidBrush(fillColor), path); + + if (isChecked) + { + path = new GraphicsPath(); + + int inwidth = this.Height - 2 * (gap + 1); + + //添加圆弧1 + path.AddArc(new RectangleF(this.Width - inwidth - gap - 1, 1 + gap, intRadius * 2, intRadius * 2), 180, 90); + //添加圆弧2 + path.AddArc(new RectangleF(this.Width - 1 - gap - 2 * intRadius, 1 + gap, intRadius * 2, intRadius * 2), 270, 90); + //添加圆弧3 + path.AddArc(new RectangleF(this.Width - 1 - gap - 2 * intRadius, this.Height - 2 * intRadius - 1 - gap, intRadius * 2, intRadius * 2), 0, 90); + //添加圆弧4 + path.AddArc(new RectangleF(this.Width - inwidth - gap - 1, this.Height - 2 * intRadius - 1 - gap, intRadius * 2, intRadius * 2), 90, 90); + + graphics.FillPath(Brushes.White, path); + + radius = inwidth * 0.5f; + + //如果文本为空,则画小圆,否则,写文字 + if (string.IsNullOrEmpty(text)) + { + graphics.DrawEllipse(new Pen(Color.White, border), new RectangleF(this.Height * 0.5f - radius * 0.5f, this.Height * 0.5f - radius * 0.5f, radius, radius)); + } + else + { + graphics.DrawString(text, this.Font, Brushes.White, new PointF(this.Height * 0.5f - size.Height * 0.5f, this.Height * 0.5f - size.Height * 0.5f)); + } + } + else + { + path = new GraphicsPath(); + + int inwidth = this.Height - 2 * (gap + 1); + + //添加圆弧1 + path.AddArc(new RectangleF(1 + gap, 1 + gap, intRadius * 2, intRadius * 2), 180, 90); + //添加圆弧2 + path.AddArc(new RectangleF(inwidth + 1 + gap - 2 * intRadius, 1 + gap, intRadius * 2, intRadius * 2), 270, 90); + //添加圆弧3 + path.AddArc(new RectangleF(inwidth + 1 + gap - 2 * intRadius, this.Height - 2 * intRadius - 1 - gap, intRadius * 2, intRadius * 2), 0, 90); + //添加圆弧4 + path.AddArc(new RectangleF(1 + gap, this.Height - 2 * intRadius - 1 - gap, intRadius * 2, intRadius * 2), 90, 90); + + graphics.FillPath(Brushes.White, path); + + radius = inwidth * 0.5f; + + //如果文本为空,则画小圆,否则,写文字 + if (string.IsNullOrEmpty(text)) + { + graphics.DrawEllipse(new Pen(Color.White, border), new RectangleF(this.Width - (1.5f * radius + 1), this.Height * 0.5f - radius * 0.5f, radius, radius)); + } + else + { + graphics.DrawString(text, this.Font, Brushes.White, new PointF(this.Width - (this.Height * 0.5f - size.Height * 0.5f) - size.Width, this.Height * 0.5f - size.Height * 0.5f)); + } + } + + break; + case ControlType.Line: + + float bigRadius = (this.Height - 2) * 0.5f; + float smallRadius = bigRadius * 0.5f; + + path = new GraphicsPath(); + //添加直线1 + path.AddLine(new PointF(1 + bigRadius + smallRadius, 1 + smallRadius), new PointF(this.Width - (1 + bigRadius + smallRadius), 1 + smallRadius)); + //添加圆弧1 + path.AddArc(new RectangleF(this.Width - (1 + bigRadius + smallRadius * 2), 1 + smallRadius, smallRadius * 2, smallRadius * 2), -90, 180); + //添加直线2 + path.AddLine(new PointF(this.Width - (1 + bigRadius + smallRadius), 1 + smallRadius + bigRadius), new PointF(1 + bigRadius + smallRadius, 1 + smallRadius + bigRadius)); + //添加圆弧2 + path.AddArc(new RectangleF(1 + bigRadius, 1 + smallRadius, smallRadius * 2, smallRadius * 2), 90, 180); + + graphics.FillPath(new SolidBrush(fillColor), path); + + if (isChecked) + { + graphics.FillEllipse(new SolidBrush(fillColor), new RectangleF(this.Width - (1 + bigRadius * 2), 1, bigRadius * 2, bigRadius * 2)); + + graphics.FillEllipse(Brushes.White, new RectangleF(this.Width - (1 + bigRadius + smallRadius), 1 + smallRadius, smallRadius * 2, smallRadius * 2)); + } + else + { + graphics.FillEllipse(new SolidBrush(fillColor), new RectangleF(1, 1, bigRadius * 2, bigRadius * 2)); + + graphics.FillEllipse(Brushes.White, new RectangleF(1 + smallRadius, 1 + smallRadius, smallRadius * 2, smallRadius * 2)); + } + + break; + default: + break; + } + } + + [Browsable(true)] + [Category("自定义事件")] + [Description("选中发生变化触发")] + public event EventHandler CheckedChanged; + + } +} diff --git a/JinYuan.ControlLib/Toggle.resx b/JinYuan.ControlLib/Toggle.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/Toggle.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/TotalQty.Designer.cs b/JinYuan.ControlLib/TotalQty.Designer.cs new file mode 100644 index 0000000..5aa9ff3 --- /dev/null +++ b/JinYuan.ControlLib/TotalQty.Designer.cs @@ -0,0 +1,69 @@ +namespace JinYuan.ControlLib +{ + partial class TotalQty + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 20F, System.Drawing.FontStyle.Bold); + this.lbl_Title.ForeColor = System.Drawing.Color.White; + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(41, 60); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = "1"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // TotalQty + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.数字指标; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.Controls.Add(this.lbl_Title); + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "TotalQty"; + this.Size = new System.Drawing.Size(41, 60); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/TotalQty.cs b/JinYuan.ControlLib/TotalQty.cs new file mode 100644 index 0000000..09dad7e --- /dev/null +++ b/JinYuan.ControlLib/TotalQty.cs @@ -0,0 +1,49 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class TotalQty : UserControl + { + public TotalQty() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + private string titleName = "1"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示数字值")] + + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + this.Invalidate(); + } + } + } +} diff --git a/JinYuan.ControlLib/TotalQty.resx b/JinYuan.ControlLib/TotalQty.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/TotalQty.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCBlower.Designer.cs b/JinYuan.ControlLib/UCBlower.Designer.cs new file mode 100644 index 0000000..c63f409 --- /dev/null +++ b/JinYuan.ControlLib/UCBlower.Designer.cs @@ -0,0 +1,46 @@ +namespace JinYuan.ControlLib +{ + partial class UCBlower + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // UCBlower + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "UCBlower"; + this.Size = new System.Drawing.Size(67, 63); + this.VisibleChanged += new System.EventHandler(this.UCBlower_VisibleChanged); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCBlower.cs b/JinYuan.ControlLib/UCBlower.cs new file mode 100644 index 0000000..fa6d27e --- /dev/null +++ b/JinYuan.ControlLib/UCBlower.cs @@ -0,0 +1,436 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class UCBlower : UserControl + { + /// + /// The entrance direction + /// + private BlowerEntranceDirection entranceDirection = BlowerEntranceDirection.None; + + /// + /// Gets or sets the entrance direction. + /// + /// The entrance direction. + [Description("入口方向"), Category("自定义")] + public BlowerEntranceDirection EntranceDirection + { + get { return entranceDirection; } + set + { + entranceDirection = value; + Invalidate(); + } + } + + /// + /// The exit direction + /// + private BlowerExitDirection exitDirection = BlowerExitDirection.Right; + + /// + /// Gets or sets the exit direction. + /// + /// The exit direction. + [Description("出口方向"), Category("自定义")] + public BlowerExitDirection ExitDirection + { + get { return exitDirection; } + set + { + exitDirection = value; + Invalidate(); + } + } + + /// + /// The blower color + /// + private Color blowerColor = Color.FromArgb(255, 77, 59); + + /// + /// Gets or sets the color of the blower. + /// + /// The color of the blower. + [Description("风机颜色"), Category("自定义")] + public Color BlowerColor + { + get { return blowerColor; } + set + { + blowerColor = value; + Invalidate(); + } + } + + /// + /// The fan color + /// + private Color fanColor = Color.FromArgb(3, 169, 243); + + /// + /// Gets or sets the color of the fan. + /// + /// The color of the fan. + [Description("风叶颜色"), Category("自定义")] + public Color FanColor + { + get { return fanColor; } + set + { + fanColor = value; + Invalidate(); + } + } + TurnAround turnAround = JinYuan.ControlLib.TurnAround.None; + [Description("风叶旋转方向,None表示不旋转"), Category("自定义")] + public TurnAround TurnAround + { + get { return turnAround; } + set + { + turnAround = value; + if (value == JinYuan.ControlLib.TurnAround.None) + { + updateTimer.Enabled = false; + jiaodu = 0; + Invalidate(); + } + else + updateTimer.Enabled = true; + } + } + + + //[Description("风叶旋转速度,100-1000,值越小 速度越快"), Category("自定义")] + //public int TurnSpeed + //{ + // get { return turnSpeed; } + // set + // { + // if (value < 0 || value > 1000) + // { + // return; + // } + + // turnSpeed = value; + // } + //} + + private int turnSpeed = 100; + private int jiaodu = 0; + + + [Description("风叶旋转速度,100-1000,值越小 速度越快"), Category("自定义")] + public int TurnSpeed + { + get { return turnSpeed; } + set + { + if (value <= 0 || value > 1000) + return; + turnSpeed = value; + updateTimer.Interval = value; + + + } + } + + /// + /// 是否显示底座 + /// + private bool isDZ = false; + + /// + /// 是否显示底座 + /// + /// 是否显示底座 + [Description("是否显示底座"), Category("自定义")] + public bool IsDZ + { + get { return isDZ; } + set + { + isDZ = value; + Invalidate(); + } + } + + private bool isExit; + [Description("是否退出"), Category("自定义")] + public bool IsExit + { + get { return isExit; } + set { isExit = value; } + } + + + /// + /// The m rect working + /// + Rectangle m_rectWorking; + //实时更新的定时器 + private System.Windows.Forms.Timer updateTimer; + /// + /// Initializes a new instance of the class. + /// + public UCBlower() + { + InitializeComponent(); + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.SizeChanged += UCBlower_SizeChanged; + this.Size = new Size(120, 120); + + updateTimer = new System.Windows.Forms.Timer(); + updateTimer.Interval = 200; + updateTimer.Tick += timer1_Tick; + updateTimer.Start(); + + //Task.Run(() => + //{ + // Timer_Thread(); + //}); + + } + + /// + /// Handles the SizeChanged event of the UCBlower control. + /// + /// The source of the event. + /// The instance containing the event data. + void UCBlower_SizeChanged(object sender, EventArgs e) + { + int intMin = Math.Min(this.Width, this.Height); + m_rectWorking = new Rectangle((this.Width - (intMin / 2 * 2)) / 2, (this.Height - (intMin / 2 * 2)) / 2, (intMin / 2 * 2), (intMin / 2 * 2)); + } + + /// + /// 引发 事件。 + /// + /// 包含事件数据的 。 + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + var g = e.Graphics; + g.SetGDIHigh(); + GraphicsPath pathLineIn = new GraphicsPath(); + GraphicsPath pathLineOut = new GraphicsPath(); + int intLinePenWidth = 0; + + switch (exitDirection) + { + case BlowerExitDirection.Left: + g.FillRectangle(new SolidBrush(blowerColor), new Rectangle(0, m_rectWorking.Top, this.Width / 2, m_rectWorking.Height / 2 - 5)); + intLinePenWidth = m_rectWorking.Height / 2 - 5; + pathLineOut.AddLine(new Point(-10, m_rectWorking.Top + (m_rectWorking.Height / 2 - 5) / 2), new Point(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + (m_rectWorking.Height / 2 - 5) / 2)); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(1, m_rectWorking.Top - 2), new Point(1, m_rectWorking.Top + (m_rectWorking.Height / 2 - 5) + 2)); + break; + case BlowerExitDirection.Right: + g.FillRectangle(new SolidBrush(blowerColor), new Rectangle(this.Width / 2, m_rectWorking.Top, this.Width / 2, m_rectWorking.Height / 2 - 5)); + intLinePenWidth = m_rectWorking.Height / 2 - 5; + pathLineOut.AddLine(new Point(this.Width + 10, m_rectWorking.Top + (m_rectWorking.Height / 2 - 5) / 2), new Point(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + (m_rectWorking.Height / 2 - 5) / 2)); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(this.Width - 2, m_rectWorking.Top - 2), new Point(this.Width - 2, m_rectWorking.Top + (m_rectWorking.Height / 2 - 5) + 2)); + break; + case BlowerExitDirection.Up: + g.FillRectangle(new SolidBrush(blowerColor), new Rectangle(m_rectWorking.Right - (m_rectWorking.Width / 2 - 5), 0, m_rectWorking.Width / 2 - 5, this.Height / 2)); + intLinePenWidth = m_rectWorking.Width / 2 - 5; + pathLineOut.AddLine(new Point(m_rectWorking.Right - (m_rectWorking.Width / 2 - 5) / 2, -10), new Point(m_rectWorking.Right - (m_rectWorking.Width / 2 - 5) / 2, m_rectWorking.Top + m_rectWorking.Height / 2)); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(m_rectWorking.Right + 2, 1), new Point(m_rectWorking.Right - (m_rectWorking.Width / 2 - 5) - 2, 1)); + break; + } + + switch (entranceDirection) + { + case BlowerEntranceDirection.Left: + g.FillRectangle(new SolidBrush(blowerColor), new Rectangle(0, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5, this.Width / 2, m_rectWorking.Height / 2 - 5)); + pathLineIn.AddLine(new Point(-10, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 + (m_rectWorking.Height / 2 - 5) / 2), new Point(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 + (m_rectWorking.Height / 2 - 5) / 2)); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(1, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 - 2), new Point(1, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 + (m_rectWorking.Height / 2 - 5) + 2)); + break; + case BlowerEntranceDirection.Right: + g.FillRectangle(new SolidBrush(blowerColor), new Rectangle(this.Width / 2, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5, this.Width / 2, m_rectWorking.Height / 2 - 5)); + pathLineIn.AddLine(new Point(this.Width + 10, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 + (m_rectWorking.Height / 2 - 5) / 2), new Point(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 + (m_rectWorking.Height / 2 - 5) / 2)); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(this.Width - 2, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 - 2), new Point(this.Width - 2, m_rectWorking.Bottom - m_rectWorking.Height / 2 + 5 + (m_rectWorking.Height / 2 - 5) + 2)); + break; + case BlowerEntranceDirection.Up: + g.FillRectangle(new SolidBrush(blowerColor), new Rectangle(m_rectWorking.Left, 0, m_rectWorking.Width / 2 - 5, this.Height / 2)); + pathLineIn.AddLine(new Point(m_rectWorking.Left + (m_rectWorking.Width / 2 - 5) / 2, -10), new Point(m_rectWorking.Left + (m_rectWorking.Width / 2 - 5) / 2, m_rectWorking.Top + m_rectWorking.Height / 2)); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(m_rectWorking.Left - 2, 1), new Point(m_rectWorking.Left + (m_rectWorking.Width / 2 - 5) + 2, 1)); + break; + } + + //渐变色 + int _intPenWidth = intLinePenWidth; + int intCount = _intPenWidth / 2 / 4; + for (int i = 0; i < intCount; i++) + { + int _penWidth = _intPenWidth / 2 - 4 * i; + if (_penWidth <= 0) + _penWidth = 1; + if (entranceDirection != BlowerEntranceDirection.None) + g.DrawPath(new Pen(new SolidBrush(Color.FromArgb(40, Color.White.R, Color.White.G, Color.White.B)), _penWidth), pathLineIn); + g.DrawPath(new Pen(new SolidBrush(Color.FromArgb(40, Color.White.R, Color.White.G, Color.White.B)), _penWidth), pathLineOut); + if (_penWidth == 1) + break; + } + + //底座 + if (isDZ) + { + GraphicsPath gpDZ = new GraphicsPath(); + gpDZ.AddLines(new Point[] + { + new Point( m_rectWorking.Left+m_rectWorking.Width/2,m_rectWorking.Top+m_rectWorking.Height/2), + new Point(m_rectWorking.Left+2,this.Height), + new Point(m_rectWorking.Right-2,this.Height) + }); + gpDZ.CloseAllFigures(); + g.FillPath(new SolidBrush(blowerColor), gpDZ); + g.FillPath(new SolidBrush(Color.FromArgb(50, Color.White)), gpDZ); + g.DrawLine(new Pen(new SolidBrush(blowerColor), 3), new Point(m_rectWorking.Left, this.Height - 2), new Point(m_rectWorking.Right, this.Height - 2)); + } + + + //中心 + g.FillEllipse(new SolidBrush(blowerColor), m_rectWorking); + g.FillEllipse(new SolidBrush(Color.FromArgb(20, Color.White)), m_rectWorking); + + + //扇叶 + Rectangle _rect = new Rectangle(m_rectWorking.Left + (m_rectWorking.Width - (m_rectWorking.Width / 3 * 2)) / 2, m_rectWorking.Top + (m_rectWorking.Height - (m_rectWorking.Width / 3 * 2)) / 2, (m_rectWorking.Width / 3 * 2), (m_rectWorking.Width / 3 * 2)); + + int _splitCount = 8; + float fltSplitValue = 360F / (float)_splitCount; + for (int i = 0; i <= _splitCount; i++) + { + float fltAngle = (fltSplitValue * i - 180) % 360 + jiaodu; + float fltY1 = (float)(_rect.Top + _rect.Width / 2 - ((_rect.Width / 2) * Math.Sin(Math.PI * (fltAngle / 180.00F)))); + float fltX1 = (float)(_rect.Left + (_rect.Width / 2 - ((_rect.Width / 2) * Math.Cos(Math.PI * (fltAngle / 180.00F))))); + float fltY2 = 0; + float fltX2 = 0; + + fltY2 = (float)(_rect.Top + _rect.Width / 2 - ((_rect.Width / 4) * Math.Sin(Math.PI * (fltAngle / 180.00F)))); + fltX2 = (float)(_rect.Left + (_rect.Width / 2 - ((_rect.Width / 4) * Math.Cos(Math.PI * (fltAngle / 180.00F))))); + + g.DrawLine(new Pen(new SolidBrush(fanColor), 2), new PointF(fltX1, fltY1), new PointF(fltX2, fltY2)); + } + + g.FillEllipse(new SolidBrush(fanColor), new Rectangle(_rect.Left + _rect.Width / 2 - _rect.Width / 4 + 2, _rect.Top + _rect.Width / 2 - _rect.Width / 4 + 2, _rect.Width / 2 - 4, _rect.Width / 2 - 4)); + g.FillEllipse(new SolidBrush(Color.FromArgb(50, Color.White)), new Rectangle(_rect.Left - 5, _rect.Top - 5, _rect.Width + 10, _rect.Height + 10)); + } + + public delegate void ShowStateHandler(); + + private void timer1_Tick(object sender, EventArgs e) + { + + ShowStateHandler stateHandler = ShowButtonEven_Run; + IAsyncResult result1 = stateHandler.BeginInvoke(null, stateHandler); + + + } + + private void ShowButtonEven_Run() + { + + if (turnAround == JinYuan.ControlLib.TurnAround.Clockwise) + { + jiaodu += 15; + if (jiaodu == 45) + jiaodu = 0; + } + else if (turnAround == JinYuan.ControlLib.TurnAround.Counterclockwise) + { + jiaodu -= 15; + if (jiaodu == -45) + jiaodu = 0; + } + this.BeginInvoke((Action)delegate + { + Invalidate(); + }); + } + + + private void UCBlower_VisibleChanged(object sender, EventArgs e) + { + //IsStop = !this.Visible; + } + } + + /// + /// Enum BlowerEntranceDirection + /// + public enum BlowerEntranceDirection + { + /// + /// The none + /// + None, + /// + /// The left + /// + Left, + /// + /// The right + /// + Right, + /// + /// Up + /// + Up + } + + /// + /// Enum BlowerExitDirection + /// + public enum BlowerExitDirection + { + /// + /// The none + /// + None, + /// + /// The left + /// + Left, + /// + /// The right + /// + Right, + /// + /// Up + /// + Up + } + /// + /// 旋转方向 + /// + public enum TurnAround + { + /// + /// 不旋转 + /// + None, + /// + /// 顺时针 + /// + Clockwise, + /// + /// 逆时针 + /// + Counterclockwise + } + +} diff --git a/JinYuan.ControlLib/UCBlower.resx b/JinYuan.ControlLib/UCBlower.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/UCBlower.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCCheckBox.Designer.cs b/JinYuan.ControlLib/UCCheckBox.Designer.cs new file mode 100644 index 0000000..d24fd29 --- /dev/null +++ b/JinYuan.ControlLib/UCCheckBox.Designer.cs @@ -0,0 +1,105 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class UCCheckBox. + /// Implements the + /// + /// + partial class UCCheckBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel1.Dock = System.Windows.Forms.DockStyle.Left; + this.panel1.Location = new System.Drawing.Point(1, 1); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(18, 28); + this.panel1.TabIndex = 0; + this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint); + this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CheckBox_MouseDown); + // + // label1 + // + this.label1.Dock = System.Windows.Forms.DockStyle.Fill; + this.label1.Font = new System.Drawing.Font("微软雅黑", 12F); + this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(62)))), ((int)(((byte)(62)))), ((int)(((byte)(62))))); + this.label1.Location = new System.Drawing.Point(19, 1); + this.label1.Name = "label1"; + this.label1.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0); + this.label1.Size = new System.Drawing.Size(213, 28); + this.label1.TabIndex = 1; + this.label1.Text = "复选框"; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.label1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CheckBox_MouseDown); + // + // UCCheckBox + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.SystemColors.Control; + this.Controls.Add(this.label1); + this.Controls.Add(this.panel1); + this.Name = "UCCheckBox"; + this.Padding = new System.Windows.Forms.Padding(1); + this.Size = new System.Drawing.Size(233, 30); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CheckBox_MouseDown); + this.ResumeLayout(false); + + } + + #endregion + + /// + /// The panel1 + /// + private System.Windows.Forms.Panel panel1; + /// + /// The label1 + /// + private System.Windows.Forms.Label label1; + } +} diff --git a/JinYuan.ControlLib/UCCheckBox.cs b/JinYuan.ControlLib/UCCheckBox.cs new file mode 100644 index 0000000..3bfc501 --- /dev/null +++ b/JinYuan.ControlLib/UCCheckBox.cs @@ -0,0 +1,226 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCCheckBox. + /// Implements the + /// + /// + [DefaultEvent("CheckedChangeEvent")] + public partial class UCCheckBox : UserControl + { + /// + /// 选中改变事件 + /// + [Description("选中改变事件"), Category("自定义")] + public event EventHandler CheckedChangeEvent; + /// + /// 字体 + /// + /// The font. + /// + /// + /// + /// + /// + /// + [Description("字体"), Category("自定义")] + public override Font Font + { + get + { + return base.Font; + } + set + { + base.Font = value; + label1.Font = value; + } + } + private Color _boxColor = Color.FromArgb(64, 158, 255); + [Description("颜色"), Category("自定义")] + public Color BoxColor + { + get { return _boxColor; } + set + { + if (_boxColor == value) return; + _boxColor = value; + panel1.Invalidate(); + } + } + /// + /// The fore color + /// + private Color _ForeColor = Color.FromArgb(62, 62, 62); + /// + /// 字体颜色 + /// + /// The color of the fore. + /// + /// + /// + [Description("字体颜色"), Category("自定义")] + public new Color ForeColor + { + get { return _ForeColor; } + set + { + base.ForeColor = value; + label1.ForeColor = value; + _ForeColor = value; + } + } + /// + /// The text + /// + private string _Text = "复选框"; + /// + /// 文本 + /// + /// The text value. + [Description("文本"), Category("自定义")] + public string TextValue + { + get { return _Text; } + set + { + label1.Text = value; + _Text = value; + } + } + /// + /// The checked + /// + private bool _checked = false; + /// + /// 是否选中 + /// + /// true if checked; otherwise, false. + [Description("是否选中"), Category("自定义")] + public bool Checked + { + get + { + return _checked; + } + set + { + if (_checked != value) + { + _checked = value; + Invalidate(); + if (CheckedChangeEvent != null) + { + CheckedChangeEvent(this, null); + } + } + } + } + + /// + /// 获取或设置一个值,该值指示控件是否可以对用户交互作出响应。 + /// + /// true if enabled; otherwise, false. + /// + /// + /// + /// + /// + /// + public new bool Enabled + { + get + { + return base.Enabled; + } + set + { + base.Enabled = value; + Invalidate(); + + } + } + /// + /// Initializes a new instance of the class. + /// + public UCCheckBox() + { + InitializeComponent(); + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + } + + /// + /// Handles the MouseDown event of the CheckBox control. + /// + /// The source of the event. + /// The instance containing the event data. + private void CheckBox_MouseDown(object sender, MouseEventArgs e) + { + Checked = !Checked; + } + + private void panel1_Paint(object sender, PaintEventArgs e) + { + e.Graphics.Clear(panel1.BackColor); + + Rectangle rect = new Rectangle(new Point(2, (this.panel1.Height - 14) / 2), new Size(14, 14)); + e.Graphics.SetGDIHigh(); + if (this.Enabled) + { + if (_checked) + { + e.Graphics.DrawRectangle(new Pen(_boxColor, 2), rect); + e.Graphics.FillRectangle(new SolidBrush(_boxColor), new Rectangle(rect.Left + 3, rect.Top + 3, 8, 8)); + } + else + { + e.Graphics.DrawRectangle(new Pen(_boxColor, 2), rect); + } + } + else + { + if (_checked) + { + e.Graphics.DrawRectangle(new Pen(Color.FromArgb(189, 189, 189), 2), rect); + e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(189, 189, 189)), new Rectangle(rect.Left + 3, rect.Top + 3, 8, 8)); + } + else + { + e.Graphics.DrawRectangle(new Pen(Color.FromArgb(189, 189, 189), 2), rect); + + } + } + } + + private void UCCheckBox_EnabledChanged(object sender, EventArgs e) + { + panel1.Invalidate(); + } + } +} diff --git a/JinYuan.ControlLib/UCCheckBox.resx b/JinYuan.ControlLib/UCCheckBox.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/UCCheckBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCControlBase.Designer.cs b/JinYuan.ControlLib/UCControlBase.Designer.cs new file mode 100644 index 0000000..ff23ff7 --- /dev/null +++ b/JinYuan.ControlLib/UCControlBase.Designer.cs @@ -0,0 +1,37 @@ +namespace JinYuan.ControlLib +{ + partial class UCControlBase + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCControlBase.cs b/JinYuan.ControlLib/UCControlBase.cs new file mode 100644 index 0000000..09687c3 --- /dev/null +++ b/JinYuan.ControlLib/UCControlBase.cs @@ -0,0 +1,265 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCControlBase. + /// Implements the + /// Implements the + /// + /// + /// + [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(System.ComponentModel.Design.IDesigner))] + public partial class UCControlBase : UserControl, IContainerControl + { + /// + /// The is radius + /// + private bool _isRadius = false; + + /// + /// The corner radius + /// + private int _cornerRadius = 24; + + + /// + /// The is show rect + /// + private bool _isShowRect = false; + + /// + /// The rect color + /// + private Color _rectColor = Color.FromArgb(220, 220, 220); + + /// + /// The rect width + /// + private int _rectWidth = 1; + + /// + /// The fill color + /// + private Color _fillColor = Color.Transparent; + /// + /// 是否圆角 + /// + /// true if this instance is radius; otherwise, false. + [Description("是否圆角"), Category("自定义")] + public virtual bool IsRadius + { + get + { + return this._isRadius; + } + set + { + this._isRadius = value; + Invalidate(); + } + } + /// + /// 圆角角度 + /// + /// The coner radius. + [Description("圆角角度"), Category("自定义")] + public virtual int ConerRadius + { + get + { + return this._cornerRadius; + } + set + { + this._cornerRadius = Math.Max(value, 1); + Invalidate(); + } + } + + /// + /// 是否显示边框 + /// + /// true if this instance is show rect; otherwise, false. + [Description("是否显示边框"), Category("自定义")] + public virtual bool IsShowRect + { + get + { + return this._isShowRect; + } + set + { + this._isShowRect = value; + Invalidate(); + } + } + /// + /// 边框颜色 + /// + /// The color of the rect. + [Description("边框颜色"), Category("自定义")] + public virtual Color RectColor + { + get + { + return this._rectColor; + } + set + { + this._rectColor = value; + Invalidate(); + } + } + /// + /// 边框宽度 + /// + /// The width of the rect. + [Description("边框宽度"), Category("自定义")] + public virtual int RectWidth + { + get + { + return this._rectWidth; + } + set + { + this._rectWidth = value; + Invalidate(); + } + } + /// + /// 当使用边框时填充颜色,当值为背景色或透明色或空值则不填充 + /// + /// The color of the fill. + [Description("当使用边框时填充颜色,当值为背景色或透明色或空值则不填充"), Category("自定义")] + public virtual Color FillColor + { + get + { + return this._fillColor; + } + set + { + this._fillColor = value; + Invalidate(); + } + } + + /// + /// Initializes a new instance of the class. + /// + public UCControlBase() + { + this.InitializeComponent(); + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.SetStyle(ControlStyles.UserPaint, true); + } + + /// + /// 引发 事件。 + /// + /// 包含事件数据的 。 + protected override void OnPaint(PaintEventArgs e) + { + if (this.Visible) + { + if (this._isRadius) + { + this.SetWindowRegion(); + } + else + { + //关闭圆角后显示为原矩形 + GraphicsPath g = new GraphicsPath(); + g.AddRectangle(base.ClientRectangle); + g.CloseFigure(); + base.Region = new Region(g); + } + + GraphicsPath graphicsPath = new GraphicsPath(); + if (this._isShowRect || (_fillColor != Color.Empty && _fillColor != Color.Transparent && _fillColor != this.BackColor)) + { + Rectangle clientRectangle = base.ClientRectangle; + if (_isRadius) + { + graphicsPath.AddArc(0, 0, _cornerRadius, _cornerRadius, 180f, 90f); + graphicsPath.AddArc(clientRectangle.Width - _cornerRadius - 1, 0, _cornerRadius, _cornerRadius, 270f, 90f); + graphicsPath.AddArc(clientRectangle.Width - _cornerRadius - 1, clientRectangle.Height - _cornerRadius - 1, _cornerRadius, _cornerRadius, 0f, 90f); + graphicsPath.AddArc(0, clientRectangle.Height - _cornerRadius - 1, _cornerRadius, _cornerRadius, 90f, 90f); + graphicsPath.CloseFigure(); + } + else + { + graphicsPath.AddRectangle(clientRectangle); + } + } + e.Graphics.SetGDIHigh(); + if (_fillColor != Color.Empty && _fillColor != Color.Transparent && _fillColor != this.BackColor) + e.Graphics.FillPath(new SolidBrush(this._fillColor), graphicsPath); + if (this._isShowRect) + { + Color rectColor = this._rectColor; + Pen pen = new Pen(rectColor, (float)this._rectWidth); + e.Graphics.DrawPath(pen, graphicsPath); + } + } + base.OnPaint(e); + } + + /// + /// Sets the window region. + /// + private void SetWindowRegion() + { + GraphicsPath path = new GraphicsPath(); + Rectangle rect = new Rectangle(-1, -1, base.Width + 1, base.Height); + path = this.GetRoundedRectPath(rect, this._cornerRadius); + base.Region = new Region(path); + } + + /// + /// Gets the rounded rect path. + /// + /// The rect. + /// The radius. + /// GraphicsPath. + private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius) + { + Rectangle rect2 = new Rectangle(rect.Location, new Size(radius, radius)); + GraphicsPath graphicsPath = new GraphicsPath(); + graphicsPath.AddArc(rect2, 180f, 90f);//左上角 + rect2.X = rect.Right - radius; + graphicsPath.AddArc(rect2, 270f, 90f);//右上角 + rect2.Y = rect.Bottom - radius; + rect2.Width += 1; + rect2.Height += 1; + graphicsPath.AddArc(rect2, 360f, 90f);//右下角 + rect2.X = rect.Left; + graphicsPath.AddArc(rect2, 90f, 90f);//左下角 + graphicsPath.CloseFigure(); + return graphicsPath; + } + + /// + /// WNDs the proc. + /// + /// 要处理的 Windows 。 + protected override void WndProc(ref Message m) + { + if (m.Msg != 20) + { + base.WndProc(ref m); + } + } + } +} diff --git a/JinYuan.ControlLib/UCElectricityMeterH.Designer.cs b/JinYuan.ControlLib/UCElectricityMeterH.Designer.cs new file mode 100644 index 0000000..f5f837d --- /dev/null +++ b/JinYuan.ControlLib/UCElectricityMeterH.Designer.cs @@ -0,0 +1,340 @@ +namespace JinYuan.ControlLib +{ + partial class UCElectricityMeterH + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UCElectricityMeterV)); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.txtAccumulatedElectricity = new JinYuan.ControlLib.TextSet(); + this.txtPhaseVoltageA = new JinYuan.ControlLib.TextSet(); + this.txtPhaseVoltageB = new JinYuan.ControlLib.TextSet(); + this.txtPhaseVoltageC = new JinYuan.ControlLib.TextSet(); + this.txtPhaseCurrentA = new JinYuan.ControlLib.TextSet(); + this.txtPhaseCurrentB = new JinYuan.ControlLib.TextSet(); + this.txtPhaseCurrentC = new JinYuan.ControlLib.TextSet(); + this.txtPhasePowerA = new JinYuan.ControlLib.TextSet(); + this.txtPhasePowerB = new JinYuan.ControlLib.TextSet(); + this.txtPowerFactor = new JinYuan.ControlLib.TextSet2(); + this.txtPhasePowerC = new JinYuan.ControlLib.TextSet(); + this.txtCt = new JinYuan.ControlLib.TextSet2(); + this.txtPt = new JinYuan.ControlLib.TextSet2(); + this.txtActivePower = new JinYuan.ControlLib.TextSet2(); + this.UCtitleName = new JinYuan.ControlLib.LongTitleStyle2(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 49.50495F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.49505F)); + this.tableLayoutPanel1.Controls.Add(this.txtAccumulatedElectricity, 0, 7); + this.tableLayoutPanel1.Controls.Add(this.txtPhaseVoltageA, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtPhaseVoltageB, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.txtPhaseVoltageC, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.txtPhaseCurrentA, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.txtPhaseCurrentB, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.txtPhaseCurrentC, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.txtPhasePowerA, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.txtPhasePowerB, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.txtPowerFactor, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.txtPhasePowerC, 0, 5); + this.tableLayoutPanel1.Controls.Add(this.txtCt, 1, 6); + this.tableLayoutPanel1.Controls.Add(this.txtPt, 1, 5); + this.tableLayoutPanel1.Controls.Add(this.txtActivePower, 1, 4); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 28); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 8; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 38F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(361, 303); + this.tableLayoutPanel1.TabIndex = 17; + // + // txtAccumulatedElectricity + // + this.txtAccumulatedElectricity.BindVarName = null; + this.tableLayoutPanel1.SetColumnSpan(this.txtAccumulatedElectricity, 2); + this.txtAccumulatedElectricity.CurrentValue = "0.0"; + this.txtAccumulatedElectricity.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtAccumulatedElectricity.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtAccumulatedElectricity.ForeColor = System.Drawing.Color.White; + this.txtAccumulatedElectricity.Location = new System.Drawing.Point(4, 271); + this.txtAccumulatedElectricity.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtAccumulatedElectricity.Name = "txtAccumulatedElectricity"; + this.txtAccumulatedElectricity.Size = new System.Drawing.Size(353, 28); + this.txtAccumulatedElectricity.TabIndex = 14; + this.txtAccumulatedElectricity.TitleName = "累计有功电能"; + this.txtAccumulatedElectricity.Unit = "kW·h"; + // + // txtPhaseVoltageA + // + this.txtPhaseVoltageA.BindVarName = null; + this.txtPhaseVoltageA.CurrentValue = "123.5"; + this.txtPhaseVoltageA.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseVoltageA.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhaseVoltageA.ForeColor = System.Drawing.Color.White; + this.txtPhaseVoltageA.Location = new System.Drawing.Point(1, 1); + this.txtPhaseVoltageA.Margin = new System.Windows.Forms.Padding(1); + this.txtPhaseVoltageA.Name = "txtPhaseVoltageA"; + this.txtPhaseVoltageA.Size = new System.Drawing.Size(176, 36); + this.txtPhaseVoltageA.TabIndex = 2; + this.txtPhaseVoltageA.TitleName = "A相电压"; + this.txtPhaseVoltageA.Unit = "V"; + // + // txtPhaseVoltageB + // + this.txtPhaseVoltageB.BindVarName = null; + this.txtPhaseVoltageB.CurrentValue = "0.0"; + this.txtPhaseVoltageB.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseVoltageB.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhaseVoltageB.ForeColor = System.Drawing.Color.White; + this.txtPhaseVoltageB.Location = new System.Drawing.Point(4, 43); + this.txtPhaseVoltageB.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhaseVoltageB.Name = "txtPhaseVoltageB"; + this.txtPhaseVoltageB.Size = new System.Drawing.Size(170, 28); + this.txtPhaseVoltageB.TabIndex = 3; + this.txtPhaseVoltageB.TitleName = "B相电压"; + this.txtPhaseVoltageB.Unit = "V"; + // + // txtPhaseVoltageC + // + this.txtPhaseVoltageC.BindVarName = null; + this.txtPhaseVoltageC.CurrentValue = "0.0"; + this.txtPhaseVoltageC.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseVoltageC.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhaseVoltageC.ForeColor = System.Drawing.Color.White; + this.txtPhaseVoltageC.Location = new System.Drawing.Point(4, 81); + this.txtPhaseVoltageC.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhaseVoltageC.Name = "txtPhaseVoltageC"; + this.txtPhaseVoltageC.Size = new System.Drawing.Size(170, 28); + this.txtPhaseVoltageC.TabIndex = 4; + this.txtPhaseVoltageC.TitleName = "C相电压"; + this.txtPhaseVoltageC.Unit = "V"; + // + // txtPhaseCurrentA + // + this.txtPhaseCurrentA.BindVarName = null; + this.txtPhaseCurrentA.CurrentValue = "0.0"; + this.txtPhaseCurrentA.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseCurrentA.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhaseCurrentA.ForeColor = System.Drawing.Color.White; + this.txtPhaseCurrentA.Location = new System.Drawing.Point(182, 5); + this.txtPhaseCurrentA.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhaseCurrentA.Name = "txtPhaseCurrentA"; + this.txtPhaseCurrentA.Size = new System.Drawing.Size(175, 28); + this.txtPhaseCurrentA.TabIndex = 5; + this.txtPhaseCurrentA.TitleName = "A相电流"; + this.txtPhaseCurrentA.Unit = "A"; + // + // txtPhaseCurrentB + // + this.txtPhaseCurrentB.BindVarName = null; + this.txtPhaseCurrentB.CurrentValue = "0.0"; + this.txtPhaseCurrentB.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseCurrentB.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhaseCurrentB.ForeColor = System.Drawing.Color.White; + this.txtPhaseCurrentB.Location = new System.Drawing.Point(182, 43); + this.txtPhaseCurrentB.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhaseCurrentB.Name = "txtPhaseCurrentB"; + this.txtPhaseCurrentB.Size = new System.Drawing.Size(175, 28); + this.txtPhaseCurrentB.TabIndex = 6; + this.txtPhaseCurrentB.TitleName = "B相电流"; + this.txtPhaseCurrentB.Unit = "A"; + // + // txtPhaseCurrentC + // + this.txtPhaseCurrentC.BindVarName = null; + this.txtPhaseCurrentC.CurrentValue = "0.0"; + this.txtPhaseCurrentC.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseCurrentC.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhaseCurrentC.ForeColor = System.Drawing.Color.White; + this.txtPhaseCurrentC.Location = new System.Drawing.Point(182, 81); + this.txtPhaseCurrentC.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhaseCurrentC.Name = "txtPhaseCurrentC"; + this.txtPhaseCurrentC.Size = new System.Drawing.Size(175, 28); + this.txtPhaseCurrentC.TabIndex = 7; + this.txtPhaseCurrentC.TitleName = "C相电流"; + this.txtPhaseCurrentC.Unit = "A"; + // + // txtPhasePowerA + // + this.txtPhasePowerA.BindVarName = null; + this.txtPhasePowerA.CurrentValue = "0.0"; + this.txtPhasePowerA.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhasePowerA.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhasePowerA.ForeColor = System.Drawing.Color.White; + this.txtPhasePowerA.Location = new System.Drawing.Point(4, 119); + this.txtPhasePowerA.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhasePowerA.Name = "txtPhasePowerA"; + this.txtPhasePowerA.Size = new System.Drawing.Size(170, 28); + this.txtPhasePowerA.TabIndex = 8; + this.txtPhasePowerA.TitleName = "A相功率"; + this.txtPhasePowerA.Unit = "W"; + // + // txtPhasePowerB + // + this.txtPhasePowerB.BindVarName = null; + this.txtPhasePowerB.CurrentValue = "0.0"; + this.txtPhasePowerB.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhasePowerB.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhasePowerB.ForeColor = System.Drawing.Color.White; + this.txtPhasePowerB.Location = new System.Drawing.Point(4, 157); + this.txtPhasePowerB.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhasePowerB.Name = "txtPhasePowerB"; + this.txtPhasePowerB.Size = new System.Drawing.Size(170, 28); + this.txtPhasePowerB.TabIndex = 9; + this.txtPhasePowerB.TitleName = "B相功率"; + this.txtPhasePowerB.Unit = "W"; + // + // txtPowerFactor + // + this.txtPowerFactor.BindVarName = null; + this.txtPowerFactor.CurrentValue = "0.0"; + this.txtPowerFactor.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPowerFactor.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPowerFactor.ForeColor = System.Drawing.Color.White; + this.txtPowerFactor.Location = new System.Drawing.Point(182, 119); + this.txtPowerFactor.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPowerFactor.Name = "txtPowerFactor"; + this.txtPowerFactor.Size = new System.Drawing.Size(175, 28); + this.txtPowerFactor.TabIndex = 19; + this.txtPowerFactor.TitleName = "总功率因素"; + // + // txtPhasePowerC + // + this.txtPhasePowerC.BindVarName = null; + this.txtPhasePowerC.CurrentValue = "0.0"; + this.txtPhasePowerC.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhasePowerC.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPhasePowerC.ForeColor = System.Drawing.Color.White; + this.txtPhasePowerC.Location = new System.Drawing.Point(4, 195); + this.txtPhasePowerC.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPhasePowerC.Name = "txtPhasePowerC"; + this.txtPhasePowerC.Size = new System.Drawing.Size(170, 28); + this.txtPhasePowerC.TabIndex = 10; + this.txtPhasePowerC.TitleName = "C相功率"; + this.txtPhasePowerC.Unit = "W"; + // + // txtCt + // + this.txtCt.BindVarName = null; + this.txtCt.CurrentValue = "0.0"; + this.txtCt.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtCt.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtCt.ForeColor = System.Drawing.Color.White; + this.txtCt.Location = new System.Drawing.Point(182, 233); + this.txtCt.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtCt.Name = "txtCt"; + this.txtCt.Size = new System.Drawing.Size(175, 28); + this.txtCt.TabIndex = 18; + this.txtCt.TitleName = "电流变比"; + // + // txtPt + // + this.txtPt.BindVarName = null; + this.txtPt.CurrentValue = "0.0"; + this.txtPt.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPt.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtPt.ForeColor = System.Drawing.Color.White; + this.txtPt.Location = new System.Drawing.Point(182, 195); + this.txtPt.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtPt.Name = "txtPt"; + this.txtPt.Size = new System.Drawing.Size(175, 28); + this.txtPt.TabIndex = 18; + this.txtPt.TitleName = "电压变比"; + // + // txtActivePower + // + this.txtActivePower.BindVarName = null; + this.txtActivePower.CurrentValue = "0.0"; + this.txtActivePower.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtActivePower.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.txtActivePower.ForeColor = System.Drawing.Color.White; + this.txtActivePower.Location = new System.Drawing.Point(182, 157); + this.txtActivePower.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtActivePower.Name = "txtActivePower"; + this.txtActivePower.Size = new System.Drawing.Size(175, 28); + this.txtActivePower.TabIndex = 20; + this.txtActivePower.TitleName = "总有功功率"; + // + // UCtitleName + // + this.UCtitleName.BackColor = System.Drawing.Color.Transparent; + this.UCtitleName.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("UCtitleName.BackgroundImage"))); + this.UCtitleName.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.UCtitleName.Dock = System.Windows.Forms.DockStyle.Top; + this.UCtitleName.Location = new System.Drawing.Point(0, 0); + this.UCtitleName.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.UCtitleName.Name = "UCtitleName"; + this.UCtitleName.Size = new System.Drawing.Size(361, 28); + this.UCtitleName.TabIndex = 1; + this.UCtitleName.TitleName = "智能电表"; + // + // UCElectricityMeter + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(31)))), ((int)(((byte)(39)))), ((int)(((byte)(104))))); + this.Controls.Add(this.tableLayoutPanel1); + this.Controls.Add(this.UCtitleName); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "UCElectricityMeter"; + this.Size = new System.Drawing.Size(361, 331); + this.tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private LongTitleStyle2 UCtitleName; + private TextSet txtPhaseVoltageA; + private TextSet txtPhaseVoltageB; + private TextSet txtPhaseVoltageC; + private TextSet txtPhaseCurrentA; + private TextSet txtPhaseCurrentB; + private TextSet txtPhaseCurrentC; + private TextSet txtPhasePowerA; + private TextSet txtPhasePowerB; + private TextSet txtPhasePowerC; + private TextSet txtAccumulatedElectricity; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private TextSet2 txtActivePower; + private TextSet2 txtCt; + private TextSet2 txtPowerFactor; + private TextSet2 txtPt; + } +} diff --git a/JinYuan.ControlLib/UCElectricityMeterH.cs b/JinYuan.ControlLib/UCElectricityMeterH.cs new file mode 100644 index 0000000..e80d325 --- /dev/null +++ b/JinYuan.ControlLib/UCElectricityMeterH.cs @@ -0,0 +1,335 @@ +using JinYuan.Models; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class UCElectricityMeterH : UserControl + { + public UCElectricityMeterH() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + //#region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + //#endregion + + + + private string smartMeter = "智能电表"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相电压")] + public override string Text + { + get { return smartMeter; } + set + { + smartMeter = value; + this.UCtitleName.Text = smartMeter; + } + } + + + #region 相电压 + private string phaseVoltageA = "A相电压"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相电压")] + public string Text1 + { + get { return phaseVoltageA; } + set + { + phaseVoltageA = value; + this.txtPhaseVoltageA.TitleName = phaseVoltageA; + } + } + + + private string phaseVoltageB = "B相电压"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件B相电压")] + public string Text2 + { + get { return phaseVoltageB; } + set + { + phaseVoltageB = value; + this.txtPhaseVoltageB.Text = phaseVoltageB; + } + } + + + private string phaseVoltageC = "C相电压"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件C相电压")] + public string Text3 + { + get { return phaseVoltageC; } + set + { + phaseVoltageC = value; + this.txtPhaseVoltageC.Text = phaseVoltageC; + } + } + #endregion + + #region 相电流 + private string phaseCurrentA = "A相电流"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相电流")] + public string Text4 + { + get { return phaseCurrentA; } + set + { + phaseCurrentA = value; + this.txtPhaseCurrentA.Text = phaseCurrentA; + } + } + + private string phaseCurrentB = "B相电流"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件B相电流")] + public string Text5 + { + get { return phaseCurrentB; } + set + { + phaseCurrentB = value; + this.txtPhaseCurrentB.Text = phaseCurrentB; + } + } + + + + private string phaseCurrentC = "C相电流"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件C相电流")] + public string Text6 + { + get { return phaseCurrentC; } + set + { + phaseCurrentC = value; + this.txtPhaseCurrentC.Text = phaseCurrentC; + } + } + #endregion + + #region 相功率 + private string phasePowerA = "A相功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相功率")] + public string Text7 + { + get { return phasePowerA; } + set + { + phasePowerA = value; + this.txtPhasePowerA.Text = phasePowerA; + } + } + + private string phasePowerB = "B相功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件B相功率")] + public string Text8 + { + get { return phasePowerB; } + set + { + phasePowerB = value; + this.txtPhasePowerB.Text = phasePowerB; + } + } + + + + private string phasePowerC = "C相功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件C相功率")] + public string Text9 + { + get { return phasePowerC; } + set + { + phasePowerC = value; + this.txtPhasePowerC.Text = phasePowerC; + } + } + #endregion + + private string activePower = "总有功功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件总有功功率")] + public string Text10 + { + get { return activePower; } + set + { + activePower = value; + this.txtActivePower.TitleName = activePower; + + } + } + + private string powerFactor = "总功率因数"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件总功率因数")] + public string Text11 + { + get { return powerFactor; } + set + { + powerFactor = value; + this.txtPowerFactor.TitleName = powerFactor; + + } + } + + private string pt = "电压变比"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件电压变比")] + public string Text12 + { + get { return pt; } + set + { + pt = value; + this.txtPt.TitleName = pt; + + } + } + + private string ct = "电流变比"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件电流变比")] + public string Text13 + { + get { return ct; } + set + { + ct = value; + this.txtCt.TitleName = ct; + + } + } + + private string accumulatedElectricity = "累计电能"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件累计电能")] + public string Text14 + { + get { return accumulatedElectricity; } + set + { + accumulatedElectricity = value; + this.txtAccumulatedElectricity.TitleName = accumulatedElectricity; + + } + } + + + private JinYuan.Models.ElectricEnergy _electricEnergy = new JinYuan.Models.ElectricEnergy(); + [Browsable(false)] + [Category("自定义属性")] + [Description("设置或获取实体类值")] + public ElectricEnergy ElectricEnergy + { + get + { + return _electricEnergy; + } + set + { + if (value != null) + { + _electricEnergy = value; + SetElectricEnergy(_electricEnergy); + } + + } + } + + + + + private void SetElectricEnergy(ElectricEnergy m) + { + //累计电能 + this.txtAccumulatedElectricity.CurrentValue = m.AccumulatedElectricity.ToString(); + //A相电压 V + this.txtPhaseVoltageA.CurrentValue = m.PhaseVoltageA.ToString(); + //B相电压 + this.txtPhaseVoltageB.CurrentValue = m.PhaseVoltageB.ToString(); + //C相电压 + this.txtPhaseVoltageC.CurrentValue = m.PhaseVoltageC.ToString(); + // A相电流 + this.txtPhaseCurrentA.CurrentValue = m.PhaseCurrentA.ToString(); + // B相电流 + this.txtPhaseCurrentB.CurrentValue = m.PhaseCurrentB.ToString(); + // C相电流 + this.txtPhaseCurrentC.CurrentValue = m.PhaseCurrentC.ToString(); + // A相功率 + this.txtPhasePowerA.CurrentValue = m.PhasePowerA.ToString(); + // B相功率 + this.txtPhasePowerB.CurrentValue = m.PhasePowerB.ToString(); + // C相功率 + this.txtPhasePowerC.CurrentValue = m.PhasePowerC.ToString(); + // 总有功功率 + this.txtActivePower.CurrentValue = m.ActivePower.ToString(); + // 总功率因数 + this.txtPowerFactor.CurrentValue = m.PowerFactor.ToString(); + // 电压变比 + this.txtPt.CurrentValue = m.pt.ToString(); + // 电流变比 + this.txtCt.CurrentValue = m.ct.ToString(); + } + } +} diff --git a/JinYuan.ControlLib/UCElectricityMeterH.resx b/JinYuan.ControlLib/UCElectricityMeterH.resx new file mode 100644 index 0000000..337f422 --- /dev/null +++ b/JinYuan.ControlLib/UCElectricityMeterH.resx @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAAkcAAAApCAYAAAA/Io30AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH + DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKNWlDQ1BzUkdCIElFQzYxOTY2LTIuMQAA + SMedlndUVNcWh8+9d3qhzTDSGXqTLjCA9C4gHQRRGGYGGMoAwwxNbIioQEQREQFFkKCAAaOhSKyIYiEo + qGAPSBBQYjCKqKhkRtZKfHl57+Xl98e939pn73P32XuftS4AJE8fLi8FlgIgmSfgB3o401eFR9Cx/QAG + eIABpgAwWempvkHuwUAkLzcXerrICfyL3gwBSPy+ZejpT6eD/0/SrFS+AADIX8TmbE46S8T5Ik7KFKSK + 7TMipsYkihlGiZkvSlDEcmKOW+Sln30W2VHM7GQeW8TinFPZyWwx94h4e4aQI2LER8QFGVxOpohvi1gz + SZjMFfFbcWwyh5kOAIoktgs4rHgRm4iYxA8OdBHxcgBwpLgvOOYLFnCyBOJDuaSkZvO5cfECui5Lj25q + bc2ge3IykzgCgaE/k5XI5LPpLinJqUxeNgCLZ/4sGXFt6aIiW5paW1oamhmZflGo/7r4NyXu7SK9Cvjc + M4jW94ftr/xS6gBgzIpqs+sPW8x+ADq2AiB3/w+b5iEAJEV9a7/xxXlo4nmJFwhSbYyNMzMzjbgclpG4 + oL/rfzr8DX3xPSPxdr+Xh+7KiWUKkwR0cd1YKUkpQj49PZXJ4tAN/zzE/zjwr/NYGsiJ5fA5PFFEqGjK + uLw4Ubt5bK6Am8Kjc3n/qYn/MOxPWpxrkSj1nwA1yghI3aAC5Oc+gKIQARJ5UNz13/vmgw8F4psXpjqx + OPefBf37rnCJ+JHOjfsc5xIYTGcJ+RmLa+JrCdCAACQBFcgDFaABdIEhMANWwBY4AjewAviBYBAO1gIW + iAfJgA8yQS7YDApAEdgF9oJKUAPqQSNoASdABzgNLoDL4Dq4Ce6AB2AEjIPnYAa8AfMQBGEhMkSB5CFV + SAsygMwgBmQPuUE+UCAUDkVDcRAPEkK50BaoCCqFKqFaqBH6FjoFXYCuQgPQPWgUmoJ+hd7DCEyCqbAy + rA0bwwzYCfaGg+E1cBycBufA+fBOuAKug4/B7fAF+Dp8Bx6Bn8OzCECICA1RQwwRBuKC+CERSCzCRzYg + hUg5Uoe0IF1IL3ILGUGmkXcoDIqCoqMMUbYoT1QIioVKQ21AFaMqUUdR7age1C3UKGoG9QlNRiuhDdA2 + aC/0KnQcOhNdgC5HN6Db0JfQd9Dj6DcYDIaG0cFYYTwx4ZgEzDpMMeYAphVzHjOAGcPMYrFYeawB1g7r + h2ViBdgC7H7sMew57CB2HPsWR8Sp4sxw7rgIHA+XhyvHNeHO4gZxE7h5vBReC2+D98Oz8dn4Enw9vgt/ + Az+OnydIE3QIdoRgQgJhM6GC0EK4RHhIeEUkEtWJ1sQAIpe4iVhBPE68QhwlviPJkPRJLqRIkpC0k3SE + dJ50j/SKTCZrkx3JEWQBeSe5kXyR/Jj8VoIiYSThJcGW2ChRJdEuMSjxQhIvqSXpJLlWMkeyXPKk5A3J + aSm8lLaUixRTaoNUldQpqWGpWWmKtKm0n3SydLF0k/RV6UkZrIy2jJsMWyZf5rDMRZkxCkLRoLhQWJQt + lHrKJco4FUPVoXpRE6hF1G+o/dQZWRnZZbKhslmyVbJnZEdoCE2b5kVLopXQTtCGaO+XKC9xWsJZsmNJ + y5LBJXNyinKOchy5QrlWuTty7+Xp8m7yifK75TvkHymgFPQVAhQyFQ4qXFKYVqQq2iqyFAsVTyjeV4KV + 9JUCldYpHVbqU5pVVlH2UE5V3q98UXlahabiqJKgUqZyVmVKlaJqr8pVLVM9p/qMLkt3oifRK+g99Bk1 + JTVPNaFarVq/2ry6jnqIep56q/ojDYIGQyNWo0yjW2NGU1XTVzNXs1nzvhZei6EVr7VPq1drTltHO0x7 + m3aH9qSOnI6XTo5Os85DXbKug26abp3ubT2MHkMvUe+A3k19WN9CP16/Sv+GAWxgacA1OGAwsBS91Hop + b2nd0mFDkqGTYYZhs+GoEc3IxyjPqMPohbGmcYTxbuNe408mFiZJJvUmD0xlTFeY5pl2mf5qpm/GMqsy + u21ONnc332jeaf5ymcEyzrKDy+5aUCx8LbZZdFt8tLSy5Fu2WE5ZaVpFW1VbDTOoDH9GMeOKNdra2Xqj + 9WnrdzaWNgKbEza/2BraJto22U4u11nOWV6/fMxO3Y5pV2s3Yk+3j7Y/ZD/ioObAdKhzeOKo4ch2bHCc + cNJzSnA65vTC2cSZ79zmPOdi47Le5bwr4urhWuja7ybjFuJW6fbYXd09zr3ZfcbDwmOdx3lPtKe3527P + YS9lL5ZXo9fMCqsV61f0eJO8g7wrvZ/46Pvwfbp8Yd8Vvnt8H67UWslb2eEH/Lz89vg98tfxT/P/PgAT + 4B9QFfA00DQwN7A3iBIUFdQU9CbYObgk+EGIbogwpDtUMjQytDF0Lsw1rDRsZJXxqvWrrocrhHPDOyOw + EaERDRGzq91W7109HmkRWRA5tEZnTdaaq2sV1iatPRMlGcWMOhmNjg6Lbor+wPRj1jFnY7xiqmNmWC6s + faznbEd2GXuKY8cp5UzE2sWWxk7G2cXtiZuKd4gvj5/munAruS8TPBNqEuYS/RKPJC4khSW1JuOSo5NP + 8WR4ibyeFJWUrJSBVIPUgtSRNJu0vWkzfG9+QzqUvia9U0AV/Uz1CXWFW4WjGfYZVRlvM0MzT2ZJZ/Gy + +rL1s3dkT+S453y9DrWOta47Vy13c+7oeqf1tRugDTEbujdqbMzfOL7JY9PRzYTNiZt/yDPJK817vSVs + S1e+cv6m/LGtHlubCyQK+AXD22y31WxHbedu799hvmP/jk+F7MJrRSZF5UUfilnF174y/ariq4WdsTv7 + SyxLDu7C7OLtGtrtsPtoqXRpTunYHt897WX0ssKy13uj9l4tX1Zes4+wT7hvpMKnonO/5v5d+z9Uxlfe + qXKuaq1Wqt5RPXeAfWDwoOPBlhrlmqKa94e4h+7WetS212nXlR/GHM44/LQ+tL73a8bXjQ0KDUUNH4/w + jowcDTza02jV2Nik1FTSDDcLm6eORR67+Y3rN50thi21rbTWouPguPD4s2+jvx064X2i+yTjZMt3Wt9V + t1HaCtuh9uz2mY74jpHO8M6BUytOdXfZdrV9b/T9kdNqp6vOyJ4pOUs4m3924VzOudnzqeenL8RdGOuO + 6n5wcdXF2z0BPf2XvC9duex++WKvU++5K3ZXTl+1uXrqGuNax3XL6+19Fn1tP1j80NZv2d9+w+pG503r + m10DywfODjoMXrjleuvyba/b1++svDMwFDJ0dzhyeOQu++7kvaR7L+9n3J9/sOkh+mHhI6lH5Y+VHtf9 + qPdj64jlyJlR19G+J0FPHoyxxp7/lP7Th/H8p+Sn5ROqE42TZpOnp9ynbj5b/Wz8eerz+emCn6V/rn6h + ++K7Xxx/6ZtZNTP+kv9y4dfiV/Kvjrxe9rp71n/28ZvkN/NzhW/l3x59x3jX+z7s/cR85gfsh4qPeh+7 + Pnl/eriQvLDwG/eE8/s6uL5TAAAACXBIWXMAAAsMAAALDAE/QCLIAAAT10lEQVR4Xu2dB9geVZmGd9fe + C9J7713pIihSbVziiljX1cWyAroiLi67uq7uirogvYYiRQFBOoiRIpAQUoAQSO8kpIf0hMDZ5/7+8yRv + hvn/RBeSy933ua47Z7755nznzJmZ8z7/O/N9+as/RbuVuZG/7oHmtk3itn/TeN22fSRu+6fWrXuSSqVS + qVQq9TKoGoxoRjAnrwrwOhqWFYxJXedt2P7VgWb9nuqy/WsCsX5b3WWkUqlUKpXqWW3xswGxNsbliN9r + qwcvR92e6Gy72lQbpGF2ADOCMXmteF2FZZuVtp30zvM+275evLHCMp9B/TajE9t0vTdXWH6D4DNj2667 + jFQqlUqlUj2rLX5WVsUDdJescF1wkoM6ruf43V3d2DbbRmKbnbqrTTRWG6UjNilvEm8J8Jr1bQPEMusZ + RLZ7m3hn5R3irYL1vE8bzboMICaI7dYS61TWFnwG63nfbbvuMlKpVCqVSvWsZuysEFOJrTH+E3eJ5YAH + IAbHGB7r8pr1juXUj0kOGyx7h2Zdt812tM9ngD3HCr5htak2SMN0gg4xEJgamxTAtLxdNE0OsMw6BgIz + s67YWGxSyw0ERodBZqA8SB4Q2uQ92mH7rcTWtdxMUJ/2+fzYdmegIJVKpVKpVM9yzKxEY+MY7thP3N2w + lryO8d8mB1gmphPbMVR4AOI9dZzgsLliO9drtk19tqMdw2ubq2Vxv+7KKy8aE+wgHaAzGBEG5JtiJ7GF + 2LSue5eImRw6TMkOMKjrC7Y/X+wvdhbb13XUZ6BscqjnNhlE2thR9BZHin3EnnXd5gLThYly2x7guiep + VCqVSqW6E/Gy4rgfExTEWOLwNmIHcaC4WxC/ie3E+JjgiKaK2M42JEXYfg9xjsBg2Tc4E0Tsjm3zHr6D + 9vkMkiMnCuo1kyqr3Ryxk3QAt2aDc6E4U3xcYJIYMAbOLtId9s6xHhOzi+gv7hMnCEwSJgeTxMBhhDBE + Tt8xqBsJ3t9XFDFbnC4wSQcJ6jNgGCzaXsEg1V1JpVKpVCrVjRQvozHC2BCDMSbE4G0FpmY/8QNBHCYe + 7ya2FE5QELupa1NF7McbbCeI/8cL4j8+AN/AZzsxgmcgdrttDBefizegjQ8LfAf+gztJ+AUbK3zKajdH + dJaO4tToJK6RzplTxXsFWRxudTEYdBiD5B3EITI4ZHwYFHOlOFpgfKjP53MwMEh8Bjtvp3mo4GCYR8WX + xWFiL4FBWk9Qj8FdvU4ylUqlUqm/UBEvBUkFTIqNETGZ2IwpOlb0ETEOE/tJkLCdTQ51MUbEY+I3poj4 + fZmI8X93gelx3MYzxMQICQ/ef484RUTf4YSIM1ZrzBxhVjA97Cg7FDsJvxAMHBkeHB2DyiBRz6aKATpY + xMGBB8TJYm+BO/UOA5kq1mGeMFHxoMAccZb4oKBfmDPaZrA62aO6K6lUKpVKpbqR4qXvFJH14S4MSQ2S + Idzh4W4N8bYZg7mDg3nBxOARMEXOGOEXdhXcJSLON2M/n8vnkz0i3mOK8A2+S8VncncKf9H0HBgy4j3+ + gnrE+zVmjnB3uDUGotlRg7vjWSJSYewgMEjcUnP2pzlAppc4QJCCY4cxOT443N/EfDUPjHlYHCUwUrRN + f3G/aY5SqVQqlVqJiJfCd4q4a4M5IWY/KNriLhwjMDncGcLQkPEhdmN4uFN0qWiL9/ABgXlyzCd7hLGi + beL+d0SbzwD8BP1zvF9j5ohOs+PcIyTD09ZZc4Y4ROAEMUd0HgfJs0FHiLZBMveKTwvqMFgMMCk9ni1i + fdvBMbPEtwSZJ99aS3OUSqVSqdRKRLwUJBWcDOGLV362qDuOE+8TmBmSGRgjzA3r/WxRdxwuMDkkT0ii + OKGCf/CzRd3BozT4Efq5Rs2RB4vO0Km2zhp2ip1ryxwxGG2DZBhMBpXBjZkjBp/1bQfHcBA5mB6szByl + UqlUKrUKIl4KkgokF0gykGwg6dAWbw1JC5IXJDFIZpDUILnBepIdbXHekCwhaULyhDr4BZIq+AeSLG3+ + wpCkwY+QtKG/a9Qc0XnSWJicts4CaTDMDOaG9BidZrBIm5E+I43WNkhA+o00HAOMMSI9x46TriNtR/qu + 7eAAaT/Sf/SPtn0PMs1RKpVKpVIrEfFSOHNEvOcxFR5X4bGVtrgLPO7CYy8xc+SYz2MyPC7TFu+BmN2W + OaJtHs9pPoQd4fEefwlrjWaOMBvsMA9A8SBUs6M8MMWDU5gTDA076KfWcYIYHgYPk9McIB7U4oEtzBMO + kkGKD3XxmQwED341DwwPiPGgmB/s4uDQNg+Urd6n11OpVCqV+guV4qWfOeILTZgc4j1fdOILT3zxqe2B + bH/bHCNF7CfeA5kn1pHh4QtXbQ9k8wUtvqjFF7bwF5gcfANt88UuvuCF+Wp7IJt+2S+sMXPk3znyDuPW + Yidxd35anffJ+GCK+Eoe9cge4e54nx2Kg8NX+3CPDBA7ynaYIuozSHwWA4ch4yuD8aDwlUIGjq8Yxp8B + oG7nlppIc5RKpVKp1EpEvBT+jSPHbeI9j9Lwkzn8dA4/oRPjsLM/xG/u2lAPs0IsJiYTm/1tc366J8Z/ + 7hRxZ4ikBv6C2G3PgOnBnFGf2M9PBkXfQTLEpop6a8wcYXToMDuPo6NzPFvEjzJheugkqTDvIINLZzEp + Njlkj7hHyKDwbBE/BoUpYnBIwTljRNaH+rTJa9/O48emOBg8W8SPUGGKOCi4U9+Kc9ud3zgSdU9SqVQq + lUp1pxoznT3y1/mdEOHZIJ4t4g4Od2v8oDbGhwwPMTgmRjBI+AW8Ae9Tnzs83CXyg9rEf99Sw1/QJp4B + g0TbrMcb4BtIkHB3yg9qY8Z8l4rt18jvHGE03GHMCk6Nn+9mwOgc5gVj4p1jYKnjQbaxoh4OkZ8Nt9Nk + 4PgMBhUThbFhJ2ObGC62YXt+rtz3NxkwBo72barcdscYQSqVSqVSqZ5VY2bTIDlBgYkhi4PJIeODSeK/ + 82IdcRgjhCFyYoTSiREMFvEbk8SzRJgk/hsxGxxiPLGeesR/t23fQH3aYHtMEl+8Yh2+w2124n7dlVde + NCYYKDpMB9gBOoNbM7xmvY1N53ZWLQGTw46yHQPFIOIIKXnNAFCf7WyqgGU+EydqF8mAYLAoec2gRlPl + tn2g656kUqlUKpXqTiFuNuM+MRYjQtzlVlf8D+C5k0QsbiYoICZViPfUZ3uSIpSYrmZixPHfbTv+0z7t + GGI/nsJtdmJ/3ZVXXmqsOVB0gkwQHQKW2QEPSKeDwnV57UFiOwaKgQB2ms/gvTZj4zapx3YMBIMMGCqn + 79z2CqbIpFKpVCqV6lkt8ZOYSmwlxhKDibsxwQHxrhGxnLjtujGGE6/ZDlPDZwCxnPX2EM26bps4z3Z4 + ABPjP2104v9qE43VRmNn6UiEdbzn7Vwv7iSwLTvCAIJ3yu93V9cDZIMFrh/bjnWXkUqlUqlUqme1xU/h + OEysJu5igmKSg+WYpGDbZl3HcGI321LH9fjM6ANi3dj2KnmA1SYaq7ijPRG3j/h973zklazbIZVKpVKp + VM9qi58Bx2HMiM2K6SnJEevG+sbmpqe6zfrGdUzdk1QqlUqlUqmXQZiLVSCakZeYk5UQt/3f1G2ybLtU + KpVKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpVKpVCqVSqVSqVQqlUql + UqlUKpVKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpf6Paq2z+yZJkiRJ + kiSV1pVJkiRJkiT/X+GfV1de0wOvbeF1lbgMrw+leUPljQ3eFHhz5S0N3ireFnh7Ld8h3hl4V2XtCsvr + ivVq6eX1xQaVjSobVzYVmwU2F1uKrcTWge3FdmLHys5iJ7GL2K2yh3h3Za/AvmI/cYA4ULyvcrB4f+UQ + cag4QhwpPiQ+XPmI+HjlGPG34ljxKfEZ8TnxBfFF8ffiS+LL4h/E1yvfECeIE8U3xXcq3xWniu9Vvl/5 + YeXH4j/F6eKn4mfiF+IscbY4V5wvzhMXi0vEZaKXuKJyjbhWXCduENfX8ibxW3GzuK1yp/iduEf8Xvyh + cp/4o3iw0kf0DTwiHhUDxaDK4+LJyhDxlBgqng4MFyPFKDFajBXjKxMqE8UzYlJlsni2MjUwPTBDzBSz + ArMrz1XmiHlibi3Ngsr8ysLAosDiUMKSBs9Xlv4ZvBBovva6CO3Ebb0uvm/cN/ezuQ9xHz0WLLP/fh3H + Bxg3l3E8PdYe+3gcgGMEHLNpgSktcLx9LvgcGSc4R8bUZc4llilHCM4rL3O+cR4OrrDMOQqcr/3FgEo/ + wXnt85xz/wFxby25HnoLXyt3ibsF188tgmvqVsH1xXX2m8qvBNeir0muT1+vvn4vFBdUuL651s+scP3/ + XPxEMC/8h/hRLZk3/k38q/CcwvxySuWfxLcEc9A/Vr4mmKeOrzB/MY8xn/2d+Lz4rDhOMN8x731CMA8y + Hx4tPiqYJ48SzJ3AMnMpc+oHBfOr51vPv+8V+1f2EczRewvmbM/je4rdK7sK5nvmfs//xALHhm3FNhXi + BxBLgLjiGLNJxTHIMWnDCvGKuGWIY+uIGOdgrYBjIyUQMx03DXEVmvGWGBzjMsSY7VgecYx3vI8+INL0 + EKbpM6L3MPYpK+NVoYzLcd0qgTlq64iJO+Cda+4weFCgOXBxYOOA2ww1DZEPWjRFPrg+2D74Phmaxiia + oWiIfMKx7JPRJ6eNESfuFsInNGbIJzknPSf/DsIXBCUXCRcLpogLh4vIpogLDGyKfAFijLhADxI2RMDF + y4V8eC0xRhiij4WSyeCTAmPEJMFkgSmyMbIpAk80mCImIEwRnCS+LU4WTFaewE4T/yKY2Jjg/l0w4TH5 + YYgwRkyK/y1sijBDhkn0IsHEyiTLZHu5uEpcLZiQfy1sim4UnsApb6/cIZjcmezBpuj+CgHiYdE0Rg4o + 5rGKAxCmaJiwMWKZYOXghSHCGBHUKAly0RzZFNkY2RxR2hRhhmLpoGtiQMYUgYO4Swf6aACiMbI5apqi + iA0H2IxEg+Jl053Z8fruaG4fie+zHI0QNPvqfvp13EdgHLwcDZLHq4nHFDzWjHt3RonjwzKlTZLNULP0 + cYdonCk5b3wO2RQZv+Yc5Jx06fOTc5Vz1ucw5gizb5Nkg+TrgWVKrhH+iACbI19PXFu3CQxS/KMEMEZc + l1yfVwpMEtfupYLrmOuZP3owR1zv59TyDIE5igaJP6CYL4A/qJhHIBokwBwBf5wxH/EHm03SV8VXBPMW + cxjGCJNkg/TpCnMgBol5EGyQKIH5kvkTg8RcephgfrVBAuZe5mHAIDEv84crczTzNfO25/Bokvjjlznf + Jsn4D2bHCWKG4wexxCaJGAM2SsQfiGbJJsl/zNsoUTrGOeZFoxTNUptJMtEoxRgcYzPEuB3jOTjOx9gf + /QC0eYboLdpo8yMRmyHTtm5VwAi5XNEcLXnhxQKLl3bHCy9hUYOFz7+UBWL+kuUlzFuydFk5d/HSTjlH + ZeS5BrMWPV9mL+oqZy5cznRYsGQZU+d3MUU8O295OXne4g7PzF1cJtVywpwuxs9Z1GHcc4vK2MCoWQs7 + jBQjZi4sw2Yu6PD0jC6GTJ/f4UmYNr8MFo9PnbeMQVPmlQHPzu3wyKQ5pd/kuaWPyj7PdPHQxOfKAxO6 + uF/cO3526T2ui3vGzupw1+iZ5U5xh7hl5Ixyq7h5xIzyW3HTiOnlxuHTyw3Dppfrhk4r1z49rVz91NRy + jfjlkKnlyiFTyhVPTimXDZ5SLheXPvFsuURc+NjkcoE4X5w7cFI5e8CkcpY4o/8z5eePTiw/7Tex/OSR + ieW/+k4oP+ozofxY5Q8fHt/hBw+NL99/aFw57cFx5XsPjC2niu/eP7accv+YcvJ9Y8q37x1TTvrD6HJS + 79HlxN6jOnz1dyPL1+8ZWb6i8kt3jejwxTuHl8/fMbx8QXzmtmEdjhOfunVoObbyyVuGlk/c/HQ5Rnz0 + pqfKx8TRguUjbxhSjhCUh13/ZDn0ui4O+fXgTvl+lXDQrwaXA699ohx4zRNl/6sfL/uJfa9azj6VPa98 + rLxb7HHFoLK7oITdLh9Udr18YNnlsoFlZ7FTr4FlR+Fy+0sHlB16DeiU214yoGwDF/cvWwe2EltetJzN + L3y0w2aBTcXGF/TrsNH5/comF3S9Zhk2DGxw3nLWP++RVtY7twsvrxtY55wu4nJk7XP6LqO79d0Rt2/W + ietjfyLud3zd3DfwOLBMGccnwth5XOPYxrHf4qKu49EkHjOOY+fYVjjWPu5mu3ou+NwAzhnOn3hOcZ7t + 9cvHynsqLO99VReci5ynB1yzHM5fzuODhc/vD9TycJ37cJSuA/Oh3wwpH7mx61rx9cO1BFxf5rO3Dyuf + E/FaZJnr83hdq1/TNcu1e4KuYZa/8ftRnWWub65zrnng+v/nOhec9sdxnfkBPGcwfwDzyemaW34mmGeY + b84UzD1w3qDJHZibLn68a55ivuo1uAvmsqs0rxnmO+a66zX3MQcyFwLzInMkc+Vto2aW24XnUMq7x3TN + rcyzzLmGOdjzMXPzw3WeZt7uW+fv/prLDfM6c/wTmuuB+R868aDGhqemLyhDFSuIG8Nr/CCWAHFl9OyF + ZYygdNwhDjkmwUTFKuKVYxdxjJgWmVZjHyVx0GUnPooZlRg7HVNNjLuOw8RnQ5yOOJ4bYrxp+oCmVzBt + vqLdf3T5E3sUL68qz/8ZLH2R8sXyP91+H9jQCZNaAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCElectricityMeterV.Designer.cs b/JinYuan.ControlLib/UCElectricityMeterV.Designer.cs new file mode 100644 index 0000000..59ec74a --- /dev/null +++ b/JinYuan.ControlLib/UCElectricityMeterV.Designer.cs @@ -0,0 +1,768 @@ +namespace JinYuan.ControlLib +{ + partial class UCElectricityMeterV + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UCElectricityMeterV)); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.lblAccumulatedElectricityUint = new System.Windows.Forms.Label(); + this.txtAccumulatedElectricity = new System.Windows.Forms.Label(); + this.lblActivePowerUint = new System.Windows.Forms.Label(); + this.lblActivePower = new System.Windows.Forms.Label(); + this.txtTotalPower = new System.Windows.Forms.Label(); + this.lblPowerFactor = new System.Windows.Forms.Label(); + this.txtPowerFactor = new System.Windows.Forms.Label(); + this.lblPhasePowerCUint = new System.Windows.Forms.Label(); + this.lblPhasePowerC = new System.Windows.Forms.Label(); + this.txtPhasePowerC = new System.Windows.Forms.Label(); + this.lblPhasePowerBUint = new System.Windows.Forms.Label(); + this.lblPhasePowerB = new System.Windows.Forms.Label(); + this.txtPhasePowerB = new System.Windows.Forms.Label(); + this.lblPhasePowerAUint = new System.Windows.Forms.Label(); + this.lblPhasePowerA = new System.Windows.Forms.Label(); + this.txtPhasePowerA = new System.Windows.Forms.Label(); + this.lblCt = new System.Windows.Forms.Label(); + this.txtCt = new System.Windows.Forms.Label(); + this.lblPhaseCurrentCUint = new System.Windows.Forms.Label(); + this.lblPhaseCurrentC = new System.Windows.Forms.Label(); + this.txtPhaseCurrentC = new System.Windows.Forms.Label(); + this.lblPhaseCurrentBUint = new System.Windows.Forms.Label(); + this.lblPhaseCurrentB = new System.Windows.Forms.Label(); + this.txtPhaseCurrentB = new System.Windows.Forms.Label(); + this.lblPhaseCurrentAUint = new System.Windows.Forms.Label(); + this.lblPhaseCurrentA = new System.Windows.Forms.Label(); + this.txtPhaseCurrentA = new System.Windows.Forms.Label(); + this.lblPt = new System.Windows.Forms.Label(); + this.txtPt = new System.Windows.Forms.Label(); + this.lblPhaseVoltageCUint = new System.Windows.Forms.Label(); + this.lblPhaseVoltageC = new System.Windows.Forms.Label(); + this.txtPhaseVoltageC = new System.Windows.Forms.Label(); + this.lblPhaseVoltageBUint = new System.Windows.Forms.Label(); + this.lblPhaseVoltageB = new System.Windows.Forms.Label(); + this.txtPhaseVoltageB = new System.Windows.Forms.Label(); + this.lblPhaseVoltageAUint = new System.Windows.Forms.Label(); + this.lblPhaseVoltageA = new System.Windows.Forms.Label(); + this.txtPhaseVoltageA = new System.Windows.Forms.Label(); + this.lblAccumulatedElectricity = new System.Windows.Forms.Label(); + this.UCtitleName = new JinYuan.ControlLib.LongTitleStyle2(); + this.tableLayoutPanel2.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 12; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 63F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 51F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 64F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 54F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 29F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 65F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 55F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 35F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 81F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 45F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Controls.Add(this.lblAccumulatedElectricityUint, 10, 3); + this.tableLayoutPanel2.Controls.Add(this.txtAccumulatedElectricity, 5, 3); + this.tableLayoutPanel2.Controls.Add(this.lblActivePowerUint, 4, 3); + this.tableLayoutPanel2.Controls.Add(this.lblActivePower, 2, 3); + this.tableLayoutPanel2.Controls.Add(this.txtTotalPower, 0, 3); + this.tableLayoutPanel2.Controls.Add(this.lblPowerFactor, 10, 2); + this.tableLayoutPanel2.Controls.Add(this.txtPowerFactor, 9, 2); + this.tableLayoutPanel2.Controls.Add(this.lblPhasePowerCUint, 8, 2); + this.tableLayoutPanel2.Controls.Add(this.lblPhasePowerC, 7, 2); + this.tableLayoutPanel2.Controls.Add(this.txtPhasePowerC, 6, 2); + this.tableLayoutPanel2.Controls.Add(this.lblPhasePowerBUint, 5, 2); + this.tableLayoutPanel2.Controls.Add(this.lblPhasePowerB, 4, 2); + this.tableLayoutPanel2.Controls.Add(this.txtPhasePowerB, 3, 2); + this.tableLayoutPanel2.Controls.Add(this.lblPhasePowerAUint, 2, 2); + this.tableLayoutPanel2.Controls.Add(this.lblPhasePowerA, 1, 2); + this.tableLayoutPanel2.Controls.Add(this.txtPhasePowerA, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.lblCt, 10, 1); + this.tableLayoutPanel2.Controls.Add(this.txtCt, 9, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseCurrentCUint, 8, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseCurrentC, 7, 1); + this.tableLayoutPanel2.Controls.Add(this.txtPhaseCurrentC, 6, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseCurrentBUint, 5, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseCurrentB, 4, 1); + this.tableLayoutPanel2.Controls.Add(this.txtPhaseCurrentB, 3, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseCurrentAUint, 2, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseCurrentA, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.txtPhaseCurrentA, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.lblPt, 10, 0); + this.tableLayoutPanel2.Controls.Add(this.txtPt, 9, 0); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseVoltageCUint, 8, 0); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseVoltageC, 7, 0); + this.tableLayoutPanel2.Controls.Add(this.txtPhaseVoltageC, 6, 0); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseVoltageBUint, 5, 0); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseVoltageB, 4, 0); + this.tableLayoutPanel2.Controls.Add(this.txtPhaseVoltageB, 3, 0); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseVoltageAUint, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.lblPhaseVoltageA, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.txtPhaseVoltageA, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.lblAccumulatedElectricity, 8, 3); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 32); + this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 5; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(569, 95); + this.tableLayoutPanel2.TabIndex = 18; + // + // lblAccumulatedElectricityUint + // + this.lblAccumulatedElectricityUint.AutoSize = true; + this.lblAccumulatedElectricityUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblAccumulatedElectricityUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblAccumulatedElectricityUint.ForeColor = System.Drawing.Color.White; + this.lblAccumulatedElectricityUint.Location = new System.Drawing.Point(525, 69); + this.lblAccumulatedElectricityUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblAccumulatedElectricityUint.Name = "lblAccumulatedElectricityUint"; + this.lblAccumulatedElectricityUint.Size = new System.Drawing.Size(37, 25); + this.lblAccumulatedElectricityUint.TabIndex = 38; + this.lblAccumulatedElectricityUint.Text = "kW·h"; + this.lblAccumulatedElectricityUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtAccumulatedElectricity + // + this.txtAccumulatedElectricity.AutoSize = true; + this.tableLayoutPanel2.SetColumnSpan(this.txtAccumulatedElectricity, 3); + this.txtAccumulatedElectricity.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtAccumulatedElectricity.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtAccumulatedElectricity.ForeColor = System.Drawing.Color.White; + this.txtAccumulatedElectricity.Location = new System.Drawing.Point(260, 69); + this.txtAccumulatedElectricity.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtAccumulatedElectricity.Name = "txtAccumulatedElectricity"; + this.txtAccumulatedElectricity.Size = new System.Drawing.Size(141, 25); + this.txtAccumulatedElectricity.TabIndex = 36; + this.txtAccumulatedElectricity.Text = "累计电能"; + this.txtAccumulatedElectricity.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblActivePowerUint + // + this.lblActivePowerUint.AutoSize = true; + this.lblActivePowerUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblActivePowerUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblActivePowerUint.ForeColor = System.Drawing.Color.White; + this.lblActivePowerUint.Location = new System.Drawing.Point(206, 69); + this.lblActivePowerUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblActivePowerUint.Name = "lblActivePowerUint"; + this.lblActivePowerUint.Size = new System.Drawing.Size(46, 25); + this.lblActivePowerUint.TabIndex = 35; + this.lblActivePowerUint.Text = "W"; + this.lblActivePowerUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblActivePower + // + this.lblActivePower.AutoSize = true; + this.tableLayoutPanel2.SetColumnSpan(this.lblActivePower, 2); + this.lblActivePower.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblActivePower.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblActivePower.ForeColor = System.Drawing.Color.White; + this.lblActivePower.Location = new System.Drawing.Point(118, 69); + this.lblActivePower.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblActivePower.Name = "lblActivePower"; + this.lblActivePower.Size = new System.Drawing.Size(80, 25); + this.lblActivePower.TabIndex = 34; + this.lblActivePower.Text = "232.5"; + this.lblActivePower.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtTotalPower + // + this.txtTotalPower.AutoSize = true; + this.tableLayoutPanel2.SetColumnSpan(this.txtTotalPower, 2); + this.txtTotalPower.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTotalPower.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtTotalPower.ForeColor = System.Drawing.Color.White; + this.txtTotalPower.Location = new System.Drawing.Point(4, 69); + this.txtTotalPower.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtTotalPower.Name = "txtTotalPower"; + this.txtTotalPower.Size = new System.Drawing.Size(106, 25); + this.txtTotalPower.TabIndex = 33; + this.txtTotalPower.Text = "总功率"; + this.txtTotalPower.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPowerFactor + // + this.lblPowerFactor.AutoSize = true; + this.lblPowerFactor.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPowerFactor.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPowerFactor.ForeColor = System.Drawing.Color.White; + this.lblPowerFactor.Location = new System.Drawing.Point(525, 44); + this.lblPowerFactor.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPowerFactor.Name = "lblPowerFactor"; + this.lblPowerFactor.Size = new System.Drawing.Size(37, 25); + this.lblPowerFactor.TabIndex = 32; + this.lblPowerFactor.Text = "1"; + this.lblPowerFactor.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPowerFactor + // + this.txtPowerFactor.AutoSize = true; + this.txtPowerFactor.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPowerFactor.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPowerFactor.ForeColor = System.Drawing.Color.White; + this.txtPowerFactor.Location = new System.Drawing.Point(444, 44); + this.txtPowerFactor.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPowerFactor.Name = "txtPowerFactor"; + this.txtPowerFactor.Size = new System.Drawing.Size(73, 25); + this.txtPowerFactor.TabIndex = 31; + this.txtPowerFactor.Text = "总功率因素"; + this.txtPowerFactor.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhasePowerCUint + // + this.lblPhasePowerCUint.AutoSize = true; + this.lblPhasePowerCUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhasePowerCUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhasePowerCUint.ForeColor = System.Drawing.Color.White; + this.lblPhasePowerCUint.Location = new System.Drawing.Point(409, 44); + this.lblPhasePowerCUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhasePowerCUint.Name = "lblPhasePowerCUint"; + this.lblPhasePowerCUint.Size = new System.Drawing.Size(27, 25); + this.lblPhasePowerCUint.TabIndex = 30; + this.lblPhasePowerCUint.Text = "W"; + this.lblPhasePowerCUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhasePowerC + // + this.lblPhasePowerC.AutoSize = true; + this.lblPhasePowerC.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhasePowerC.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhasePowerC.ForeColor = System.Drawing.Color.White; + this.lblPhasePowerC.Location = new System.Drawing.Point(354, 44); + this.lblPhasePowerC.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhasePowerC.Name = "lblPhasePowerC"; + this.lblPhasePowerC.Size = new System.Drawing.Size(47, 25); + this.lblPhasePowerC.TabIndex = 29; + this.lblPhasePowerC.Text = "0"; + this.lblPhasePowerC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhasePowerC + // + this.txtPhasePowerC.AutoSize = true; + this.txtPhasePowerC.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhasePowerC.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhasePowerC.ForeColor = System.Drawing.Color.White; + this.txtPhasePowerC.Location = new System.Drawing.Point(289, 44); + this.txtPhasePowerC.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhasePowerC.Name = "txtPhasePowerC"; + this.txtPhasePowerC.Size = new System.Drawing.Size(57, 25); + this.txtPhasePowerC.TabIndex = 28; + this.txtPhasePowerC.Text = "C相功率"; + this.txtPhasePowerC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhasePowerBUint + // + this.lblPhasePowerBUint.AutoSize = true; + this.lblPhasePowerBUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhasePowerBUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhasePowerBUint.ForeColor = System.Drawing.Color.White; + this.lblPhasePowerBUint.Location = new System.Drawing.Point(260, 44); + this.lblPhasePowerBUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhasePowerBUint.Name = "lblPhasePowerBUint"; + this.lblPhasePowerBUint.Size = new System.Drawing.Size(21, 25); + this.lblPhasePowerBUint.TabIndex = 27; + this.lblPhasePowerBUint.Text = "W"; + this.lblPhasePowerBUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhasePowerB + // + this.lblPhasePowerB.AutoSize = true; + this.lblPhasePowerB.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhasePowerB.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhasePowerB.ForeColor = System.Drawing.Color.White; + this.lblPhasePowerB.Location = new System.Drawing.Point(206, 44); + this.lblPhasePowerB.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhasePowerB.Name = "lblPhasePowerB"; + this.lblPhasePowerB.Size = new System.Drawing.Size(46, 25); + this.lblPhasePowerB.TabIndex = 26; + this.lblPhasePowerB.Text = "232.5"; + this.lblPhasePowerB.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhasePowerB + // + this.txtPhasePowerB.AutoSize = true; + this.txtPhasePowerB.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhasePowerB.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhasePowerB.ForeColor = System.Drawing.Color.White; + this.txtPhasePowerB.Location = new System.Drawing.Point(142, 44); + this.txtPhasePowerB.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhasePowerB.Name = "txtPhasePowerB"; + this.txtPhasePowerB.Size = new System.Drawing.Size(56, 25); + this.txtPhasePowerB.TabIndex = 25; + this.txtPhasePowerB.Text = "B相功率"; + this.txtPhasePowerB.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhasePowerAUint + // + this.lblPhasePowerAUint.AutoSize = true; + this.lblPhasePowerAUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhasePowerAUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhasePowerAUint.ForeColor = System.Drawing.Color.White; + this.lblPhasePowerAUint.Location = new System.Drawing.Point(118, 44); + this.lblPhasePowerAUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhasePowerAUint.Name = "lblPhasePowerAUint"; + this.lblPhasePowerAUint.Size = new System.Drawing.Size(16, 25); + this.lblPhasePowerAUint.TabIndex = 24; + this.lblPhasePowerAUint.Text = "W"; + this.lblPhasePowerAUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhasePowerA + // + this.lblPhasePowerA.AutoSize = true; + this.lblPhasePowerA.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhasePowerA.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhasePowerA.ForeColor = System.Drawing.Color.White; + this.lblPhasePowerA.Location = new System.Drawing.Point(67, 44); + this.lblPhasePowerA.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhasePowerA.Name = "lblPhasePowerA"; + this.lblPhasePowerA.Size = new System.Drawing.Size(43, 25); + this.lblPhasePowerA.TabIndex = 23; + this.lblPhasePowerA.Text = "232.5"; + this.lblPhasePowerA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhasePowerA + // + this.txtPhasePowerA.AutoSize = true; + this.txtPhasePowerA.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhasePowerA.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhasePowerA.ForeColor = System.Drawing.Color.White; + this.txtPhasePowerA.Location = new System.Drawing.Point(4, 44); + this.txtPhasePowerA.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhasePowerA.Name = "txtPhasePowerA"; + this.txtPhasePowerA.Size = new System.Drawing.Size(55, 25); + this.txtPhasePowerA.TabIndex = 22; + this.txtPhasePowerA.Text = "A相功率"; + this.txtPhasePowerA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblCt + // + this.lblCt.AutoSize = true; + this.lblCt.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblCt.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblCt.ForeColor = System.Drawing.Color.White; + this.lblCt.Location = new System.Drawing.Point(525, 24); + this.lblCt.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblCt.Name = "lblCt"; + this.lblCt.Size = new System.Drawing.Size(37, 20); + this.lblCt.TabIndex = 21; + this.lblCt.Text = "1"; + this.lblCt.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtCt + // + this.txtCt.AutoSize = true; + this.txtCt.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtCt.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtCt.ForeColor = System.Drawing.Color.White; + this.txtCt.Location = new System.Drawing.Point(444, 24); + this.txtCt.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtCt.Name = "txtCt"; + this.txtCt.Size = new System.Drawing.Size(73, 20); + this.txtCt.TabIndex = 20; + this.txtCt.Text = "电流变比"; + this.txtCt.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseCurrentCUint + // + this.lblPhaseCurrentCUint.AutoSize = true; + this.lblPhaseCurrentCUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseCurrentCUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseCurrentCUint.ForeColor = System.Drawing.Color.White; + this.lblPhaseCurrentCUint.Location = new System.Drawing.Point(409, 24); + this.lblPhaseCurrentCUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseCurrentCUint.Name = "lblPhaseCurrentCUint"; + this.lblPhaseCurrentCUint.Size = new System.Drawing.Size(27, 20); + this.lblPhaseCurrentCUint.TabIndex = 19; + this.lblPhaseCurrentCUint.Text = "A"; + this.lblPhaseCurrentCUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseCurrentC + // + this.lblPhaseCurrentC.AutoSize = true; + this.lblPhaseCurrentC.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseCurrentC.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseCurrentC.ForeColor = System.Drawing.Color.White; + this.lblPhaseCurrentC.Location = new System.Drawing.Point(354, 24); + this.lblPhaseCurrentC.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseCurrentC.Name = "lblPhaseCurrentC"; + this.lblPhaseCurrentC.Size = new System.Drawing.Size(47, 20); + this.lblPhaseCurrentC.TabIndex = 18; + this.lblPhaseCurrentC.Text = "232.5"; + this.lblPhaseCurrentC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhaseCurrentC + // + this.txtPhaseCurrentC.AutoSize = true; + this.txtPhaseCurrentC.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseCurrentC.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhaseCurrentC.ForeColor = System.Drawing.Color.White; + this.txtPhaseCurrentC.Location = new System.Drawing.Point(289, 24); + this.txtPhaseCurrentC.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhaseCurrentC.Name = "txtPhaseCurrentC"; + this.txtPhaseCurrentC.Size = new System.Drawing.Size(57, 20); + this.txtPhaseCurrentC.TabIndex = 17; + this.txtPhaseCurrentC.Text = "C相电流"; + this.txtPhaseCurrentC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseCurrentBUint + // + this.lblPhaseCurrentBUint.AutoSize = true; + this.lblPhaseCurrentBUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseCurrentBUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseCurrentBUint.ForeColor = System.Drawing.Color.White; + this.lblPhaseCurrentBUint.Location = new System.Drawing.Point(260, 24); + this.lblPhaseCurrentBUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseCurrentBUint.Name = "lblPhaseCurrentBUint"; + this.lblPhaseCurrentBUint.Size = new System.Drawing.Size(21, 20); + this.lblPhaseCurrentBUint.TabIndex = 16; + this.lblPhaseCurrentBUint.Text = "A"; + this.lblPhaseCurrentBUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseCurrentB + // + this.lblPhaseCurrentB.AutoSize = true; + this.lblPhaseCurrentB.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseCurrentB.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseCurrentB.ForeColor = System.Drawing.Color.White; + this.lblPhaseCurrentB.Location = new System.Drawing.Point(206, 24); + this.lblPhaseCurrentB.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseCurrentB.Name = "lblPhaseCurrentB"; + this.lblPhaseCurrentB.Size = new System.Drawing.Size(46, 20); + this.lblPhaseCurrentB.TabIndex = 15; + this.lblPhaseCurrentB.Text = "232.5"; + this.lblPhaseCurrentB.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhaseCurrentB + // + this.txtPhaseCurrentB.AutoSize = true; + this.txtPhaseCurrentB.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseCurrentB.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhaseCurrentB.ForeColor = System.Drawing.Color.White; + this.txtPhaseCurrentB.Location = new System.Drawing.Point(142, 24); + this.txtPhaseCurrentB.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhaseCurrentB.Name = "txtPhaseCurrentB"; + this.txtPhaseCurrentB.Size = new System.Drawing.Size(56, 20); + this.txtPhaseCurrentB.TabIndex = 14; + this.txtPhaseCurrentB.Text = "B相电流"; + this.txtPhaseCurrentB.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseCurrentAUint + // + this.lblPhaseCurrentAUint.AutoSize = true; + this.lblPhaseCurrentAUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseCurrentAUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseCurrentAUint.ForeColor = System.Drawing.Color.White; + this.lblPhaseCurrentAUint.Location = new System.Drawing.Point(118, 24); + this.lblPhaseCurrentAUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseCurrentAUint.Name = "lblPhaseCurrentAUint"; + this.lblPhaseCurrentAUint.Size = new System.Drawing.Size(16, 20); + this.lblPhaseCurrentAUint.TabIndex = 13; + this.lblPhaseCurrentAUint.Text = "A"; + this.lblPhaseCurrentAUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseCurrentA + // + this.lblPhaseCurrentA.AutoSize = true; + this.lblPhaseCurrentA.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseCurrentA.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseCurrentA.ForeColor = System.Drawing.Color.White; + this.lblPhaseCurrentA.Location = new System.Drawing.Point(67, 24); + this.lblPhaseCurrentA.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseCurrentA.Name = "lblPhaseCurrentA"; + this.lblPhaseCurrentA.Size = new System.Drawing.Size(43, 20); + this.lblPhaseCurrentA.TabIndex = 12; + this.lblPhaseCurrentA.Text = "232.5"; + this.lblPhaseCurrentA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhaseCurrentA + // + this.txtPhaseCurrentA.AutoSize = true; + this.txtPhaseCurrentA.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseCurrentA.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhaseCurrentA.ForeColor = System.Drawing.Color.White; + this.txtPhaseCurrentA.Location = new System.Drawing.Point(4, 24); + this.txtPhaseCurrentA.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhaseCurrentA.Name = "txtPhaseCurrentA"; + this.txtPhaseCurrentA.Size = new System.Drawing.Size(55, 20); + this.txtPhaseCurrentA.TabIndex = 11; + this.txtPhaseCurrentA.Text = "A相电流"; + this.txtPhaseCurrentA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPt + // + this.lblPt.AutoSize = true; + this.lblPt.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPt.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPt.ForeColor = System.Drawing.Color.White; + this.lblPt.Location = new System.Drawing.Point(525, 0); + this.lblPt.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPt.Name = "lblPt"; + this.lblPt.Size = new System.Drawing.Size(37, 24); + this.lblPt.TabIndex = 10; + this.lblPt.Text = "1"; + this.lblPt.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPt + // + this.txtPt.AutoSize = true; + this.txtPt.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPt.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPt.ForeColor = System.Drawing.Color.White; + this.txtPt.Location = new System.Drawing.Point(444, 0); + this.txtPt.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPt.Name = "txtPt"; + this.txtPt.Size = new System.Drawing.Size(73, 24); + this.txtPt.TabIndex = 9; + this.txtPt.Text = "电压变比"; + this.txtPt.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseVoltageCUint + // + this.lblPhaseVoltageCUint.AutoSize = true; + this.lblPhaseVoltageCUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseVoltageCUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseVoltageCUint.ForeColor = System.Drawing.Color.White; + this.lblPhaseVoltageCUint.Location = new System.Drawing.Point(409, 0); + this.lblPhaseVoltageCUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseVoltageCUint.Name = "lblPhaseVoltageCUint"; + this.lblPhaseVoltageCUint.Size = new System.Drawing.Size(27, 24); + this.lblPhaseVoltageCUint.TabIndex = 8; + this.lblPhaseVoltageCUint.Text = "V"; + this.lblPhaseVoltageCUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseVoltageC + // + this.lblPhaseVoltageC.AutoSize = true; + this.lblPhaseVoltageC.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseVoltageC.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseVoltageC.ForeColor = System.Drawing.Color.White; + this.lblPhaseVoltageC.Location = new System.Drawing.Point(354, 0); + this.lblPhaseVoltageC.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseVoltageC.Name = "lblPhaseVoltageC"; + this.lblPhaseVoltageC.Size = new System.Drawing.Size(47, 24); + this.lblPhaseVoltageC.TabIndex = 7; + this.lblPhaseVoltageC.Text = "232.5"; + this.lblPhaseVoltageC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhaseVoltageC + // + this.txtPhaseVoltageC.AutoSize = true; + this.txtPhaseVoltageC.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseVoltageC.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhaseVoltageC.ForeColor = System.Drawing.Color.White; + this.txtPhaseVoltageC.Location = new System.Drawing.Point(289, 0); + this.txtPhaseVoltageC.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhaseVoltageC.Name = "txtPhaseVoltageC"; + this.txtPhaseVoltageC.Size = new System.Drawing.Size(57, 24); + this.txtPhaseVoltageC.TabIndex = 6; + this.txtPhaseVoltageC.Text = "C相电压"; + this.txtPhaseVoltageC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseVoltageBUint + // + this.lblPhaseVoltageBUint.AutoSize = true; + this.lblPhaseVoltageBUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseVoltageBUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseVoltageBUint.ForeColor = System.Drawing.Color.White; + this.lblPhaseVoltageBUint.Location = new System.Drawing.Point(260, 0); + this.lblPhaseVoltageBUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseVoltageBUint.Name = "lblPhaseVoltageBUint"; + this.lblPhaseVoltageBUint.Size = new System.Drawing.Size(21, 24); + this.lblPhaseVoltageBUint.TabIndex = 5; + this.lblPhaseVoltageBUint.Text = "V"; + this.lblPhaseVoltageBUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseVoltageB + // + this.lblPhaseVoltageB.AutoSize = true; + this.lblPhaseVoltageB.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseVoltageB.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseVoltageB.ForeColor = System.Drawing.Color.White; + this.lblPhaseVoltageB.Location = new System.Drawing.Point(206, 0); + this.lblPhaseVoltageB.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseVoltageB.Name = "lblPhaseVoltageB"; + this.lblPhaseVoltageB.Size = new System.Drawing.Size(46, 24); + this.lblPhaseVoltageB.TabIndex = 4; + this.lblPhaseVoltageB.Text = "232.5"; + this.lblPhaseVoltageB.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhaseVoltageB + // + this.txtPhaseVoltageB.AutoSize = true; + this.txtPhaseVoltageB.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseVoltageB.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhaseVoltageB.ForeColor = System.Drawing.Color.White; + this.txtPhaseVoltageB.Location = new System.Drawing.Point(142, 0); + this.txtPhaseVoltageB.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhaseVoltageB.Name = "txtPhaseVoltageB"; + this.txtPhaseVoltageB.Size = new System.Drawing.Size(56, 24); + this.txtPhaseVoltageB.TabIndex = 3; + this.txtPhaseVoltageB.Text = "B相电压"; + this.txtPhaseVoltageB.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseVoltageAUint + // + this.lblPhaseVoltageAUint.AutoSize = true; + this.lblPhaseVoltageAUint.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseVoltageAUint.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseVoltageAUint.ForeColor = System.Drawing.Color.White; + this.lblPhaseVoltageAUint.Location = new System.Drawing.Point(118, 0); + this.lblPhaseVoltageAUint.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseVoltageAUint.Name = "lblPhaseVoltageAUint"; + this.lblPhaseVoltageAUint.Size = new System.Drawing.Size(16, 24); + this.lblPhaseVoltageAUint.TabIndex = 2; + this.lblPhaseVoltageAUint.Text = "V"; + this.lblPhaseVoltageAUint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblPhaseVoltageA + // + this.lblPhaseVoltageA.AutoSize = true; + this.lblPhaseVoltageA.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPhaseVoltageA.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblPhaseVoltageA.ForeColor = System.Drawing.Color.White; + this.lblPhaseVoltageA.Location = new System.Drawing.Point(67, 0); + this.lblPhaseVoltageA.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPhaseVoltageA.Name = "lblPhaseVoltageA"; + this.lblPhaseVoltageA.Size = new System.Drawing.Size(43, 24); + this.lblPhaseVoltageA.TabIndex = 1; + this.lblPhaseVoltageA.Text = "232.5"; + this.lblPhaseVoltageA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // txtPhaseVoltageA + // + this.txtPhaseVoltageA.AutoSize = true; + this.txtPhaseVoltageA.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPhaseVoltageA.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPhaseVoltageA.ForeColor = System.Drawing.Color.White; + this.txtPhaseVoltageA.Location = new System.Drawing.Point(4, 0); + this.txtPhaseVoltageA.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.txtPhaseVoltageA.Name = "txtPhaseVoltageA"; + this.txtPhaseVoltageA.Size = new System.Drawing.Size(55, 24); + this.txtPhaseVoltageA.TabIndex = 0; + this.txtPhaseVoltageA.Text = "A相电压"; + this.txtPhaseVoltageA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // lblAccumulatedElectricity + // + this.lblAccumulatedElectricity.AutoSize = true; + this.tableLayoutPanel2.SetColumnSpan(this.lblAccumulatedElectricity, 2); + this.lblAccumulatedElectricity.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblAccumulatedElectricity.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblAccumulatedElectricity.ForeColor = System.Drawing.Color.White; + this.lblAccumulatedElectricity.Location = new System.Drawing.Point(409, 69); + this.lblAccumulatedElectricity.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblAccumulatedElectricity.Name = "lblAccumulatedElectricity"; + this.lblAccumulatedElectricity.Size = new System.Drawing.Size(108, 25); + this.lblAccumulatedElectricity.TabIndex = 37; + this.lblAccumulatedElectricity.Text = "232.5"; + this.lblAccumulatedElectricity.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // UCtitleName + // + this.UCtitleName.BackColor = System.Drawing.Color.Transparent; + this.UCtitleName.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("UCtitleName.BackgroundImage"))); + this.UCtitleName.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.UCtitleName.Dock = System.Windows.Forms.DockStyle.Top; + this.UCtitleName.Location = new System.Drawing.Point(0, 0); + this.UCtitleName.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); + this.UCtitleName.Name = "UCtitleName"; + this.UCtitleName.Size = new System.Drawing.Size(569, 32); + this.UCtitleName.TabIndex = 1; + this.UCtitleName.TitleName = "智能电表"; + // + // UCElectricityMeterV + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(31)))), ((int)(((byte)(39)))), ((int)(((byte)(104))))); + this.Controls.Add(this.tableLayoutPanel2); + this.Controls.Add(this.UCtitleName); + this.Font = new System.Drawing.Font("微软雅黑", 7.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); + this.Name = "UCElectricityMeterV"; + this.Size = new System.Drawing.Size(569, 127); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private LongTitleStyle2 UCtitleName; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label lblPhaseVoltageBUint; + private System.Windows.Forms.Label lblPhaseVoltageB; + private System.Windows.Forms.Label txtPhaseVoltageB; + private System.Windows.Forms.Label lblPhaseVoltageAUint; + private System.Windows.Forms.Label lblPhaseVoltageA; + private System.Windows.Forms.Label txtPhaseVoltageA; + private System.Windows.Forms.Label txtPowerFactor; + private System.Windows.Forms.Label lblPhasePowerCUint; + private System.Windows.Forms.Label lblPhasePowerC; + private System.Windows.Forms.Label txtPhasePowerC; + private System.Windows.Forms.Label lblPhasePowerBUint; + private System.Windows.Forms.Label lblPhasePowerB; + private System.Windows.Forms.Label txtPhasePowerB; + private System.Windows.Forms.Label lblPhasePowerAUint; + private System.Windows.Forms.Label lblPhasePowerA; + private System.Windows.Forms.Label txtPhasePowerA; + private System.Windows.Forms.Label lblCt; + private System.Windows.Forms.Label txtCt; + private System.Windows.Forms.Label lblPhaseCurrentCUint; + private System.Windows.Forms.Label lblPhaseCurrentC; + private System.Windows.Forms.Label txtPhaseCurrentC; + private System.Windows.Forms.Label lblPhaseCurrentBUint; + private System.Windows.Forms.Label lblPhaseCurrentB; + private System.Windows.Forms.Label txtPhaseCurrentB; + private System.Windows.Forms.Label lblPhaseCurrentAUint; + private System.Windows.Forms.Label lblPhaseCurrentA; + private System.Windows.Forms.Label txtPhaseCurrentA; + private System.Windows.Forms.Label lblPt; + private System.Windows.Forms.Label txtPt; + private System.Windows.Forms.Label lblPhaseVoltageCUint; + private System.Windows.Forms.Label lblPhaseVoltageC; + private System.Windows.Forms.Label txtPhaseVoltageC; + private System.Windows.Forms.Label lblAccumulatedElectricityUint; + private System.Windows.Forms.Label txtAccumulatedElectricity; + private System.Windows.Forms.Label lblActivePowerUint; + private System.Windows.Forms.Label lblActivePower; + private System.Windows.Forms.Label txtTotalPower; + private System.Windows.Forms.Label lblPowerFactor; + private System.Windows.Forms.Label lblAccumulatedElectricity; + } +} diff --git a/JinYuan.ControlLib/UCElectricityMeterV.cs b/JinYuan.ControlLib/UCElectricityMeterV.cs new file mode 100644 index 0000000..951abe3 --- /dev/null +++ b/JinYuan.ControlLib/UCElectricityMeterV.cs @@ -0,0 +1,341 @@ +using JinYuan.Models; +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class UCElectricityMeterV : UserControl + { + public UCElectricityMeterV() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + //#region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + //#endregion + + + + private string smartMeter = "智能电表"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相电压")] + public override string Text + { + get { return smartMeter; } + set + { + smartMeter = value; + this.UCtitleName.TitleName = smartMeter; + } + } + + + #region 相电压 + private string phaseVoltageA = "A相电压"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相电压")] + public string Text1 + { + get { return phaseVoltageA; } + set + { + phaseVoltageA = value; + this.txtPhaseVoltageA.Text = phaseVoltageA; + } + } + + + private string phaseVoltageB = "B相电压"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件B相电压")] + public string Text2 + { + get { return phaseVoltageB; } + set + { + phaseVoltageB = value; + this.txtPhaseVoltageB.Text = phaseVoltageB; + } + } + + + private string phaseVoltageC = "C相电压"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件C相电压")] + public string Text3 + { + get { return phaseVoltageC; } + set + { + phaseVoltageC = value; + this.txtPhaseVoltageC.Text = phaseVoltageC; + } + } + #endregion + + #region 相电流 + private string phaseCurrentA = "A相电流"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相电流")] + public string Text4 + { + get { return phaseCurrentA; } + set + { + phaseCurrentA = value; + this.txtPhaseCurrentA.Text = phaseCurrentA; + } + } + + private string phaseCurrentB = "B相电流"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件B相电流")] + public string Text5 + { + get { return phaseCurrentB; } + set + { + phaseCurrentB = value; + this.txtPhaseCurrentB.Text = phaseCurrentB; + } + } + + + + private string phaseCurrentC = "C相电流"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件C相电流")] + public string Text6 + { + get { return phaseCurrentC; } + set + { + phaseCurrentC = value; + this.txtPhaseCurrentC.Text = phaseCurrentC; + } + } + #endregion + + #region 相功率 + private string phasePowerA = "A相功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件A相功率")] + public string Text7 + { + get { return phasePowerA; } + set + { + phasePowerA = value; + this.txtPhasePowerA.Text = phasePowerA; + } + } + + private string phasePowerB = "B相功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件B相功率")] + public string Text8 + { + get { return phasePowerB; } + set + { + phasePowerB = value; + this.txtPhasePowerB.Text = phasePowerB; + } + } + + + + private string phasePowerC = "C相功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件C相功率")] + public string Text9 + { + get { return phasePowerC; } + set + { + phasePowerC = value; + this.txtPhasePowerC.Text = phasePowerC; + } + } + #endregion + + private string activePower = "总有功功率"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件总有功功率")] + public string Text10 + { + get { return activePower; } + set + { + activePower = value; + this.txtTotalPower.Text = activePower; + + } + } + + private string powerFactor = "总功率因素"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件总功率因素")] + public string Text11 + { + get { return powerFactor; } + set + { + powerFactor = value; + this.txtPowerFactor.Text = powerFactor; + + } + } + + + + + private string pt = "电压变比"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件电压变比")] + public string Text12 + { + get { return pt; } + set + { + pt = value; + this.txtPt.Text = pt; + + } + } + + private string ct = "电流变比"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件电流变比")] + public string Text13 + { + get { return ct; } + set + { + ct = value; + this.txtCt.Text = ct; + + } + } + + + + private string accumulatedElectricity = "累计电能"; + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取控件累计电能")] + public string Text14 + { + get { return accumulatedElectricity; } + set + { + accumulatedElectricity = value; + this.txtAccumulatedElectricity.Text = accumulatedElectricity; + + } + } + + + + private JinYuan.Models.ElectricEnergy _electricEnergy = new JinYuan.Models.ElectricEnergy(); + [Browsable(false)] + [Category("自定义属性")] + [Description("设置或获取实体类值")] + public ElectricEnergy ElectricEnergy + { + get + { + return _electricEnergy; + } + set + { + if (value != null) + { + _electricEnergy = value; + SetElectricEnergy(_electricEnergy); + } + + } + } + + + + + private void SetElectricEnergy(ElectricEnergy m) + { + //累计电能 + this.lblAccumulatedElectricity.Text = m.AccumulatedElectricity.ToString(); + //A相电压 V + this.lblPhaseVoltageA.Text = m.PhaseVoltageA.ToString(); + //B相电压 + this.lblPhaseVoltageB.Text = m.PhaseVoltageB.ToString(); + //C相电压 + this.lblPhaseVoltageC.Text = m.PhaseVoltageC.ToString(); + // A相电流 + this.lblPhaseCurrentA.Text = m.PhaseCurrentA.ToString(); + // B相电流 + this.lblPhaseCurrentB.Text = m.PhaseCurrentB.ToString(); + // C相电流 + this.lblPhaseCurrentC.Text = m.PhaseCurrentC.ToString(); + // A相功率 + this.lblPhasePowerA.Text = m.PhasePowerA.ToString(); + // B相功率 + this.lblPhasePowerB.Text = m.PhasePowerB.ToString(); + // C相功率 + this.lblPhasePowerC.Text = m.PhasePowerC.ToString(); + // 总有功功率 + this.lblActivePower.Text = m.ActivePower.ToString(); + // 总功率因数 + this.lblPowerFactor.Text = m.PowerFactor.ToString(); + // 电压变比 + this.lblPt.Text = m.pt.ToString(); + // 电流变比 + this.lblCt.Text = m.ct.ToString(); + } + } +} diff --git a/JinYuan.ControlLib/UCElectricityMeterV.resx b/JinYuan.ControlLib/UCElectricityMeterV.resx new file mode 100644 index 0000000..032a807 --- /dev/null +++ b/JinYuan.ControlLib/UCElectricityMeterV.resx @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + ATf+uVn+L91+H9j2IH7hAAAAAElFTkSuQmCC + + + + True + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCFengSu.Designer.cs b/JinYuan.ControlLib/UCFengSu.Designer.cs new file mode 100644 index 0000000..b73a03a --- /dev/null +++ b/JinYuan.ControlLib/UCFengSu.Designer.cs @@ -0,0 +1,120 @@ +namespace JinYuan.ControlLib +{ + partial class UCFengSu + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.MainTableLayoutControl = new System.Windows.Forms.TableLayoutPanel(); + this.ucbFengSu = new JinYuan.ControlLib.UCBlower(); + this.lbl_Value = new System.Windows.Forms.Label(); + this.lbl_Title = new System.Windows.Forms.Label(); + this.MainTableLayoutControl.SuspendLayout(); + this.SuspendLayout(); + // + // MainTableLayoutControl + // + this.MainTableLayoutControl.ColumnCount = 3; + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 19.83594F)); + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 44.35146F)); + this.MainTableLayoutControl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 35.98326F)); + this.MainTableLayoutControl.Controls.Add(this.ucbFengSu, 0, 0); + this.MainTableLayoutControl.Controls.Add(this.lbl_Value, 2, 0); + this.MainTableLayoutControl.Controls.Add(this.lbl_Title, 1, 0); + this.MainTableLayoutControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.MainTableLayoutControl.Location = new System.Drawing.Point(0, 0); + this.MainTableLayoutControl.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.MainTableLayoutControl.Name = "MainTableLayoutControl"; + this.MainTableLayoutControl.RowCount = 1; + this.MainTableLayoutControl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.MainTableLayoutControl.Size = new System.Drawing.Size(239, 33); + this.MainTableLayoutControl.TabIndex = 0; + // + // ucbFengSu + // + this.ucbFengSu.BlowerColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(77)))), ((int)(((byte)(59))))); + this.ucbFengSu.Dock = System.Windows.Forms.DockStyle.Fill; + this.ucbFengSu.EntranceDirection = JinYuan.ControlLib.BlowerEntranceDirection.None; + this.ucbFengSu.ExitDirection = JinYuan.ControlLib.BlowerExitDirection.None; + this.ucbFengSu.FanColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(169)))), ((int)(((byte)(243))))); + this.ucbFengSu.IsDZ = true; + this.ucbFengSu.IsExit = false; + this.ucbFengSu.Location = new System.Drawing.Point(1, 1); + this.ucbFengSu.Margin = new System.Windows.Forms.Padding(1); + this.ucbFengSu.Name = "ucbFengSu"; + this.ucbFengSu.Size = new System.Drawing.Size(45, 31); + this.ucbFengSu.TabIndex = 0; + this.ucbFengSu.TurnAround = JinYuan.ControlLib.TurnAround.None; + this.ucbFengSu.TurnSpeed = 100; + // + // lbl_Value + // + this.lbl_Value.AutoSize = true; + this.lbl_Value.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Value.Location = new System.Drawing.Point(156, 0); + this.lbl_Value.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lbl_Value.Name = "lbl_Value"; + this.lbl_Value.Size = new System.Drawing.Size(79, 33); + this.lbl_Value.TabIndex = 1; + this.lbl_Value.Text = "0"; + this.lbl_Value.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // lbl_Title + // + this.lbl_Title.AutoSize = true; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Location = new System.Drawing.Point(50, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(99, 33); + this.lbl_Title.TabIndex = 2; + this.lbl_Title.Text = "参数项名称"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // UCFengSu + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 19F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.Controls.Add(this.MainTableLayoutControl); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.ForeColor = System.Drawing.Color.White; + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "UCFengSu"; + this.Size = new System.Drawing.Size(239, 33); + this.MainTableLayoutControl.ResumeLayout(false); + this.MainTableLayoutControl.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel MainTableLayoutControl; + private UCBlower ucbFengSu; + private System.Windows.Forms.Label lbl_Value; + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/UCFengSu.cs b/JinYuan.ControlLib/UCFengSu.cs new file mode 100644 index 0000000..d681906 --- /dev/null +++ b/JinYuan.ControlLib/UCFengSu.cs @@ -0,0 +1,147 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + + [DefaultEvent("ControlDoubleClick")] + public partial class UCFengSu : UserControl + { + public UCFengSu() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.Size = new System.Drawing.Size(232, 43); + } + + + //private int titleScale = 50; + //[Browsable(true)] + //[Category("自定义属性")] + //[Description("设置或获取标题所占比例")] + //public int TitleScale + //{ + // get { return titleScale; } + // set + // { + // titleScale = value; + + // this.MainTableLayoutControl.ColumnStyles[0] = new ColumnStyle(SizeType.Percent, titleScale); + // } + //} + + + //private int valueScale = 30; + //[Browsable(true)] + //[Category("自定义属性")] + //[Description("设置或获取数据所占比例")] + //public int ValueScale + //{ + // get { return valueScale; } + // set + // { + // valueScale = value; + + // this.MainTableLayoutControl.ColumnStyles[1] = new ColumnStyle(SizeType.Percent, valueScale); + // } + //} + + private string titleName = "参数名称设置"; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取参数名称")] + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + + this.lbl_Title.Text = titleName; + } + } + + private Color ucFengSuBG = Color.FromArgb(255, 77, 59); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取风扇控件背景颜色")] + public Color UcFengSuBG + { + get { return ucFengSuBG; } + set + { + ucFengSuBG = value; + this.ucbFengSu.BlowerColor = ucFengSuBG; + } + } + + private Color ucFengSuFan = Color.FromArgb(3, 169, 243); + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取风扇叶子颜色")] + public Color UcFengSuFan + { + get { return ucFengSuFan; } + set + { + ucFengSuFan = value; + this.ucbFengSu.FanColor = ucFengSuFan; + } + } + + + private float currentValue = 0.0f; + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取当前数值")] + public float CurrentValue + { + get { return currentValue; } + set + { + currentValue = value; + + this.lbl_Value.Text = currentValue.ToString(); + this.ucbFengSu.TurnSpeed = 100; + if (value > 0.0f) + { + this.ucbFengSu.TurnAround = TurnAround.Clockwise; + this.ucbFengSu.TurnSpeed = (int)value; + } + else + { + this.ucbFengSu.TurnAround = TurnAround.None; + } + + } + } + + [Browsable(true)] + [Category("自定义属性")] + [Description("设置或获取绑定变量名称")] + public string BindVarName { get; set; } + + + + [Browsable(true)] + [Category("自定义事件")] + [Description("控件双击事件")] + public event EventHandler ControlDoubleClick; + + private void lbl_Value_DoubleClick(object sender, EventArgs e) + { + if (ControlDoubleClick != null) + { + ControlDoubleClick(this, e); + } + } + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/UCFengSu.resx b/JinYuan.ControlLib/UCFengSu.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/UCFengSu.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCHelper/ControlHelper.cs b/JinYuan.ControlLib/UCHelper/ControlHelper.cs new file mode 100644 index 0000000..7be583a --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/ControlHelper.cs @@ -0,0 +1,2464 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 控件工具类 + /// + public static class ControlHelper + { + #region Graphics + + /// + /// 获取指定窗口(包括非工作区)的Graphics + /// + /// 指定窗口的handle + /// 返回g + /// 返回hDC + public static void GetWindowGraphics(IntPtr handle, out Graphics g, out IntPtr hDC) + { + hDC = NativeMethods.GetWindowDC(handle); + g = Graphics.FromHdc(hDC); + } + + /// + /// 获取指定窗口(只包括工作区)的Graphics + /// + /// 指定窗口的handle + /// 返回g + /// 返回hDC + public static void GetWindowClientGraphics(IntPtr handle, out Graphics g, out IntPtr hDC) + { + hDC = NativeMethods.GetDC(handle); + g = Graphics.FromHdc(hDC); + } + + #endregion + + #region 圆角、边框 + + /// + /// 绘制Rectangle 1个像素边框(圆角边框半径为3个像素) + /// + /// 要绘制边框的控件 + /// 要绘制边框的控件画布 + /// 是否为圆角边框(圆角边框半径为3个像素) + /// 边框颜色 + /// 父控件背景色(圆角边框平滑过度颜色) + /// 控件背景色(圆角边框平滑过度颜色) + public static void DrawControlBorder(Control control, Graphics g, bool roundCorner, Color borderColor, Color borderOutOverColor, Color borderInOverColor) + { + Rectangle rect = control.ClientRectangle; + + SmoothingMode smoothingMode = g.SmoothingMode; + CompositingMode compositingMode = g.CompositingMode; + CompositingQuality compositingQuality = g.CompositingQuality; + InterpolationMode interpolationMode = g.InterpolationMode; + + g.SmoothingMode = SmoothingMode.None; + g.CompositingMode = CompositingMode.SourceCopy; + g.CompositingQuality = CompositingQuality.Default; + g.InterpolationMode = InterpolationMode.Default; + + if (roundCorner) + { + Pen border_pen = new Pen(borderColor); + + //边框 + g.DrawPolygon(border_pen, new Point[] { + new Point(rect.Left,rect.Top+1), + new Point(rect.Left+1,rect.Top+1), + new Point(rect.Left+1,rect.Top), + + new Point(rect.Right-1-1,rect.Top), + new Point(rect.Right-1-1,rect.Top+1), + new Point(rect.Right-1,rect.Top+1), + + new Point(rect.Right-1,rect.Bottom-1-1), + new Point(rect.Right-1-1,rect.Bottom-1-1), + new Point(rect.Right-1-1,rect.Bottom-1), + + new Point(rect.Left+1,rect.Bottom-1), + new Point(rect.Left+1,rect.Bottom-1-1), + new Point(rect.Left,rect.Bottom-1-1), + }); + + //边框圆角外平滑过度 + border_pen.Color = Color.FromArgb(borderColor.R + (borderOutOverColor.R - borderColor.R) / 4, borderColor.G + (borderOutOverColor.G - borderColor.G) / 4, borderColor.B + (borderOutOverColor.B - borderColor.B) / 4); + g.DrawLine(border_pen, new Point(rect.Left, rect.Top + 1), new Point(rect.Left + 1, rect.Top)); + g.DrawLine(border_pen, new Point(rect.Right - 2, rect.Top), new Point(rect.Right - 1, rect.Top + 1)); + g.DrawLine(border_pen, new Point(rect.Right - 1, rect.Bottom - 2), new Point(rect.Right - 2, rect.Bottom - 1)); + g.DrawLine(border_pen, new Point(rect.Left + 1, rect.Bottom - 1), new Point(rect.Left, rect.Bottom - 2)); + + //边框圆角内平滑过度 + SolidBrush sb = new SolidBrush(Color.FromArgb((borderColor.R + borderInOverColor.R) / 2, (borderColor.G + borderInOverColor.G) / 2, (borderColor.B + borderInOverColor.B) / 2)); + g.FillRectangle(sb, new Rectangle(rect.Left + 1, rect.Top + 1, 1, 1)); + g.FillRectangle(sb, new Rectangle(rect.Right - 2, rect.Top + 1, 1, 1)); + g.FillRectangle(sb, new Rectangle(rect.Right - 2, rect.Bottom - 2, 1, 1)); + g.FillRectangle(sb, new Rectangle(rect.Left + 1, rect.Bottom - 2, 1, 1)); + + sb.Dispose(); + border_pen.Dispose(); + } + else + { + Pen border_pen = new Pen(borderColor); + g.DrawRectangle(border_pen, new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1)); + border_pen.Dispose(); + } + + g.SmoothingMode = smoothingMode; + g.CompositingMode = compositingMode; + g.CompositingQuality = compositingQuality; + g.InterpolationMode = interpolationMode; + } + + /// + /// 计算Rectangle 1个像素圆角形状路径(圆角边框半径为3个像素) + /// + /// rect + /// + public static GraphicsPath AdjustRectangleShapePath(Rectangle rect) + { + GraphicsPath gp = new GraphicsPath(); + gp.AddPolygon(new Point[] { + + new Point(rect.Left,rect.Top+1), + new Point(rect.Left+1,rect.Top+1), + new Point(rect.Left+1,rect.Top), + + new Point(rect.Right-1,rect.Top), + new Point(rect.Right-1,rect.Top+1), + new Point(rect.Right,rect.Top+1), + + new Point(rect.Right,rect.Bottom-1), + new Point(rect.Right-1,rect.Bottom-1), + new Point(rect.Right-1,rect.Bottom), + + new Point(rect.Left+1,rect.Bottom), + new Point(rect.Left+1,rect.Bottom-1), + new Point(rect.Left,rect.Bottom-1), + + }); + + return gp; + } + + /// + /// 计算点到矩形的最大圆形最大半径 + /// + /// 矩形 + /// 点 + /// + public static int AdjustRectangleMaxRadiusForPoint(Rectangle rect, Point point) + { + int radius = 0; + + radius = Math.Max(radius, (int)Math.Ceiling(Math.Sqrt(Math.Pow(Math.Abs(point.X - rect.X), 2) + Math.Pow(Math.Abs(point.Y - rect.Y), 2)))); + radius = Math.Max(radius, (int)Math.Ceiling(Math.Sqrt(Math.Pow(Math.Abs(point.X - rect.Right), 2) + Math.Pow(Math.Abs(point.Y - rect.Y), 2)))); + radius = Math.Max(radius, (int)Math.Ceiling(Math.Sqrt(Math.Pow(Math.Abs(point.X - rect.Right), 2) + Math.Pow(Math.Abs(point.Y - rect.Bottom), 2)))); + radius = Math.Max(radius, (int)Math.Ceiling(Math.Sqrt(Math.Pow(Math.Abs(point.X - rect.X), 2) + Math.Pow(Math.Abs(point.Y - rect.Bottom), 2)))); + + return radius; + } + + /// + /// 转换成圆角 + /// + /// 要转换的rect + /// 圆角半径的大小 + /// + public static GraphicsPath AdjustCircularPath(Rectangle rect, int radius) + { + return AdjustCircularPath(rect, radius, radius, radius, radius); + } + + /// + /// 转换成圆角 + /// + /// 要转换的rect + /// 左上角 + /// 右上角 + /// 右下角 + /// 左下角 + /// + public static GraphicsPath AdjustCircularPath(Rectangle rect, int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) + { + leftTopRadius = Math.Abs(leftTopRadius); + int leftTopDiameter = leftTopRadius * 2; + rightTopRadius = Math.Abs(rightTopRadius); + int rightTopDiameter = rightTopRadius * 2; + rightBottomRadius = Math.Abs(rightBottomRadius); + int rightBottomDiameter = rightBottomRadius * 2; + leftBottomRadius = Math.Abs(leftBottomRadius); + int leftBottomDiameter = leftBottomRadius * 2; + + PointF leftTop_x = new PointF(rect.Left, rect.Top); + PointF leftTop_y = new PointF(rect.Left, rect.Top); + if (leftTopRadius > 0) + { + leftTop_x = new PointF(rect.Left + leftTopRadius, rect.Top); + leftTop_y = new PointF(rect.Left, rect.Top + leftTopRadius); + } + + PointF rightTop_x = new PointF(rect.Right, rect.Top); + PointF rightTop_y = new PointF(rect.Right, rect.Top); + if (rightTopRadius > 0) + { + rightTop_x = new PointF(rect.Right - rightTopRadius, rect.Top); + rightTop_y = new PointF(rect.Right, rect.Top + rightTopRadius); + } + + PointF rightBottom_x = new PointF(rect.Right, rect.Bottom); + PointF rightBottom_y = new PointF(rect.Right, rect.Bottom); + if (rightBottomRadius > 0) + { + rightBottom_x = new PointF(rect.Right - rightBottomRadius, rect.Bottom); + rightBottom_y = new PointF(rect.Right, rect.Bottom - rightBottomRadius); + } + + PointF leftBottom_x = new PointF(rect.Left, rect.Bottom); + PointF leftBottom_y = new PointF(rect.Left, rect.Bottom); + if (leftBottomRadius > 0) + { + leftBottom_x = new PointF(rect.Left + leftBottomRadius, rect.Bottom); + leftBottom_y = new PointF(rect.Left, rect.Bottom - leftBottomRadius); + } + + GraphicsPath gp = new GraphicsPath(); + + if (leftTopRadius > 0) + { + RectangleF lefttop_rect = new RectangleF(rect.Left, rect.Top, leftTopDiameter, leftTopDiameter); + gp.AddArc(lefttop_rect, 180, 90); + } + gp.AddLine(leftTop_x, rightTop_x); + + if (rightTopRadius > 0) + { + RectangleF righttop_rect = new RectangleF(rect.Right - rightTopDiameter, rect.Top, rightTopDiameter, rightTopDiameter); + gp.AddArc(righttop_rect, 270, 90); + } + gp.AddLine(rightTop_y, rightBottom_y); + + if (rightBottomRadius > 0) + { + RectangleF rightbottom_rect = new RectangleF(rect.Right - rightBottomDiameter, rect.Bottom - rightBottomDiameter, rightBottomDiameter, rightBottomDiameter); + gp.AddArc(rightbottom_rect, 0, 90); + } + gp.AddLine(rightBottom_x, leftBottom_x); + + if (leftBottomRadius > 0) + { + RectangleF leftbottom_rect = new RectangleF(rect.Left, rect.Bottom - leftBottomDiameter, leftBottomDiameter, leftBottomDiameter); + gp.AddArc(leftbottom_rect, 90, 90); + } + gp.AddLine(leftBottom_y, leftTop_y); + + gp.CloseAllFigures(); + return gp; + } + + /// + /// 转换成圆角 + /// + /// 要转换的rect + /// 左上角 + /// 右上角 + /// 右下角 + /// 左下角 + /// + public static Region AdjustCircularRegion(Rectangle rect, int leftTopRadius, int rightTopRadius, int rightBottomRadius, int leftBottomRadius) + { + Region r = new Region(rect); + GraphicsPath gp = new GraphicsPath(); + + leftTopRadius = Math.Abs(leftTopRadius); + int leftTopDiameter = leftTopRadius * 2; + rightTopRadius = Math.Abs(rightTopRadius); + int rightTopDiameter = rightTopRadius * 2; + rightBottomRadius = Math.Abs(rightBottomRadius); + int rightBottomDiameter = rightBottomRadius * 2; + leftBottomRadius = Math.Abs(leftBottomRadius); + int leftBottomDiameter = leftBottomRadius * 2; + + if (leftTopRadius > 0) + { + Region lefttop_r = new Region(new Rectangle(rect.Left, rect.Top, leftTopRadius, leftTopRadius)); + gp.Reset(); + gp.AddPie(new Rectangle(rect.Left, rect.Top, leftTopDiameter, leftTopDiameter), 180, 90); + lefttop_r.Exclude(gp); + r.Exclude(lefttop_r); + lefttop_r.Dispose(); + } + + if (rightTopRadius > 0) + { + Region righttop_r = new Region(new Rectangle(rect.Right - rightTopRadius, rect.Top, rightTopRadius, rightTopRadius)); + gp.Reset(); + gp.AddPie(new Rectangle(rect.Right - rightTopDiameter, rect.Top, rightTopDiameter, rightTopDiameter), 270, 90); + righttop_r.Exclude(gp); + r.Exclude(righttop_r); + righttop_r.Dispose(); + } + + if (rightBottomRadius > 0) + { + Region rightbottom_r = new Region(new Rectangle(rect.Right - rightBottomRadius, rect.Bottom - rightBottomRadius, rightBottomRadius, rightBottomRadius)); + gp.Reset(); + gp.AddPie(new Rectangle(rect.Right - rightBottomDiameter, rect.Bottom - rightBottomDiameter, rightBottomDiameter, rightBottomDiameter), 0, 90); + rightbottom_r.Exclude(gp); + r.Exclude(rightbottom_r); + rightbottom_r.Dispose(); + } + + if (leftBottomRadius > 0) + { + Region leftbottom_r = new Region(new Rectangle(rect.Left, rect.Bottom - leftBottomRadius, leftBottomRadius, leftBottomRadius)); + gp.Reset(); + gp.AddPie(new Rectangle(rect.Left, rect.Bottom - leftBottomDiameter, leftBottomDiameter, leftBottomDiameter), 90, 90); + leftbottom_r.Exclude(gp); + r.Exclude(leftbottom_r); + leftbottom_r.Dispose(); + } + + gp.Dispose(); + return r; + } + + /// + /// 根据画笔大小计算出真是rectf + /// + /// 要转换的rectf + /// 画笔大小大小 + /// 画笔对齐方式 + /// + public static RectangleF TransformRectangleF(RectangleF rectf, float pen, PenAlignment alignment = PenAlignment.Center) + { + if (pen <= 0) + { + return rectf; + } + + RectangleF result = new RectangleF(); + if (alignment == PenAlignment.Center || alignment == PenAlignment.Left || alignment == PenAlignment.Right || alignment == PenAlignment.Outset) + { + result.Width = rectf.Width - pen; + result.Height = rectf.Height - pen; + result.X = rectf.X + ((int)pen) / 2; + result.Y = rectf.Y + ((int)pen) / 2; + } + else if (alignment == PenAlignment.Inset) + { + + if (pen > 0 && pen < 2) + { + result.Width = rectf.Width - 1; + result.Height = rectf.Height - 1; + } + else + { + result.Width = rectf.Width; + result.Height = rectf.Height; + } + + result.X = rectf.X; + result.Y = rectf.Y; + } + + return result; + } + + /// + /// 根据画笔大小计算出真是rectf + /// + /// 要转换的rect + /// 画笔大小大小 + /// 画笔对齐方式 + /// + public static Rectangle TransformRectangle(Rectangle rect, int pen, PenAlignment alignment = PenAlignment.Center) + { + if (pen <= 0) + { + return rect; + } + + Rectangle result = new Rectangle(); + if (alignment == PenAlignment.Center || alignment == PenAlignment.Left || alignment == PenAlignment.Right || alignment == PenAlignment.Outset) + { + result.Width = rect.Width - pen; + result.Height = rect.Height - pen; + result.X = rect.X + ((int)pen) / 2; + result.Y = rect.Y + ((int)pen) / 2; + } + else if (alignment == PenAlignment.Inset) + { + + if (pen > 0 && pen < 2) + { + result.Width = rect.Width - 1; + result.Height = rect.Height - 1; + } + else + { + result.Width = rect.Width; + result.Height = rect.Height; + } + + result.X = rect.X; + result.Y = rect.Y; + } + + return result; + } + + #endregion + + #region 字体 + + /// + /// 获取字体顶部空格 + /// + /// + public static int GetFontTopHiatus(Font font) + { + return Math.Max(1, font.Height * 2 / 10); + } + + /// + /// 获取字体真实高度 + /// + /// + public static int GetFontRealHeight(Font font) + { + return Math.Max(1, font.Height * 8 / 10); + } + + #endregion + + #region (Size、Point)角度 + + /// + /// 计算指定角度的坐标 + /// + /// 圆心坐标 + /// 圆半径 + /// 角度 + /// + public static PointF CalculatePointForAngle(PointF center, float radius, float angle) + { + if (radius == 0) + return center; + + float w = 0; + float h = 0; + if (angle <= 90) + { + w = radius * (float)Math.Cos(Math.PI / 180 * angle); + h = radius * (float)Math.Sin(Math.PI / 180 * angle); + } + else if (angle <= 180) + { + w = -radius * (float)Math.Sin(Math.PI / 180 * (angle - 90)); + h = radius * (float)Math.Cos(Math.PI / 180 * (angle - 90)); + + } + else if (angle <= 270) + { + w = -radius * (float)Math.Cos(Math.PI / 180 * (angle - 180)); + h = -radius * (float)Math.Sin(Math.PI / 180 * (angle - 180)); + } + else + { + w = radius * (float)Math.Sin(Math.PI / 180 * (angle - 270)); + h = -radius * (float)Math.Cos(Math.PI / 180 * (angle - 270)); + + } + return new PointF(center.X + w, center.Y + h); + } + + /// + /// 计算两个坐标的夹角 + /// + /// 坐标1 + /// 坐标2 + /// + public static double CalculateAngleForPoint(PointF point1, PointF point2) + { + double tmp = Math.Atan2((point2.Y - point1.Y), (point2.X - point1.X)) * 180 / Math.PI; + if (tmp < 0) + { + tmp = 180 + 180 - Math.Abs(tmp); + } + return tmp; + } + + /// + /// 获取Size旋转指定角度后新的Size + /// + /// 源Size + /// 指定角度 + /// 新的Size + public static SizeF ConvertToAngleSize(SizeF size, float angle) + { + PointF angle_point = ControlHelper.CalculatePointForAngle(new PointF(0, 0), size.Width / 2, (angle + 360) % 360); + PointF righttop_point = ControlHelper.CalculatePointForAngle(angle_point, size.Height / 2, (angle - 90 + 360) % 360); + PointF rightbottom_point = ControlHelper.CalculatePointForAngle(angle_point, size.Height / 2, (angle + 90 + 360) % 360); + + float w = Math.Max(Math.Abs(righttop_point.X), Math.Abs(rightbottom_point.X)) * 2; + float h = Math.Max(Math.Abs(righttop_point.Y), Math.Abs(rightbottom_point.Y)) * 2; + + return new SizeF(w, h); + } + + #endregion + + #region 画笔Rectangle转换 + + /// + /// 根据画笔大小转换rectf + /// + /// 要转换的rectf + /// 画笔大小大小 + /// + public static RectangleF TransformRectangleByPen(RectangleF rectf, float pen) + { + RectangleF result = new RectangleF(); + result.Width = rectf.Width - (pen < 1 ? 0 : pen); + result.Height = rectf.Height - (pen < 1 ? 0 : pen); + result.X = rectf.X + (float)(pen / 2); + result.Y = rectf.Y + (float)(pen / 2); + return result; + } + + #endregion + + #region 颜色 + + /// + /// 转换成灰色颜色值 + /// + /// 要转换的颜色 + /// + public static Color ConvertToDisableColor(Color color) + { + int tmp = (color.R + color.G + color.B) / 3; + return Color.FromArgb(color.A, tmp, tmp, tmp); + } + + /// + /// 根据控件Enabled状态转换成对应颜色值 + /// + /// 颜色所属的控件 + /// 要转换的颜色 + /// + public static Color ConvertToAutoColor(Control control, Color color) + { + if (control == null || control.Enabled) + { + return color; + } + return ConvertToDisableColor(color); + } + + /// + /// 根据状态转换成对应颜色值 + /// + /// 是否为禁用状态 + /// 要转换的颜色 + /// + public static Color ConvertToAutoColor(bool disable, Color color) + { + if (!disable) + { + return color; + } + return ConvertToDisableColor(color); + } + + /// + /// 转换成动画效果颜色值 + /// + /// 要转换的颜色 + /// + public static Color ConvertToAnimationColor(Color color) + { + if (color.GetBrightness() >= 0.5) + { + Color tmp = ControlPaint.Dark(color); + return Color.FromArgb(15, tmp.R, tmp.G, tmp.B); + } + else + { + Color tmp = ControlPaint.Light(color); + return Color.FromArgb(80, tmp.R, tmp.G, tmp.B); + } + } + + /// + /// 根据控件Enabled状态和背景色转换文本字体对应颜色值 + /// + /// 颜色所属的控件 + /// 背景色 + /// 前景色 + /// + public static Color ConvertToForeColorByBackColor(Control control, Color backColor, Color foreColor) + { + if (control == null || control.Enabled) + { + return foreColor; + } + + Color tmp = ConvertToAutoColor(control, backColor); + if (Math.Abs(tmp.GetBrightness() - foreColor.GetBrightness()) < 0.2) + { + return tmp.GetBrightness() >= 0.5 ? ControlPaint.Dark(backColor) : ControlPaint.Light(backColor); + } + else + { + return ConvertToDisableColor(foreColor); + } + + } + + /// + /// 根据状态和背景色转换文本字体对应颜色值 + /// + /// 是否为禁用状态 + /// 背景色 + /// 前景色 + /// + public static Color ConvertToForeColorByBackColor(bool disable, Color backColor, Color foreColor) + { + if (!disable) + { + return foreColor; + } + + Color tmp = ConvertToAutoColor(disable, backColor); + if (Math.Abs(tmp.GetBrightness() - foreColor.GetBrightness()) < 0.2) + { + return tmp.GetBrightness() >= 0.5 ? ControlPaint.Dark(backColor) : ControlPaint.Light(backColor); + } + else + { + return ConvertToDisableColor(foreColor); + } + + } + + /// + /// 根据指定颜色Brightness转换成有对比颜色 + /// + /// 指定颜色 + /// + public static Color ConvertToDarkOrLightColor(Color color) + { + return ((double)color.GetBrightness() >= 0.5) ? ControlPaint.Dark(color) : ControlPaint.Light(color); + } + + /// + /// 检查RGB值ed有效范围 + /// + /// + /// + public static int VerifyRGB(int rgb) + { + if (rgb < 0) + return 0; + if (rgb > 255) + return 255; + return rgb; + } + + #endregion + + #region 图片 + + private static ColorMatrix disabledImageColorMatrix; + /// + /// 用于创建禁用状态灰色图片(NET源码拷贝) + /// + private static ColorMatrix DisabledImageColorMatrix + { + get + { + if (disabledImageColorMatrix == null) + { + float[][] greyscale = new float[5][]; + greyscale[0] = new float[5] { 0.2125f, 0.2125f, 0.2125f, 0, 0 }; + greyscale[1] = new float[5] { 0.2577f, 0.2577f, 0.2577f, 0, 0 }; + greyscale[2] = new float[5] { 0.0361f, 0.0361f, 0.0361f, 0, 0 }; + greyscale[3] = new float[5] { 0, 0, 0, 1, 0 }; + greyscale[4] = new float[5] { 0.38f, 0.38f, 0.38f, 0, 1 }; + + float[][] transparency = new float[5][]; + transparency[0] = new float[5] { 1, 0, 0, 0, 0 }; + transparency[1] = new float[5] { 0, 1, 0, 0, 0 }; + transparency[2] = new float[5] { 0, 0, 1, 0, 0 }; + transparency[3] = new float[5] { 0, 0, 0, .7F, 0 }; + transparency[4] = new float[5] { 0, 0, 0, 0, 0 }; + + + int size = 5; + float[][] result = new float[size][]; + for (int row = 0; row < size; row++) + { + result[row] = new float[size]; + } + + float[] column = new float[size]; + for (int j = 0; j < size; j++) + { + for (int k = 0; k < size; k++) + { + column[k] = transparency[k][j]; + } + for (int i = 0; i < size; i++) + { + float[] row = greyscale[i]; + float s = 0; + for (int k = 0; k < size; k++) + { + s += row[k] * column[k]; + } + result[i][j] = s; + } + } + + disabledImageColorMatrix = new ColorMatrix(result); + + } + + return disabledImageColorMatrix; + } + } + + /// + /// 创建禁用状态灰色图片(NET源码拷贝) + /// + /// 要处理的图片 + /// + public static Image CreateDisabledImage(Image normalImage) + { + ImageAttributes imgAttrib = new ImageAttributes(); + imgAttrib.ClearColorKey(); + imgAttrib.SetColorMatrix(DisabledImageColorMatrix); + + Size size = normalImage.Size; + Bitmap disabledBitmap = new Bitmap(size.Width, size.Height); + Graphics graphics = Graphics.FromImage(disabledBitmap); + + graphics.DrawImage(normalImage, new Rectangle(0, 0, size.Width, size.Height), 0, 0, size.Width, size.Height, GraphicsUnit.Pixel, imgAttrib); + graphics.Dispose(); + + return disabledBitmap; + } + + /// + /// 缩放图片 + /// + /// 源图片 + /// 目标Size + /// + public static Image ScaleImage(Image sourceImage, Size targetSize) + { + if (sourceImage == null) + return null; + + Bitmap bmp = new Bitmap(targetSize.Width, targetSize.Height); + Graphics g = Graphics.FromImage(bmp); + g.DrawImage(sourceImage, new Rectangle(0, 0, targetSize.Width, targetSize.Height), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel); + + g.Dispose(); + + return bmp; + } + + #endregion + + #region 小数位数截取 + + /// + /// 保留指定位数小数 + /// + /// 要处理数 + /// 要保留小数位数 + public static float ReserveDecimals(float value, int places) + { + return (float)ReserveDecimals(value, places); + } + + /// + /// 保留指定位数小数 + /// + /// 要处理数 + /// 要保留小数位数 + public static double ReserveDecimals(double value, int places) + { + return (double)ReserveDecimals(value, places); + } + + /// + /// 保留指定位数小数 + /// + /// 要处理数 + /// 要保留小数位数 + public static string ReserveDecimals(string value, int places) + { + if (places < 0) + return value; + + value = value.Trim(); + int index = value.IndexOf('.'); + + if (places == 0 && index > -1) + { + return value.Substring(0, index); + } + + if (index > -1) + { + value = value.Substring(0, Math.Min(index + places + 1, value.Length)); + value = value.PadRight(value.IndexOf('.') + places + 1, '0'); + } + else if (places > 0) + { + value = (value + ".").PadRight(value.Length + 1 + places, '0'); + } + + return value; + } + + #endregion + + + /// + /// 设置GDI高质量模式抗锯齿 + /// + /// + public static void SetGDIHigh(this Graphics g) + { + //消除锯齿 + g.SmoothingMode = SmoothingMode.AntiAlias; + //文字显示效果 + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + //插补模式 + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + //图片呈现质量 + g.CompositingQuality = CompositingQuality.HighQuality; + + + + } + + + + #region 设置控件Enabled,切不改变控件颜色 + /// + /// 功能描述:设置控件Enabled,切不改变控件颜色 + /// 作  者:HZH + /// 创建日期:2019-03-04 13:43:32 + /// 任务编号:POS + /// + /// c + /// enabled + public static void SetControlEnabled(this Control c, bool enabled) + { + if (!c.IsDisposed) + { + if (enabled) + { + ControlHelper.SetWindowLong(c.Handle, -16, -134217729 & ControlHelper.GetWindowLong(c.Handle, -16)); + } + else + { + ControlHelper.SetWindowLong(c.Handle, -16, 134217728 + ControlHelper.GetWindowLong(c.Handle, -16)); + } + } + } + + /// + /// 功能描述:设置控件Enabled,切不改变控件颜色 + /// 作  者:HZH + /// 创建日期:2019-03-04 13:43:32 + /// 任务编号:POS + /// + /// cs + /// enabled + public static void SetControlEnableds(Control[] cs, bool enabled) + { + for (int i = 0; i < cs.Length; i++) + { + Control c = cs[i]; + SetControlEnabled(c, enabled); + } + } + #endregion + /// + /// Sets the window long. + /// + /// The h WND. + /// Index of the n. + /// The wndproc. + /// System.Int32. + [DllImport("user32.dll ")] + public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int wndproc); + + /// + /// Gets the window long. + /// + /// The h WND. + /// Index of the n. + /// System.Int32. + [DllImport("user32.dll ")] + public static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + /// + /// Gets the foreground window. + /// + /// IntPtr. + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern IntPtr GetForegroundWindow(); + + /// + /// Threads the base call back. + /// + /// The parent. + /// The object. + private static void ThreadBaseCallBack(Control parent, object obj) + { + if (obj is Exception) + { + if (parent != null) + { + ThreadInvokerControl(parent, delegate + { + Exception ex = obj as Exception; + }); + } + } + } + /// + /// 委托调用主线程控件 + /// + /// 主线程控件 + /// 修改控件方法 + public static void ThreadInvokerControl(Control parent, Action action) + { + if (parent != null) + { + if (parent.InvokeRequired) + { + parent.BeginInvoke(action); + } + else + { + action(); + SetForegroundWindow(parent.Handle); + } + } + } + /// + /// 使用一个线程执行一个操作 + /// + /// 父控件 + /// 执行内容 + /// 执行后回调 + /// 执行期间禁用控件列表 + /// 执行期间是否显示等待提示 + /// 执行期间等待提示内容,默认为“正在处理,请稍候...” + /// 延迟显示等待提示时间 + public static void ThreadRunExt( + Control parent, + Action func, + Action callback, + Control enableControl = null, + bool blnShowSplashScreen = true, + string strMsg = null, + int intSplashScreenDelayTime = 200) + { + ThreadRunExt(parent, func, callback, new Control[] { enableControl }, blnShowSplashScreen, strMsg, intSplashScreenDelayTime); + } + /// + /// 使用一个线程执行一个操作 + /// + /// 父控件 + /// 执行内容 + /// 执行后回调 + /// 执行期间禁用控件列表 + /// 执行期间是否显示等待提示 + /// 执行期间等待提示内容,默认为“正在处理,请稍候...” + /// 延迟显示等待提示时间 + public static void ThreadRunExt( + Control parent, + Action func, + Action callback, + Control[] enableControl = null, + bool blnShowSplashScreen = true, + string strMsg = null, + int intSplashScreenDelayTime = 200) + { + if (blnShowSplashScreen) + { + if (string.IsNullOrEmpty(strMsg)) + { + strMsg = "正在处理,请稍候..."; + } + if (parent != null) + { + ShowProcessPanel(parent, strMsg, intSplashScreenDelayTime); + } + } + if (enableControl != null) + { + List lstCs = new List(); + foreach (var c in enableControl) + { + if (c == null) + continue; + if (c is Form) + { + lstCs.AddRange(c.Controls.ToArray()); + } + else + { + lstCs.Add(c); + } + } + SetControlEnableds(lstCs.ToArray(), false); + } + ThreadPool.QueueUserWorkItem(delegate (object a) + { + try + { + func(); + if (callback != null) + { + callback(null); + } + } + catch (Exception obj) + { + if (callback != null) + { + callback(obj); + } + else + { + ThreadBaseCallBack(parent, obj); + } + } + finally + { + if (parent != null) + { + ThreadInvokerControl(parent, delegate + { + CloseProcessPanel(parent); + SetForegroundWindow(parent.Handle); + }); + } + if (enableControl != null) + { + if (parent != null) + { + ThreadInvokerControl(parent, delegate + { + List lstCs = new List(); + foreach (var c in enableControl) + { + if (c == null) + continue; + if (c is Form) + { + lstCs.AddRange(c.Controls.ToArray()); + } + else + { + lstCs.Add(c); + } + } + SetControlEnableds(lstCs.ToArray(), true); + }); + } + } + } + }); + } + + /// + /// Sets the foreground window. + /// + /// The h WND. + /// true if XXXX, false otherwise. + [DllImport("user32.dll")] + public static extern bool SetForegroundWindow(IntPtr hWnd); + /// + /// Shows the process panel. + /// + /// The parent. + /// The string message. + /// The int splash screen delay time. + public static void ShowProcessPanel(Control parent, string strMessage, int intSplashScreenDelayTime = 0) + { + if (parent.InvokeRequired) + { + parent.BeginInvoke(new MethodInvoker(delegate + { + ShowProcessPanel(parent, strMessage, intSplashScreenDelayTime); + })); + } + else + { + parent.VisibleChanged -= new EventHandler(parent_VisibleChanged); + parent.VisibleChanged += new EventHandler(parent_VisibleChanged); + parent.FindForm().FormClosing -= ControlHelper_FormClosing; + parent.FindForm().FormClosing += ControlHelper_FormClosing; + Control control = null; + lock (parent) + { + control = HaveProcessPanelControl(parent); + if (control == null) + { + control = CreateProgressPanel(); + parent.Controls.Add(control); + } + } + Forms.FrmWaiting frmWaitingEx = control.Tag as Forms.FrmWaiting; + frmWaitingEx.Msg = strMessage; + frmWaitingEx.ShowForm(intSplashScreenDelayTime); + } + } + + /// + /// Handles the FormClosing event of the ControlHelper control. + /// + /// The source of the event. + /// The instance containing the event data. + static void ControlHelper_FormClosing(object sender, FormClosingEventArgs e) + { + Control control = sender as Control; + control.FindForm().FormClosing -= ControlHelper_FormClosing; + CloseWaiting(control); + } + + /// + /// Handles the VisibleChanged event of the parent control. + /// + /// The source of the event. + /// The instance containing the event data. + private static void parent_VisibleChanged(object sender, EventArgs e) + { + Control control = sender as Control; + control.VisibleChanged -= new EventHandler(parent_VisibleChanged); + if (!control.Visible) + { + CloseWaiting(control); + } + } + + /// + /// Closes the waiting. + /// + /// The control. + private static void CloseWaiting(Control control) + { + Control[] array = control.Controls.Find("myprogressPanelext", false); + if (array.Length > 0) + { + Control control2 = array[0]; + if (control2.Tag != null && control2.Tag is Forms.FrmWaiting) + { + Forms.FrmWaiting frmWaitingEx = control2.Tag as Forms.FrmWaiting; + if (frmWaitingEx != null && !frmWaitingEx.IsDisposed && frmWaitingEx.Visible) + { + frmWaitingEx.Hide(); + } + } + } + } + + /// + /// Closes the process panel. + /// + /// The parent. + public static void CloseProcessPanel(Control parent) + { + if (parent.InvokeRequired) + { + parent.BeginInvoke(new MethodInvoker(delegate + { + CloseProcessPanel(parent); + })); + } + else if (parent != null) + { + Control control = HaveProcessPanelControl(parent); + if (control != null) + { + Form frm = control.Tag as Form; + if (frm != null && !frm.IsDisposed && frm.Visible) + { + if (frm.InvokeRequired) + { + frm.BeginInvoke(new MethodInvoker(delegate + { + frm.Hide(); + })); + } + else + { + frm.Hide(); + } + } + } + } + } + + /// + /// Haves the process panel control. + /// + /// The parent. + /// Control. + public static Control HaveProcessPanelControl(Control parent) + { + Control[] array = parent.Controls.Find("myprogressPanelext", false); + Control result; + if (array.Length > 0) + { + result = array[0]; + } + else + { + result = null; + } + return result; + } + + /// + /// Creates the progress panel. + /// + /// Control. + public static Control CreateProgressPanel() + { + return new Label + { + Name = "myprogressPanelext", + Visible = false, + Tag = new Forms.FrmWaiting + { + TopMost = true, + Opacity = 0.0 + } + }; + } + + /// + /// Converts to array. + /// + /// The controls. + /// Control[]. + public static Control[] ToArray(this System.Windows.Forms.Control.ControlCollection controls) + { + if (controls == null || controls.Count <= 0) + return new Control[0]; + List lst = new List(); + foreach (Control item in controls) + { + lst.Add(item); + } + return lst.ToArray(); + } + + + #region 根据控件宽度截取字符串 + /// + /// 功能描述:根据控件宽度截取字符串 + /// 作  者:HZH + /// 创建日期:2019-06-27 10:49:10 + /// 任务编号:POS + /// + /// 字符串 + /// 控件宽度 + /// Graphics + /// 字体 + /// 截取后的字符串 + public static string GetSubString( + string strSource, + float fltControlWidth, + System.Drawing.Graphics g, + System.Drawing.Font font) + { + try + { + fltControlWidth = fltControlWidth - 20; + strSource = strSource.Trim(); + while (true) + { + + System.Drawing.SizeF sizeF = g.MeasureString(strSource.Replace(" ", "A"), font); + if (sizeF.Width > fltControlWidth) + { + strSource = strSource.TrimEnd('…'); + if (strSource.Length <= 1) + return ""; + strSource = strSource.Substring(0, strSource.Length - 1).Trim() + "…"; + } + else + { + return strSource; + } + } + } + finally + { + g.Dispose(); + } + } + #endregion + + #region 获取字符串宽度 + /// + /// 功能描述:获取字符串宽度 + /// 作  者:HZH + /// 创建日期:2019-06-27 11:54:50 + /// 任务编号:POS + /// + /// strSource + /// g + /// font + /// 返回值 + public static int GetStringWidth( + string strSource, + System.Drawing.Graphics g, + System.Drawing.Font font) + { + string[] strs = strSource.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + float fltWidth = 0; + foreach (var item in strs) + { + System.Drawing.SizeF sizeF = g.MeasureString(strSource.Replace(" ", "A"), font); + if (sizeF.Width > fltWidth) + fltWidth = sizeF.Width; + } + + return (int)fltWidth; + } + #endregion + + #region 动画特效 + /// + /// Animates the window. + /// + /// The WHND. + /// The dwtime. + /// The dwflag. + /// true if XXXX, false otherwise. + [DllImport("user32.dll")] + public static extern bool AnimateWindow(IntPtr whnd, int dwtime, int dwflag); + //dwflag的取值如下 + /// + /// The aw hor positive + /// + public const Int32 AW_HOR_POSITIVE = 0x00000001; + //从左到右显示 + /// + /// The aw hor negative + /// + public const Int32 AW_HOR_NEGATIVE = 0x00000002; + //从右到左显示 + /// + /// The aw ver positive + /// + public const Int32 AW_VER_POSITIVE = 0x00000004; + //从上到下显示 + /// + /// The aw ver negative + /// + public const Int32 AW_VER_NEGATIVE = 0x00000008; + //从下到上显示 + /// + /// The aw center + /// + public const Int32 AW_CENTER = 0x00000010; + //若使用了AW_HIDE标志,则使窗口向内重叠,即收缩窗口;否则使窗口向外扩展,即展开窗口 + /// + /// The aw hide + /// + public const Int32 AW_HIDE = 0x00010000; + //隐藏窗口,缺省则显示窗口 + /// + /// The aw activate + /// + public const Int32 AW_ACTIVATE = 0x00020000; + //激活窗口。在使用了AW_HIDE标志后不能使用这个标志 + /// + /// The aw slide + /// + public const Int32 AW_SLIDE = 0x00040000; + //使用滑动类型。缺省则为滚动动画类型。当使用AW_CENTER标志时,这个标志就被忽略 + /// + /// The aw blend + /// + public const Int32 AW_BLEND = 0x00080000; + //透明度从高到低 + #endregion + + #region 检查文本控件输入类型是否有效 + /// + /// 功能描述:检查文本控件输入类型是否有效 + /// 作  者:HZH + /// 创建日期:2019-02-28 10:23:34 + /// 任务编号:POS + /// + /// 值 + /// 控制类型 + /// 最大值 + /// 最小值 + /// 小数位长度 + /// 正则 + /// 返回值 + public static bool CheckInputType( + string strValue, + TextInputType inputType, + decimal decMaxValue = default(decimal), + decimal decMinValue = default(decimal), + int intLength = 2, + string strRegexPattern = null) + { + bool result; + switch (inputType) + { + case TextInputType.NotControl: + result = true; + return result; + case TextInputType.UnsignNumber: + if (string.IsNullOrEmpty(strValue)) + { + result = true; + return result; + } + else + { + if (strValue.IndexOf("-") >= 0) + { + result = false; + return result; + } + } + break; + case TextInputType.Number: + if (string.IsNullOrEmpty(strValue)) + { + result = true; + return result; + } + else + { + if (!Regex.IsMatch(strValue, "^-?\\d*(\\.?\\d*)?$")) + { + result = false; + return result; + } + } + break; + case TextInputType.Integer: + if (string.IsNullOrEmpty(strValue)) + { + result = true; + return result; + } + else + { + if (!Regex.IsMatch(strValue, "^-?\\d*$")) + { + result = false; + return result; + } + } + break; + case TextInputType.PositiveInteger: + if (string.IsNullOrEmpty(strValue)) + { + result = true; + return result; + } + else + { + if (!Regex.IsMatch(strValue, "^\\d+$")) + { + result = false; + return result; + } + } + break; + case TextInputType.Regex: + result = (string.IsNullOrEmpty(strRegexPattern) || Regex.IsMatch(strValue, strRegexPattern)); + return result; + } + if (strValue == "-") + { + return true; + } + decimal d; + if (!decimal.TryParse(strValue, out d)) + { + result = false; + } + else if (d < decMinValue || d > decMaxValue) + { + result = false; + } + else + { + if (inputType == TextInputType.Number || inputType == TextInputType.UnsignNumber || inputType == TextInputType.PositiveNumber) + { + if (strValue.IndexOf(".") >= 0) + { + string text = strValue.Substring(strValue.IndexOf(".")); + if (text.Length > intLength + 1) + { + result = false; + return result; + } + } + } + result = true; + } + return result; + } + #endregion + + #region 冻结控件 + /// + /// The m LST freeze control + /// + static Dictionary m_lstFreezeControl = new Dictionary(); + /// + /// 功能描述:停止更新控件 + /// 作  者:HZH + /// 创建日期:2019-07-13 11:11:32 + /// 任务编号:POS + /// + /// control + /// 是否停止更新 + public static void FreezeControl(Control control, bool blnToFreeze) + { + if (blnToFreeze && control.IsHandleCreated && control.Visible && !control.IsDisposed && (!m_lstFreezeControl.ContainsKey(control) || (m_lstFreezeControl.ContainsKey(control) && m_lstFreezeControl[control] == false))) + { + m_lstFreezeControl[control] = true; + control.Disposed += control_Disposed; + NativeMethods.SendMessage(control.Handle, 11, 0, 0); + } + else if (!blnToFreeze && !control.IsDisposed && m_lstFreezeControl.ContainsKey(control) && m_lstFreezeControl[control] == true) + { + m_lstFreezeControl.Remove(control); + NativeMethods.SendMessage(control.Handle, 11, 1, 0); + control.Invalidate(true); + } + } + + /// + /// Handles the Disposed event of the control control. + /// + /// The source of the event. + /// The instance containing the event data. + static void control_Disposed(object sender, EventArgs e) + { + try + { + if (m_lstFreezeControl.ContainsKey((Control)sender)) + m_lstFreezeControl.Remove((Control)sender); + } + catch { } + } + #endregion + + + /// + /// 根据矩形和圆得到一个圆角矩形Path + /// + /// The rect. + /// The corner radius. + /// GraphicsPath. + public static GraphicsPath CreateRoundedRectanglePath(this Rectangle rect, int cornerRadius) + { + GraphicsPath roundedRect = new GraphicsPath(); + roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90); + roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y); + roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90); + roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2); + roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90); + roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom); + roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90); + roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2); + roundedRect.CloseFigure(); + return roundedRect; + } + + /// + /// Creates the rounded rectangle path. + /// + /// The rect. + /// The corner radius. + /// GraphicsPath. + public static GraphicsPath CreateRoundedRectanglePath(this RectangleF rect, int cornerRadius) + { + GraphicsPath roundedRect = new GraphicsPath(); + roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90); + roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y); + roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90); + roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2); + roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90); + roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom); + roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90); + roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2); + roundedRect.CloseFigure(); + return roundedRect; + } + /// + /// Gets the colors. + /// + /// The colors. + public static Color[] Colors { get; private set; } + + static ControlHelper() + { + List list = new List(); + list.Add(Color.FromArgb(55, 162, 218)); + list.Add(Color.FromArgb(50, 197, 233)); + list.Add(Color.FromArgb(103, 224, 227)); + list.Add(Color.FromArgb(159, 230, 184)); + list.Add(Color.FromArgb(255, 219, 92)); + list.Add(Color.FromArgb(255, 159, 127)); + list.Add(Color.FromArgb(251, 114, 147)); + list.Add(Color.FromArgb(224, 98, 174)); + list.Add(Color.FromArgb(230, 144, 209)); + list.Add(Color.FromArgb(231, 188, 243)); + list.Add(Color.FromArgb(157, 150, 245)); + list.Add(Color.FromArgb(131, 120, 234)); + list.Add(Color.FromArgb(150, 191, 255)); + + list.Add(Color.FromArgb(243, 67, 54)); + list.Add(Color.FromArgb(156, 39, 176)); + list.Add(Color.FromArgb(103, 58, 183)); + list.Add(Color.FromArgb(63, 81, 181)); + list.Add(Color.FromArgb(33, 150, 243)); + list.Add(Color.FromArgb(0, 188, 211)); + list.Add(Color.FromArgb(3, 169, 244)); + list.Add(Color.FromArgb(0, 150, 136)); + list.Add(Color.FromArgb(139, 195, 74)); + list.Add(Color.FromArgb(76, 175, 80)); + list.Add(Color.FromArgb(204, 219, 57)); + list.Add(Color.FromArgb(233, 30, 99)); + list.Add(Color.FromArgb(254, 234, 59)); + list.Add(Color.FromArgb(254, 192, 7)); + list.Add(Color.FromArgb(254, 152, 0)); + list.Add(Color.FromArgb(255, 87, 34)); + list.Add(Color.FromArgb(121, 85, 72)); + list.Add(Color.FromArgb(158, 158, 158)); + list.Add(Color.FromArgb(96, 125, 139)); + list.Add(Color.FromArgb(252, 117, 85)); + list.Add(Color.FromArgb(172, 113, 191)); + list.Add(Color.FromArgb(115, 131, 253)); + list.Add(Color.FromArgb(78, 206, 255)); + list.Add(Color.FromArgb(121, 195, 82)); + list.Add(Color.FromArgb(255, 163, 28)); + list.Add(Color.FromArgb(255, 185, 15)); + list.Add(Color.FromArgb(255, 181, 197)); + list.Add(Color.FromArgb(255, 110, 180)); + list.Add(Color.FromArgb(255, 69, 0)); + list.Add(Color.FromArgb(255, 48, 48)); + list.Add(Color.FromArgb(154, 205, 50)); + list.Add(Color.FromArgb(155, 205, 155)); + list.Add(Color.FromArgb(154, 50, 205)); + list.Add(Color.FromArgb(131, 111, 255)); + list.Add(Color.FromArgb(124, 205, 124)); + list.Add(Color.FromArgb(0, 206, 209)); + list.Add(Color.FromArgb(0, 178, 238)); + list.Add(Color.FromArgb(56, 142, 142)); + + Type typeFromHandle = typeof(Color); + PropertyInfo[] properties = typeFromHandle.GetProperties(); + PropertyInfo[] array = properties; + for (int i = 0; i < array.Length; i++) + { + PropertyInfo propertyInfo = array[i]; + if (propertyInfo.PropertyType == typeof(Color) && (propertyInfo.Name.StartsWith("Dark") || propertyInfo.Name.StartsWith("Medium"))) + { + object value = propertyInfo.GetValue(null, null); + list.Add((Color)value); + } + } + Colors = list.ToArray(); + } + /// + /// Draws the string. + /// + /// The g. + /// The s. + /// The font. + /// The brush. + /// The point. + /// The format. + /// The angle. + public static void DrawString(Graphics g, string s, Font font, Brush brush, PointF point, StringFormat format, float angle) + { + Matrix transform = g.Transform; + Matrix transform2 = g.Transform; + transform2.RotateAt(angle, point); + g.Transform = transform2; + g.DrawString(s, font, brush, point, format); + g.Transform = transform; + } + + /// + /// Gets the rhombus from rectangle. + /// + /// The rect. + /// Point[]. + public static Point[] GetRhombusFromRectangle(Rectangle rect) + { + return new Point[5] + { + new Point(rect.X, rect.Y + rect.Height / 2), + new Point(rect.X + rect.Width / 2, rect.Y + rect.Height - 1), + new Point(rect.X + rect.Width - 1, rect.Y + rect.Height / 2), + new Point(rect.X + rect.Width / 2, rect.Y), + new Point(rect.X, rect.Y + rect.Height / 2) + }; + } + + /// + /// Computes the paint location y. + /// + /// The maximum. + /// The minimum. + /// The height. + /// The value. + /// System.Single. + public static float ComputePaintLocationY(int max, int min, int height, int value) + { + if ((float)(max - min) == 0f) + { + return height; + } + return (float)height - (float)(value - min) * 1f / (float)(max - min) * (float)height; + } + + /// + /// Computes the paint location y. + /// + /// The maximum. + /// The minimum. + /// The height. + /// The value. + /// System.Single. + public static float ComputePaintLocationY(float max, float min, float height, float value) + { + if (max - min == 0f) + { + return height; + } + return height - (value - min) / (max - min) * height; + } + + + /// + /// Paints the coordinate divide. + /// + /// The g. + /// The pen line. + /// The pen dash. + /// The font. + /// The brush. + /// The sf. + /// The degree. + /// The maximum. + /// The minimum. + /// The width. + /// The height. + /// The left. + /// The right. + /// Up. + /// Down. + public static void PaintCoordinateDivide(Graphics g, System.Drawing.Pen penLine, System.Drawing.Pen penDash, Font font, System.Drawing.Brush brush, StringFormat sf, int degree, int max, int min, int width, int height, int left = 60, int right = 8, int up = 8, int down = 8) + { + for (int i = 0; i <= degree; i++) + { + int value = (max - min) * i / degree + min; + int num = (int)ComputePaintLocationY(max, min, height - up - down, value) + up + 1; + g.DrawLine(penLine, left - 1, num, left - 4, num); + if (i != 0) + { + g.DrawLine(penDash, left, num, width - right, num); + } + g.DrawString(value.ToString(), font, brush, new Rectangle(-5, num - font.Height / 2, left, font.Height), sf); + } + } + + /// + /// Paints the triangle. + /// + /// The g. + /// The brush. + /// The point. + /// The size. + /// The direction. + public static void PaintTriangle(Graphics g, System.Drawing.Brush brush, Point point, int size, GraphDirection direction) + { + Point[] array = new Point[4]; + switch (direction) + { + case GraphDirection.Leftward: + array[0] = new Point(point.X, point.Y - size); + array[1] = new Point(point.X, point.Y + size); + array[2] = new Point(point.X - 2 * size, point.Y); + break; + case GraphDirection.Rightward: + array[0] = new Point(point.X, point.Y - size); + array[1] = new Point(point.X, point.Y + size); + array[2] = new Point(point.X + 2 * size, point.Y); + break; + case GraphDirection.Upward: + array[0] = new Point(point.X - size, point.Y); + array[1] = new Point(point.X + size, point.Y); + array[2] = new Point(point.X, point.Y - 2 * size); + break; + default: + array[0] = new Point(point.X - size, point.Y); + array[1] = new Point(point.X + size, point.Y); + array[2] = new Point(point.X, point.Y + 2 * size); + break; + } + array[3] = array[0]; + g.FillPolygon(brush, array); + } + + /// + /// Paints the triangle. + /// + /// The g. + /// The brush. + /// The point. + /// The size. + /// The direction. + public static void PaintTriangle(Graphics g, System.Drawing.Brush brush, PointF point, int size, GraphDirection direction) + { + PointF[] array = new PointF[4]; + switch (direction) + { + case GraphDirection.Leftward: + array[0] = new PointF(point.X, point.Y - (float)size); + array[1] = new PointF(point.X, point.Y + (float)size); + array[2] = new PointF(point.X - (float)(2 * size), point.Y); + break; + case GraphDirection.Rightward: + array[0] = new PointF(point.X, point.Y - (float)size); + array[1] = new PointF(point.X, point.Y + (float)size); + array[2] = new PointF(point.X + (float)(2 * size), point.Y); + break; + case GraphDirection.Upward: + array[0] = new PointF(point.X - (float)size, point.Y); + array[1] = new PointF(point.X + (float)size, point.Y); + array[2] = new PointF(point.X, point.Y - (float)(2 * size)); + break; + default: + array[0] = new PointF(point.X - (float)size, point.Y); + array[1] = new PointF(point.X + (float)size, point.Y); + array[2] = new PointF(point.X, point.Y + (float)(2 * size)); + break; + } + array[3] = array[0]; + g.FillPolygon(brush, array); + } + + /// + /// Adds the array data. + /// + /// + /// The array. + /// The data. + /// The maximum. + public static void AddArrayData(ref T[] array, T[] data, int max) + { + if (data == null || data.Length == 0) + { + return; + } + if (array.Length == max) + { + Array.Copy(array, data.Length, array, 0, array.Length - data.Length); + Array.Copy(data, 0, array, array.Length - data.Length, data.Length); + } + else if (array.Length + data.Length > max) + { + T[] array2 = new T[max]; + for (int i = 0; i < max - data.Length; i++) + { + array2[i] = array[i + (array.Length - max + data.Length)]; + } + for (int j = 0; j < data.Length; j++) + { + array2[array2.Length - data.Length + j] = data[j]; + } + array = array2; + } + else + { + T[] array3 = new T[array.Length + data.Length]; + for (int k = 0; k < array.Length; k++) + { + array3[k] = array[k]; + } + for (int l = 0; l < data.Length; l++) + { + array3[array3.Length - data.Length + l] = data[l]; + } + array = array3; + } + } + + /// + /// Converts the size. + /// + /// The size. + /// The angle. + /// SizeF. + public static SizeF ConvertSize(SizeF size, float angle) + { + System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix(); + matrix.Rotate(angle); + PointF[] array = new PointF[4]; + array[0].X = (0f - size.Width) / 2f; + array[0].Y = (0f - size.Height) / 2f; + array[1].X = (0f - size.Width) / 2f; + array[1].Y = size.Height / 2f; + array[2].X = size.Width / 2f; + array[2].Y = size.Height / 2f; + array[3].X = size.Width / 2f; + array[3].Y = (0f - size.Height) / 2f; + matrix.TransformPoints(array); + float num = float.MaxValue; + float num2 = float.MinValue; + float num3 = float.MaxValue; + float num4 = float.MinValue; + PointF[] array2 = array; + for (int i = 0; i < array2.Length; i++) + { + PointF pointF = array2[i]; + if (pointF.X < num) + { + num = pointF.X; + } + if (pointF.X > num2) + { + num2 = pointF.X; + } + if (pointF.Y < num3) + { + num3 = pointF.Y; + } + if (pointF.Y > num4) + { + num4 = pointF.Y; + } + } + return new SizeF(num2 - num, num4 - num3); + } + + + + /// + /// Gets the pow. + /// + /// The digit. + /// System.Int32. + private static int GetPow(int digit) + { + int num = 1; + for (int i = 0; i < digit; i++) + { + num *= 10; + } + return num; + } + + /// + /// Calculates the maximum section from. + /// + /// The values. + /// System.Int32. + public static double CalculateMaxSectionFrom(double[] values) + { + double num = values.Max(); + return CalculateMaxSection(num); + } + + public static double CalculateMaxSectionFrom(double[][] values) + { + double num = values.Max(p => p.Max()); + return CalculateMaxSection(num); + } + + private static double CalculateMaxSection(double num) + { + if (num <= 5) + { + return 5; + } + if (num <= 10) + { + return 10; + } + int digit = num.ToString().Length - 2; + int num2 = int.Parse(num.ToString().Substring(0, 2)); + if (num2 < 12) + { + return 12 * GetPow(digit); + } + if (num2 < 14) + { + return 14 * GetPow(digit); + } + if (num2 < 16) + { + return 16 * GetPow(digit); + } + if (num2 < 18) + { + return 18 * GetPow(digit); + } + if (num2 < 20) + { + return 20 * GetPow(digit); + } + if (num2 < 22) + { + return 22 * GetPow(digit); + } + if (num2 < 24) + { + return 24 * GetPow(digit); + } + if (num2 < 26) + { + return 26 * GetPow(digit); + } + if (num2 < 28) + { + return 28 * GetPow(digit); + } + if (num2 < 30) + { + return 30 * GetPow(digit); + } + if (num2 < 40) + { + return 40 * GetPow(digit); + } + if (num2 < 50) + { + return 50 * GetPow(digit); + } + if (num2 < 60) + { + return 60 * GetPow(digit); + } + if (num2 < 80) + { + return 80 * GetPow(digit); + } + return 100 * GetPow(digit); + } + + /// + /// Gets the color light. + /// + /// The color. + /// System.Drawing.Color. + public static System.Drawing.Color GetColorLight(System.Drawing.Color color) + { + return System.Drawing.Color.FromArgb(color.R + (255 - color.R) * 40 / 100, color.G + (255 - color.G) * 40 / 100, color.B + (255 - color.B) * 40 / 100); + } + + /// + /// Gets the color light five. + /// + /// The color. + /// System.Drawing.Color. + public static System.Drawing.Color GetColorLightFive(System.Drawing.Color color) + { + return System.Drawing.Color.FromArgb(color.R + (255 - color.R) * 50 / 100, color.G + (255 - color.G) * 50 / 100, color.B + (255 - color.B) * 50 / 100); + } + + /// + /// Gets the points from. + /// + /// The points. + /// Width of the soure. + /// Height of the source. + /// The width. + /// The height. + /// The dx. + /// The dy. + /// PointF[]. + public static PointF[] GetPointsFrom(string points, float soureWidth, float sourceHeight, float width, float height, float dx = 0f, float dy = 0f) + { + string[] array = points.Split(new char[1] + { + ' ' + }, StringSplitOptions.RemoveEmptyEntries); + PointF[] array2 = new PointF[array.Length]; + for (int i = 0; i < array.Length; i++) + { + int num = array[i].IndexOf(','); + float num2 = Convert.ToSingle(array[i].Substring(0, num)); + float num3 = Convert.ToSingle(array[i].Substring(num + 1)); + array2[i] = new PointF(width * (num2 + dx) / soureWidth, height * (num3 + dy) / sourceHeight); + } + return array2; + } + + public static bool IsDesignMode() + { + bool returnFlag = false; + + if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) + { + returnFlag = true; + } + else if (Process.GetCurrentProcess().ProcessName == "devenv") + { + returnFlag = true; + } + + return returnFlag; + } + + #region 滚动条 English:scroll bar + static uint SB_HORZ = 0x0; + static uint SB_VERT = 0x1; + static uint SB_CTL = 0x2; + static uint SB_BOTH = 0x3; + [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetScrollInfo")] + private static extern int GetScrollInfo(IntPtr hWnd, uint fnBar, ref SCROLLINFO psbi); + [DllImport("user32.dll")]//[return: MarshalAs(UnmanagedType.Bool)] + private static extern int SetScrollInfo(IntPtr handle, uint fnBar, ref SCROLLINFO si, bool fRedraw); + + [DllImport("user32.dll", EntryPoint = "PostMessage")] + private static extern bool PostMessage(IntPtr handle, int msg, uint wParam, uint lParam); + [DllImport("User32.dll", EntryPoint = "SendMessage")] + private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); + /// + /// ShowScrollBar + /// + /// hWnd + /// 0:horizontal,1:vertical,3:both + /// bShow + /// + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow); + /// + ///获取水平滚动条信息 + /// + /// The h WND. + /// Scrollbarinfo. + public static SCROLLINFO GetHScrollBarInfo(IntPtr hWnd) + { + SCROLLINFO info = new SCROLLINFO(); + info.cbSize = (int)Marshal.SizeOf(info); + info.fMask = (int)ScrollInfoMask.SIF_DISABLENOSCROLL | (int)ScrollInfoMask.SIF_ALL; + int intRef = GetScrollInfo(hWnd, SB_HORZ, ref info); + return info; + } + /// + /// 获取垂直滚动条信息 + /// + /// The h WND. + /// Scrollbarinfo. + public static SCROLLINFO GetVScrollBarInfo(IntPtr hWnd) + { + SCROLLINFO info = new SCROLLINFO(); + info.cbSize = (int)Marshal.SizeOf(info); + info.fMask = (int)ScrollInfoMask.SIF_DISABLENOSCROLL | (int)ScrollInfoMask.SIF_ALL; + int intRef = GetScrollInfo(hWnd, SB_VERT, ref info); + return info; + } + public struct SCROLLINFO + { + public int cbSize; + public int fMask; + public int nMin; + public int nMax; + public int nPage; + public int nPos; + public int nTrackPos; + public int ScrollMax { get { return nMax + 1 - nPage; } } + } + public enum ScrollInfoMask : uint + { + SIF_RANGE = 0x1, + SIF_PAGE = 0x2, + SIF_POS = 0x4, + SIF_DISABLENOSCROLL = 0x8, + SIF_TRACKPOS = 0x10, + SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS), + SB_THUMBTRACK = 5, + WM_HSCROLL = 0x0114, + WM_VSCROLL = 0x0115, + SB_LINEUP = 0, + SB_LINEDOWN = 1, + SB_LINELEFT = 0, + SB_LINERIGHT = 1, + } + + public static void SetVScrollValue(IntPtr handle, int value) + { + var info = GetVScrollBarInfo(handle); + info.nPos = value; + SetScrollInfo(handle, SB_VERT, ref info, true); + PostMessage(handle, (int)ScrollInfoMask.WM_VSCROLL, MakeLong((short)ScrollInfoMask.SB_THUMBTRACK, highPart: (short)info.nPos), 0); + } + public static void SetHScrollValue(IntPtr handle, int value) + { + var info = GetHScrollBarInfo(handle); + info.nPos = value; + SetScrollInfo(handle, SB_HORZ, ref info, true); + PostMessage(handle, (int)ScrollInfoMask.WM_HSCROLL, MakeLong((short)ScrollInfoMask.SB_THUMBTRACK, highPart: (short)info.nPos), 0); + } + private static uint MakeLong(short lowPart, short highPart) + { + return (ushort)lowPart | (uint)(highPart << 16); + } + /// + /// 控件向上滚动一个单位 + /// + /// 控件句柄 + public static void ScrollUp(IntPtr handle) + { + SendMessage(handle, (int)ScrollInfoMask.WM_VSCROLL, (int)ScrollInfoMask.SB_LINEUP, 0); + } + + /// + /// 控件向下滚动一个单位 + /// + /// 控件句柄 + public static void ScrollDown(IntPtr handle) + { + SendMessage(handle, (int)ScrollInfoMask.WM_VSCROLL, (int)ScrollInfoMask.SB_LINEDOWN, 0); + } + /// + /// 控件向左滚动一个单位 + /// + /// 控件句柄 + public static void ScrollLeft(IntPtr handle) + { + SendMessage(handle, (int)ScrollInfoMask.WM_HSCROLL, (int)ScrollInfoMask.SB_LINELEFT, 0); + } + + /// + /// 控件向右滚动一个单位 + /// + /// 控件句柄 + public static void ScrollRight(IntPtr handle) + { + SendMessage(handle, (int)ScrollInfoMask.WM_VSCROLL, (int)ScrollInfoMask.SB_LINERIGHT, 0); + } + #endregion + + + /// + /// 返回指定图片中的非透明区域; + /// + /// 位图 + /// + public static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap, Color? colorTransparent = null) + { + // Create GraphicsPath for our bitmap calculation + //创建 GraphicsPath + GraphicsPath graphicsPath = new GraphicsPath(); + // Use the top left pixel as our transparent color + //使用左上角的一点的颜色作为我们透明色 + + Color _colorTransparent = bitmap.GetPixel(0, 0); + if (colorTransparent != null && colorTransparent != Color.Transparent && colorTransparent != Color.Empty) + _colorTransparent = colorTransparent.Value; + // This is to store the column value where an opaque pixel is first found. + // This value will determine where we start scanning for trailing opaque pixels. + //第一个找到点的X + int colOpaquePixel = 0; + // Go through all rows (Y axis) + // 偏历所有行(Y方向) + for (int row = 0; row < bitmap.Height; row++) + { + // Reset value + //重设 + colOpaquePixel = 0; + // Go through all columns (X axis) + //偏历所有列(X方向) + for (int col = 0; col < bitmap.Width; col++) + { + // If this is an opaque pixel, mark it and search for anymore trailing behind + //如果是不需要透明处理的点则标记,然后继续偏历 + if (bitmap.GetPixel(col, row) != _colorTransparent) + { + // Opaque pixel found, mark current position + //记录当前 + colOpaquePixel = col; + // Create another variable to set the current pixel position + //建立新变量来记录当前点 + int colNext = col; + // Starting from current found opaque pixel, search for anymore opaque pixels + // trailing behind, until a transparent pixel is found or minimum width is reached + ///从找到的不透明点开始,继续寻找不透明点,一直到找到或则达到图片宽度 + for (colNext = colOpaquePixel; colNext < bitmap.Width; colNext++) + if (bitmap.GetPixel(colNext, row) == _colorTransparent) + break; + // Form a rectangle for line of opaque pixels found and add it to our graphics path + //将不透明点加到graphics path + graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1)); + // No need to scan the line of opaque pixels just found + col = colNext; + } + } + } + // Return calculated graphics path + return graphicsPath; + } + + /// + /// 颜色加深 + /// + /// + /// -1.0f <= correctionFactor <= 1.0f + /// + public static Color ChangeColor(this Color color, float correctionFactor) + { + float red = (float)color.R; + float green = (float)color.G; + float blue = (float)color.B; + + if (correctionFactor < 0) + { + correctionFactor = 1 + correctionFactor; + red *= correctionFactor; + green *= correctionFactor; + blue *= correctionFactor; + } + else + { + red = (255 - red) * correctionFactor + red; + green = (255 - green) * correctionFactor + green; + blue = (255 - blue) * correctionFactor + blue; + } + + if (red < 0) red = 0; + + if (red > 255) red = 255; + + if (green < 0) green = 0; + + if (green > 255) green = 255; + + if (blue < 0) blue = 0; + + if (blue > 255) blue = 255; + + + + return Color.FromArgb(color.A, (int)red, (int)green, (int)blue); + } + + + /// + /// 相对于屏幕显示的位置 + /// + /// 窗体需要显示的屏幕 + /// left + /// top + /// + public static Point GetScreenLocation(Screen screen, int left, int top) + { + return new Point(screen.Bounds.Left + left, screen.Bounds.Top + top); + } + } + + public enum GraphDirection + { + /// + /// The upward + /// + Upward = 1, + /// + /// The downward + /// + Downward, + /// + /// The leftward + /// + Leftward, + /// + /// The rightward + /// + Rightward + } + + /// + /// 功能描述:文本控件输入类型 + /// 作  者:HZH + /// 创建日期:2019-02-28 10:09:00 + /// + public enum TextInputType + { + /// + /// 不控制输入 + /// + [Description("不控制输入")] + NotControl = 1, + /// + /// 任意数字 + /// + [Description("任意数字")] + Number = 2, + /// + /// 非负数 + /// + [Description("非负数")] + UnsignNumber = 4, + /// + /// 正数 + /// + [Description("正数")] + PositiveNumber = 8, + /// + /// 整数 + /// + [Description("整数")] + Integer = 16, + /// + /// 非负整数 + /// + [Description("非负整数")] + PositiveInteger = 32, + /// + /// 正则验证 + /// + [Description("正则验证")] + Regex = 64 + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/UCHelper/DpiControl.cs b/JinYuan.ControlLib/UCHelper/DpiControl.cs new file mode 100644 index 0000000..de780c6 --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/DpiControl.cs @@ -0,0 +1,65 @@ +using System.ComponentModel; +using System.Drawing.Design; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 缩放控件基类 + /// + [Description("缩放控件基类")] + [ToolboxItem(true)] + public abstract class DpiControl : Control, IDpiControl + { + #region 新增属性 + + private float scaleDpi = 1.0f; + /// + /// 控件当前缩放Dpi + /// + [Description("控件当前缩放Dpi")] + [Browsable(false)] + [Localizable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual float ScaleDpi + { + get { return this.scaleDpi; } + set + { + if (value <= 0) + return; + + this.scaleDpi = value; + this.OnScaleDpiChangedInitialize(); + } + } + + #endregion + + public DpiControl() + { + + } + + #region 重写 + + protected override void CreateHandle() + { + base.CreateHandle(); + + this.ScaleDpi = DpiHelper.GetControlDpi(this); + } + + #endregion + + #region 要实现 + + /// + /// 控件DPI更改后重新初始化控件Rectangle信息 + /// + protected abstract void OnScaleDpiChangedInitialize(); + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCHelper/DpiHelper.cs b/JinYuan.ControlLib/UCHelper/DpiHelper.cs new file mode 100644 index 0000000..19a23fe --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/DpiHelper.cs @@ -0,0 +1,53 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 系统缩放比例 + /// + public class DpiHelper + { + #region 公开方法 + + /// + /// 获取控件对应的系统缩放比例 + /// + /// + /// + public static float GetControlDpi(Control control) + { + IntPtr hDC = IntPtr.Zero; + Graphics g = null; + ControlHelper.GetWindowClientGraphics(control.Handle, out g, out hDC); + + float dpi = g.DpiX / 96f; + + g.Dispose(); + NativeMethods.ReleaseDC(control.Handle, hDC); + + return dpi; + } + + /// + /// 获取控件对应的系统缩放比例 + /// + /// + /// + public static float GetControlDpi(IntPtr hWnd) + { + IntPtr hDC = IntPtr.Zero; + Graphics g = null; + ControlHelper.GetWindowClientGraphics(hWnd, out g, out hDC); + + float dpi = g.DpiX / 96f; + + g.Dispose(); + NativeMethods.ReleaseDC(hWnd, hDC); + + return dpi; + } + #endregion + } +} diff --git a/JinYuan.ControlLib/UCHelper/Ext.cs b/JinYuan.ControlLib/UCHelper/Ext.cs new file mode 100644 index 0000000..2dbceda --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/Ext.cs @@ -0,0 +1,474 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System; +using System.Reflection; +using System.Text; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// Class Ext. + /// + public static partial class Ext + { + /// + /// Clones the model. + /// + /// + /// The class object. + /// T. + public static T CloneModel(this T classObject) where T : class + { + T result; + if (classObject == null) + { + result = default(T); + } + else + { + object obj = Activator.CreateInstance(typeof(T)); + PropertyInfo[] properties = typeof(T).GetProperties(); + PropertyInfo[] array = properties; + for (int i = 0; i < array.Length; i++) + { + PropertyInfo propertyInfo = array[i]; + if (propertyInfo.CanWrite) + propertyInfo.SetValue(obj, propertyInfo.GetValue(classObject, null), null); + } + result = (obj as T); + } + return result; + } + /// + /// ASCII编码的数组转换为英文字符串 + /// + /// 字符串 + /// 结果 + public static string ToEnString(this byte[] s) + { + return ToEncodeString(s, Encoding.ASCII).Trim('\0').Trim(); + } + + /// + /// 数组按指定编码转换为字符串 + /// + /// 数组 + /// 编码 + /// 结果 + public static string ToEncodeString(this byte[] dealBytes, Encoding encode) + { + return encode.GetString(dealBytes); + } + #region 转换为base64字符串 + /// + /// 功能描述:转换为base64字符串 + /// 作  者:HZH + /// 创建日期:2019-03-29 10:12:38 + /// 任务编号:POS + /// + /// data + /// 返回值 + public static string ToBase64Str(this string data) + { + if (data.IsEmpty()) + return string.Empty; + byte[] buffer = Encoding.Default.GetBytes(data); + return Convert.ToBase64String(buffer); + } + #endregion + /// + /// 转换为坐标 + /// + /// The data. + /// System.Drawing.Point. + public static System.Drawing.Point ToPoint(this string data) + { + if (!System.Text.RegularExpressions.Regex.IsMatch(data, @"^\s*\d+(\.\d+)?\s*\,\s*\d+(\.\d+)?\s*$")) + { + return System.Drawing.Point.Empty; + } + else + { + string[] strs = data.Split(','); + return new System.Drawing.Point(strs[0].ToInt(), strs[1].ToInt()); + } + } + + #region 数值转换 + /// + /// 转换为整型 + /// + /// 数据 + /// System.Int32. + public static int ToInt(this object data) + { + if (data == null) + return 0; + if (data is bool) + { + return (bool)data ? 1 : 0; + } + int result; + var success = int.TryParse(data.ToString(), out result); + if (success) + return result; + try + { + return Convert.ToInt32(ToDouble(data, 0)); + } + catch (Exception) + { + return 0; + } + } + + /// + /// 转换为可空整型 + /// + /// 数据 + /// System.Nullable<System.Int32>. + public static int? ToIntOrNull(this object data) + { + if (data == null) + return null; + int result; + bool isValid = int.TryParse(data.ToString(), out result); + if (isValid) + return result; + return null; + } + + /// + /// 转换为双精度浮点数 + /// + /// 数据 + /// System.Double. + public static double ToDouble(this object data) + { + if (data == null) + return 0; + double result; + return double.TryParse(data.ToString(), out result) ? result : 0; + } + + /// + /// 转换为双精度浮点数,并按指定的小数位4舍5入 + /// + /// 数据 + /// 小数位数 + /// System.Double. + public static double ToDouble(this object data, int digits) + { + return Math.Round(ToDouble(data), digits, System.MidpointRounding.AwayFromZero); + } + + /// + /// 转换为可空双精度浮点数 + /// + /// 数据 + /// System.Nullable<System.Double>. + public static double? ToDoubleOrNull(this object data) + { + if (data == null) + return null; + double result; + bool isValid = double.TryParse(data.ToString(), out result); + if (isValid) + return result; + return null; + } + + /// + /// 转换为高精度浮点数 + /// + /// 数据 + /// System.Decimal. + public static decimal ToDecimal(this object data) + { + if (data == null) + return 0; + decimal result; + return decimal.TryParse(data.ToString(), out result) ? result : 0; + } + + /// + /// 转换为高精度浮点数,并按指定的小数位4舍5入 + /// + /// 数据 + /// 小数位数 + /// System.Decimal. + public static decimal ToDecimal(this object data, int digits) + { + return Math.Round(ToDecimal(data), digits, System.MidpointRounding.AwayFromZero); + } + + /// + /// 转换为可空高精度浮点数 + /// + /// 数据 + /// System.Nullable<System.Decimal>. + public static decimal? ToDecimalOrNull(this object data) + { + if (data == null) + return null; + decimal result; + bool isValid = decimal.TryParse(data.ToString(), out result); + if (isValid) + return result; + return null; + } + + /// + /// 转换为可空高精度浮点数,并按指定的小数位4舍5入 + /// + /// 数据 + /// 小数位数 + /// System.Nullable<System.Decimal>. + public static decimal? ToDecimalOrNull(this object data, int digits) + { + var result = ToDecimalOrNull(data); + if (result == null) + return null; + return Math.Round(result.Value, digits, System.MidpointRounding.AwayFromZero); + } + + #endregion + + #region 日期转换 + /// + /// 转换为日期 + /// + /// 数据 + /// DateTime. + public static DateTime ToDate(this object data) + { + try + { + if (data == null) + return DateTime.MinValue; + if (System.Text.RegularExpressions.Regex.IsMatch(data.ToStringExt(), @"^\d{8}$")) + { + string strValue = data.ToStringExt(); + return new DateTime(strValue.Substring(0, 4).ToInt(), strValue.Substring(4, 2).ToInt(), strValue.Substring(6, 2).ToInt()); + } + DateTime result; + return DateTime.TryParse(data.ToString(), out result) ? result : DateTime.MinValue; + } + catch + { + return DateTime.MinValue; + } + } + + /// + /// 转换为可空日期 + /// + /// 数据 + /// System.Nullable<DateTime>. + public static DateTime? ToDateOrNull(this object data) + { + try + { + if (data == null) + return null; + if (System.Text.RegularExpressions.Regex.IsMatch(data.ToStringExt(), @"^\d{8}$")) + { + string strValue = data.ToStringExt(); + return new DateTime(strValue.Substring(0, 4).ToInt(), strValue.Substring(4, 2).ToInt(), strValue.Substring(6, 2).ToInt()); + } + DateTime result; + bool isValid = DateTime.TryParse(data.ToString(), out result); + if (isValid) + return result; + return null; + } + catch + { + return null; + } + } + + #endregion + + #region 布尔转换 + /// + /// 转换为布尔值 + /// + /// 数据 + /// true if XXXX, false otherwise. + public static bool ToBool(this object data) + { + if (data == null) + return false; + bool? value = GetBool(data); + if (value != null) + return value.Value; + bool result; + return bool.TryParse(data.ToString(), out result) && result; + } + + /// + /// 获取布尔值 + /// + /// The data. + /// true if XXXX, false otherwise. + private static bool? GetBool(this object data) + { + switch (data.ToString().Trim().ToLower()) + { + case "0": + return false; + case "1": + return true; + case "是": + return true; + case "否": + return false; + case "yes": + return true; + case "no": + return false; + default: + return null; + } + } + + /// + /// 转换为可空布尔值 + /// + /// 数据 + /// true if XXXX, false otherwise. + public static bool? ToBoolOrNull(this object data) + { + if (data == null) + return null; + bool? value = GetBool(data); + if (value != null) + return value.Value; + bool result; + bool isValid = bool.TryParse(data.ToString(), out result); + if (isValid) + return result; + return null; + } + + #endregion + + #region 字符串转换 + /// + /// 字符串转换为byte[] + /// + /// The data. + /// System.Byte[]. + public static byte[] ToBytes(this string data) + { + return System.Text.Encoding.GetEncoding("GBK").GetBytes(data); + } + /// + /// Converts to bytesdefault. + /// + /// The data. + /// System.Byte[]. + public static byte[] ToBytesDefault(this string data) + { + return System.Text.Encoding.Default.GetBytes(data); + } + /// + /// 转换为字符串 + /// + /// 数据 + /// System.String. + public static string ToStringExt(this object data) + { + return data == null ? string.Empty : data.ToString(); + } + #endregion + + /// + /// 安全返回值 + /// + /// + /// 可空值 + /// T. + public static T SafeValue(this T? value) where T : struct + { + return value ?? default(T); + } + /// + /// 是否为空 + /// + /// 值 + /// true if the specified value is empty; otherwise, false. + public static bool IsEmpty(this string value) + { + return string.IsNullOrWhiteSpace(value); + } + /// + /// 是否为空 + /// + /// 值 + /// true if the specified value is empty; otherwise, false. + public static bool IsEmpty(this Guid? value) + { + if (value == null) + return true; + return IsEmpty(value.Value); + } + /// + /// 是否为空 + /// + /// 值 + /// true if the specified value is empty; otherwise, false. + public static bool IsEmpty(this Guid value) + { + if (value == Guid.Empty) + return true; + return false; + } + /// + /// 是否为空 + /// + /// 值 + /// true if the specified value is empty; otherwise, false. + public static bool IsEmpty(this object value) + { + if (value != null && !string.IsNullOrEmpty(value.ToString())) + { + return false; + } + else + { + return true; + } + } + + #region 是否数字 + /// + /// 功能描述:是否数字 + /// 作  者:HZH + /// 创建日期:2019-03-06 09:03:05 + /// 任务编号:POS + /// + /// value + /// 返回值 + public static bool IsNum(this string value) + { + return System.Text.RegularExpressions.Regex.IsMatch(value, @"^\d+(\.\d*)?$"); + } + #endregion + + } +} diff --git a/JinYuan.ControlLib/UCHelper/IDpiControl.cs b/JinYuan.ControlLib/UCHelper/IDpiControl.cs new file mode 100644 index 0000000..3984bd3 --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/IDpiControl.cs @@ -0,0 +1,13 @@ +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 缩放控件接口 + /// + public interface IDpiControl + { + /// + /// Dpi + /// + float ScaleDpi { get; set; } + } +} diff --git a/JinYuan.ControlLib/UCHelper/MainThreadAnimationControl.cs b/JinYuan.ControlLib/UCHelper/MainThreadAnimationControl.cs new file mode 100644 index 0000000..6138296 --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/MainThreadAnimationControl.cs @@ -0,0 +1,159 @@ +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 主线程动画控件基类,不能时耗时操作,该定时器时UI线程计时器。耗时长对导致画面卡顿。 + /// + [ToolboxItem(false)] + [Description("动画控件基类")] + public abstract class MainThreadAnimationControl : DpiControl + { + #region 字段 + + /// + /// 动画控件集合锁 + /// + private static object animationcontrols_lock = new object(); + /// + /// 动画控件集合 + /// + private static List animationcontrols = new List(); + /// + /// 动画定时器锁 + /// + private static object timer_lock = new object(); + + /// + /// 定时器间隔 + /// + private static Thread thread = null; + /// + /// 线程间隔 + /// + private static int threadInterval = 100; + + + private static CancellationTokenSource cts = new CancellationTokenSource(); + /// + /// 停止线程 + /// + private static ManualResetEvent stopEvent = new ManualResetEvent(false); + + //private static Timer timer = null; + + #endregion + + public MainThreadAnimationControl() + { + if (thread == null) + { + lock (timer_lock) + { + thread = new Thread(() => ThreadFunction()); + thread.IsBackground = true; + thread.Start(); + } + } + } + + #region 虚方法 + + /// + /// 动画控件动画中要处理的内容(不能时耗时操作,该定时器为UI线程计时器。耗时长对导致画面卡顿) + /// + /// 动画定时器间隔时间 + protected virtual void Animationing(int interval) + { + + } + + #endregion + + #region 私有方法 + + /// + /// 定时器事件 + /// + /// + /// + internal static void ThreadFunction() + { + ArrayList indexArr = new ArrayList(); + while (true) + { + if (cts.Token.IsCancellationRequested) + { + return; + } + // stopEvent.WaitOne(); + + for (int i = 0; i < animationcontrols.Count; i++) + { + if (animationcontrols[i] != null) + { + animationcontrols[i].Animationing(threadInterval); + } + else + { + indexArr.Add(i); + } + } + + if (indexArr.Count > 0) + { + for (int i = 0; i < indexArr.Count; i++) + { + animationcontrols.RemoveAt((int)indexArr[i] - i); + } + } + if (animationcontrols.Count < 1) + { + stopEvent.Set(); + } + + Thread.Sleep(threadInterval); + } + } + + /// + /// 开始指定控件动画 + /// + /// + internal static void AnimationStart(MainThreadAnimationControl control) + { + if (control == null) + return; + + lock (animationcontrols_lock) + { + if (animationcontrols.IndexOf(control) < 0) + { + animationcontrols.Add(control); + } + } + stopEvent.Reset(); + } + + /// + /// 停止指定控件动画 + /// + /// + internal static void AnimationStop(MainThreadAnimationControl control) + { + if (control == null) + return; + + lock (animationcontrols_lock) + { + animationcontrols.Remove(control); + } + } + + #endregion + + } +} diff --git a/JinYuan.ControlLib/UCHelper/MouseHook.cs b/JinYuan.ControlLib/UCHelper/MouseHook.cs new file mode 100644 index 0000000..e6cf444 --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/MouseHook.cs @@ -0,0 +1,195 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 鼠标全局钩子 + /// + public static class MouseHook + { + /// + /// The wm mousemove + /// + private const int WM_MOUSEMOVE = 0x200; + /// + /// The wm lbuttondown + /// + private const int WM_LBUTTONDOWN = 0x201; + /// + /// The wm rbuttondown + /// + private const int WM_RBUTTONDOWN = 0x204; + /// + /// The wm mbuttondown + /// + private const int WM_MBUTTONDOWN = 0x207; + /// + /// The wm lbuttonup + /// + private const int WM_LBUTTONUP = 0x202; + /// + /// The wm rbuttonup + /// + private const int WM_RBUTTONUP = 0x205; + /// + /// The wm mbuttonup + /// + private const int WM_MBUTTONUP = 0x208; + /// + /// The wm lbuttondblclk + /// + private const int WM_LBUTTONDBLCLK = 0x203; + /// + /// The wm rbuttondblclk + /// + private const int WM_RBUTTONDBLCLK = 0x206; + /// + /// The wm mbuttondblclk + /// + private const int WM_MBUTTONDBLCLK = 0x209; + + /// + /// 点 + /// + [StructLayout(LayoutKind.Sequential)] + public class POINT + { + /// + /// The x + /// + public int x; + /// + /// The y + /// + public int y; + } + + /// + /// 钩子结构体 + /// + [StructLayout(LayoutKind.Sequential)] + public class MouseHookStruct + { + /// + /// The pt + /// + public POINT pt; + /// + /// The h WND + /// + public int hWnd; + /// + /// The w hit test code + /// + public int wHitTestCode; + /// + /// The dw extra information + /// + public int dwExtraInfo; + } + + + // 全局的鼠标事件 + /// + /// Occurs when [on mouse activity]. + /// + public static event MouseEventHandler OnMouseActivity; + + + /// + /// The h mouse hook + /// + private static int _hMouseHook = 0; // 鼠标钩子句柄 + /// + /// 启动全局钩子 + /// + /// SetWindowsHookEx failed. + /// SetWindowsHookEx failed. + public static void Start() + { + // 安装鼠标钩子 + if (_hMouseHook != 0) + { + Stop(); + } + // 生成一个HookProc的实例. + WindowsHook.HookMsgChanged += WindowsHook_HookMsgChanged; + _hMouseHook = WindowsHook.StartHook(HookType.WH_MOUSE_LL); + + //假设装置失败停止钩子 + if (_hMouseHook == 0) + { + Stop(); + } + } + + static void WindowsHook_HookMsgChanged(string strHookName, int nCode, IntPtr msg, IntPtr lParam) + { + // 假设正常执行而且用户要监听鼠标的消息 + if (nCode >= 0 && OnMouseActivity != null) + { + MouseButtons button = MouseButtons.None; + int clickCount = 0; + + switch ((int)msg) + { + case WM_LBUTTONDOWN: + button = MouseButtons.Left; + clickCount = 1; + break; + case WM_LBUTTONUP: + button = MouseButtons.Left; + clickCount = 1; + break; + case WM_LBUTTONDBLCLK: + button = MouseButtons.Left; + clickCount = 2; + break; + case WM_RBUTTONDOWN: + button = MouseButtons.Right; + clickCount = 1; + break; + case WM_RBUTTONUP: + button = MouseButtons.Right; + clickCount = 1; + break; + case WM_RBUTTONDBLCLK: + button = MouseButtons.Right; + clickCount = 2; + break; + } + if (button != MouseButtons.None && clickCount > 0) + { + // 从回调函数中得到鼠标的信息 + MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)); + MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0); + OnMouseActivity(null, e); + } + } + } + + /// + /// 停止全局钩子 + /// + /// UnhookWindowsHookEx failed. + /// UnhookWindowsHookEx failed. + public static void Stop() + { + bool retMouse = true; + + if (_hMouseHook != 0) + { + retMouse = WindowsHook.StopHook(_hMouseHook); + _hMouseHook = 0; + } + + // 假设卸下钩子失败 + if (!(retMouse)) + throw new Exception("UnhookWindowsHookEx failed."); + } + + + } +} diff --git a/JinYuan.ControlLib/UCHelper/NativeMethods.cs b/JinYuan.ControlLib/UCHelper/NativeMethods.cs new file mode 100644 index 0000000..7a8848f --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/NativeMethods.cs @@ -0,0 +1,312 @@ +using System; +using System.Runtime.InteropServices; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// Win32 + /// + public static class NativeMethods + { + #region 消息 + + public const int WM_USER = 0x0400;//用户自定义消息 + public const int WM_USER_DROPDROWLISTPLUS_MOUSEENTER = NativeMethods.WM_USER + 10;// DropDrowListPlus MouseEnter消息 + public const int WM_USER_DROPDROWLISTPLUS_MOUSELEAVE = NativeMethods.WM_USER + 11;// DropDrowListPlus MouseLeave消息 + public const int WM_USER_DROPDROWLISTPLUS_MOUSEDOWN = NativeMethods.WM_USER + 12;// DropDrowListPlus MouseDown消息 + public const int WM_USER_DROPDROWLISTPLUS_MOUSEUP = NativeMethods.WM_USER + 13;// DropDrowListPlus MouseUp消息 + public const int WM_USER_DROPDROWLISTPLUS_MOUSEMOVE = NativeMethods.WM_USER + 14;// DropDrowListPlus MouseMove消息 + public const int WM_USER_DROPDROWLISTPLUS_CLOSED = NativeMethods.WM_USER + 15;// DropDrowListPlus 下拉面板Closed消息 + public const int WM_USER_DROPDROWLISTPLUS_MOUSEWHEEL = NativeMethods.WM_USER + 16;// DropDrowListPlus 下拉面板MouseWheel消息 + public const int WM_USER_DROPDROWLISTPLUS_PAINT = NativeMethods.WM_USER + 17;// DropDrowListPlus 下拉面板Paint消息 + + + public const int LOGPIXELSX = 88; + public const int LOGPIXELSY = 90; + + #endregion + + #region 结构 + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int left; + public int top; + public int right; + public int bottom; + + public RECT(int left, int top, int right, int bottom) + { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public RECT(System.Drawing.Rectangle r) + { + this.left = r.Left; + this.top = r.Top; + this.right = r.Right; + this.bottom = r.Bottom; + } + + public static RECT FromXYWH(int x, int y, int width, int height) + { + return new RECT(x, y, x + width, y + height); + } + + public System.Drawing.Size Size + { + get + { + return new System.Drawing.Size(this.right - this.left, this.bottom - this.top); + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public class POINT + { + public int x; + public int y; + + public POINT() + { + } + + public POINT(int x, int y) + { + this.x = x; + this.y = y; + } + + } + + #endregion + + #region 扩展 + + [DllImport("User32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)] + public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex); + + [DllImport("User32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)] + public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex); + + public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size == 4) + { + return GetWindowLong32(hWnd, nIndex); + } + return GetWindowLongPtr64(hWnd, nIndex); + } + + [DllImport("User32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)] + public static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("User32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)] + public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong) + { + if (IntPtr.Size == 4) + { + return SetWindowLongPtr32(hWnd, nIndex, dwNewLong); + } + return SetWindowLongPtr64(hWnd, nIndex, dwNewLong); + } + + [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + public static extern IntPtr PostMessage(IntPtr hWnd, int msg, int wParam, int lParam); + + [DllImport("User32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr PostMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); + + [DllImport("User32.dll", EntryPoint = "SendMessage")] + public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); + + [DllImport("User32.dll", EntryPoint = "SendMessage")] + public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); + + [DllImport("User32.dll", ExactSpelling = true, SetLastError = true)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + + /// + /// 检索指定窗口的边界矩形的尺寸。 尺寸以相对于屏幕左上角的屏幕坐标提供。 + /// + /// 窗口的句柄 + /// 指向 RECT 结构的指针,用于接收窗口左上角和右下角的屏幕坐标 + /// + [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + public static extern bool GetWindowRect(IntPtr hWnd, [In, Out] ref RECT rect); + + /// + /// 激活指定窗口 + /// + /// 窗口的句柄 + /// + [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + public static extern IntPtr SetActiveWindow(IntPtr hWnd); + + [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + public static extern bool IsWindowVisible(IntPtr hWnd); + + + + /// + /// 获得的设备环境覆盖了整个窗口(包括非客户区) + /// + /// + /// + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern IntPtr GetWindowDC(IntPtr hwnd); + + /// + /// 用于获得hWnd参数所指定窗口的客户区域的一个设备环境 + /// + /// + /// + [DllImport("user32.dll")] + public static extern IntPtr GetDC(IntPtr ptr); + + [DllImport("User32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hdc); + + + + /// + /// DPI的缩放由程序自己处理 + /// + /// + [DllImport("user32.dll")] + public static extern bool SetProcessDPIAware(); + + [DllImport("user32.dll")] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("gdi32.dll")] + public static extern int GetDeviceCaps(IntPtr hdc, int nIndex); + + + + public static int MAKELONG(int low, int high) + { + return (high << 16) | (low & 0xffff); + } + + public static IntPtr MAKELPARAM(int low, int high) + { + return (IntPtr)((high << 16) | (low & 0xffff)); + } + + /// + /// 高16位(无符号) + /// + /// + /// + public static int HIWORD(IntPtr n) + { + return HIWORD(unchecked((int)(long)n)); + } + /// + /// 高16位(无符号) + /// + /// + /// + public static int HIWORD(int n) + { + return (n >> 16) & 0xffff; + } + + /// + /// 低16位(无符号) + /// + /// + /// + public static int LOWORD(IntPtr n) + { + return LOWORD(unchecked((int)(long)n)); + } + /// + /// 低16位(无符号) + /// + /// + /// + public static int LOWORD(int n) + { + return n & 0xffff; + } + + /// + /// 高16位(有符号) + /// + /// + /// + public static int SignedHIWORD(IntPtr n) + { + return SignedHIWORD(unchecked((int)(long)n)); + } + /// + /// 高16位(有符号) + /// + /// + /// + public static int SignedHIWORD(int n) + { + return (int)(short)((n >> 16) & 0xffff); + } + + /// + /// 低16位(有符号) + /// + /// + /// + public static int SignedLOWORD(IntPtr n) + { + return SignedLOWORD(unchecked((int)(long)n)); + } + /// + /// 低16位(有符号) + /// + /// + /// + public static int SignedLOWORD(int n) + { + return (int)(short)(n & 0xFFFF); + } + + + + + /// + /// 结构转指针 + /// + /// 结构类型 + /// + /// + public static IntPtr StructToIntPtr(T info) + { + int size = Marshal.SizeOf(info); + IntPtr intPtr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(info, intPtr, true); + return intPtr; + } + + /// + /// 指针转结构 + /// + /// 结构类型 + /// + /// + public static T IntPtrToStruct(IntPtr info) + { + return (T)Marshal.PtrToStructure(info, typeof(T)); + } + + + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCHelper/PropertyOrderAttribute.cs b/JinYuan.ControlLib/UCHelper/PropertyOrderAttribute.cs new file mode 100644 index 0000000..98eb9b9 --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/PropertyOrderAttribute.cs @@ -0,0 +1,27 @@ +using System; + +namespace JinYuan.ControlLib.UCHelper +{ + // + // 摘要: + // 属性排序(升序) + [AttributeUsage(AttributeTargets.Property)] + public class PropertyOrderAttribute : Attribute + { + private float order; + + // + // 摘要: + // 序号 + public float Order => order; + + // + // 参数: + // order: + // 序号 + public PropertyOrderAttribute(float order) + { + this.order = order; + } + } +} diff --git a/JinYuan.ControlLib/UCHelper/PropertyOrderConverter.cs b/JinYuan.ControlLib/UCHelper/PropertyOrderConverter.cs new file mode 100644 index 0000000..5801608 --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/PropertyOrderConverter.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Globalization; + +namespace JinYuan.ControlLib.UCHelper +{ + // + // 摘要: + // 对属性进行排序 + public class PropertyOrderConverter : TypeConverter + { + // + // 摘要: + // 当该属性为展开属性选型时,属性编辑器删除该属性的描述 + // + // 参数: + // context: + // + // culture: + // + // value: + // + // destinationType: + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string)) + { + return string.Empty; + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value, attributes); + ArrayList arrayList = new ArrayList(); + foreach (PropertyDescriptor item in properties) + { + Attribute attribute = item.Attributes[typeof(PropertyOrderAttribute)]; + arrayList.Add(new PropertyOrderPair(item.Name, (attribute == null) ? 0f : ((PropertyOrderAttribute)attribute).Order)); + } + + arrayList.Sort(); + ArrayList arrayList2 = new ArrayList(); + foreach (PropertyOrderPair item2 in arrayList) + { + arrayList2.Add(item2.CategoryName); + } + + return properties.Sort((string[])arrayList2.ToArray(typeof(string))); + } + } +} diff --git a/JinYuan.ControlLib/UCHelper/PropertyOrderPair.cs b/JinYuan.ControlLib/UCHelper/PropertyOrderPair.cs new file mode 100644 index 0000000..11f6bad --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/PropertyOrderPair.cs @@ -0,0 +1,49 @@ +using System; + +namespace JinYuan.ControlLib.UCHelper +{ + + // + // 摘要: + // 属性排序 序号比较器 + public class PropertyOrderPair : IComparable + { + private float order; + + private string categoryName; + + // + // 摘要: + // 类别名称 + public string CategoryName => categoryName; + + // + // 参数: + // categoryName: + // 类别名称 + // + // order: + // 序号 + public PropertyOrderPair(string categoryName, float order) + { + this.order = order; + this.categoryName = categoryName; + } + + public int CompareTo(object obj) + { + PropertyOrderPair propertyOrderPair = (PropertyOrderPair)obj; + if (propertyOrderPair.order == order) + { + return string.Compare(categoryName, propertyOrderPair.categoryName); + } + + if (propertyOrderPair.order > order) + { + return -1; + } + + return 1; + } + } +} diff --git a/JinYuan.ControlLib/UCHelper/WindowsHook.cs b/JinYuan.ControlLib/UCHelper/WindowsHook.cs new file mode 100644 index 0000000..349861f --- /dev/null +++ b/JinYuan.ControlLib/UCHelper/WindowsHook.cs @@ -0,0 +1,177 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace JinYuan.ControlLib.UCHelper +{ + /// + /// 钩子类型 + /// + public enum HookType : int + { + /// + /// 安装一个钩子过程,该过程监视由于对话框,消息框,菜单或滚动条中的输入事件而生成的消息。 + /// 有关更多信息,请参阅MessageProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644987(v=vs.85))挂接过程。 + /// + WH_MSGFILTER = -1, + /// + /// 安装一个钩子过程,记录发布到系统消息队列的输入消息。 此挂钩对于录制宏非常有用。 + /// 有关更多信息,请参阅JournalRecordProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644983(v=vs.85))挂钩过程。 + /// + WH_JOURNALRECORD = 0, + /// + /// 安装一个挂钩过程,该过程发布先前由WH_JOURNALRECORD挂钩过程记录的消息。 + /// 有关更多信息,请参阅JournalPlaybackProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644982(v=vs.85))挂钩过程。 + /// + WH_JOURNALPLAYBACK = 1, + /// + /// 安装一个监视击键消息的钩子程序。 + /// 有关更多信息,请参阅KeyboardProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644984(v=vs.85))挂钩过程。 + /// + WH_KEYBOARD = 2, + /// + /// 安装一个钩子过程来监视发布到消息队列的消息。 + /// 有关更多信息,请参阅GetMsgProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644981(v=vs.85))挂接过程。 + /// + WH_GETMESSAGE = 3, + /// + /// 安装一个钩子过程,在系统将消息发送到目标窗口过程之前监视消息。 + /// 有关更多信息,请参阅CallWndProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644975(v=vs.85))挂接过程。 + /// + WH_CALLWNDPROC = 4, + /// + /// 安装一个钩子程序,接收对CBT应用程序有用的通知。 + /// 有关更多信息,请参阅CBTProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644977(v=vs.85))挂钩过程。 + /// + WH_CBT = 5, + /// + /// 安装一个钩子过程,该过程监视由于对话框,消息框,菜单或滚动条中的输入事件而生成的消息。 + /// 钩子过程监视与调用线程在同一桌面中的所有应用程序的这些消息。 + /// 有关更多信息,请参阅SysMsgProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644992(v=vs.85))挂接过程。 + /// + WH_SYSMSGFILTER = 6, + /// + /// 安装监视鼠标消息的钩子过程。 + /// 有关更多信息,请参阅MouseProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644988(v=vs.85))挂钩过程。 + /// + WH_MOUSE = 7, + /// + /// 安装一个用于调试其他钩子过程的钩子过程。 + /// 有关更多信息,请参阅DebugProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644978(v=vs.85))挂接过程。 + /// + WH_DEBUG = 9, + /// + /// 安装一个钩子过程,接收对shell应用程序有用的通知。 + /// 有关更多信息,请参阅ShellProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644991(v=vs.85))挂钩过程。 + /// + WH_SHELL = 10, + /// + /// 安装一个钩子过程,当应用程序的前台线程即将变为空闲时将调用该过程。 + /// 此挂钩对于在空闲时执行低优先级任务非常有用。 + /// 有关更多信息,请参阅ForegroundIdleProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644980(v=vs.85))挂钩过程。 + /// + WH_FOREGROUNDIDLE = 11, + /// + /// 安装一个钩子过程,该过程在目标窗口过程处理完消息后对其进行监视。 + /// 有关更多信息,请参阅CallWndRetProc(https://docs.microsoft.com/windows/desktop/api/winuser/nc-winuser-hookproc)挂接过程。 + /// + WH_CALLWNDPROCRET = 12, + /// + /// 安装一个监视低级键盘输入事件的钩子过程。 有关更多信息, + /// 请参阅LowLevelKeyboardProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644985(v=vs.85))挂接过程。 + /// + WH_KEYBOARD_LL = 13, + /// + /// 安装一个监视低级鼠标输入事件的钩子过程。 有关更多信息, + /// 请参阅LowLevelMouseProc(https://docs.microsoft.com/previous-versions/windows/desktop/legacy/ms644986(v=vs.85))挂接过程。 + /// + WH_MOUSE_LL = 14, + } + public class WindowsHook + { + public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); + // 装置钩子的函数 + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, int hInstance, int threadId); + + // 卸下钩子的函数 + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + public static extern bool UnhookWindowsHookEx(int idHook); + + // 下一个钩挂的函数 + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); + [DllImport("User32.dll", CharSet = CharSet.Auto)] + public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + /// + /// Delegate HookMsgHandler + /// + /// 钩子名称 + /// 消息值 + public delegate void HookMsgHandler(string strHookName, int nCode, IntPtr msg, IntPtr lParam); + /// + /// 钩子消息事件 + /// + public static event HookMsgHandler HookMsgChanged; + /// + /// 启动一个钩子 + /// + /// 钩子类型 + /// 模块句柄,为空则为当前模块 + /// 进程句柄,默认为0则表示当前进程 + /// 钩子名称 + /// 钩子句柄(消耗钩子时需要使用) + /// SetWindowsHookEx failed. + public static int StartHook(HookType hookType, int wParam = 0, int pid = 0, string strHookName = "") + { + int _hHook = 0; + // 生成一个HookProc的实例. + var _hookProcedure = new HookProc((nCode, msg, lParam) => + { + + if (HookMsgChanged != null) + { + try + { + HookMsgChanged(strHookName, nCode, msg, lParam); + } + catch { } + } + + int inext = CallNextHookEx(_hHook, nCode, msg, lParam); + return inext; + }); + if (pid == 0) + pid = Thread.CurrentThread.ManagedThreadId; + _hHook = SetWindowsHookEx((int)hookType, _hookProcedure, wParam, pid); + + //假设装置失败停止钩子 + if (_hHook == 0) + { + StopHook(_hHook); + } + return _hHook; + } + + /// + /// 停止钩子 + /// + /// StartHook函数返回的钩子句柄 + /// true if 停止成功, false 否则. + public static bool StopHook(int _hHook) + { + bool ret = true; + + if (_hHook != 0) + { + ret = UnhookWindowsHookEx(_hHook); + } + + // 假设卸下钩子失败 + if (!ret) + return false; + return true; + } + } +} diff --git a/JinYuan.ControlLib/UCLed.Designer.cs b/JinYuan.ControlLib/UCLed.Designer.cs new file mode 100644 index 0000000..ee295d3 --- /dev/null +++ b/JinYuan.ControlLib/UCLed.Designer.cs @@ -0,0 +1,42 @@ +namespace Controls +{ + partial class UCLed + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_blinkTimer != null) + { + _blinkTimer.Stop(); + _blinkTimer.Dispose(); + _blinkTimer = null; + } + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCLed.cs b/JinYuan.ControlLib/UCLed.cs new file mode 100644 index 0000000..b0375dd --- /dev/null +++ b/JinYuan.ControlLib/UCLed.cs @@ -0,0 +1,277 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace Controls +{ + [ToolboxItem(true)] + [Description("一个用于显示通信状态的LED指示器控件")] + public partial class UCLed : UserControl + { + private Color _onColor = Color.Green; + private Color _offColor = Color.Red; + private Color _blinkColor = Color.Yellow; + private Color _textColor = Color.White; + private string _statusText = "NG"; + private bool _isOn = false; + private bool _isBlinking = false; + private bool _blinkState = false; + private int _blinkInterval = 500; // 默认闪烁间隔(毫秒) + private Timer _blinkTimer; + + private int _cornerRadius = 10; // 新增:控制圆角半径的字段 + + public UCLed() + { + InitializeComponent(); + SetStyle(ControlStyles.SupportsTransparentBackColor | + ControlStyles.OptimizedDoubleBuffer | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.UserPaint, true); + this.BackColor = Color.Transparent; + } + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + InitializeTimer(); + } + + private void InitializeTimer() + { + if (_blinkTimer == null) + { + _blinkTimer = new Timer(); + _blinkTimer.Tick += BlinkTimer_Tick; + _blinkTimer.Interval = _blinkInterval; + } + } + + [Category("外观")] + [DefaultValue(typeof(Color), "Green")] + public Color OnColor + { + get => _onColor; + set + { + if (_onColor != value) + { + _onColor = value; + Invalidate(); + } + } + } + + [Category("外观")] + [DefaultValue(typeof(Color), "Red")] + public Color OffColor + { + get => _offColor; + set + { + if (_offColor != value) + { + _offColor = value; + Invalidate(); + } + } + } + + [Category("外观")] + [DefaultValue(typeof(Color), "Yellow")] + public Color BlinkColor + { + get => _blinkColor; + set + { + if (_blinkColor != value) + { + _blinkColor = value; + Invalidate(); + } + } + } + + [Category("外观")] + [DefaultValue(typeof(Color), "White")] + public Color TextColor + { + get => _textColor; + set + { + if (_textColor != value) + { + _textColor = value; + Invalidate(); + } + } + } + + [Category("外观")] + [DefaultValue(10)] + public int CornerRadius + { + get => _cornerRadius; + set + { + if (_cornerRadius != value) + { + _cornerRadius = value; + Invalidate(); + } + } + } + + + [Category("外观")] + [DefaultValue("NG")] + public string StatusText + { + get => _statusText; + set + { + if (_statusText != value) + { + _statusText = value; + Invalidate(); + } + } + } + + [Category("行为")] + [DefaultValue(false)] + public bool IsOn + { + get => _isOn; + set + { + if (_isOn != value) + { + _isOn = value; + if (!_isBlinking) + { + Invalidate(); + } + } + } + } + + [Category("行为")] + [DefaultValue(false)] + public bool IsBlinking + { + get => _isBlinking; + set + { + if (_isBlinking != value) + { + _isBlinking = value; + if (_isBlinking) + _blinkTimer?.Start(); + else + { + _blinkTimer?.Stop(); + _blinkState = false; + } + Invalidate(); + } + } + } + + [Category("行为")] + [DefaultValue(500)] + public int BlinkInterval + { + get => _blinkInterval; + set + { + if (_blinkInterval != value) + { + _blinkInterval = value; + if (_blinkTimer != null && !DesignMode) + { + _blinkTimer.Interval = _blinkInterval; + } + } + } + } + + + + + private void BlinkTimer_Tick(object sender, EventArgs e) + { + _blinkState = !_blinkState; + this.BeginInvoke(new Action(() => this.Invalidate())); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + Graphics g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + + Color currentColor; + + if (_isBlinking) + { + currentColor = _blinkState ? _blinkColor : (_isOn ? _onColor : _offColor); + } + else + { + currentColor = _isOn ? _onColor : _offColor; + } + + using (GraphicsPath path = CreateRoundedRectangle(ClientRectangle, _cornerRadius)) + using (SolidBrush backBrush = new SolidBrush(currentColor)) + { + g.FillPath(backBrush, path); + } + + using (Brush textBrush = new SolidBrush(_textColor)) + { + StringFormat sf = new StringFormat(); + sf.Alignment = StringAlignment.Center; + sf.LineAlignment = StringAlignment.Center; + g.DrawString(_statusText, Font, textBrush, ClientRectangle, sf); + } + } + + private GraphicsPath CreateRoundedRectangle(Rectangle bounds, int radius) + { + int diameter = radius * 2; + Size size = new Size(diameter, diameter); + Rectangle arc = new Rectangle(bounds.Location, size); + GraphicsPath path = new GraphicsPath(); + + if (radius == 0) + { + path.AddRectangle(bounds); + return path; + } + + // 左上角 + path.AddArc(arc, 180, 90); + + // 右上角 + arc.X = bounds.Right - diameter; + path.AddArc(arc, 270, 90); + + // 右下角 + arc.Y = bounds.Bottom - diameter; + path.AddArc(arc, 0, 90); + + // 左下角 + arc.X = bounds.Left; + path.AddArc(arc, 90, 90); + + path.CloseFigure(); + return path; + } + + + } +} + diff --git a/JinYuan.ControlLib/UCLedAvatar.Designer.cs b/JinYuan.ControlLib/UCLedAvatar.Designer.cs new file mode 100644 index 0000000..6f3ca30 --- /dev/null +++ b/JinYuan.ControlLib/UCLedAvatar.Designer.cs @@ -0,0 +1,49 @@ +using System.Drawing; + +namespace Controls +{ + partial class UCLedAvatar + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_blinkTimer != null) + { + _blinkTimer.Stop(); + _blinkTimer.Dispose(); + _blinkTimer = null; + } + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Size = new Size(32, 32); + this.ResumeLayout(false); + } + + + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCLedAvatar.cs b/JinYuan.ControlLib/UCLedAvatar.cs new file mode 100644 index 0000000..b3e0f27 --- /dev/null +++ b/JinYuan.ControlLib/UCLedAvatar.cs @@ -0,0 +1,149 @@ +using AntdUI; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace Controls +{ + public enum LedStatus + { + Default, // 默认状态(灰色) + Running, // 运行状态(绿色) + Idle, // 闲置状态(橙色) + Alarm // 报警状态(红色) + } + + + [ToolboxItem(true)] + [Description("一个用于显示通信状态的LED指示器控件")] + public partial class UCLedAvatar : UserControl + { + private Avatar avatar; + private LedStatus _status = LedStatus.Default; + private bool _isBlinking = false; + private bool _blinkState = false; + private System.Windows.Forms.Timer _blinkTimer; + + // 定义状态对应的颜色 + private static readonly Dictionary StatusColors = new Dictionary + { + { LedStatus.Default, Color.FromArgb(128, 128, 128) }, // 灰色 + { LedStatus.Running, Color.FromArgb(16, 192, 101) }, // 绿色 #10c065 + { LedStatus.Idle, Color.FromArgb(255, 147, 0) }, // 橙色 #ff9300 + { LedStatus.Alarm, Color.FromArgb(241, 11, 18) } // 红色 #f10b12 + }; + + // SVG 模板 + private const string SVG_TEMPLATE = @" + + "; + + public UCLedAvatar() + { + InitializeComponent(); + InitializeAvatar(); + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.BackColor = Color.Transparent; + } + + + private void InitializeAvatar() + { + avatar = new Avatar + { + Dock = DockStyle.Fill, + Round = false, + ImageSvg = string.Format(SVG_TEMPLATE, ColorTranslator.ToHtml(StatusColors[LedStatus.Default])) + }; + + this.Controls.Add(avatar); + InitializeTimer(); + } + + private void InitializeTimer() + { + _blinkTimer = new System.Windows.Forms.Timer(); + _blinkTimer.Tick += BlinkTimer_Tick; + _blinkTimer.Interval = 500; // 默认闪烁间隔 + } + + [Category("行为")] + [DefaultValue(LedStatus.Default)] + public LedStatus Status + { + get => _status; + set + { + if (_status != value) + { + _status = value; + UpdateLedState(); + } + } + } + + [Category("行为")] + [DefaultValue(false)] + public bool IsBlinking + { + get => _isBlinking; + set + { + if (_isBlinking != value) + { + _isBlinking = value; + if (_isBlinking) + { + _blinkTimer.Start(); + } + else + { + _blinkTimer.Stop(); + _blinkState = false; + UpdateLedState(); + } + } + } + } + + [Category("行为")] + [DefaultValue(500)] + public int BlinkInterval + { + get => _blinkTimer.Interval; + set + { + if (value > 0 && _blinkTimer.Interval != value) + { + _blinkTimer.Interval = value; + } + } + } + + private void BlinkTimer_Tick(object sender, EventArgs e) + { + _blinkState = !_blinkState; + UpdateLedState(); + } + + private void UpdateLedState() + { + Color currentColor; + if (_status == LedStatus.Alarm && _isBlinking) + { + // 报警状态下的闪烁在灰色和红色之间切换 + currentColor = _blinkState ? StatusColors[LedStatus.Alarm] : StatusColors[LedStatus.Default]; + } + else + { + // 非报警状态不闪烁 + currentColor = StatusColors[_status]; + } + + avatar.ImageSvg = string.Format(SVG_TEMPLATE, ColorTranslator.ToHtml(currentColor)); + } + + } +} diff --git a/JinYuan.ControlLib/UCRollText.Designer.cs b/JinYuan.ControlLib/UCRollText.Designer.cs new file mode 100644 index 0000000..ee15197 --- /dev/null +++ b/JinYuan.ControlLib/UCRollText.Designer.cs @@ -0,0 +1,39 @@ +namespace JinYuan.ControlLib +{ + partial class UCRollText + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + StopAnimation(); + components.Dispose(); + } + base.Dispose(disposing); + } + + + #region 组件设计器生成的代码 + + ///// + ///// 设计器支持所需的方法 - 不要修改 + ///// 使用代码编辑器修改此方法的内容。 + ///// + //private void InitializeComponent() + //{ + // components = new System.ComponentModel.Container(); + // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + //} + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCRollText.cs b/JinYuan.ControlLib/UCRollText.cs new file mode 100644 index 0000000..15a2eaa --- /dev/null +++ b/JinYuan.ControlLib/UCRollText.cs @@ -0,0 +1,321 @@ +using AntdUI; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Text; +using System.Runtime.CompilerServices; +using System.Windows.Forms; + + +namespace JinYuan.ControlLib +{ + public partial class UCRollText : UserControl + { + private Rectangle _textRect; // 文字绘制矩形 + private int _moveDirection = 1; // 移动方向 + private const int MIN_MOVE_PIXELS = 1; + private const int DEFAULT_MOVE_STEP = 2; // 减小步长,使滚动更平滑 + private const int MIN_INTERVAL = 80; // 最小间隔 16ms ≈ 60fps + + private Timer _timer; + private long _lastTickTime; + private bool _isAnimating = false; // 用于标记是否有异步操作正在执行,避免并发问题 + private string _lastText = ""; // 缓存上次文本,避免重复测量 + private Size _textSize; // 缓存文本尺寸 + + #region Properties + + public override Font Font + { + get => base.Font; + set + { + base.Font = value; + _textSize = Size.Empty; // 字体改变,需要重新测量 + UpdateTextRect(); + } + } + + public override string Text + { + get => base.Text; + set + { + if (base.Text != value) + { + base.Text = value; + _lastText = value; + _textSize = Size.Empty; // 文本改变,需要重新测量 + UpdateTextRect(); + if (_isChangeReset) ResetTextPosition(); + } + } + } + + private RollStyle _rollStyle = RollStyle.LeftToRight; + public RollStyle RollStyle + { + get => _rollStyle; + set + { + if (_rollStyle != value) + { + _rollStyle = value; + _moveDirection = value == RollStyle.RightToLeft ? -1 : 1; + ResetTextPosition(); + } + } + } + + private bool _isChangeReset = true; + [Description("文本改变是否重新从边缘运动"), Category("自定义")] + public bool IsChangeReset + { + get => _isChangeReset; + set => _isChangeReset = value; + } + + private bool _isExit; + [Description("是否退出"), Category("自定义")] + public bool IsExit + { + get => _isExit; + set + { + _isExit = value; + if (value) StopAnimation(); + } + } + + private int _moveInterval = MIN_INTERVAL; + [Description("每次滚动间隔时间,越小速度越快"), Category("自定义")] + public int MoveInterval + { + get => _moveInterval; + set + { + _moveInterval = Math.Max(value, MIN_INTERVAL); + if (_timer != null) + { + _timer.Interval = _moveInterval; + } + } + } + + #endregion + + public UCRollText() + { + InitializeControl(); + StartAnimation(); + } + + private void InitializeControl() + { + // 高性能绘制样式 + SetStyle(ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer | + ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.SupportsTransparentBackColor, true); + DoubleBuffered = true; + + Size = new Size(450, 30); + Text = "滚动文字"; + ForeColor = Color.FromArgb(255, 77, 59); + } + + private void StartAnimation() + { + if (_isAnimating || _timer != null) return; + + _isAnimating = true; + _lastTickTime = Stopwatch.GetTimestamp(); + + _timer = new Timer(); + _timer.Interval = _moveInterval; + _timer.Tick += Timer_Tick; + _timer.Start(); + } + + private void Timer_Tick(object sender, EventArgs e) + { + if (!_isAnimating || !Visible || this.IsDisposed) return; + + try + { + long now = Stopwatch.GetTimestamp(); + long elapsedMs = (now - _lastTickTime) * 1000 / Stopwatch.Frequency; + _lastTickTime = now; + + // 根据经过的时间计算平滑步长 + int step = (int)(DEFAULT_MOVE_STEP * (elapsedMs / (float)_moveInterval)); + if (step < 1) step = 1; + + UpdateTextPosition(step); + + //// 调试输出(发布时可注释) + //Console.WriteLine($"UCRollText Tick elapsed={elapsedMs}ms"); + } + catch { } + } + + private void StopAnimation() + { + _isAnimating = false; + if (_timer != null) + { + _timer.Stop(); + _timer.Dispose(); + _timer = null; + } + } + + private void UpdateTextPosition(int step) + { + if (_textRect.IsEmpty) return; + + // 只有在BackAndForth模式下才检查文字宽度 + if (_rollStyle == RollStyle.BackAndForth && _textRect.Width >= Width) return; + + int oldX = _textRect.X; + + // 更新位置 + _textRect.X += step * _moveDirection; + + // 边界处理 + switch (_rollStyle) + { + case RollStyle.BackAndForth: + if (_textRect.X <= 0) + _moveDirection = 1; + else if (_textRect.Right >= Width) + _moveDirection = -1; + break; + + case RollStyle.LeftToRight: + if (_textRect.X > Width) + _textRect.X = -_textRect.Width - 1; + break; + + case RollStyle.RightToLeft: + if (_textRect.Right < 0) + _textRect.X = Width; + break; + } + + // 只有位置变化才重绘 + if (Math.Abs(_textRect.X - oldX) >= MIN_MOVE_PIXELS) + { + if (IsHandleCreated && !IsDisposed && Visible) + { + Invalidate(); + } + } + } + + private void UpdateTextRect() + { + if (string.IsNullOrEmpty(Text)) + { + _textRect = Rectangle.Empty; + return; + } + + // 只有在文本或字体改变时才重新测量 + if (_textSize.IsEmpty || Text != _lastText) + { + _textSize = TextRenderer.MeasureText(Text, Font); + _lastText = Text; + } + + _textRect = new Rectangle( + _isChangeReset ? 0 : _textRect.X, + (Height - _textSize.Height) / 2, + _textSize.Width, + _textSize.Height + ); + + if (IsHandleCreated && Visible) + Invalidate(); + } + + private void ResetTextPosition() + { + if (_textRect.IsEmpty) return; + + switch (_rollStyle) + { + case RollStyle.LeftToRight: + _textRect.X = -_textRect.Width - 1; + break; + case RollStyle.RightToLeft: + _textRect.X = Width; + break; + default: + _textRect.X = 0; + break; + } + + if (IsHandleCreated && Visible) + Invalidate(); + } + + protected override void OnPaint(PaintEventArgs e) + { + // 禁用基类绘制,减少绘制层次 + // base.OnPaint(e); + if (!_textRect.IsEmpty && !string.IsNullOrEmpty(Text) && Visible) + { + // 使用TextRenderer的优化方法,指定文本格式 + TextRenderer.DrawText(e.Graphics, Text, Font, _textRect, ForeColor, TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.NoClipping); + } + } + + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + if (_textRect != Rectangle.Empty) + { + _textRect.Y = (Height - _textRect.Height) / 2; + Invalidate(); + } + } + + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged(e); + // 控件不可见时停止动画,节省资源 + if (Visible) + { + StartAnimation(); + } + else + { + StopAnimation(); + } + } + + protected override void OnHandleDestroyed(EventArgs e) + { + StopAnimation(); + base.OnHandleDestroyed(e); + } + + private void InitializeComponent() + { + this.SuspendLayout(); + this.Name = "UCRollText"; + this.Size = new Size(450, 30); + this.ResumeLayout(false); + } + } + + public enum RollStyle + { + LeftToRight, + RightToLeft, + BackAndForth + } +} \ No newline at end of file diff --git a/JinYuan.ControlLib/UCSplitLine_H.Designer.cs b/JinYuan.ControlLib/UCSplitLine_H.Designer.cs new file mode 100644 index 0000000..9a51258 --- /dev/null +++ b/JinYuan.ControlLib/UCSplitLine_H.Designer.cs @@ -0,0 +1,65 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class UCSplitLine_H. + /// Implements the + /// + /// + partial class UCSplitLine_H + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // UCSplitLine_H + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232))))); + this.Name = "UCSplitLine_H"; + this.Size = new System.Drawing.Size(100, 1); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCSplitLine_H.cs b/JinYuan.ControlLib/UCSplitLine_H.cs new file mode 100644 index 0000000..b6f0b31 --- /dev/null +++ b/JinYuan.ControlLib/UCSplitLine_H.cs @@ -0,0 +1,36 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCSplitLine_H. + /// Implements the + /// + /// + public partial class UCSplitLine_H : UserControl + { + /// + /// Initializes a new instance of the class. + /// + public UCSplitLine_H() + { + InitializeComponent(); + this.TabStop = false; + } + } +} diff --git a/JinYuan.ControlLib/UCSplitLine_H.resx b/JinYuan.ControlLib/UCSplitLine_H.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/UCSplitLine_H.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UCSplitLine_V.Designer.cs b/JinYuan.ControlLib/UCSplitLine_V.Designer.cs new file mode 100644 index 0000000..ddad8f5 --- /dev/null +++ b/JinYuan.ControlLib/UCSplitLine_V.Designer.cs @@ -0,0 +1,65 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +namespace JinYuan.ControlLib +{ + /// + /// Class UCSplitLine_V. + /// Implements the + /// + /// + partial class UCSplitLine_V + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // UCSplitLine_V + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232))))); + this.Name = "UCSplitLine_V"; + this.Size = new System.Drawing.Size(1, 100); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/UCSplitLine_V.cs b/JinYuan.ControlLib/UCSplitLine_V.cs new file mode 100644 index 0000000..bdcb6b1 --- /dev/null +++ b/JinYuan.ControlLib/UCSplitLine_V.cs @@ -0,0 +1,36 @@ +// *********************************************************************** +// Assembly : JinYuan.ControlLib +// Created : 08-08-2019 +// +// *********************************************************************** +// +// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com +// +// +// Blog: https://www.cnblogs.com/bfyx +// GitHub:https://github.com/kwwwvagaa/NetWinformControl +// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git +// +// If you use this code, please keep this note. +// *********************************************************************** +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + /// + /// Class UCSplitLine_V. + /// Implements the + /// + /// + public partial class UCSplitLine_V : UserControl + { + /// + /// Initializes a new instance of the class. + /// + public UCSplitLine_V() + { + InitializeComponent(); + this.TabStop = false; + } + } +} diff --git a/JinYuan.ControlLib/UCSplitLine_V.resx b/JinYuan.ControlLib/UCSplitLine_V.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/UCSplitLine_V.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UpDownLabel.Designer.cs b/JinYuan.ControlLib/UpDownLabel.Designer.cs new file mode 100644 index 0000000..84d33cd --- /dev/null +++ b/JinYuan.ControlLib/UpDownLabel.Designer.cs @@ -0,0 +1,101 @@ +namespace JinYuan.ControlLib +{ + partial class UpDownLabel + { + /// + /// ±ØÐèµÄÉè¼ÆÆ÷±äÁ¿¡£ + /// + private System.ComponentModel.IContainer components = null; + + /// + /// ÇåÀíËùÓÐÕýÔÚʹÓõÄ×ÊԴ¡£ + /// + /// Èç¹ûӦÊͷÅÍйÜ×ÊԴ£¬Ϊ true£»·ñÔòΪ false¡£ + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region ×é¼þÉè¼ÆÆ÷Éú³ɵĴúÂë + + /// + /// Éè¼ÆÆ÷֧³ÖËùÐèµķ½·¨ - ²»ҪÐ޸Ä + /// ʹÓôúÂë±༭Æ÷Ð޸Ĵ˷½·¨µÄÄÚÈݡ£ + /// + private void InitializeComponent() + { + this.btn_Dec = new System.Windows.Forms.Button(); + this.btn_Add = new System.Windows.Forms.Button(); + this.lbl_Data = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // btn_Dec + // + this.btn_Dec.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(27)))), ((int)(((byte)(161)))), ((int)(((byte)(226))))); + this.btn_Dec.Dock = System.Windows.Forms.DockStyle.Left; + this.btn_Dec.FlatAppearance.BorderSize = 0; + this.btn_Dec.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Dec.Font = new System.Drawing.Font("΢ÈíÑźÚ", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Dec.ForeColor = System.Drawing.Color.White; + this.btn_Dec.Location = new System.Drawing.Point(0, 0); + this.btn_Dec.Name = "btn_Dec"; + this.btn_Dec.Size = new System.Drawing.Size(37, 37); + this.btn_Dec.TabIndex = 0; + this.btn_Dec.Text = "-"; + this.btn_Dec.UseVisualStyleBackColor = false; + this.btn_Dec.Click += new System.EventHandler(this.btn_Dec_Click); + // + // btn_Add + // + this.btn_Add.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(27)))), ((int)(((byte)(161)))), ((int)(((byte)(226))))); + this.btn_Add.Dock = System.Windows.Forms.DockStyle.Right; + this.btn_Add.FlatAppearance.BorderSize = 0; + this.btn_Add.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Add.Font = new System.Drawing.Font("΢ÈíÑźÚ", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Add.ForeColor = System.Drawing.Color.White; + this.btn_Add.Location = new System.Drawing.Point(89, 0); + this.btn_Add.Name = "btn_Add"; + this.btn_Add.Size = new System.Drawing.Size(37, 37); + this.btn_Add.TabIndex = 1; + this.btn_Add.Text = "+"; + this.btn_Add.UseVisualStyleBackColor = false; + this.btn_Add.Click += new System.EventHandler(this.btn_Add_Click); + // + // lbl_Data + // + this.lbl_Data.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Data.Location = new System.Drawing.Point(37, 0); + this.lbl_Data.Margin = new System.Windows.Forms.Padding(3); + this.lbl_Data.Name = "lbl_Data"; + this.lbl_Data.Size = new System.Drawing.Size(52, 37); + this.lbl_Data.TabIndex = 2; + this.lbl_Data.Text = "0"; + this.lbl_Data.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // UpDownLabel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(243)))), ((int)(((byte)(255))))); + this.Controls.Add(this.lbl_Data); + this.Controls.Add(this.btn_Add); + this.Controls.Add(this.btn_Dec); + this.Font = new System.Drawing.Font("΢ÈíÑźÚ", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(0); + this.Name = "UpDownLabel"; + this.Size = new System.Drawing.Size(126, 37); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button btn_Dec; + private System.Windows.Forms.Button btn_Add; + private System.Windows.Forms.Label lbl_Data; + } +} diff --git a/JinYuan.ControlLib/UpDownLabel.cs b/JinYuan.ControlLib/UpDownLabel.cs new file mode 100644 index 0000000..00eebd0 --- /dev/null +++ b/JinYuan.ControlLib/UpDownLabel.cs @@ -0,0 +1,157 @@ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [DefaultEvent("ValueChanged")] + public partial class UpDownLabel : UserControl + { + public UpDownLabel() + { + InitializeComponent(); + } + + private Color themeColor = Color.FromArgb(27, 161, 226); + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡÖ÷ÌâÑÕɫ")] + public Color ThemeColor + { + get { return themeColor; } + set + { + themeColor = value; + + this.btn_Add.BackColor = themeColor; + this.btn_Dec.BackColor = themeColor; + } + } + + + + private Color themeForeColor = Color.White; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡÖ÷Ìâǰ¾°ɫ")] + public Color ThemeForeColor + { + get { return themeForeColor; } + set + { + themeForeColor = value; + + this.btn_Add.ForeColor = themeForeColor; + this.btn_Dec.ForeColor = themeForeColor; + } + } + + + + private int textWidth = 52; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡÎı¾¿òµĿí¶È")] + public int TextWidth + { + get { return textWidth; } + set + { + textWidth = value; + + this.btn_Add.Width = (this.Width - this.textWidth) / 2; + this.btn_Dec.Width = (this.Width - this.textWidth) / 2; + } + } + + + private float maxValue = 1000.0f; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡ×î´óֵ")] + public float MaxValue + { + get { return maxValue; } + set + { + maxValue = value; + } + } + + + private float minValue = -1000.0f; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡ×îСֵ")] + public float MinValue + { + get { return minValue; } + set + { + minValue = value; + } + } + + private float stepValue = 1.0f; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡ²½½øֵ")] + public float StepValue + { + get { return stepValue; } + set + { + stepValue = value; + } + } + + + private float currentValue = 0.0f; + [Browsable(true)] + [Category("×Զ¨ÒåÊôÐÔ")] + [Description("ÉèÖûò»ñȡµ±ǰֵ")] + public float CurrentValue + { + get { return currentValue; } + set + { + if (value > maxValue) + { + return; + } + + if (value < minValue) + { + return; + } + + if (currentValue == value) + { + return; + } + + currentValue = value; + + ValueChanged?.Invoke(this, null); + + this.lbl_Data.Text = currentValue.ToString(); + } + } + + private void btn_Dec_Click(object sender, EventArgs e) + { + CurrentValue -= stepValue; + } + + private void btn_Add_Click(object sender, EventArgs e) + { + CurrentValue += stepValue; + } + [Browsable(true)] + [Category("×Զ¨Òåʼþ")] + [Description("µ±ǰÊýֵ·¢Éú±仯´¥·¢")] + public event EventHandler ValueChanged; + } +} diff --git a/JinYuan.ControlLib/UpDownLabel.resx b/JinYuan.ControlLib/UpDownLabel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/UpDownLabel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/UserStateChangedEvent.cs b/JinYuan.ControlLib/UserStateChangedEvent.cs new file mode 100644 index 0000000..c2e49f6 --- /dev/null +++ b/JinYuan.ControlLib/UserStateChangedEvent.cs @@ -0,0 +1,24 @@ +using System; + +namespace JinYuan.ControlLib +{ + public delegate void UserStateChangedEventHandler( + object sender, + UserStateChangedEventArgs e); + + public class UserStateChangedEventArgs : EventArgs + { + private bool _active; + + public UserStateChangedEventArgs(bool active) + : base() + { + _active = active; + } + + public bool Active + { + get { return _active; } + } + } +} diff --git a/JinYuan.ControlLib/UserStateMonitor.cs b/JinYuan.ControlLib/UserStateMonitor.cs new file mode 100644 index 0000000..99bcca2 --- /dev/null +++ b/JinYuan.ControlLib/UserStateMonitor.cs @@ -0,0 +1,174 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Threading; + +namespace JinYuan.ControlLib +{ + /// + /// 监视鼠标键盘操作。 + /// + public class UserStateMonitor : Component + { + //通过 Interval 属性调节扫描键盘鼠标状态的间隔时间,通过 Timeout 属性(无键盘操作时间间隔)控制判断是否离开 + + /// + /// 离开时间,单位:秒 + /// + private int _timeout = 5000; + private int _lastActiveTick; + private Timer _timer; + private int _interval = 1000; + private bool _started; + private bool _active = true; + + private static readonly object EventUseStateChanged = new object(); + + public UserStateMonitor() + : base() + { + } + + public UserStateMonitor(IContainer container) + : base() + { + container.Add(this); + } + + public event UserStateChangedEventHandler UserStateChanged + { + add { base.Events.AddHandler(EventUseStateChanged, value); } + remove { base.Events.RemoveHandler(EventUseStateChanged, value); } + } + + /// + /// 默认值:30分钟 + /// + [DefaultValue(1800000)] + public int Timeout + { + get { return _timeout; } + set + { + _timeout = Math.Max(5000, value); + } + } + + [DefaultValue(1000)] + public int Interval + { + get { return _interval; } + set + { + _interval = Math.Max(500, value); + if (_started) + { + Timer.Change(0, _interval); + } + else + { + Timer.Change(System.Threading.Timeout.Infinite, _interval); + } + } + } + + private Timer Timer + { + get + { + if (_timer == null) + { + _timer = new Timer( + new TimerCallback(delegate (object obj) + { + LASTINPUTINFO lii = new LASTINPUTINFO(); + lii.size = 8; + + if (GetLastInputInfo(ref lii)) + { + _lastActiveTick = Math.Max(lii.lastTick, _lastActiveTick); + bool active = Environment.TickCount - _lastActiveTick < _timeout; + if (_active != active) + { + _active = active; + OnUserStateChanged(new UserStateChangedEventArgs(active)); + } + } + }), + null, + System.Threading.Timeout.Infinite, + _interval); + } + return _timer; + } + } + + public void Start() + { + if (!_started) + { + Timer.Change(_interval, _interval); + _started = true; + } + } + + /// + /// 开始监控 + /// + /// 监控时间间隔,单位:分钟 + public void Start(int timeOut) + { + if (!_started) + { + + _timeout = timeOut * 1000;//转换成秒 + + Timer.Change(_interval, _interval); + _started = true; + } + } + + public void Stop() + { + if (_started) + { + Timer.Change(System.Threading.Timeout.Infinite, _interval); + _started = false; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct LASTINPUTINFO + { + public int size; + public int lastTick; + } + + [DllImport("user32.dll")] + private static extern bool GetLastInputInfo(ref LASTINPUTINFO lii); + + protected virtual void OnUserStateChanged(UserStateChangedEventArgs e) + { + UserStateChangedEventHandler handler = + base.Events[EventUseStateChanged] as UserStateChangedEventHandler; + if (handler != null) + { + handler(this, e); + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + Stop(); + if (_timer != null) + { + _timer.Dispose(); + _timer = null; + } + } + } + } +} diff --git a/JinYuan.ControlLib/Wave.Designer.cs b/JinYuan.ControlLib/Wave.Designer.cs new file mode 100644 index 0000000..06bdcf1 --- /dev/null +++ b/JinYuan.ControlLib/Wave.Designer.cs @@ -0,0 +1,36 @@ +namespace JinYuan.ControlLib +{ + partial class Wave + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/JinYuan.ControlLib/Wave.cs b/JinYuan.ControlLib/Wave.cs new file mode 100644 index 0000000..d5f7a7a --- /dev/null +++ b/JinYuan.ControlLib/Wave.cs @@ -0,0 +1,294 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class Wave : Control + { + /// + /// Occurs when [on painted]. + /// + public event PaintEventHandler OnPainted; + + /// + /// The m wave color + /// + private Color m_waveColor = Color.FromArgb(255, 77, 59); + + /// + /// Gets or sets the color of the wave. + /// + /// The color of the wave. + [Description("波纹颜色"), Category("自定义")] + public Color WaveColor + { + get { return m_waveColor; } + set + { + m_waveColor = value; + this.Invalidate(); + } + } + + /// + /// The m wave width + /// + private int m_waveWidth = 200; + /// + /// 为方便计算,强制使用10的倍数 + /// + /// The width of the wave. + [Description("波纹宽度(为方便计算,强制使用10的倍数)"), Category("自定义")] + public int WaveWidth + { + get { return m_waveWidth; } + set + { + m_waveWidth = value; + m_waveWidth = m_waveWidth / 10 * 10; + intLeftX = value * -1; + this.Invalidate(); + } + } + + /// + /// The m wave height + /// + private int m_waveHeight = 30; + /// + /// 波高 + /// + /// The height of the wave. + [Description("波高"), Category("自定义")] + public int WaveHeight + { + get { return m_waveHeight; } + set + { + m_waveHeight = value; + this.Invalidate(); + } + } + + /// + /// The m wave sleep + /// + private int m_waveSleep = 50; + /// + /// 波运行速度(运行时间间隔,毫秒) + /// + /// The wave sleep. + [Description("波运行速度(运行时间间隔,毫秒)"), Category("自定义")] + public int WaveSleep + { + get { return m_waveSleep; } + set + { + if (value <= 0) + return; + m_waveSleep = value; + if (timer != null) + { + timer.Enabled = false; + timer.Interval = value; + timer.Enabled = true; + } + } + } + private int m_bubbleSpeed = 0; + /// + /// 气泡速度(0表示不启用) + /// + /// The wave sleep. + [Description("气泡速度(0表示不启用)"), Category("自定义")] + public int BubbleSpeed + { + get { return m_bubbleSpeed; } + set + { + m_bubbleSpeed = value; + this.Invalidate(); + } + } + + private int m_bubbleIntervalTime = 500; + /// + /// 气泡生成间隔时间(毫秒,不准确,根据波运行速度判断) + /// + /// The wave sleep. + [Description("气泡生成间隔时间(毫秒,不准确,根据波运行速度判断)"), Category("自定义")] + public int BubbleIntervalTime + { + get { return m_bubbleIntervalTime; } + set + { + m_bubbleIntervalTime = value; + this.Invalidate(); + } + } + /// + /// 上次生成气泡的时间 + /// + private int lastBubbleTime = 0; + /// + /// 气泡列表 + /// + private List m_lstBubble = new List(); + /// + /// The timer + /// + Timer timer = new Timer(); + /// + /// The int left x + /// + int intLeftX = -200; + /// + /// Initializes a new instance of the class. + /// + public Wave() + { + this.Size = new Size(600, 100); + ////设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + timer.Interval = m_waveSleep; + timer.Tick += timer_Tick; + this.VisibleChanged += UCWave_VisibleChanged; + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + /// + /// Handles the VisibleChanged event of the UCWave control. + /// + /// The source of the event. + /// The instance containing the event data. + void UCWave_VisibleChanged(object sender, EventArgs e) + { + timer.Enabled = this.Visible; + } + + /// + /// Handles the Tick event of the timer control. + /// + /// The source of the event. + /// The instance containing the event data. + void timer_Tick(object sender, EventArgs e) + { + intLeftX -= 10; + if (intLeftX == m_waveWidth * -2) + intLeftX = m_waveWidth * -1; + + if (m_bubbleSpeed > 0) + { + lastBubbleTime += m_waveSleep; + if (lastBubbleTime >= m_bubbleIntervalTime) + { + lastBubbleTime = 0; + var r = new Random(DateTime.Now.Millisecond); + var b_x = r.Next(0, this.Width); + var b = new Bubble(); + b.Key = Guid.NewGuid().ToString(); + b.BubblePoint = new Point(b_x, 0); + b.BubbleWidth = 5; + m_lstBubble.Add(b); + } + } + else + { + m_lstBubble.Clear(); + } + this.Invalidate(); + } + /// + /// Handles the event. + /// + /// The instance containing the event data. + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + var g = e.Graphics; + g.SetGDIHigh(); + List lst1 = new List(); + List lst2 = new List(); + int m_intX = intLeftX; + while (true) + { + lst1.Add(new Point(m_intX, 1)); + lst1.Add(new Point(m_intX + m_waveWidth / 2, m_waveHeight)); + + lst2.Add(new Point(m_intX + m_waveWidth / 2, 1)); + lst2.Add(new Point(m_intX + m_waveWidth / 2 + m_waveWidth / 2, m_waveHeight)); + m_intX += m_waveWidth; + if (m_intX > this.Width + m_waveWidth) + break; + } + + GraphicsPath path1 = new GraphicsPath(); + path1.AddCurve(lst1.ToArray(), 0.5F); + path1.AddLine(this.Width + 1, -1, this.Width + 1, this.Height); + path1.AddLine(this.Width + 1, this.Height, -1, this.Height); + path1.AddLine(-1, this.Height, -1, -1); + + GraphicsPath path2 = new GraphicsPath(); + path2.AddCurve(lst2.ToArray(), 0.5F); + path2.AddLine(this.Width + 1, -1, this.Width + 1, this.Height); + path2.AddLine(this.Width + 1, this.Height, -1, this.Height); + path2.AddLine(-1, this.Height, -1, -1); + + g.FillPath(new SolidBrush(Color.FromArgb(220, m_waveColor.R, m_waveColor.G, m_waveColor.B)), path1); + g.FillPath(new SolidBrush(Color.FromArgb(220, m_waveColor.R, m_waveColor.G, m_waveColor.B)), path2); + //气泡 + foreach (var item in m_lstBubble) + { + GraphicsPath gp = new GraphicsPath(); + Rectangle rec = new Rectangle(item.BubblePoint.X - item.BubbleWidth / 2, this.Height - (item.BubblePoint.Y - item.BubbleWidth / 2), item.BubbleWidth / 3 * 2, item.BubbleWidth / 3 * 2); + gp.AddEllipse(rec); + + Color[] surroundColor = new Color[] { Color.FromArgb(50, Color.White) }; + PathGradientBrush pb = new PathGradientBrush(gp); + pb.CenterColor = Color.FromArgb(150, Color.White); + pb.SurroundColors = surroundColor; + g.FillPath(pb, gp); + + item.BubblePoint = new Point(item.BubblePoint.X, item.BubblePoint.Y + m_bubbleSpeed); + item.BubbleWidth += 1; + } + + if (OnPainted != null) + { + OnPainted(this, e); + } + } + internal class Bubble + { + internal string Key { get; set; } + /// + /// 坐标 + /// + internal Point BubblePoint { get; set; } + /// + /// 宽度 + /// + internal int BubbleWidth { get; set; } + } + } +} diff --git a/JinYuan.ControlLib/WaveProcess.Designer.cs b/JinYuan.ControlLib/WaveProcess.Designer.cs new file mode 100644 index 0000000..9e9fdf0 --- /dev/null +++ b/JinYuan.ControlLib/WaveProcess.Designer.cs @@ -0,0 +1,65 @@ +namespace JinYuan.ControlLib +{ + partial class WaveProcess + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.wave1 = new JinYuan.ControlLib.Wave(); + this.SuspendLayout(); + // + // wave1 + // + this.wave1.BubbleIntervalTime = 500; + this.wave1.BubbleSpeed = 0; + this.wave1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.wave1.Location = new System.Drawing.Point(0, 84); + this.wave1.Name = "wave1"; + this.wave1.Size = new System.Drawing.Size(116, 22); + this.wave1.TabIndex = 0; + this.wave1.Text = "wave1"; + this.wave1.WaveColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192))))); + this.wave1.WaveHeight = 30; + this.wave1.WaveSleep = 50; + this.wave1.WaveWidth = 200; + // + // WaveProcess + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Gainsboro; + this.Controls.Add(this.wave1); + this.Name = "WaveProcess"; + this.Size = new System.Drawing.Size(116, 106); + this.ResumeLayout(false); + + } + + #endregion + + private Wave wave1; + } +} diff --git a/JinYuan.ControlLib/WaveProcess.cs b/JinYuan.ControlLib/WaveProcess.cs new file mode 100644 index 0000000..9177454 --- /dev/null +++ b/JinYuan.ControlLib/WaveProcess.cs @@ -0,0 +1,346 @@ +using JinYuan.ControlLib.UCHelper; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class WaveProcess : ControlBase + { + /// + /// The m is rectangle + /// + private bool m_isRectangle = false; + /// + /// Gets or sets a value indicating whether this instance is rectangle. + /// + /// true if this instance is rectangle; otherwise, false. + [Description("是否矩形"), Category("自定义")] + public bool IsRectangle + { + get { return m_isRectangle; } + set + { + m_isRectangle = value; + if (value) + { + base.ConerRadius = 10; + } + else + { + base.ConerRadius = Math.Min(this.Width, this.Height); + } + this.Invalidate(); + } + } + + #region 不再使用的父类属性 English:Parent class attributes that are no longer used + /// + /// 圆角角度 + /// + /// The coner radius. + [Browsable(false)] + public new int ConerRadius + { + get; + set; + } + /// + /// 是否圆角 + /// + /// true if this instance is radius; otherwise, false. + [Browsable(false)] + public new bool IsRadius + { + get; + set; + } + + /// + /// 当使用边框时填充颜色,当值为背景色或透明色或空值则不填充 + /// + /// The color of the fill. + [Browsable(false)] + public new Color FillColor + { + get; + set; + } + #endregion + + + /// + /// Occurs when [value changed]. + /// + [Description("值变更事件"), Category("自定义")] + public event EventHandler ValueChanged; + /// + /// The m value + /// + int m_value = 0; + /// + /// Gets or sets the value. + /// + /// The value. + [Description("当前属性"), Category("自定义")] + public int Value + { + set + { + if (value > m_maxValue) + m_value = m_maxValue; + else if (value < 0) + m_value = 0; + else + m_value = value; + if (ValueChanged != null) + ValueChanged(this, null); + wave1.Height = (int)((double)m_value / (double)m_maxValue * this.Height) + wave1.WaveHeight; + this.Invalidate(); + } + get + { + return m_value; + } + } + + /// + /// The m maximum value + /// + private int m_maxValue = 100; + + /// + /// Gets or sets the maximum value. + /// + /// The maximum value. + [Description("最大值"), Category("自定义")] + public int MaxValue + { + get { return m_maxValue; } + set + { + if (value < m_value) + m_maxValue = m_value; + else + m_maxValue = value; + this.Invalidate(); + } + } + + /// + /// 获取或设置控件显示的文字的字体。 + /// + public override Font Font + { + get + { + return base.Font; + } + set + { + base.Font = value; + this.Invalidate(); + } + } + + /// + /// 获取或设置控件的前景色。 + /// + + public override Color ForeColor + { + get + { + return base.ForeColor; + } + set + { + base.ForeColor = value; + this.Invalidate(); + } + } + + /// + /// Gets or sets the color of the value. + /// + + [Description("值颜色"), Category("自定义")] + public Color WaveColor + { + get { return this.wave1.WaveColor; } + set + { + this.wave1.WaveColor = value; + //this.Refresh(); + } + } + + /// + /// 边框宽度 + /// + + [Description("边框宽度"), Category("自定义")] + public override int RectWidth + { + get + { + return base.RectWidth; + } + set + { + if (value < 4) + base.RectWidth = 4; + else + base.RectWidth = value; + this.Invalidate(); + } + } + /// + /// 气泡速度(0表示不启用) + /// + + [Description("气泡速度(0表示不启用)"), Category("自定义")] + public int BubbleSpeed + { + get { return this.wave1.BubbleSpeed; } + set + { + this.wave1.BubbleSpeed = value; + //this.Invalidate(); + } + } + + /// + /// 气泡生成间隔时间(毫秒,不准确,根据波运行速度判断) + /// + + [Description("气泡生成间隔时间(毫秒,不准确,根据波运行速度判断)"), Category("自定义")] + public int BubbleIntervalTime + { + get { return this.wave1.BubbleIntervalTime; } + set + { + this.wave1.BubbleIntervalTime = value; + this.Invalidate(); + } + } + + + /// + /// Initializes a new instance of the class. + /// + public WaveProcess() + { + InitializeComponent(); + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + + base.IsRadius = true; + base.IsShowRect = false; + RectWidth = 4; + RectColor = Color.White; + ForeColor = Color.White; + wave1.Height = (int)((double)m_value / (double)m_maxValue * this.Height) + wave1.WaveHeight; + this.SizeChanged += ProcessWave_SizeChanged; + this.wave1.OnPainted += wave1_Painted; + base.ConerRadius = Math.Min(this.Width, this.Height); + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + + /// + /// Handles the Painted event of the wave1 control. + /// + /// The source of the event. + /// The instance containing the event data. + private void wave1_Painted(object sender, PaintEventArgs e) + { + e.Graphics.SetGDIHigh(); + if (IsShowRect) + { + if (m_isRectangle) + { + Color rectColor = RectColor; + Pen pen = new Pen(rectColor, (float)RectWidth); + Rectangle clientRectangle = new Rectangle(0, this.wave1.Height - this.Height, this.Width, this.Height); + GraphicsPath graphicsPath = new GraphicsPath(); + graphicsPath.AddArc(clientRectangle.X, clientRectangle.Y, 10, 10, 180f, 90f); + graphicsPath.AddArc(clientRectangle.Width - 10 - 1, clientRectangle.Y, 10, 10, 270f, 90f); + graphicsPath.AddArc(clientRectangle.Width - 10 - 1, clientRectangle.Bottom - 10 - 1, 10, 10, 0f, 90f); + graphicsPath.AddArc(clientRectangle.X, clientRectangle.Bottom - 10 - 1, 10, 10, 90f, 90f); + graphicsPath.CloseFigure(); + e.Graphics.DrawPath(pen, graphicsPath); + } + else + { + SolidBrush solidBrush = new SolidBrush(RectColor); + e.Graphics.DrawEllipse(new Pen(solidBrush, RectWidth), new Rectangle(0, this.wave1.Height - this.Height, this.Width, this.Height)); + } + } + + if (!m_isRectangle) + { + //这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡 + SolidBrush solidBrush1 = new SolidBrush(RectColor); + e.Graphics.DrawEllipse(new Pen(solidBrush1, 2), new Rectangle(-1, this.wave1.Height - this.Height - 1, this.Width + 2, this.Height + 2)); + } + string strValue = ((double)m_value / (double)m_maxValue).ToString("0.%"); + SizeF sizeF = e.Graphics.MeasureString(strValue, Font); + e.Graphics.DrawString(strValue, Font, new SolidBrush(ForeColor), new PointF((this.Width - sizeF.Width) / 2, (this.wave1.Height - this.Height) + (this.Height - sizeF.Height) / 2)); + } + + /// + /// Handles the SizeChanged event of the UCProcessWave control. + /// + /// The source of the event. + /// The instance containing the event data. + private void ProcessWave_SizeChanged(object sender, EventArgs e) + { + if (!m_isRectangle) + { + base.ConerRadius = Math.Min(this.Width, this.Height); + if (this.Width != this.Height) + { + this.Size = new Size(Math.Min(this.Width, this.Height), Math.Min(this.Width, this.Height)); + } + } + } + + /// + /// Handles the event. + /// + /// The instance containing the event data. + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + e.Graphics.SetGDIHigh(); + if (!m_isRectangle) + { + //这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡 + SolidBrush solidBrush = new SolidBrush(RectColor); + e.Graphics.DrawEllipse(new Pen(solidBrush, 2), new Rectangle(-1, -1, this.Width + 2, this.Height + 2)); + } + string strValue = ((double)m_value / (double)m_maxValue).ToString("0.%"); + SizeF sizeF = e.Graphics.MeasureString(strValue, Font); + e.Graphics.DrawString(strValue, Font, new SolidBrush(ForeColor), new PointF((this.Width - sizeF.Width) / 2, (this.Height - sizeF.Height) / 2 + 1)); + + } + } +} diff --git a/JinYuan.ControlLib/WaveProcess.resx b/JinYuan.ControlLib/WaveProcess.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/WaveProcess.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/WithBgBox.Designer.cs b/JinYuan.ControlLib/WithBgBox.Designer.cs new file mode 100644 index 0000000..c0b2ca1 --- /dev/null +++ b/JinYuan.ControlLib/WithBgBox.Designer.cs @@ -0,0 +1,82 @@ +namespace JinYuan.ControlLib +{ + partial class WithBgBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbl_Title = new System.Windows.Forms.Label(); + this.panel1 = new System.Windows.Forms.Panel(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // lbl_Title + // + this.lbl_Title.BackColor = System.Drawing.Color.Transparent; + this.lbl_Title.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbl_Title.Font = new System.Drawing.Font("微软雅黑", 16F, System.Drawing.FontStyle.Bold); + this.lbl_Title.ForeColor = System.Drawing.Color.Transparent; + this.lbl_Title.Location = new System.Drawing.Point(0, 0); + this.lbl_Title.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lbl_Title.Name = "lbl_Title"; + this.lbl_Title.Size = new System.Drawing.Size(827, 66); + this.lbl_Title.TabIndex = 0; + this.lbl_Title.Text = " 标题展示"; + this.lbl_Title.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.Transparent; + this.panel1.Controls.Add(this.lbl_Title); + this.panel1.Dock = System.Windows.Forms.DockStyle.Top; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(827, 66); + this.panel1.TabIndex = 1; + // + // WithBgBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 19F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(28)))), ((int)(((byte)(68))))); + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources._4; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.Controls.Add(this.panel1); + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "WithBgBox"; + this.Size = new System.Drawing.Size(827, 433); + this.panel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label lbl_Title; + } +} diff --git a/JinYuan.ControlLib/WithBgBox.cs b/JinYuan.ControlLib/WithBgBox.cs new file mode 100644 index 0000000..06f835e --- /dev/null +++ b/JinYuan.ControlLib/WithBgBox.cs @@ -0,0 +1,54 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + public partial class WithBgBox : UserControl + { + public WithBgBox() + { + InitializeComponent(); + + //设置控件样式,去除缓冲 + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.DoubleBuffer, true); + this.SetStyle(ControlStyles.ResizeRedraw, true); + this.SetStyle(ControlStyles.Selectable, true); + this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); + } + + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + private string titleName = "标题名称"; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示标题名称")] + + public string TitleName + { + get { return titleName; } + set + { + titleName = value; + this.lbl_Title.Text = titleName; + } + } + + //private void WithBgBox_Resize(object sender, EventArgs e) + //{ + // lbl_Title.Left = (ClientSize.Width - lbl_Title.Width) / 2; + // lbl_Title.Top = (ClientSize.Height - lbl_Title.Height) / 2; + //} + } +} diff --git a/JinYuan.ControlLib/WithBgBox.resx b/JinYuan.ControlLib/WithBgBox.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/WithBgBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/app.config b/JinYuan.ControlLib/app.config new file mode 100644 index 0000000..6b39d48 --- /dev/null +++ b/JinYuan.ControlLib/app.config @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JinYuan.ControlLib/packages.config b/JinYuan.ControlLib/packages.config new file mode 100644 index 0000000..3f63466 --- /dev/null +++ b/JinYuan.ControlLib/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/JinYuan.ControlLib/ucPanel_400_200.Designer.cs b/JinYuan.ControlLib/ucPanel_400_200.Designer.cs new file mode 100644 index 0000000..8b7df8b --- /dev/null +++ b/JinYuan.ControlLib/ucPanel_400_200.Designer.cs @@ -0,0 +1,82 @@ +namespace JinYuan.ControlLib +{ + partial class ucPanel_400_200 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbTitle = new System.Windows.Forms.Label(); + this.pbArrow = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pbArrow)).BeginInit(); + this.SuspendLayout(); + // + // lbTitle + // + this.lbTitle.AutoSize = true; + this.lbTitle.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbTitle.ForeColor = System.Drawing.Color.White; + this.lbTitle.Location = new System.Drawing.Point(25, 16); + this.lbTitle.Name = "lbTitle"; + this.lbTitle.Size = new System.Drawing.Size(65, 19); + this.lbTitle.TabIndex = 3; + this.lbTitle.Text = "信息标题"; + // + // pbArrow + // + this.pbArrow.Image = global::JinYuan.ControlLib.Properties.Resources.big_arrow_l; + this.pbArrow.Location = new System.Drawing.Point(98, 17); + this.pbArrow.Name = "pbArrow"; + this.pbArrow.Size = new System.Drawing.Size(21, 19); + this.pbArrow.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pbArrow.TabIndex = 2; + this.pbArrow.TabStop = false; + // + // ucPanel_400_200 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.big_box; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbTitle); + this.Controls.Add(this.pbArrow); + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "ucPanel_400_200"; + this.Size = new System.Drawing.Size(400, 200); + ((System.ComponentModel.ISupportInitialize)(this.pbArrow)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lbTitle; + private System.Windows.Forms.PictureBox pbArrow; + } +} diff --git a/JinYuan.ControlLib/ucPanel_400_200.cs b/JinYuan.ControlLib/ucPanel_400_200.cs new file mode 100644 index 0000000..6993a22 --- /dev/null +++ b/JinYuan.ControlLib/ucPanel_400_200.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] + public partial class ucPanel_400_200 : UserControl + { + public ucPanel_400_200() + { + InitializeComponent(); + } + + [Category("自定义参数")] + [DefaultValue("标题文字")] + [Description("标题文字")] + [Browsable(true)] + public string Title + { + set + { + lbTitle.Text = value; + lbTitle.Invalidate(); + pbArrow.Left = lbTitle.Right + 3; + } + get + { + return lbTitle.Text; + } + } + } +} diff --git a/JinYuan.ControlLib/ucPanel_400_200.resx b/JinYuan.ControlLib/ucPanel_400_200.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/ucPanel_400_200.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.ControlLib/ucPanel_900_450.Designer.cs b/JinYuan.ControlLib/ucPanel_900_450.Designer.cs new file mode 100644 index 0000000..f19c0f7 --- /dev/null +++ b/JinYuan.ControlLib/ucPanel_900_450.Designer.cs @@ -0,0 +1,82 @@ +namespace JinYuan.ControlLib +{ + partial class ucPanel_900_450 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.lbTitle = new System.Windows.Forms.Label(); + this.pbArrow = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pbArrow)).BeginInit(); + this.SuspendLayout(); + // + // lbTitle + // + this.lbTitle.AutoSize = true; + this.lbTitle.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbTitle.ForeColor = System.Drawing.Color.White; + this.lbTitle.Location = new System.Drawing.Point(15, 12); + this.lbTitle.Name = "lbTitle"; + this.lbTitle.Size = new System.Drawing.Size(65, 19); + this.lbTitle.TabIndex = 3; + this.lbTitle.Text = "信息标题"; + // + // pbArrow + // + this.pbArrow.Image = global::JinYuan.ControlLib.Properties.Resources.big_arrow; + this.pbArrow.Location = new System.Drawing.Point(85, 13); + this.pbArrow.Name = "pbArrow"; + this.pbArrow.Size = new System.Drawing.Size(21, 19); + this.pbArrow.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pbArrow.TabIndex = 2; + this.pbArrow.TabStop = false; + // + // ucPanel_900_450 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.BackgroundImage = global::JinYuan.ControlLib.Properties.Resources.big_box_super; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.lbTitle); + this.Controls.Add(this.pbArrow); + this.DoubleBuffered = true; + this.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "ucPanel_900_450"; + this.Size = new System.Drawing.Size(400, 200); + ((System.ComponentModel.ISupportInitialize)(this.pbArrow)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lbTitle; + private System.Windows.Forms.PictureBox pbArrow; + } +} diff --git a/JinYuan.ControlLib/ucPanel_900_450.cs b/JinYuan.ControlLib/ucPanel_900_450.cs new file mode 100644 index 0000000..f06a10b --- /dev/null +++ b/JinYuan.ControlLib/ucPanel_900_450.cs @@ -0,0 +1,51 @@ +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Windows.Forms; + +namespace JinYuan.ControlLib +{ + [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] + public partial class ucPanel_900_450 : UserControl + { + public ucPanel_900_450() + { + InitializeComponent(); + } + + [Category("自定义参数")] + [DefaultValue("标题文字")] + [Description("标题文字")] + [Browsable(true)] + public string Title + { + set + { + lbTitle.Text = value; + lbTitle.Invalidate(); + pbArrow.Left = lbTitle.Right + 3; + } + get + { + return lbTitle.Text; + } + } + + + + private bool titleVisible = true; + [Browsable(true)]//是否可见 + [Category("自定义属性")] //类别 + [Description("设置或显示上边箭头是否隐藏")] + public bool TitleVisible + { + get { return titleVisible; } + set + { + titleVisible = value; + pbArrow.Visible = titleVisible; + this.Invalidate();//点击后立即生效 + } + } + + } +} diff --git a/JinYuan.ControlLib/ucPanel_900_450.resx b/JinYuan.ControlLib/ucPanel_900_450.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/JinYuan.ControlLib/ucPanel_900_450.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JinYuan.DAL/Enums/Enums.cs b/JinYuan.DAL/Enums/Enums.cs new file mode 100644 index 0000000..daa4c71 --- /dev/null +++ b/JinYuan.DAL/Enums/Enums.cs @@ -0,0 +1,100 @@ +namespace JinYuan.DAL.Enums +{ + /// + /// 查询条件枚举 + /// + public enum QueryOperator + { + /// + /// 相等 + /// + Equal, + /// + /// 匹配 + /// + Like, + /// + /// 大于 + /// + GreaterThan, + /// + /// 大于或等于 + /// + GreaterThanOrEqual, + /// + /// 小于 + /// + LessThan, + /// + /// 小于或等于 + /// + LessThanOrEqual, + /// + /// 等于集合 + /// + In, + /// + /// 不等于集合 + /// + NotIn, + /// + /// 左边匹配 + /// + LikeLeft, + /// + /// 右边匹配 + /// + LikeRight, + /// + /// 不相等 + /// + NoEqual, + /// + /// 为空或空 + /// + IsNullOrEmpty, + /// + /// 不为空 + /// + IsNot, + /// + /// 不匹配 + /// + NoLike, + /// + /// 时间段 值用 "|" 隔开 + /// + DateRange + } + + + /// + /// 查询条件运算符 + /// + public enum QueryCharacter + { + /// + /// 且 + /// + And, + /// + /// 或 + /// + Or, + } + + /// + /// 排序枚举 + /// + public enum OrderSequence + { + /// + /// 正序 + /// + Asc, + /// + /// 倒序 + /// + Desc + } +} diff --git a/JinYuan.DAL/ISugarHelper.cs b/JinYuan.DAL/ISugarHelper.cs new file mode 100644 index 0000000..9fdeb74 --- /dev/null +++ b/JinYuan.DAL/ISugarHelper.cs @@ -0,0 +1,626 @@ +using JinYuan.DAL.Models; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.DAL +{ + public interface ISugarHelper : IDisposable + { + /// + /// 直接暴露 SqlSugar 原生客户端 + /// + //ISqlSugarClient DbClient { get; } + + /// + /// 初始化数据库连接 + /// + /// + void SetConnectionStr(string connectionStr, SqlSugar.DbType dbType); + + #region 数据库管理 + /// + /// 添加列 + /// + /// 表名 + /// 列信息 + /// + bool AddColumn(string tableName, DbColumnInfo column); + /// + /// 添加主键 + /// + /// 表名 + /// 列名 + /// + bool AddPrimaryKey(string tableName, string columnName); + /// + /// 备份数据库 + /// + /// 数据库名 + /// 文件名 + /// + bool BackupDataBase(string databaseName, string fullFileName); + /// + /// 备份表 + /// + /// 旧表名 + /// 行表名 + /// 行数 + /// + bool BackupTable(string oldTableName, string newTableName, int maxBackupDataRows = int.MaxValue); + /// + /// 创建表 + /// + /// 表名 + /// 列集合 + /// 是否创建主键 + /// + bool CreateTable(string tableName, List columns, bool isCreatePrimaryKey = true); + /// + /// 删除列 + /// + /// 表名 + /// 列名 + /// + bool DropColumn(string tableName, string columnName); + /// + /// 删除约束 + /// + /// 表名 + /// 约束名 + /// + bool DropConstraint(string tableName, string constraintName); + /// + /// 删除表 + /// + /// + /// + bool DropTable(string tableName); + /// + /// 获取列信息 + /// + /// 表名 + /// 是否缓存 + /// + List GetColumnInfosByTableName(string tableName, bool isCache = true); + /// + /// 获取自增列 + /// + /// 表名 + /// + List GetIsIdentities(string tableName); + /// + /// 获取主键 + /// + /// 表名 + /// + List GetPrimaries(string tableName); + /// + /// 获取表集合 + /// + /// 是否缓存 + /// + List GetTableInfoList(bool isCache = true); + /// + /// 获取视图集合 + /// + /// 是否缓存 + /// + List GetViewInfoList(bool isCache = true); + /// + /// 检测列是否存在 + /// + /// 表名 + /// 列名 + /// + bool IsAnyColumn(string tableName, string column); + /// + /// 检测约束 + /// + /// 约束名称 + /// + bool IsAnyConstraint(string constraintName); + /// + /// 检测是否有任何系统表权限 + /// + /// + bool IsAnySystemTablePermissions(); + /// + /// 检测表是否存在 + /// + /// 表名 + /// 是否缓存 + /// + bool IsAnyTable(string tableName, bool isCache = true); + /// + /// 检测列是否自增列 + /// + /// 表名 + /// 列名 + /// + bool IsIdentity(string tableName, string column); + /// + /// 检测列是否主键 + /// + /// 表名 + /// 列名 + /// + bool IsPrimaryKey(string tableName, string column); + /// + /// 重置列名 + /// + /// 表名 + /// 旧列名 + /// 新列名 + /// + bool RenameColumn(string tableName, string oldColumnName, string newColumnName); + /// + /// 重置表数据 + /// + /// 表名 + /// + bool TruncateTable(string tableName); + /// + /// 修改列信息 + /// + /// 表名 + /// 列信息 + /// + bool UpdateColumn(string tableName, DbColumnInfo column); + + /// + /// 获取数据库时间 + /// + /// 返回值 + DateTime GetDataBaseTime(); + #endregion + + #region 查询 + + + /// + /// 查询所有 + /// + /// + /// + List QueryAll() where T : class, new(); + /// + /// 查询-返回自定义数据 + /// + /// 泛型参数(集合成员的类型) + /// 返回值类型 + /// 返回值表达式 + /// 查询表达式 + /// 值 + TResult QuerySelect(Expression> expression, Expression> whereLambda = null) where T : class, new(); + + /// + /// 查询-返回自定义数据 + /// + /// 泛型参数(集合成员的类型) + /// 返回值类型 + /// 返回值表达式 + /// 查询表达式 + /// 值 + List QuerySelectList(Expression> expression, Expression> whereLambda = null) where T : class, new(); + + /// + /// 根据条件查询单条数据 + /// + /// 泛型参数(集合成员的类型) + /// 查询表达式 + /// + T Query(Expression> whereLambda = null) where T : class, new(); + + /// + /// 根据条件异步查询单条数据 + /// + /// + /// + /// + Task QueryAsync(Expression> whereLambda = null) where T : class, new(); + + /// + /// 根据条件查询排序数据 + /// + /// + /// + /// + /// + T Query(Expression> whereLambda = null, Expression> whereLambda2 = null, OrderByType byType = OrderByType.Desc) where T : class, new(); + /// + /// 根据条件查询集合 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 实体 + List QueryWhereList(Expression> whereLambda = null) where T : class, new(); + + Task> QueryWhereListAsync(Expression> whereLambda = null) where T : class, new(); + + /// + /// 查询排序数据 + /// + /// + /// + /// + List QueryList(QueryDescriptor query = null) where T : class, new(); + /// + /// 查询前N条数据 + /// + /// + /// 排序列名 + /// 前N条数据 + /// 条件 + /// 升序/降序 + /// + List QueryList(string sort, int Take, Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new(); + /// + /// 异步查询前N条数据 + /// + /// + /// + /// + /// + /// + /// + Task> QueryListAsync(string sort, int Take, Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new(); + /// + /// 根据字段查询排列 + /// + /// + /// + /// + /// + /// + List QueryList(string sort, Expression> whereLambda = null, OrderByType byType = OrderByType.Asc) where T : class, new (); + /// + /// 异步根据字段查询排列 + /// + /// + /// + /// + /// + /// + Task> QueryListAsync(string sort, Expression> whereLambda = null, OrderByType byType = OrderByType.Asc) where T : class, new(); + /// + /// 查询集合 + /// + /// 泛型参数(集合成员的类型) + /// sql + /// 实体 + List QuerySqlList(string sql) where T : class, new(); + + /// + /// 异步查询集合 + /// + /// + /// + /// + Task> QuerySqlListAsync(string sql) where T : class, new(); + /// + /// 分页查询 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 总行数 + /// 实体 + List QueryPageList(QueryDescriptor query, out int totalCount) where T : class, new(); + + /// + /// 通过多值查询数据集 + /// + /// 泛型参数(集合成员的类型) + /// 字段名 + /// 数据集合 + /// + List In(string inFieldName, List inValues) where T : class, new(); + + /// + /// 通过多值(主键)查询数据集 + /// + /// 泛型参数(集合成员的类型) + /// 主键数据集合 + /// + List In(List values) where T : class, new(); + + /// + /// 条件查询DataTable + /// + /// 泛型参数(集合成员的类型) + /// 查询表达式 + /// 实体 + DataTable QueryDataTable(Expression> whereLambda = null) where T : class, new(); + + /// + /// 查询DataTable + /// + /// sql + /// 实体 + DataTable QueryDataTable(string sql); + /// + /// 查询单个值 + /// + /// sql + /// 单个值 + object QuerySqlScalar(string sql); + + /// + /// 分页查询 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 总行数 + /// DataTable + DataTable QueryDataTablePageList(QueryDescriptor query, out int totalCount) where T : class, new(); + + #endregion + + #region 新增 + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 操作影响的行数 + int Add(T entity) where T : class, new(); + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 泛型集合 + /// 操作影响的行数 + int Add(List entitys) where T : class, new(); + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 字典集合(Key:列名 Value:值) + /// 操作影响的行数 + int Add(Dictionary keyValues) where T : class, new(); + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 返回实体 + T AddReturnEntity(T entity) where T : class, new(); + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 返回自增列 + int AddReturnIdentity(T entity) where T : class, new(); + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 返回bool + bool AddReturnBool(T entity) where T : class, new(); + /// + /// 异步新增 + /// + /// + /// + /// + Task AddReturnBoolAsync(T entity) where T : class, new(); + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 泛型集合 + /// 返回bool + bool AddReturnBool(List entitys) where T : class, new(); + /// + /// 异步增加 + /// + /// + /// + /// + Task AddReturnBoolAsync(List entitys) where T : class, new(); + #endregion + + #region 修改 + /// + /// 修改(主键是更新条件) + /// + /// 泛型参数(集合成员的类型) + /// 实体对象(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + int Update(T entity, List lstIgnoreColumns = null, bool isLock = true) where T : class, new(); + + /// + /// 修改(主键是更新条件) + /// + /// 泛型参数(集合成员的类型) + /// 实体对象集合(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + int Update(List entitys, List lstIgnoreColumns = null, bool isLock = true) where T : class, new(); + + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 条件 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + int Update(T entity, Expression> where, List lstIgnoreColumns = null, + bool isLock = true) where T : class, new(); + + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + int Update(Expression> update, Expression> where = null, bool isLock = true) where T : class, new(); + /// + /// 修改+1 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + int Update(Expression> update, Expression> where = null, bool isLock = true) where T : class, new(); + /// + /// 异步修改+1 + /// + /// + /// + /// + /// + /// + Task UpdateAsync(Expression> update, Expression> where = null, bool isLock = true) where T : class, new(); + + Task UpdateAsync(List entitys, List lstIgnoreColumns = null, bool isLock = true) where T : class, new(); + + /// + /// 修改单条数据 + /// + /// + /// + /// + /// + int UpdateSingle(T entity, Expression> where = null, Expression> where2 = null, bool isLock = true) where T : class, new(); + /// + /// 异步修改 + /// + /// + /// + /// + /// + /// + /// + Task UpdateSingleAsync(T entity, Expression> where = null, Expression> where2 = null, bool isLock = true) where T : class, new(); + + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 字典集合(Key:列名 Value:值) + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + int Update(Dictionary keyValues, Expression> where = null, bool isLock = true) + where T : class, new(); + + /// + /// 批量修改需要更新的列 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 更新指定列 + /// 条件(为空则以主键更新,反之需要把wherecolumns中的列加到UpdateColumns中) + /// 是否加锁 + /// 操作影响的行数 + int UpdateColumns(List entitys, Expression> updateColumns, + Expression> wherecolumns = null, bool isLock = true) where T : class, new(); + + /// + /// 修改 通过RowVer及主键Code 更新 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + int UpdateRowVer(T entity, List lstIgnoreColumns = null, bool isLock = true) where T : class, new(); + + /// + /// 修改 通过RowVer及主键Code 更新 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 更新条件 + /// 是否加锁 + /// 操作影响的行数 + int UpdateRowVer(Expression> update, Dictionary where, bool isLock = true) where T : class, new(); + #endregion + + + #region 删除 + + /// + /// 删除 通过主键数据 + /// + /// 泛型参数(集合成员的类型) + /// 主键值 + /// 是否加锁 + /// 操作影响的行数 + int DeleteByPrimary(List primaryKeyValues, bool isLock = true) where T : class, new(); + + /// + /// 根据实体类删除 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 是否加锁 + /// 操作影响的行数 + int Delete(T entity, bool isLock = true) where T : class, new(); + + /// + /// 初始化表 + /// + /// + void Delete() where T : class, new(); + + /// + /// 根据实体类集合删除 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 (必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 是否加锁 + /// 操作影响的行数 + int Delete(List entity, bool isLock = true) where T : class, new(); + + /// + /// 删除 + /// + /// 泛型参数(集合成员的类型) + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + int Delete(Expression> where, bool isLock = true) where T : class, new(); + /// + /// 异步删除 + /// + /// + /// + /// + /// + Task DeleteAsync(Expression> where, bool isLock = true) where T : class, new(); + /// + /// 通过多值(主键)删除数据集 + /// + /// 泛型参数(集合成员的类型) + /// 数据集合 + /// + int DeleteIn(List inValues) where T : class, new(); + + #endregion + + + + + } +} diff --git a/JinYuan.DAL/JinYuan.DAL.csproj b/JinYuan.DAL/JinYuan.DAL.csproj new file mode 100644 index 0000000..564e64a --- /dev/null +++ b/JinYuan.DAL/JinYuan.DAL.csproj @@ -0,0 +1,137 @@ + + + + + Debug + AnyCPU + {114AA012-29C9-418C-A2D6-3173C5341F51} + Library + Properties + JinYuan.DAL + JinYuan.DAL + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll + + + ..\packages\BouncyCastle.Cryptography.2.3.1\lib\net461\BouncyCastle.Cryptography.dll + + + ..\packages\Google.Protobuf.3.26.1\lib\net45\Google.Protobuf.dll + + + ..\packages\K4os.Compression.LZ4.1.3.8\lib\net462\K4os.Compression.LZ4.dll + + + ..\packages\K4os.Compression.LZ4.Streams.1.3.8\lib\net462\K4os.Compression.LZ4.Streams.dll + + + ..\packages\K4os.Hash.xxHash.1.0.8\lib\net462\K4os.Hash.xxHash.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\MySql.Data.9.1.0\lib\net48\MySql.Data.dll + + + ..\packages\SqlSugar.5.1.4.175\lib\SqlSugar.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + ..\packages\System.Configuration.ConfigurationManager.8.0.0\lib\net462\System.Configuration.ConfigurationManager.dll + + + + + ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.IO.Pipelines.7.0.0\lib\net462\System.IO.Pipelines.dll + + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + ..\packages\System.Security.AccessControl.6.0.0\lib\net461\System.Security.AccessControl.dll + + + ..\packages\System.Security.Permissions.7.0.0\lib\net462\System.Security.Permissions.dll + + + ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll + + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + ..\packages\ZstdSharp.Port.0.8.0\lib\net462\ZstdSharp.dll + + + + + + + + + + + + + + + + + + + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360} + JinYuan.Helper + + + + \ No newline at end of file diff --git a/JinYuan.DAL/Models/OrderSortEntity.cs b/JinYuan.DAL/Models/OrderSortEntity.cs new file mode 100644 index 0000000..591ea62 --- /dev/null +++ b/JinYuan.DAL/Models/OrderSortEntity.cs @@ -0,0 +1,19 @@ +using JinYuan.DAL.Enums; + +namespace JinYuan.DAL.Models +{ + /// + /// 排序实体 + /// + public class OrderSortEntity + { + /// + /// 排序字段 + /// + public string Sort { get; set; } + /// + /// 排序类型 + /// + public OrderSequence Order { get; set; } + } +} diff --git a/JinYuan.DAL/Models/QueryCondition.cs b/JinYuan.DAL/Models/QueryCondition.cs new file mode 100644 index 0000000..d5b1716 --- /dev/null +++ b/JinYuan.DAL/Models/QueryCondition.cs @@ -0,0 +1,24 @@ +using JinYuan.DAL.Enums; + +namespace JinYuan.DAL.Models +{ + public class QueryCondition + { + /// + /// 字段名称 + /// + public string Key { get; set; } + /// + /// 查询操作 + /// + public QueryOperator Operator { get; set; } + /// + /// 值 + /// + public object Value { get; set; } + /// + /// 运算符 + /// + public QueryCharacter Character { get; set; } + } +} diff --git a/JinYuan.DAL/Models/QueryDescriptor.cs b/JinYuan.DAL/Models/QueryDescriptor.cs new file mode 100644 index 0000000..b8f04ee --- /dev/null +++ b/JinYuan.DAL/Models/QueryDescriptor.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace JinYuan.DAL.Models +{ + /// + /// 查询集合 + /// + public class QueryDescriptor + { + /// + /// 行数 + /// + public int PageSize { get; set; } + /// + /// 页码 + /// + public int PageIndex { get; set; } + /// + /// 排序 + /// + public List OrderBys { get; set; } + /// + /// 条件 + /// + public List Conditions { get; set; } + } +} diff --git a/JinYuan.DAL/Properties/AssemblyInfo.cs b/JinYuan.DAL/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9741fe1 --- /dev/null +++ b/JinYuan.DAL/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.DAL")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.DAL")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("114aa012-29c9-418c-a2d6-3173c5341f51")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.DAL/SQLSugarHelper.cs b/JinYuan.DAL/SQLSugarHelper.cs new file mode 100644 index 0000000..b601a4b --- /dev/null +++ b/JinYuan.DAL/SQLSugarHelper.cs @@ -0,0 +1,83 @@ + +using JinYuan.Helper; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace JinYuan.DAL +{ + public class SQLSugarHelper + { + /// + /// 数据库连接字符串 + /// + public static string connString = string.Empty; + + /// + /// 数据库类型 + /// + public static SqlSugar.DbType dbType = SqlSugar.DbType.SqlServer; + + public static SqlSugarScope SqlSugarClient + { + get + { + //如果配置了 SlaveConnectionConfigs那就是主从模式,所有的写入删除更新都走主库,查询走从库, + var db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = connString, + DbType = dbType, //数据库类型 + IsAutoCloseConnection = true, //默认false,自动释放和关闭数据库连接,设置为true无需使用using或者close操作 + InitKeyType = InitKeyType.Attribute //默认SystemTable,该属性是不是主键,是不是标识列等等信息 + + }); + db.Ado.CommandTimeOut = 3000;//设置执行语法超时时间 + db.Aop.OnLogExecuted = (sql, pars) => //SQL执行完事件 + { + LogHelper.Instance.WriteLog($"执行时间:{db.Ado.SqlExecutionTime.TotalMilliseconds}毫秒 \r\nSQL如下:{sql} \r\n参数:{GetParams(pars)} ", "SQL执行"); + }; + db.Aop.OnLogExecuting = (sql, pars) => //SQL执行前事件 + { + if (db.TempItems == null) db.TempItems = new Dictionary(); + }; + db.Aop.OnError = (exp) =>//执行SQL 错误事件 + { + LogHelper.Instance.WriteError($"SQL错误:{exp.Message}\r\nSQL如下:{exp.Sql}", "SQL执行"); + throw new Exception(exp.Message); + }; + db.Aop.OnDiffLogEvent = (it) => //可以方便拿到 数据库操作前和操作后的数据变化。 + { + var editBeforeData = it.BeforeData; //变化前数据 + var editAfterData = it.AfterData; //变化后数据 + var sql = it.Sql; //SQL + var parameter = it.Parameters; //参数 + var data = it.BusinessData; //业务数据 + var time = it.Time ?? new TimeSpan(); //时间 + var diffType = it.DiffType; //枚举值 insert 、update 和 delete 用来作业务区分 + + //你可以在这里面写日志方法 + var log = $"时间:{time.TotalMilliseconds}\r\n"; + log += $"类型:{diffType.ToString()}\r\n"; + log += $"SQL:{sql}\r\n"; + log += $"参数:{GetParams(parameter)}\r\n"; + log += $"业务数据:{JsonHelper.EntityToJson(data)}\r\n"; + log += $"变化前数据:{JsonHelper.EntityToJson(editBeforeData)}\r\n"; + log += $"变化后数据:{JsonHelper.EntityToJson(editAfterData)}\r\n"; + //SqlLogHelper.WriteLog(log, "数据变化前后"); + }; + return db; + } + } + + /// + /// 获取参数信息 + /// + /// + /// + private static string GetParams(SugarParameter[] pars) + { + return pars.Aggregate("", (current, p) => current + $"{p.ParameterName}:{p.Value}, "); + } + } +} diff --git a/JinYuan.DAL/SQLSugarService.cs b/JinYuan.DAL/SQLSugarService.cs new file mode 100644 index 0000000..2f62ada --- /dev/null +++ b/JinYuan.DAL/SQLSugarService.cs @@ -0,0 +1,1883 @@ +using JinYuan.DAL.Enums; +using JinYuan.DAL.Models; +using JinYuan.Helper; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace JinYuan.DAL +{ + + public class SQLSugarService : ISugarHelper + { + private ISqlSugarClient _db; + + // 实现属性 + //public ISqlSugarClient DbClient => _db; + + public ISqlSugarClient Db => SqlSugarDb; + + // 兼容你原来的代码,可保留 + //public ISqlSugarClient DbClient => SqlSugarDb; + + public void SetConnectionStr(string connectionStr, SqlSugar.DbType dbType) + { + SQLSugarHelper.connString = connectionStr; + SQLSugarHelper.dbType = dbType; + SqlSugarDb = SQLSugarHelper.SqlSugarClient; + + } + + /// + /// 数据库连接对象 + /// + public SqlSugarScope SqlSugarDb { get; set; } + + + #region 数据库管理 + /// + /// 添加列 + /// + /// 表名 + /// 列信息 + /// 值 + public bool AddColumn(string tableName, DbColumnInfo column) + { + return SqlSugarDb.DbMaintenance.AddColumn(tableName, column); + } + /// + /// 添加主键 + /// + /// 表名 + /// 列名 + /// 值 + public bool AddPrimaryKey(string tableName, string columnName) + { + return SqlSugarDb.DbMaintenance.AddPrimaryKey(tableName, columnName); + } + /// + /// 备份数据库 + /// + /// 数据库名 + /// 文件名 + /// 值 + public bool BackupDataBase(string databaseName, string fullFileName) + { + return SqlSugarDb.DbMaintenance.BackupDataBase(databaseName, fullFileName); + } + /// + /// 备份表 + /// + /// 旧表名 + /// 行表名 + /// 行数 + /// 值 + public bool BackupTable(string oldTableName, string newTableName, int maxBackupDataRows = int.MaxValue) + { + return SqlSugarDb.DbMaintenance.BackupTable(oldTableName, newTableName, maxBackupDataRows); + } + /// + /// 创建表 + /// + /// 表名 + /// 列集合 + /// 是否创建主键 + /// 值 + public bool CreateTable(string tableName, List columns, bool isCreatePrimaryKey = true) + { + return SqlSugarDb.DbMaintenance.CreateTable(tableName, columns, isCreatePrimaryKey); + } + /// + /// 删除列 + /// + /// 表名 + /// 列名 + /// 值 + public bool DropColumn(string tableName, string columnName) + { + return SqlSugarDb.DbMaintenance.DropColumn(tableName, columnName); + } + /// + /// 删除约束 + /// + /// 表名 + /// 约束名 + /// 值 + public bool DropConstraint(string tableName, string constraintName) + { + return SqlSugarDb.DbMaintenance.DropConstraint(tableName, constraintName); + } + /// + /// 删除表 + /// + /// + /// 值 + public bool DropTable(string tableName) + { + return SqlSugarDb.DbMaintenance.DropTable(tableName); + } + /// + /// 获取列信息 + /// + /// 表名 + /// 是否缓存 + /// 值 + public List GetColumnInfosByTableName(string tableName, bool isCache = true) + { + return SqlSugarDb.DbMaintenance.GetColumnInfosByTableName(tableName, isCache); + } + /// + /// 获取自增列 + /// + /// 表名 + /// 值 + public List GetIsIdentities(string tableName) + { + return SqlSugarDb.DbMaintenance.GetIsIdentities(tableName); + } + /// + /// 获取主键 + /// + /// 表名 + /// 值 + public List GetPrimaries(string tableName) + { + return SqlSugarDb.DbMaintenance.GetPrimaries(tableName); + } + /// + /// 获取表集合 + /// + /// 是否缓存 + /// 值 + public List GetTableInfoList(bool isCache = true) + { + return SqlSugarDb.DbMaintenance.GetTableInfoList(isCache); + } + /// + /// 获取视图集合 + /// + /// 是否缓存 + /// 值 + public List GetViewInfoList(bool isCache = true) + { + return SqlSugarDb.DbMaintenance.GetViewInfoList(isCache); + } + /// + /// 检测列是否存在 + /// + /// 表名 + /// 列名 + /// 值 + public bool IsAnyColumn(string tableName, string column) + { + return SqlSugarDb.DbMaintenance.IsAnyColumn(tableName, column); + } + /// + /// 检测约束 + /// + /// 约束名称 + /// 值 + public bool IsAnyConstraint(string constraintName) + { + return SqlSugarDb.DbMaintenance.IsAnyConstraint(constraintName); + } + /// + /// 检测是否有任何系统表权限 + /// + /// 值 + public bool IsAnySystemTablePermissions() + { + return SqlSugarDb.DbMaintenance.IsAnySystemTablePermissions(); + } + /// + /// 检测表是否存在 + /// + /// 表名 + /// 是否缓存 + /// 值 + public bool IsAnyTable(string tableName, bool isCache = true) + { + return SqlSugarDb.DbMaintenance.IsAnyTable(tableName, isCache); + } + /// + /// 检测列是否自增列 + /// + /// 表名 + /// 列名 + /// 值 + public bool IsIdentity(string tableName, string column) + { + return SqlSugarDb.DbMaintenance.IsIdentity(tableName, column); + } + /// + /// 检测列是否主键 + /// + /// 表名 + /// 列名 + /// 值 + public bool IsPrimaryKey(string tableName, string column) + { + return SqlSugarDb.DbMaintenance.IsPrimaryKey(tableName, column); + } + /// + /// 重置列名 + /// + /// 表名 + /// 旧列名 + /// 新列名 + /// 值 + public bool RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + return SqlSugarDb.DbMaintenance.RenameColumn(tableName, oldColumnName, newColumnName); + } + /// + /// 重置表数据 + /// + /// 表名 + /// 值 + public bool TruncateTable(string tableName) + { + return SqlSugarDb.DbMaintenance.TruncateTable(tableName); + } + /// + /// 修改列信息 + /// + /// 表名 + /// 列信息 + /// 值 + public bool UpdateColumn(string tableName, DbColumnInfo column) + { + return SqlSugarDb.DbMaintenance.UpdateColumn(tableName, column); + } + + /// + /// 获取数据库时间 + /// + /// 返回值 + public DateTime GetDataBaseTime() + { + return SqlSugarDb.GetDate(); + } + #endregion + + #region 查询 + + /// + /// 查询所有 + /// + /// + /// + /// + public List QueryAll() where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.UpdLock); + return up.ToList(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + /// + /// 查询-返回自定义数据 + /// + /// 泛型参数(集合成员的类型) + /// 返回值类型 + /// 返回值表达式 + /// 查询表达式 + /// 值 + public TResult QuerySelect(Expression> expression, Expression> whereLambda = null) where T : class, new() + { + try + { + var datas = SqlSugarDb.Queryable().With(SqlWith.NoLock).Where(whereLambda).Select(expression).First(); + return datas; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + /// + /// 查询-返回自定义数据 + /// + /// 泛型参数(集合成员的类型) + /// 返回值类型 + /// 返回值表达式 + /// 查询表达式 + /// 值 + public List QuerySelectList(Expression> expression, Expression> whereLambda = null) where T : class, new() + { + try + { + var datas = SqlSugarDb.Queryable().With(SqlWith.NoLock).Where(whereLambda).Select(expression).ToList(); + return datas; + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + /// + /// 查询单条数据 + /// + /// 泛型参数(集合成员的类型) + /// 查询表达式 + /// 值 + public T Query(Expression> whereLambda = null) where T : class, new() + { + + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + return up.First(); + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + + /// + /// 异步查询单条数据 + /// + /// 泛型参数(集合成员的类型) + /// 查询表达式 + /// + /// + public Task QueryAsync(Expression> whereLambda = null) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + return up.FirstAsync(); + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + + /// + /// 根据条件查询排序数据 + /// + /// + /// + /// + /// + public T Query(Expression> whereLambda2 = null, Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + + if (whereLambda2 != null) + { + up = up.Where(whereLambda2); + } + if (whereLambda != null) + { + up = up.OrderBy(whereLambda, byType); + } + return up.First(); + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + public T Query(QueryDescriptor query = null) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (query != null) + { + if (query.Conditions != null) + { + var conds = ParseCondition(query.Conditions); + up = up.Where(conds); + } + + if (query.OrderBys != null) + { + var orderBys = ParseOrderBy(query.OrderBys); + up = up.OrderBy(orderBys); + } + } + return up.First(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + /// + /// 查询集合 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 实体 + public List QueryWhereList(Expression> whereLambda = null) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.UpdLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + return up.ToList(); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"查询集合异常:{ex}", "SysErrorLog"); + return null; + //throw new Exception(ex.Message); + } + + } + + public async Task> QueryWhereListAsync(Expression> whereLambda = null) where T : class, new() + { + try + { + var up = SqlSugarDb.Queryable().With(SqlWith.UpdLock); + if (whereLambda != null) + up = up.Where(whereLambda); + return await up.ToListAsync(); + } + catch + { + return new List(); + } + } + + /// + /// 查询集合 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 实体 + public List QueryList(QueryDescriptor query = null) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (query != null) + { + if (query.Conditions != null) + { + var conds = ParseCondition(query.Conditions); + up = up.Where(conds); + } + + if (query.OrderBys != null) + { + var orderBys = ParseOrderBy(query.OrderBys); + up = up.OrderBy(orderBys); + } + } + return up.ToList(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + /// + /// 查询前N条数据 + /// + /// + /// + /// + /// + /// + /// + public List QueryList(string sort, int Take, Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + if (sort != "") + { + var orderBys = ParseOrderBy(sort, byType); + up = up.OrderBy(orderBys).Take(Take); + } + return up.ToList(); + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 异步查询前N条数据 + /// + /// + /// + /// + /// + /// + /// + /// + public async Task> QueryListAsync(string sort, int Take, Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.CopyNew().Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + if (sort != "") + { + var orderBys = ParseOrderBy(sort, byType); + up = up.OrderBy(orderBys).Take(Take); + } + return await up.ToListAsync(); + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 查询列表数据,根据字段排序排列 + /// + /// + /// + /// + /// + /// + /// + public List QueryList(string sort = "", Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new() + { + try + { + + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + if (sort != "") + { + var orderBys = ParseOrderBy(sort, byType); + up = up.OrderBy(orderBys); + } + return up.ToList(); + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + } + + /// + /// 异步根据字段查询排列 + /// + /// + /// + /// + /// + /// + public async Task> QueryListAsync(string sort = "", Expression> whereLambda = null, OrderByType byType = OrderByType.Desc) where T : class, new() + { + try + { + + ISugarQueryable up = SqlSugarDb.CopyNew().Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + if (sort != "") + { + var orderBys = ParseOrderBy(sort, byType); + up = up.OrderBy(orderBys); + } + return await up.ToListAsync(); + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + } + + + /// + /// 排序转换 + /// + /// + /// + /// + private string ParseOrderBy(string sort, OrderByType order) + { + var conds = ""; + + switch (order) + { + case OrderByType.Asc: + conds += $"{sort} asc,"; + break; + case OrderByType.Desc: + conds += $"{sort} desc,"; + break; + default: + throw new ArgumentOutOfRangeException(); + } + return conds.TrimEnd(','); + } + + + /// + /// 查询集合 + /// + /// 泛型参数(集合成员的类型) + /// sql + /// 实体 + public List QuerySqlList(string sql) where T : class, new() + { + try + { + return SqlSugarDb.SqlQueryable(sql).ToList(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + /// + /// 异步查询集合-多值 + /// + /// + /// + /// + /// + public async Task> QuerySqlListAsync(string sql) where T : class, new() + { + try + { + return await SqlSugarDb.CopyNew().SqlQueryable(sql).ToListAsync(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + /// + /// 分页查询 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 总行数 + /// 实体 + public List QueryPageList(QueryDescriptor query, out int totalCount) where T : class, new() + { + if (query == null) + { + throw new ArgumentNullException(nameof(query)); + } + var listDatas = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (query.Conditions != null) + { + var conds = ParseCondition(query.Conditions); + listDatas = listDatas.Where(conds); + } + + if (query.OrderBys != null) + { + var orderBys = ParseOrderBy(query.OrderBys); + listDatas = listDatas.OrderBy(orderBys); + } + + totalCount = 0; + if (query.PageSize == 0) + { + var datas = listDatas.ToList(); + totalCount = datas.Count; + return datas; + } + else + { + var datas = listDatas.ToPageList(query.PageIndex, query.PageSize, ref totalCount); + return datas; + } + + } + /// + /// 查询集合-多值 + /// + /// 泛型参数(集合成员的类型) + /// 字段名 + /// 数据集合 + /// 值 + public List In(string inFieldName, List inValues) where T : class, new() + { + try + { + return SqlSugarDb.Queryable().With(SqlWith.NoLock).In(inFieldName, inValues).ToList(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + + /// + /// 查询集合-通过多值(主键) + /// + /// 泛型参数(集合成员的类型) + /// 主键数据集合 + /// 值 + public List In(List values) where T : class, new() + { + return SqlSugarDb.Queryable().With(SqlWith.NoLock).In(values).ToList(); + } + + /// + /// 查询集合 + /// + /// 泛型参数(集合成员的类型) + /// 查询表达式 + /// 实体 + public DataTable QueryDataTable(Expression> whereLambda = null) where T : class, new() + { + try + { + ISugarQueryable up = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (whereLambda != null) + { + up = up.Where(whereLambda); + } + return up.ToDataTable(); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + /// + /// 查询集合 + /// + /// sql + /// 实体 + public DataTable QueryDataTable(string sql) + { + try + { + return SqlSugarDb.Ado.GetDataTable(sql); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + + + + /// + /// 查询单个值 + /// + /// sql + /// 单个值 + public object QuerySqlScalar(string sql) + { + try + { + return SqlSugarDb.Ado.GetScalar(sql); + } + catch (Exception ex) { throw new Exception(ex.Message); } + + } + /// + /// 分页查询 + /// + /// 泛型参数(集合成员的类型) + /// 过滤条件 + /// 总行数 + /// DataTable + public DataTable QueryDataTablePageList(QueryDescriptor query, out int totalCount) where T : class, new() + { + if (query == null) + { + throw new ArgumentNullException(nameof(query)); + } + var listDatas = SqlSugarDb.Queryable().With(SqlWith.NoLock); + if (query.Conditions != null) + { + var conds = ParseCondition(query.Conditions); + listDatas = listDatas.Where(conds); + } + + if (query.OrderBys != null) + { + var orderBys = ParseOrderBy(query.OrderBys); + listDatas = listDatas.OrderBy(orderBys); + } + + totalCount = 0; + var datas = listDatas.ToDataTablePage(query.PageIndex, query.PageSize, ref totalCount); + return datas; + } + #endregion + + #region 新增 + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 操作影响的行数 + public int Add(T entity) where T : class, new() + { + try + { + var result = SqlSugarDb.Insertable(entity).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + } + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 泛型集合 + /// 操作影响的行数 + public int Add(List entitys) where T : class, new() + { + try + { + if (entitys.Count == 0) return 1; + var result = SqlSugarDb.Insertable(entitys).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + } + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 字典集合(Key:列名 Value:值) + /// 操作影响的行数 + public int Add(Dictionary keyValues) where T : class, new() + { + try + { + var result = SqlSugarDb.Insertable(keyValues).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + } + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 返回实体 + public T AddReturnEntity(T entity) where T : class, new() + { + try + { + var result = SqlSugarDb.Insertable(entity).ExecuteReturnEntity(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 返回自增列 + public int AddReturnIdentity(T entity) where T : class, new() + { + try + { + var result = SqlSugarDb.Insertable(entity).ExecuteReturnIdentity(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 返回bool + public bool AddReturnBool(T entity) where T : class, new() + { + try + { + var result = SqlSugarDb.Insertable(entity).With(SqlWith.UpdLock).ExecuteCommand() > 0; + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + public async Task AddReturnBoolAsync(T entity) where T : class, new() + { + try + { + var result = await SqlSugarDb.Insertable(entity).With(SqlWith.UpdLock).ExecuteCommandAsync() > 0; + return result; + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + + /// + /// 新增 + /// + /// 泛型参数(集合成员的类型) + /// 泛型集合 + /// 返回bool + public bool AddReturnBool(List entitys) where T : class, new() + { + try + { + if (entitys.Count == 0) return true; + var result = SqlSugarDb.Insertable(entitys).ExecuteCommand() > 0; + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + public async Task AddReturnBoolAsync(List entitys) where T : class, new() + { + try + { + if (entitys == null || entitys.Count == 0) return true; + var count = await SqlSugarDb.Insertable(entitys).ExecuteCommandAsync(); + return count > 0; + //var result = await SqlSugarDb.Insertable(entitys).With(SqlWith.UpdLock).ExecuteCommandAsync() > 0; + //return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + #endregion + + #region 修改 + + /// + /// 修改(主键是更新条件) + /// + /// 泛型参数(集合成员的类型) + /// 实体对象(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + /// + public int Update(T entity, List lstIgnoreColumns = null, bool isLock = true) where T : class, new() + { + try + { + IUpdateable up = SqlSugarDb.Updateable(entity); + if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0) + { + up = up.IgnoreColumns(false); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + /// + /// 修改(主键是更新条件) + /// + /// 泛型参数(集合成员的类型) + /// 实体对象集合(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + public int Update(List entitys, List lstIgnoreColumns = null, bool isLock = true) where T : class, new() + { + try + { + if (entitys.Count == 0) return 1; + IUpdateable up = SqlSugarDb.Updateable(entitys); + if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0) + { + up = up.IgnoreColumns(lstIgnoreColumns.Contains(lstIgnoreColumns.First())); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 条件 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + public int Update(T entity, Expression> where, List lstIgnoreColumns = null, bool isLock = true) where T : class, new() + { + try + { + IUpdateable up = SqlSugarDb.Updateable(entity); + if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0) + { + up = up.IgnoreColumns(lstIgnoreColumns.Contains(lstIgnoreColumns.First())); + } + up = up.Where(where); + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + public int Update(Expression> update, Expression> where = null, bool isLock = true) where T : class, new() + { + try + { + IUpdateable up = SqlSugarDb.Updateable().UpdateColumns(update); + if (where != null) + { + up = up.Where(where); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 修改加1 + /// + /// + /// + /// + /// + /// + public int Update(Expression> update, Expression> where = null, bool isLock = true) where T : class, new() + { + try + { + IUpdateable up = SqlSugarDb.Updateable().SetColumns(update); + if (where != null) + { + up = up.Where(where); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + ///异步修改加1 + /// + /// + /// + /// + /// + /// + /// + public async Task UpdateAsync(Expression> update, Expression> where = null, bool isLock = true) where T : class, new() + { + try + { + IUpdateable up = SqlSugarDb.Updateable().SetColumns(update); + if (where != null) + { + up = up.Where(where); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = await up.ExecuteCommandAsync(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + public async Task UpdateAsync(List entitys, List lstIgnoreColumns = null, bool isLock = true) where T : class, new() + { + if (entitys == null || entitys.Count == 0) return 0; + var up = SqlSugarDb.Updateable(entitys); + if (lstIgnoreColumns != null && lstIgnoreColumns.Any()) + up = up.IgnoreColumns(lstIgnoreColumns.First()); + if (isLock) + up = up.With(SqlWith.UpdLock); + return await up.ExecuteCommandAsync(); + } + + + /// + /// 修改单条数据 + /// + /// + /// 实体类 + /// 指定更新行 + /// 更新表达式 + /// 是否加锁 + /// + /// + public int UpdateSingle(T entity, Expression> IgnoreColumns = null, Expression> where = null, bool isLock = true) where T : class, new() + { + try + { + + IUpdateable up = SqlSugarDb.Updateable(entity); + if (IgnoreColumns != null) + { + up = up.UpdateColumns(IgnoreColumns); + } + if (where != null) + { + up = up.Where(where); + } + var result = up.ExecuteCommand(); + return result; + + //SqlSugarDb.Updateable(new T () + //{ + // Id = entity.Id, + // EmailArr = "test@test.com", + // EmailContent = "测试邮件,请忽略111" + //}).UpdateColumns(it => new { it.EmailArr, it.EmailContent }).ExecuteCommandAsync(); + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + + /// + /// 异步更新 + /// + /// + /// + /// + /// + /// + /// + /// + public async Task UpdateSingleAsync(T entity, Expression> IgnoreColumns = null, Expression> where = null, bool isLock = true) where T : class, new() + { + try + { + + IUpdateable up = SqlSugarDb.Updateable(entity); + if (IgnoreColumns != null) + { + up = up.UpdateColumns(IgnoreColumns); + } + if (where != null) + { + up = up.Where(where); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = await up.ExecuteCommandAsync(); + return result; + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + + + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 字典集合(Key:列名 Value:值) + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + public int Update(Dictionary keyValues, Expression> where = null, bool isLock = true) where T : class, new() + { + try + { + IUpdateable up = SqlSugarDb.Updateable(keyValues); + if (where != null) + { + up = up.Where(where); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + + /// + /// 批量修改需要更新的列 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象(必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 更新指定列 + /// 条件(为空则以主键更新,反之需要把wherecolumns中的列加到UpdateColumns中) + /// 是否加锁 + /// 操作影响的行数 + public int UpdateColumns(List entitys, Expression> updateColumns, Expression> wherecolumns = null, bool isLock = true) where T : class, new() + { + try + { + if (entitys.Count == 0) return 1; + IUpdateable up = SqlSugarDb.Updateable(entitys).UpdateColumns(updateColumns); + if (wherecolumns != null) + { + up = up.WhereColumns(wherecolumns); + } + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + /// + /// 修改 通过RowVer及主键Code 更新 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 不更新的列 + /// 是否加锁 + /// 操作影响的行数 + public int UpdateRowVer(T entity, List lstIgnoreColumns = null, bool isLock = true) where T : class, new() + { + try + { + Type ts = entity.GetType(); + var rowVerProperty = ts.GetProperty("RowVer"); + if (rowVerProperty == null) + { + throw new Exception("Column RowVer Not Exist"); + } + if (rowVerProperty.GetValue(entity, null) == null) + { + throw new Exception("RowVer Value Is Null"); + } + var codeProperty = ts.GetProperty("Code"); + if (codeProperty == null) + { + throw new Exception("Column Code Not Exist"); + } + if (codeProperty.GetValue(entity, null) == null) + { + throw new Exception("Code Value Is Null"); + } + var rowVerValue = int.Parse(rowVerProperty.GetValue(entity, null).ToString()); + var codeValue = codeProperty.GetValue(entity, null).ToString(); + var sqlWhere = $" RowVer={rowVerValue} AND Code='{codeValue}'"; + rowVerProperty.SetValue(entity, rowVerValue + 1, null); + IUpdateable up = SqlSugarDb.Updateable(entity); + if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0) + { + up = up.IgnoreColumns(lstIgnoreColumns.Contains(lstIgnoreColumns.First())); + } + up = up.Where(sqlWhere); + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + + + //表达式写2列更新2列,其他不会更新 + /// + /// 修改 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 + /// 更新条件 + /// 是否加锁 + /// 操作影响的行数 + public int UpdateRowVer(Expression> update, Dictionary where, bool isLock = true) where T : class, new() + { + try + { + if (!where.ContainsKey("RowVer")) + { + throw new Exception("Column RowVer Not Exist"); + } + if (where["RowVer"] == null) + { + throw new Exception("RowVer Value Is Null"); + } + if (update.Body.ToString().IndexOf("RowVer", StringComparison.Ordinal) == -1) + { + throw new Exception("Column RowVer Update Is Null"); + } + var sqlWhere = ""; + foreach (var item in where) + { + sqlWhere += string.IsNullOrWhiteSpace(sqlWhere) ? $" {item.Key}='{item.Value}'" : $" and {item.Key}='{item.Value}'"; + } + IUpdateable up = SqlSugarDb.Updateable().UpdateColumns(update).Where(sqlWhere); + if (isLock) + { + up = up.With(SqlWith.UpdLock); + } + var result = up.ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + #endregion + + #region 删除 + /// + /// 初始化表 + /// + /// + /// + public void Delete() where T : class, new() + { + try + { + SqlSugarDb.DbMaintenance.TruncateTable(); + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + /// + /// 删除 + /// + /// 泛型参数(集合成员的类型) + /// 主键值 + /// 是否加锁 + /// 操作影响的行数 + public int DeleteByPrimary(List primaryKeyValues, bool isLock = true) where T : class, new() + { + try + { + var result = isLock ? + SqlSugarDb.Deleteable().In(primaryKeyValues).With(SqlWith.RowLock).ExecuteCommand() + : SqlSugarDb.Deleteable().In(primaryKeyValues).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + /// + /// 删除 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 (必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 是否加锁 + /// 操作影响的行数 + public int Delete(T entity, bool isLock = true) where T : class, new() + { + try + { + var result = isLock ? + SqlSugarDb.Deleteable(entity).With(SqlWith.RowLock).ExecuteCommand() + : SqlSugarDb.Deleteable(entity).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + /// + /// 删除 + /// + /// 泛型参数(集合成员的类型) + /// 实体对象 (必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]),如果是联合主键,请使用Where条件 + /// 是否加锁 + /// 操作影响的行数 + public int Delete(List entity, bool isLock = true) where T : class, new() + { + try + { + var result = isLock ? + SqlSugarDb.Deleteable(entity).With(SqlWith.RowLock).ExecuteCommand() + : SqlSugarDb.Deleteable(entity).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + /// + /// 删除 + /// + /// 泛型参数(集合成员的类型) + /// 条件 + /// 是否加锁 + /// 操作影响的行数 + public int Delete(Expression> where, bool isLock = true) where T : class, new() + { + try + { + var result = isLock ? + SqlSugarDb.Deleteable().Where(where).With(SqlWith.RowLock).ExecuteCommand() + : SqlSugarDb.Deleteable().Where(where).ExecuteCommand(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 异步删除 + /// + /// + /// + /// + /// + /// + public Task DeleteAsync(Expression> where, bool isLock = true) where T : class, new() + { + try + { + var result = isLock ? + SqlSugarDb.Deleteable().Where(where).With(SqlWith.RowLock).ExecuteCommandAsync() + : SqlSugarDb.Deleteable().Where(where).ExecuteCommandAsync(); + return result; + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + + } + + /// + /// 通过多值(主键)删除数据集 + /// + /// 泛型参数(集合成员的类型) + /// 数据集合 + /// 值 + public int DeleteIn(List inValues) where T : class, new() + { + return SqlSugarDb.Deleteable().With(SqlWith.RowLock).In(inValues).ExecuteCommand(); + } + + + #endregion + + + + #region 私有方法 + + /// + /// SqlParameter转换SugarParameter + /// + /// 参数 + /// + private List ConvetParameter(List parameters) + { + var listParams = new List(); + foreach (var p in parameters) + { + var par = new SugarParameter(p.ParameterName, p.Value) + { + DbType = p.DbType, + Direction = p.Direction + }; + if (!string.IsNullOrWhiteSpace(p.TypeName)) + { + par.TypeName = p.TypeName; + } + listParams.Add(par); + } + + return listParams; + } + + /// + /// 过滤条件转换 + /// + /// 过滤条件 + /// 值 + private List ParseCondition(List contitons) + { + var conds = new List(); + contitons.Insert(0, new QueryCondition + { + Operator = QueryOperator.Equal, + Key = "1", + Value = "1" + }); + + #region Or条件组装 + var orConditional = new ConditionalCollections { ConditionalList = new List>() }; + foreach (var con in contitons.Where(m => m.Character == QueryCharacter.Or)) + { + if (orConditional.ConditionalList.Count == 0) + { + var cond = new KeyValuePair + (WhereType.And, new ConditionalModel() + { + FieldName = con.Key, + ConditionalType = (ConditionalType)(int)con.Operator, + FieldValue = con.Value.ToString() + }); + orConditional.ConditionalList.Add(cond); + } + else + { + var cond = new KeyValuePair + (WhereType.Or, new ConditionalModel() + { + FieldName = con.Key, + ConditionalType = (ConditionalType)(int)con.Operator, + FieldValue = con.Value.ToString() + }); + orConditional.ConditionalList.Add(cond); + } + } + #endregion + + #region And条件组装 + foreach (var con in contitons.Where(m => m.Character == QueryCharacter.And)) + { + if (con.Key.Contains(",")) + { + ParseKeyOr(con, orConditional); + } + else if (con.Operator == QueryOperator.DateRange) + { + conds.AddRange(ParseRange(con, con.Operator)); + } + else + { + conds.Add(new ConditionalModel() + { + FieldName = con.Key, + ConditionalType = (ConditionalType)(int)con.Operator, + FieldValue = con.Value.ToString() + }); + } + } + + #endregion + + //Or条件是否存在 + if (orConditional.ConditionalList.Count > 0) + { + conds.Add(orConditional); + } + + return conds; + } + + /// + /// Key逗号隔开转换Or条件 + /// + /// 过滤条件 + /// 条件集合 + /// 值 + private void ParseKeyOr(QueryCondition condition, ConditionalCollections conditionalCollections) + { + var objectKeys = condition.Key.Split(','); + foreach (var objKey in objectKeys) + { + if (conditionalCollections.ConditionalList.Count == 0) + { + var cond = new KeyValuePair + (WhereType.And, new ConditionalModel() + { + FieldName = objKey, + ConditionalType = (ConditionalType)(int)condition.Operator, + FieldValue = condition.Value.ToString() + }); + conditionalCollections.ConditionalList.Add(cond); + } + else + { + var cond = new KeyValuePair + (WhereType.Or, new ConditionalModel() + { + FieldName = objKey, + ConditionalType = (ConditionalType)(int)condition.Operator, + FieldValue = condition.Value.ToString() + }); + conditionalCollections.ConditionalList.Add(cond); + } + } + } + + /// + /// 转换区域 + /// + /// 过滤条件 + /// 条件类型 + /// 值 + private List ParseRange(QueryCondition condition, QueryOperator queryOperator) + { + var objectValue = condition.Value.ToString().Split('|'); + + var conditionalList = new List(); + if (objectValue.Length == 2) + { + var startValue = objectValue[0]; + var endValue = objectValue[1]; + if (queryOperator == QueryOperator.DateRange) + { + if (startValue.IndexOf(":", StringComparison.Ordinal) == -1) + { + startValue = startValue + " 00:00:00"; + } + if (endValue.IndexOf(":", StringComparison.Ordinal) == -1) + { + endValue = endValue + " 23:59:59"; + } + } + if (!string.IsNullOrWhiteSpace(objectValue[0])) + { + conditionalList.Add(new ConditionalModel() + { + FieldName = condition.Key, + ConditionalType = ConditionalType.GreaterThanOrEqual, + FieldValue = startValue + }); + } + if (!string.IsNullOrWhiteSpace(objectValue[1])) + { + conditionalList.Add(new ConditionalModel() + { + FieldName = condition.Key, + ConditionalType = ConditionalType.LessThanOrEqual, + FieldValue = endValue + }); + } + } + return conditionalList; + } + + /// + /// 排序转换 + /// + /// 排序 + /// 值 + private string ParseOrderBy(List orderBys) + { + var conds = ""; + foreach (var con in orderBys) + { + switch (con.Order) + { + case OrderSequence.Asc: + conds += $"{con.Sort} asc,"; + break; + case OrderSequence.Desc: + conds += $"{con.Sort} desc,"; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return conds.TrimEnd(','); + } + + #endregion + + public void Dispose() + { + SqlSugarDb.Ado.Dispose(); + SqlSugarDb.Dispose(); + + } + + + } +} diff --git a/JinYuan.DAL/app.config b/JinYuan.DAL/app.config new file mode 100644 index 0000000..01c6fee --- /dev/null +++ b/JinYuan.DAL/app.config @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JinYuan.DAL/packages.config b/JinYuan.DAL/packages.config new file mode 100644 index 0000000..c74b161 --- /dev/null +++ b/JinYuan.DAL/packages.config @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JinYuan.Helper/ArrayHelper.cs b/JinYuan.Helper/ArrayHelper.cs new file mode 100644 index 0000000..b57c9b0 --- /dev/null +++ b/JinYuan.Helper/ArrayHelper.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JinYuan.Helper +{ + public class ArrayHelper + { + /// + /// 判断两个数组的元素是否相等 + /// + /// + /// + /// + public static bool Equal(T[] arr1, T[] arr2) + { + bool res = false; + if (arr1 == null || arr2 == null) + { + return res; + } + if (arr1.Length == arr2.Length) + { + res = true; + for (int index = 0; index < arr1.Length; ++index) + { + if (!arr1[index].Equals(arr2[index])) + { + res = false; + break; + } + } + } + return res; + } + + /// + /// 获取数组的子数组 + /// + /// 类型 + /// 数组 + /// 起始索引 + /// 长度 + /// + public static T[] GetSubArray(T[] arr, int startIndex, int length) + { + T[] res = new T[length]; + for (int index = 0; index < length; ++index) + { + res[index] = arr[startIndex + index]; + } + return res; + } + + /// + /// 数组合并 + /// + /// + /// + /// + /// + public static byte[] Combine(IEnumerable tList) + { + int allLength = 0; + foreach (byte[] t in tList) + { + allLength += t.Length; + } + byte[] res = new byte[allLength]; + int lenIndex = 0; + foreach (byte[] t in tList) + { + Array.Copy(t, 0, res, lenIndex, t.Length); + lenIndex += t.Length; + } + return res; + } + + /// + /// 数组格式化输出字符串 + /// + /// 待处理数据 + /// + public static string ArrayFormatOutput(T[] arr) + { + StringBuilder res = new StringBuilder(); + for (int index = 0; index < arr.Count() - 1; ++index) + { + res.Append(string.Format("{0}-", arr[index].ToString())); + } + if (arr.Count() - 1 > 0) + { + res.Append(arr[arr.Count() - 1]); + } + return res.ToString(); + } + + /// + /// 数组格式化输出字符串 + /// + /// + /// 待处理数据 + /// buffer 参数中开始发送数据的位置,该位置从零开始计数。 + /// 要发送的字节数。 + /// + public static string ArrayFormatOutput(T[] arr, int offset, int size) + { + StringBuilder res = new StringBuilder(); + for (int index = offset; index < size; ++index) + { + res.Append(string.Format("{0}-", arr[index].ToString())); + } + if (size - 1 > 0) + { + res.Append(arr[size]); + } + return res.ToString(); + } + + } +} diff --git a/JinYuan.Helper/CSVHelper.cs b/JinYuan.Helper/CSVHelper.cs new file mode 100644 index 0000000..080a651 --- /dev/null +++ b/JinYuan.Helper/CSVHelper.cs @@ -0,0 +1,346 @@ +using CsvHelper; +using CsvHelper.Configuration; +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +namespace JinYuan.Helper +{ + public class CSVHelper + { + /// + /// 读取CSV文件 + /// + /// csv文件名 + /// + public static List ReadCSV(string fileName, string strSeparator = "\t") + { + if (!File.Exists(fileName)) return null; + + using (var reader = new StreamReader(fileName, Encoding.Default)) + { + var cfg = new CsvConfiguration(CultureInfo.InvariantCulture) + { + Mode = CsvMode.Escape, + Escape = '\\', + Delimiter = strSeparator, // 设置分隔符号 + HeaderValidated = null, // 跳过表头验证 + MissingFieldFound = null // 忽略缺失字段 + }; + + using (var csv = new CsvReader(reader, cfg)) + { + var list = csv.GetRecords().ToList(); + return list; + } + } + } + + + /// + /// 写入CSV文件 + /// + /// csv文件名 + /// + public static bool WriterCSV(string fileName, List records) + { + try + { + FileStream Log = null; + if (!Directory.Exists(fileName)) + Directory.CreateDirectory(fileName); + string file = (fileName + DateTime.Now.ToString("yyyyMMdd")) + ".csv"; + var cfg = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture); + if (!File.Exists(file)) + { + Log = new FileStream(file, FileMode.Create); + } + else + { + cfg.HasHeaderRecord = false;//是否将第一行作为标题 + } + if (Log != null) + { + Log.Close(); + } + //Nuget获取CsvHelper + using (var writer = new StreamWriter(file, true, Encoding.Default)) + { + using (var csv = new CsvWriter(writer, cfg)) + { + csv.WriteRecords(records); + writer.Flush(); + return true; + } + } + } + catch (Exception ex) + { + + throw ex; + } + } + + + /// + /// 写入指定列表CSV文件 + /// + /// + /// + /// + /// + /// + public static bool WriterCSV(string directory, string fileName, string title, string content) + { + FileStream fs = null; + StreamWriter sw = null; + + try + { + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + string fullFileName = $@"{directory}\{fileName}"; + if (!File.Exists(fullFileName)) + { + fs = new FileStream(fullFileName, FileMode.Create, FileAccess.Write); + sw = new StreamWriter(fs, Encoding.UTF8); + sw.WriteLine(title); + } + else + { + fs = new FileStream(fullFileName, FileMode.Append, FileAccess.Write); + sw = new StreamWriter(fs, Encoding.UTF8); + } + + sw.WriteLine(content); + + sw.Close(); + fs.Close(); + + return true; + } + catch (Exception ex) + { + sw?.Close(); + fs?.Close(); + } + + return false; + } + + + /// + /// 获取当天的日期的文件 + /// + /// + /// + public static List FindTodayFile(string CurrPath) + { + try + { + if (!Directory.Exists(CurrPath)) + { + return null; + } + DirectoryInfo di = new DirectoryInfo(CurrPath); + FileInfo[] ffis = di.GetFiles(); + string today = DateTime.Now.Year.ToString().Substring(0, 4) + DateTime.Now.Month.ToString("0#") + DateTime.Now.Day.ToString("0#"); + List listFilePath = new List(); + + for (int i = 0; i < ffis.Length; i++) + { + FileInfo tmp = ffis[i]; + if (tmp.Name.Substring(0, 8) == today) + { + listFilePath.Add(tmp.FullName); + } + } + return (listFilePath.Count > 0) ? listFilePath : null; + } + catch (Exception ex) + { + + throw ex; + } + + } + + /// + /// + /// + /// + /// + public static List FindHostFile(string CurrPath, DateTime date) + { + try + { + if (!Directory.Exists(CurrPath)) + { + return null; + } + DirectoryInfo di = new DirectoryInfo(CurrPath); + FileInfo[] ffis = di.GetFiles(); + string today = date.ToString().Substring(0, 4) + date.Month.ToString("0#") + date.Day.ToString("0#"); + //var result1 = Regex.Replace(date, @"[^0-9]+", ""); + //string today = result1.Substring(0,8); + List listFilePath = new List(); + + for (int i = 0; i < ffis.Length; i++) + { + FileInfo tmp = ffis[i]; + if (tmp.Name.Substring(0, 8) == today) + { + listFilePath.Add(tmp.FullName); + } + } + return (listFilePath.Count > 0) ? listFilePath : null; + } + catch (Exception ex) + { + + throw ex; + } + + } + + + /// + /// 导出到CSV文件 + /// + /// 报表DataTable + /// 导出路径 + /// 输出信息 + /// 自定义的列名称,以','英文逗号分隔 + /// 表名,一般为空 + /// 是否导出成功 + public static bool ExportDataTableToCSV(DataTable table, string filePath, out string msg, string columnName = null, string tableHeader = null) + { + try + { + string dirPath = Path.GetDirectoryName(filePath); + if (!Directory.Exists(dirPath)) + { + Directory.CreateDirectory(dirPath);//文件的父目录不存在就创建新目录 + } + bool IsAppend = false; //false为创建 true为追加 + if (File.Exists(filePath)) + { + IsAppend = true;//如果文件存在就不写入表头 + } + using (FileStream _stream = new FileStream(filePath, FileMode.Create | FileMode.Append, FileAccess.Write)) + { + StreamWriter _writer = new StreamWriter(_stream, Encoding.UTF8); + if (tableHeader != null) + { + _writer.WriteLine(tableHeader); + } + + if (columnName != null && !IsAppend) + { + _writer.WriteLine(columnName); + } + else if (columnName == null && !IsAppend) + { + List columnNameList = new List(); + foreach (DataColumn dc in table.Columns) + { + columnNameList.Add(dc.ColumnName); + } + _writer.WriteLine(string.Join(",", columnNameList)); + } + + for (int i = 0; i < table.Rows.Count; i++) + { + for (int j = 0; j < table.Columns.Count; j++) + { + _writer.Write(table.Rows[i][j].ToString()); + _writer.Write(","); + } + _writer.WriteLine(); + } + _writer.Close(); + msg = "导出CSV文件成功"; + return true; + } + } + catch (Exception ex) + { + msg = string.Format("导出CSV文件失败,原因:{0}", ex.Message); + return false; + } + } + + + /// + /// 导出报表为Csv + /// + /// DataTable + /// 物理路径 + /// 表头 + /// 字段标题,逗号分隔 + public static bool dt2csv(DataTable dt, string strFilePath, string tableheader, string columname) + { + try + { + string strBufferLine = ""; + StreamWriter strmWriterObj = new StreamWriter(strFilePath, false, System.Text.Encoding.UTF8); + strmWriterObj.WriteLine(tableheader); + strmWriterObj.WriteLine(columname); + for (int i = 0; i < dt.Rows.Count; i++) + { + strBufferLine = ""; + for (int j = 0; j < dt.Columns.Count; j++) + { + if (j > 0) + strBufferLine += ","; + strBufferLine += dt.Rows[i][j].ToString(); + } + strmWriterObj.WriteLine(strBufferLine); + } + strmWriterObj.Close(); + return true; + } + catch + { + return false; + } + } + + /// + /// 将Csv读入DataTable + /// + /// csv文件路径 + /// 表示第n行是字段title,第n+1行是记录开始 + public static DataTable csv2dt(string filePath, int n, DataTable dt) + { + StreamReader reader = new StreamReader(filePath, System.Text.Encoding.UTF8, false); + int i = 0, m = 0; + reader.Peek(); + while (reader.Peek() > 0) + { + m = m + 1; + string str = reader.ReadLine(); + if (m >= n + 1) + { + string[] split = str.Split(','); + + System.Data.DataRow dr = dt.NewRow(); + for (i = 0; i < split.Length; i++) + { + dr[i] = split[i]; + } + dt.Rows.Add(dr); + } + } + return dt; + } + + } +} diff --git a/JinYuan.Helper/ChartHelper.cs b/JinYuan.Helper/ChartHelper.cs new file mode 100644 index 0000000..d64fe17 --- /dev/null +++ b/JinYuan.Helper/ChartHelper.cs @@ -0,0 +1,313 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Text; +using System.Windows.Forms.DataVisualization.Charting; + +namespace JinYuan.Helper +{ + public class ChartHelper + { + // 字体缓存 + private static readonly Dictionary _fontCache = new Dictionary(); + private static PrivateFontCollection _fontCollection; + private static readonly object _fontLock = new object(); + + /// + /// 初始化字体集合 + /// + private static void InitializeFontCollection() + { + if (_fontCollection == null) + { + lock (_fontLock) + { + if (_fontCollection == null) + { + _fontCollection = new PrivateFontCollection(); + try + { + // 只加载一次字体文件 + string fontPath = Environment.CurrentDirectory + "\\Assts\\Fonts\\Zen圓体-Regular.ttf"; + if (System.IO.File.Exists(fontPath)) + { + _fontCollection.AddFontFile(fontPath); + } + } + catch (Exception ex) + { + // 字体加载失败,使用默认字体 + LogHelper.Instance.WriteError($"字体加载失败: {ex.Message}", "FontError"); + } + } + } + } + } + + /// + /// 获取字体 + /// + /// 字体大小 + /// 字体样式 + /// 字体对象 + private static Font GetFont(float size, FontStyle style) + { + string key = $"{size}_{style}"; + + if (_fontCache.TryGetValue(key, out Font cachedFont)) + { + return cachedFont; + } + + lock (_fontLock) + { + if (_fontCache.TryGetValue(key, out cachedFont)) + { + return cachedFont; + } + + InitializeFontCollection(); + Font font; + + try + { + if (_fontCollection != null && _fontCollection.Families.Length > 0) + { + FontFamily fontFamily = new FontFamily(_fontCollection.Families[0].Name, _fontCollection); + font = new Font(fontFamily, size, style); + } + else + { + // 使用默认字体作为 fallback + font = new Font("微软雅黑", size, style); + } + } + catch + { + // 字体创建失败,使用默认字体 + font = new Font("微软雅黑", size, style); + } + + _fontCache[key] = font; + return font; + } + } + + /// + /// 清理字体缓存 + /// + public static void ClearFontCache() + { + lock (_fontLock) + { + foreach (var font in _fontCache.Values) + { + font.Dispose(); + } + _fontCache.Clear(); + + if (_fontCollection != null) + { + _fontCollection.Dispose(); + _fontCollection = null; + } + } + } + + /// + /// Name:添加序列 + /// + /// + /// 图表对象 + /// 序列名称 + /// 图表类型 + /// 图表值类型 + /// 标记样式 + /// 标记大小 + /// 颜色 + /// 标记点颜色 + /// 标签样式 + /// 是否显示百分比 + /// 是否显示数值 + public static void AddSeries(Chart chart, string seriesName, SeriesChartType chartType, ChartValueType chartValueType, MarkerStyle markerStyle, int markerSize, Color seriesColor, Color markColor, string LabelStyle, bool isShowBFH, bool showValue = false) + { + chart.Series.Add(seriesName); + chart.Series[seriesName].ChartType = chartType; + chart.Series[seriesName].Color = seriesColor; + if (showValue) + { + Font myFont = GetFont(9.0f, FontStyle.Bold); + + chart.Series[seriesName].IsValueShownAsLabel = showValue; + chart.Series[seriesName].XValueType = chartValueType; + chart.Series[seriesName].Label = LabelStyle; + chart.Series[seriesName].Font = myFont; + chart.Series[seriesName].MarkerStyle = markerStyle; + chart.Series[seriesName].MarkerColor = markColor; + chart.Series[seriesName].MarkerStyle = MarkerStyle.Circle; //线条上的数据点标志类型 + chart.Series[seriesName].MarkerSize = markerSize; //标志大小 + chart.Series[seriesName].LabelToolTip = "#VALX: #VALY"; + chart.Series[seriesName].LabelForeColor = markColor; + chart.Series[seriesName].LabelAngle = -75; + chart.Series[seriesName].BorderWidth = 3; + chart.Series[seriesName].LabelBorderWidth = 5; + + if (isShowBFH) + { + chart.Series[seriesName].YAxisType = AxisType.Secondary; + } + + } + } + + /// + /// Name:设置标题 + /// + /// + /// 图表对象 + /// 图表名称 + /// 字体 + /// 停靠位置 + /// 前景色 + public static void SetTitle(Chart chart, string chartName, Font font, Docking docking, Color foreColor) + { + chart.Titles.Add(chartName); + chart.Titles[0].Font = font; + chart.Titles[0].Docking = docking; + chart.Titles[0].ForeColor = foreColor; + } + + /// + /// Name:设置样式 + /// 2019-04-23 14:04 + /// + /// 图表对象 + /// 背景颜色 + /// 字体颜色 + public static void SetStyle(Chart chart, Color backColor, Color foreColor) + { + chart.BackColor = backColor; + chart.ChartAreas[0].BackColor = backColor; + chart.ForeColor = Color.Red; + } + + /// + /// Name:设置图例 + /// Author: + /// + /// 图表对象 + /// 停靠位置 + /// 对齐方式 + /// 背景颜色 + /// 字体颜色 + public static void SetLegend(Chart chart, Docking docking, StringAlignment align, Color backColor, Color foreColor) + { + Font myFont = GetFont(9.0f, FontStyle.Regular); + + chart.Legends[0].Docking = docking; + chart.Legends[0].Alignment = align; + chart.Legends[0].BackColor = backColor; + chart.Legends[0].ForeColor = foreColor; + chart.Legends[0].Font = myFont; + + } + + /// + /// Name:设置XY轴 + /// Author: + /// + /// 图表对象 + /// X轴标题 + /// Y轴标题 + /// 角度 + /// 坐标轴标题对齐方式 + /// 坐标轴字体颜色 + /// 坐标轴颜色 + /// 坐标轴箭头样式 + /// X轴的间距 + /// 是否显示百分比 + /// 是否显示时间 + public static void SetXY(Chart chart, string xTitle, string yTitle, int Angle, StringAlignment align, Color foreColor, Color lineColor, AxisArrowStyle arrowStyle, double xInterval, bool isShowBFH, bool isShowTime = false) + { + Font myFont = GetFont(15f, FontStyle.Regular); + + chart.ChartAreas[0].AxisX.TitleForeColor = foreColor; + chart.ChartAreas[0].AxisX.LabelStyle = new LabelStyle() { ForeColor = foreColor }; + chart.ChartAreas[0].AxisX.LabelStyle.Angle = Angle; + chart.ChartAreas[0].AxisX.LineColor = lineColor; + chart.ChartAreas[0].AxisX.LabelStyle.ForeColor = lineColor; + chart.ChartAreas[0].AxisX.ArrowStyle = arrowStyle; + chart.ChartAreas[0].AxisX.Interval = xInterval; + chart.ChartAreas[0].AxisX.Title = xTitle; + chart.ChartAreas[0].AxisX.TitleAlignment = align; + + chart.ChartAreas[0].AxisY.TitleForeColor = foreColor; + chart.ChartAreas[0].AxisY.LabelStyle = new LabelStyle() { ForeColor = foreColor }; + chart.ChartAreas[0].AxisY.LineColor = lineColor; + chart.ChartAreas[0].AxisY.LabelStyle.ForeColor = lineColor; + chart.ChartAreas[0].AxisY.ArrowStyle = arrowStyle; + chart.ChartAreas[0].AxisY.Title = yTitle; + chart.ChartAreas[0].AxisY.TitleAlignment = align; + + if (isShowBFH) + { + chart.ChartAreas[0].AxisY2.Minimum = 0; + chart.ChartAreas[0].AxisY2.Maximum = 1.2; + chart.ChartAreas[0].AxisY2.Interval = 0.2; + chart.ChartAreas[0].AxisY2.LabelStyle = new LabelStyle() { ForeColor = foreColor }; + chart.ChartAreas[0].AxisY2.LineColor = lineColor; + chart.ChartAreas[0].AxisY2.LabelStyle.ForeColor = lineColor; + chart.ChartAreas[0].AxisY2.LabelStyle.Format = "0.00%"; + } + + ////设置图表显示样式 + if (isShowTime) + { + chart.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss"; //毫秒格式: hh:mm:ss.fff ,后面几个f则保留几位毫秒小数,此时要注意轴的最大值和最小值不要差太大 + chart.ChartAreas[0].AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Seconds; + chart.ChartAreas[0].AxisX.Interval = xInterval; //坐标值间隔1S + chart.ChartAreas[0].AxisX.LabelStyle.IsEndLabelVisible = false; //防止X轴坐标跳跃 + chart.ChartAreas[0].AxisX.MajorGrid.IntervalType = DateTimeIntervalType.Seconds; + + //chart.ChartAreas[0].AxisY.L = 1; //网格间隔 + + chart.ChartAreas[0].AxisX.Minimum = DateTime.Now.ToOADate(); //当前时间 + chart.ChartAreas[0].AxisX.Maximum = DateTime.Now.ToOADate(); + } + } + + /// + /// Name:设置网格 + /// Author: + /// + /// 图表对象 + /// 网格线颜色 + /// X轴网格的间距 + /// Y轴网格的间距 + /// 是否显示X轴网格 + /// 是否显示Y轴网格 + public static void SetMajorGrid(Chart chart, Color lineColor, double xInterval, double yInterval, bool isMajorGridX = false, bool isMajorGridY = false) + { + chart.ChartAreas[0].AxisX.MajorGrid.Enabled = isMajorGridX; + chart.ChartAreas[0].AxisY.MajorGrid.Enabled = isMajorGridY; + chart.ChartAreas[0].AxisY2.MajorGrid.Enabled = isMajorGridY; + if (isMajorGridX) + { + chart.ChartAreas[0].AxisX.MajorGrid.LineColor = lineColor; + + chart.ChartAreas[0].AxisX.MajorGrid.Interval = xInterval; + + chart.ChartAreas[0].AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dash; + + } + + if (isMajorGridY) + { + chart.ChartAreas[0].AxisY.MajorGrid.LineColor = lineColor; + chart.ChartAreas[0].AxisY.MajorGrid.Interval = yInterval; + chart.ChartAreas[0].AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash; + } + + } + } +} \ No newline at end of file diff --git a/JinYuan.Helper/ClearMemoryHelper.cs b/JinYuan.Helper/ClearMemoryHelper.cs new file mode 100644 index 0000000..e1cf8b2 --- /dev/null +++ b/JinYuan.Helper/ClearMemoryHelper.cs @@ -0,0 +1,31 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace JinYuan.Helper +{ + public class ClearMemoryHelper + { + [DllImport("kernel32.dll")] + private static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max); + /// + /// 释放内存 + /// + public static void ClearMemory() + { + Task.Run(async () => + { + while (true) + { + await Task.Delay(4000).ConfigureAwait(false); + GC.Collect(); + GC.WaitForPendingFinalizers(); + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); + } + } + }); + } + } +} diff --git a/JinYuan.Helper/ConvertHelper.cs b/JinYuan.Helper/ConvertHelper.cs new file mode 100644 index 0000000..62a1371 --- /dev/null +++ b/JinYuan.Helper/ConvertHelper.cs @@ -0,0 +1,18 @@ +using System.Linq; + +namespace JinYuan.Helper +{ + public static class ConvertHelper + { + /// + /// 字节数组高低位转换 + /// + /// + /// + public static byte[] ByteReverse(this byte[] Arrbyte) + { + byte[] ArrByte = Arrbyte.Select((x, i) => new { x, i }).GroupBy(x => x.i / 2).SelectMany(x => new byte[] { x.Last().x, x.First().x }).ToArray(); + return ArrByte; + } + } +} diff --git a/JinYuan.Helper/DataGridViewHelper.cs b/JinYuan.Helper/DataGridViewHelper.cs new file mode 100644 index 0000000..69fc700 --- /dev/null +++ b/JinYuan.Helper/DataGridViewHelper.cs @@ -0,0 +1,132 @@ +using System; +using System.Drawing; +using System.Reflection; +using System.Windows.Forms; + +namespace JinYuan.Helper +{ + public static class DataGridViewHelper + { + /// + /// 给DataGridView添加行号 + /// + /// dgv控件 + /// dgv参数 + public static void DgvRowPostPaint(DataGridView dgv, DataGridViewRowPostPaintEventArgs e) + { + try + { + //添加行号 + SolidBrush solidBrush = new SolidBrush(dgv.RowHeadersDefaultCellStyle.ForeColor); + string lineNo = (e.RowIndex + 1).ToString(); + e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + StringFormat sf = new StringFormat(); + sf.LineAlignment = StringAlignment.Center; + sf.Alignment = StringAlignment.Center; + e.Graphics.DrawString(lineNo, e.InheritedRowStyle.Font, solidBrush, new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, dgv.RowHeadersWidth, dgv.RowTemplate.Height), sf); + } + catch (Exception ex) + { + MessageBox.Show("添加行号时发生错误,错误信息:" + ex.Message, "操作失败"); + } + } + + /// + /// 给DataGridView指定列改变前景色 + /// + /// + /// + public static void DgvRowPrePaint(DataGridView dgv, string Column, object sender, DataGridViewRowPrePaintEventArgs e) + { + + if (e.RowIndex > dgv.Rows.Count - 1) + return; + DataGridViewRow dr = (sender as DataGridView).Rows[e.RowIndex]; + + try + { + if (dr.Cells[Column].Value != null && dr.Cells[Column].Value.Equals("OK")) + { + // 设置单元格的前景色 + dr.Cells[Column].Style.ForeColor = Color.LightGreen; + } + else + { + dr.Cells[Column].Style.ForeColor = Color.Red; + } + } + catch (Exception ex) + { + MessageBox.Show("更改状态时发生错误,错误信息:" + ex.Message, "操作失败"); + + } + } + + /// + /// 给DataGridView绘制边框 + /// + /// dgv控件 + /// dgv参数 + public static void DgvRowPaint(DataGridView dgv, PaintEventArgs e, Color borderColor) + { + e.Graphics.DrawRectangle(new Pen(borderColor), new Rectangle(0, 0, dgv.Width - 1, dgv.Height - 1)); + } + + /// + /// 奇偶换色 + /// + public static void DgvStyle(DataGridView dgv, Color defaultBackColor, Color alternatingBackColor, Color gridColor) + { + //奇数行的背景色 + dgv.AlternatingRowsDefaultCellStyle.BackColor = alternatingBackColor; + dgv.AlternatingRowsDefaultCellStyle.SelectionBackColor = alternatingBackColor; + + //默认的行样式 + dgv.RowsDefaultCellStyle.BackColor = defaultBackColor; + dgv.RowsDefaultCellStyle.SelectionBackColor = defaultBackColor; + + + dgv.RowHeadersDefaultCellStyle.BackColor = defaultBackColor; + dgv.RowHeadersDefaultCellStyle.SelectionBackColor = defaultBackColor; + + //数据网格颜色 + dgv.GridColor = gridColor; + } + + + + + /// + /// 双缓冲,解决闪烁问题 + /// + /// + /// + public static void DoubleBufferedDataGirdView(this DataGridView dgv, bool flag) + { + Type dgvType = dgv.GetType(); + PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic); + pi.SetValue(dgv, flag, null); + } + + + /// + /// 双缓冲,解决闪烁问题 + /// + /// + /// + public static void DoubleBufferedListView(this ListView lv, bool flag) + { + Type lvType = lv.GetType(); + PropertyInfo pi = lvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic); + pi.SetValue(lv, flag, null); + } + + public static void DoubleBufferedListBox(this ListBox lb, bool flag) + { + Type lvType = lb.GetType(); + PropertyInfo pi = lvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic); + pi.SetValue(lb, flag, null); + } + } +} diff --git a/JinYuan.Helper/DataTableExtend.cs b/JinYuan.Helper/DataTableExtend.cs new file mode 100644 index 0000000..b1cb9ee --- /dev/null +++ b/JinYuan.Helper/DataTableExtend.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; + +namespace JinYuan.Helper +{ + /// + /// DataTable扩展方法类 + /// + public static class DataTableExtend + { + /// + /// DataTable转成List + /// + public static List ToDataList(this DataTable dt) + { + var list = new List(); + var plist = new List(typeof(T).GetProperties()); + + if (dt == null || dt.Rows.Count == 0) + { + return null; + } + + foreach (DataRow item in dt.Rows) + { + T s = Activator.CreateInstance(); + for (int i = 0; i < dt.Columns.Count; i++) + { + PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName); + if (info != null) + { + try + { + if (!Convert.IsDBNull(item[i])) + { + object v = null; + if (info.PropertyType.ToString().Contains("System.Nullable")) + { + v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType)); + } + else + { + v = Convert.ChangeType(item[i], info.PropertyType); + } + info.SetValue(s, v, null); + } + } + catch (Exception ex) + { + throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message); + } + } + } + list.Add(s); + } + return list; + } + + + /// + /// DataTable转成实体对象 + /// + /// + /// + /// + public static T ToDataEntity(this DataTable dt) + { + T s = Activator.CreateInstance(); + if (dt == null || dt.Rows.Count == 0) + { + return default(T); + } + var plist = new List(typeof(T).GetProperties()); + for (int i = 0; i < dt.Columns.Count; i++) + { + PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName); + if (info != null) + { + try + { + if (!Convert.IsDBNull(dt.Rows[0][i])) + { + object v = null; + if (info.PropertyType.ToString().Contains("System.Nullable")) + { + v = Convert.ChangeType(dt.Rows[0][i], Nullable.GetUnderlyingType(info.PropertyType)); + } + else + { + v = Convert.ChangeType(dt.Rows[0][i], info.PropertyType); + } + info.SetValue(s, v, null); + } + } + catch (Exception ex) + { + throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message); + } + } + } + return s; + } + + /// + /// List转成DataTable + /// + /// 实体类型 + /// 实体集合 + public static DataTable ToDataTable(List entities) + { + if (entities == null || entities.Count == 0) + { + return null; + } + + var result = CreateTable(); + FillData(result, entities); + return result; + } + + /// + /// 创建表 + /// + private static DataTable CreateTable() + { + var result = new DataTable(); + var type = typeof(T); + foreach (var property in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) + { + var propertyType = property.PropertyType; + if ((propertyType.IsGenericType) && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))) + propertyType = propertyType.GetGenericArguments()[0]; + result.Columns.Add(property.Name, propertyType); + } + return result; + } + + /// + /// 填充数据 + /// + private static void FillData(DataTable dt, IEnumerable entities) + { + foreach (var entity in entities) + { + dt.Rows.Add(CreateRow(dt, entity)); + } + } + + /// + /// 创建行 + /// + private static DataRow CreateRow(DataTable dt, T entity) + { + DataRow row = dt.NewRow(); + var type = typeof(T); + foreach (var property in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) + { + row[property.Name] = property.GetValue(entity) ?? DBNull.Value; + } + return row; + } + } +} diff --git a/JinYuan.Helper/DeleteLog.cs b/JinYuan.Helper/DeleteLog.cs new file mode 100644 index 0000000..d71c767 --- /dev/null +++ b/JinYuan.Helper/DeleteLog.cs @@ -0,0 +1,206 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace JinYuan.Helper +{ + public class DeleteLog + { + public static void Start(string[] strPata, short[] methodSelect) + { + Init(strPata, methodSelect); + } + + private static void Init(string[] strPata, short[] methodSelect) + { + Task.Run(() => + { + try + { + while (true) + { + for (int i = 0; i < strPata.Length; i++) + { + switch (methodSelect[i]) + { + case 0: + bool b = DeleteDirectory(strPata[i], 30); //删除该目录下 超过 30天的文件 + if (b) + { + LogHelper.Instance.WriteLog($"已清除路径:{strPata[i]},30天内过期日志"); + } + break; + case 1: + bool c = DeleteFile(strPata[i], 30); + if (c) + { + LogHelper.Instance.WriteLog($"已清除路径:{strPata[i]},30天内过期日志"); + } + break; + default: + break; + } + } + //24小时清一次 + Thread.Sleep(1000 * 60 * 60 * 24); + } + } + catch (Exception e) + { + Thread.Sleep(1000 * 60 * 60 * 28); + } + }); + } + + public static void DeleteDirectory(string target_dir) + { + string[] files = Directory.GetFiles(target_dir); + string[] dirs = Directory.GetDirectories(target_dir); + foreach (string file in files) + { + File.SetAttributes(file, FileAttributes.Normal); + File.Delete(file); + } + foreach (string dir in dirs) + { + DeleteDirectory(dir); + } + Directory.Delete(target_dir, false); + } + + private static bool DeleteDirectory(string fileDirect, int saveDay) + { + try + { + if (!Directory.Exists(fileDirect)) + { + LogHelper.Instance.WriteLog($"{fileDirect},文件夹不存在"); + return false; + } + DateTime nowTime = DateTime.Now; + string[] files = Directory.GetFiles(fileDirect, "*.*", SearchOption.AllDirectories); //获取该目录下所有 .txt文件 + foreach (string file in files) + { + FileInfo fileInfo = new FileInfo(file); + TimeSpan t = DateTime.Now - fileInfo.CreationTime; //当前时间 减去 文件创建时间 + int day = t.Days; + if (day > saveDay) //保存的时间,单位:天 + { + if (IsOccupy(fileInfo.FullName)) //判断文件是否被占用 + { + if (fileDirect.Contains("Mes"))//MesLogs + { + Directory.Delete(fileInfo.Directory.Parent.FullName, true); + return true; + } + else//其它 + { + Directory.Delete(fileInfo.Directory.FullName, true); + return true; + } + } + else + { + LogHelper.Instance.WriteLog($"{fileInfo.FullName},文件被占用,无法操作!"); + } + } + } + } + catch (Exception err) + { + LogHelper.Instance.WriteLog($"APILog日志删除异常,异常原因:{err}"); + } + return false; + } + + public static bool DeleteFile(string fileDirect, int saveDay) + { + try + { + if (!Directory.Exists(fileDirect)) + { + LogHelper.Instance.WriteLog($"{fileDirect},文件夹不存在"); + return false; + } + DateTime nowTime = DateTime.Now; + string[] files = Directory.GetFiles(fileDirect, "*.*", SearchOption.AllDirectories); //获取该目录下所有 .txt文件 + foreach (string file in files) + { + FileInfo fileInfo = new FileInfo(file); + + TimeSpan t = DateTime.Now - fileInfo.LastWriteTime;// fileInfo.CreationTime; //当前时间 减去 文件创建时间 + int day = t.Days; + if (day > saveDay) //保存的时间,单位:天 + { + if (IsOccupy(fileInfo.FullName)) //判断文件是否被占用 + { + System.IO.File.Delete(fileInfo.FullName); //删除文件 + } + else + { + LogHelper.Instance.WriteLog($"{fileInfo.FullName},文件被占用,无法操作!"); + } + } + } + return true; + } + catch (Exception err) + { + LogHelper.Instance.WriteLog($"Logs日志删除异常,异常原因:{err}"); + } + return false; + } + + [DllImport("kernel32.dll")] + public static extern IntPtr _lopen(string lpPathName, int iReadWrite); + + [DllImport("kernel32.dll")] + public static extern bool CloseHandle(IntPtr hObject); + + public const int OF_READWRITE = 2; + public const int OF_SHARE_DENY_NONE = 0x40; + public static readonly IntPtr HFILE_ERROR = new IntPtr(-1); + + /// + /// 判断文件是否被占用 + /// + /// + /// + private static bool IsOccupy(string file) + { + bool result = true; //默认状态此文件未被占用 + try + { + //string vFileName = @"c:\temp\temp.bmp"; + string vFileName = file; + if (!System.IO.File.Exists(vFileName)) + { + //Logger.Info("文件都不存在!"); + result = false; + } + IntPtr vHandle = _lopen(vFileName, OF_READWRITE | OF_SHARE_DENY_NONE); + if (vHandle == HFILE_ERROR) + { + + //Log4Helper.WriteLog("文件被占用!", "错误提示"); + result = false; + } + CloseHandle(vHandle); + // Log4Helper.WriteLog("没有被占用!", "错误提示"); + + + } + catch (Exception err) + { + result = false; + //Log4Helper.WriteLog("判断文件是否被占用", err); + + + } + return result; + } + + } +} diff --git a/JinYuan.Helper/EnergyMeterHelper.cs b/JinYuan.Helper/EnergyMeterHelper.cs new file mode 100644 index 0000000..446acd8 --- /dev/null +++ b/JinYuan.Helper/EnergyMeterHelper.cs @@ -0,0 +1,348 @@ +using JinYuan.Models; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; + +namespace JinYuan.Helper +{ + public class EnergyMeterHelper + { + public const int BufferSize = 1024;//6kb + + private int _timeout = 2000; + private Ping _ping = null; + private IPEndPoint _endPoint = null; + private Socket EnergyMeterSocket = null; + private PingReply _pingReply = null; + private string _lastError = ""; + + public enum ModBusExceptionCode //错误代码 + { + IllegalFunction = 01, + IllegalDataAddress, + IllegalDataValue, + SlaveDeviceFailure, + Acknowledge, + SlaveDeviceBusy, + GatewayPathUnavailable, + GatewayTargetDeviceFailed2Respond, + } + + /// + /// 构造函数 + /// + public EnergyMeterHelper() + { + // used to ping the PLC + // + this._ping = new Ping(); + + // EndPoint parametres + // + this._endPoint = new IPEndPoint(0, 0); + } + + /// + /// set ip and port + /// + public void SetTCPParams(IPAddress ip, int port) + { + this._endPoint.Address = ip; + this._endPoint.Port = port; + } + + /// + /// returns the connection status + /// + public bool Connected + { + get + { + try + { + return (EnergyMeterSocket == null) ? false : EnergyMeterSocket.Connected; + } + catch (Exception ex) + { + //PrintfLog.LogError(ex.Message); + return false; + } + } + } + + /// + /// close the socket + /// + /// + public void Close() + { + lock (this) + { + if (EnergyMeterSocket == null) return; + if (Connected) + { + EnergyMeterSocket.Disconnect(false); + EnergyMeterSocket.Close(); + } + EnergyMeterSocket.Dispose(); + EnergyMeterSocket = null; + } + } + + public bool Connect() + { + if (this.Connected == true) + { + return true; + } + + try + { + if (this.TCPConnect()) + { + return true; + } + else + { + return false; + } + } + catch (Exception ex) + { + Close(); + return false; + } + } + + private bool TCPConnect() + { + try + { + if (EnergyMeterSocket != null) + { + EnergyMeterSocket.Dispose(); + } + EnergyMeterSocket = new Socket(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + EnergyMeterSocket.SendTimeout = _timeout; + EnergyMeterSocket.ReceiveTimeout = _timeout; + EnergyMeterSocket.Connect(this._endPoint); + return this.Connected; + } + catch (System.Exception ex) + { + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 智能电表:网口连接失败"); + return false; + } + } + + public bool Ping() + { + try + { + if (this._endPoint.Address == null) return false; + + this._pingReply = this._ping.Send(this._endPoint.Address, this._timeout); + + return (this._pingReply.Status == IPStatus.Success) ? true : false; + + } + catch (Exception) + { + //PrintfLog.LogError("ECFFU ping exception"); + return false; + } + } + + public bool SendAndGetRes(byte[] bytes, ref List listM)//, ref JetReturnResult jet + { + var arrayPool = ArrayPool.Shared; + byte[] buffer = arrayPool.Rent(BufferSize);//new byte[1024]; + byte[] RecvData = new byte[88 * 4 + 9];//0x58 + int size = 88 * 4 + 9;//0x58 + + if (!Ping()) + { + return false; + } + try + { + // 发送 + Send(bytes, bytes.Length); + // 接收 + Receive(ref RecvData, size); + // 解析 + if ((RecvData[0] == Convert.ToByte(01 >> 8) && RecvData[1] == Convert.ToByte(01)))//pTask.id + { + if (RecvData[7] == 0x04)//读线圈寄存器功能码 + { + //数据赋值 + Array.Copy(RecvData, 0, buffer, 0, RecvData.Length); + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取原始数据:{string.Join(" ", RecvData)}"); + + decimal PhaseVoltageA = Convert.ToDecimal(HextoFloat(buffer[9], buffer[10], buffer[11], buffer[12])); + decimal PhaseVoltageB = Convert.ToDecimal(HextoFloat(buffer[13], buffer[14], buffer[15], buffer[16])); + decimal PhaseVoltageC = Convert.ToDecimal(HextoFloat(buffer[17], buffer[18], buffer[19], buffer[20])); + decimal PhaseCurrentA = Convert.ToDecimal(HextoFloat(buffer[21], buffer[22], buffer[23], buffer[24])); + decimal PhaseCurrentB = Convert.ToDecimal(HextoFloat(buffer[25], buffer[26], buffer[27], buffer[28])); + decimal PhaseCurrentC = Convert.ToDecimal(HextoFloat(buffer[29], buffer[30], buffer[31], buffer[32])); + decimal PhasePowerA = Convert.ToDecimal(HextoFloat(buffer[33], buffer[34], buffer[35], buffer[36])); + decimal PhasePowerB = Convert.ToDecimal(HextoFloat(buffer[37], buffer[38], buffer[39], buffer[40])); + decimal PhasePowerC = Convert.ToDecimal(HextoFloat(buffer[41], buffer[42], buffer[43], buffer[44])); + decimal ActivePower = Convert.ToDecimal(HextoFloat(buffer[121], buffer[122], buffer[123], buffer[124])); + decimal PowerFactor = Convert.ToDecimal(HextoFloat(buffer[133], buffer[134], buffer[135], buffer[136])); + decimal pt = 1; + decimal ct = 150 / 5; + decimal AccumulatedElectricity = Convert.ToDecimal(HextoFloat(buffer[181], buffer[182], buffer[183], buffer[184])); + + ElectricEnergy m = new ElectricEnergy(); + m.PhaseVoltageA = PhaseVoltageA; + m.PhaseVoltageB = PhaseVoltageB; + m.PhaseVoltageC = PhaseVoltageC; + m.PhaseCurrentA = PhaseCurrentA * ct; + m.PhaseCurrentB = PhaseCurrentB * ct; + m.PhaseCurrentC = PhaseCurrentC * ct; + m.PhasePowerA = PhaseVoltageA * PhaseCurrentA * ct; + m.PhasePowerB = PhaseVoltageB * PhaseCurrentB * ct; + m.PhasePowerC = PhaseVoltageC * PhaseCurrentC * ct; + m.ActivePower = ActivePower * ct; + m.PowerFactor = PowerFactor * ct; + m.pt = pt;//Convert.ToDecimal(HextoFloat(buffer[0], buffer[0], buffer[0], buffer[0])); + m.ct = ct;//Convert.ToDecimal(HextoFloat(buffer[0], buffer[0], buffer[0], buffer[0])); + m.AccumulatedElectricity = AccumulatedElectricity; + listM.Add(m); + } + else + { + switch (RecvData[8]) + { + case (byte)ModBusExceptionCode.IllegalDataAddress: + _lastError = string.Format("SendAndGetRes():ReadInputRegister [IllegalDataAddress]"); + break; + case (byte)ModBusExceptionCode.IllegalDataValue: + _lastError = string.Format("SendAndGetRes():ReadInputRegister [IllegalDataValue]"); + break; + case (byte)ModBusExceptionCode.IllegalFunction: + _lastError = string.Format("SendAndGetRes():ReadInputRegister [IllegalFunction]"); + break; + default: + _lastError = string.Format("SendAndGetRes():ReadInputRegister [FunctionException]"); + break; + } + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取数据异常,原因:{_lastError}"); + } + } + } + catch (Exception ex) + { + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取原始数据:{string.Join(" ", RecvData)}"); + TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取数据异常,原因:{ex}"); + Close(); + return false; + } + finally + { + arrayPool.Return(buffer); + } + return true; + } + + /// + /// send a command to energy meter device + /// + /// + /// + /// + private int Send(Byte[] command, int cmdLen) + { + if (!Connected) + { + throw new Exception("EnergyMeter Socket is not connected."); + } + // sends the command + // + int bytesSent = EnergyMeterSocket.Send(command, cmdLen, SocketFlags.None); + + // it checks the number of bytes sent + // + if (bytesSent != cmdLen) + { + string msg = string.Format("EnergyMeter Sending error. (Expected bytes: {0} Sent: {1})", cmdLen, bytesSent); + throw new Exception(msg); + } + return bytesSent; + } + + /// + /// receives a response from the plc + /// + /// + /// + /// + private int Receive(ref Byte[] response, int respLen) + { + if (!this.Connected) + { + throw new Exception("EnergyMeter Socket is not connected."); + } + + // receives the response, this is a synchronous method and can hang the process + int bytesRecv = EnergyMeterSocket.Receive(response, respLen, SocketFlags.None); + + // check the number of bytes received + // + // if (bytesRecv != respLen) + // { + // string msg = string.Format("Receiving error. (Expected: {0} Received: {1})" + // , respLen, bytesRecv); + // throw new Exception(msg); + // } + return bytesRecv; + } + + + /// + /// HexToFloat + /// + /// 高字高字节 + /// 高字低字节 + /// 低字高字节 + /// 低字低字节 + /// float + public static float HextoFloat(byte H1, byte H2, byte D1, byte D2) + { + try + { + //byte-->short + int s1, s2; + s1 = Convert.ToInt32(H1 * 256) + Convert.ToInt32(H2); + s2 = Convert.ToInt32(D1 * 256) + Convert.ToInt32(D2); + + //将输入数值short转化为无符号unsigned short + int us1 = s1, us2 = s2; + if (s1 < 0) us1 += 65536; + if (s2 < 0) us2 += 65536; + //sign: 符号位, exponent: 阶码, mantissa:尾数 + int sign, exponent; + float mantissa; + //计算符号位 + sign = us1 / 32768; + //去掉符号位 + int emCode = us1 % 32768; + //计算阶码 + exponent = emCode / 128; + //计算尾数 + mantissa = (float)(emCode % 128 * 65536 + us2) / 8388608; + //代入公式 fValue = (-1) ^ S x 2 ^ (E - 127) x (1 + M) + return (float)Math.Pow(-1, sign) * (float)Math.Pow(2, exponent - 127) * (1 + mantissa); + } + catch (Exception ex) + { + return 0; + } + } + } +} diff --git a/JinYuan.Helper/FileHelper.cs b/JinYuan.Helper/FileHelper.cs new file mode 100644 index 0000000..e7eea94 --- /dev/null +++ b/JinYuan.Helper/FileHelper.cs @@ -0,0 +1,267 @@ +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; + +namespace JinYuan.Helper +{ + public class FileHelper + { + #region 1.文本文件读写 + + + public static void WriteToTxt(string path, string content, bool isAppend = false) + { + //【1】创建文件流 + FileStream fileStream = new FileStream(path, isAppend ? FileMode.Append : FileMode.Create); + + //【2】创建写入器 + StreamWriter streamWriter = new StreamWriter(fileStream); + + //【3】以流的形式写入数据 + streamWriter.Write(content); + + //【4】关闭写入器 + streamWriter.Close(); + + //【5】关闭文件流 + fileStream.Close(); + } + + + public static string ReadFromTxt(string path) + { + //判断文件是否存在 + if (!File.Exists(path)) + { + return string.Empty; + } + + //【1】创建文件流 + FileStream fileStream = new FileStream(path, FileMode.Open); + + //【2】创建读取器 + StreamReader streamReader = new StreamReader(fileStream); + + //【3】以流的方式读取 + string content = streamReader.ReadToEnd(); + + //【4】关闭读取器 + streamReader.Close(); + + //【5】关闭文件流 + fileStream.Close(); + + return content; + + } + + #endregion + + #region 2.对象序列化文件 + + /// + /// 序列化一个对象到一个文件中 + /// + /// + /// + public static void SerializeObject(object obj, string path) + { + FileStream fileStream = null; + + try + { + fileStream = new FileStream(path, FileMode.Create); + + BinaryFormatter binaryFormatter = new BinaryFormatter(); + + binaryFormatter.Serialize(fileStream, obj); + + } + catch (Exception ex) + { + throw new Exception("序列化对象出错:" + ex.Message); + } + finally + { + fileStream.Close(); + } + } + + + public static T DeSerializeObject(string path) + { + FileStream fileStream = null; + + try + { + fileStream = new FileStream(path, FileMode.Open); + + BinaryFormatter binaryFormatter = new BinaryFormatter(); + + return (T)binaryFormatter.Deserialize(fileStream); + + } + catch (Exception ex) + { + throw new Exception("反序列化对象出错:" + ex.Message); + } + finally + { + fileStream.Close(); + } + } + + + #endregion + + #region 3.对象序列化字符串 + + /// + /// 将对象序列化成字符串 + /// + /// + /// + public static string SerializeObjToString(object obj) + { + IFormatter formatter = new BinaryFormatter(); + + string result = string.Empty; + + using (MemoryStream stream = new MemoryStream()) + { + formatter.Serialize(stream, obj); + + byte[] bytes = stream.ToArray(); + + result = Convert.ToBase64String(bytes); + + stream.Flush(); + + } + return result; + } + + /// + /// 将字符串反序列化成对象 + /// + /// + /// + /// + public static T DeSerializeObjFromString(string str) where T : class + { + IFormatter formatter = new BinaryFormatter(); + + byte[] bytes = Convert.FromBase64String(str); + + T obj = null; + + using (MemoryStream stream = new MemoryStream(bytes, 0, bytes.Length)) + { + obj = (T)formatter.Deserialize(stream); + } + + return obj; + } + + #endregion + + #region 4.文件的基本操作 + + /// + /// 文件复制 + /// + /// + /// + public static void CopyFile(string srcFileName, string desFileName) + { + if (File.Exists(desFileName)) + { + File.Delete(desFileName); + } + + File.Copy(srcFileName, desFileName); + + } + + + /// + /// 文件移动 + /// + /// + /// + public static void MoveFile(string srcFileName, string desFileName) + { + if (File.Exists(srcFileName)) + { + if (File.Exists(desFileName)) + { + File.Delete(desFileName); + } + + File.Move(srcFileName, desFileName); + } + } + + /// + /// 文件删除 + /// + /// + public static void DeleteFile(string fileName) + { + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + } + + #endregion + + + #region 5.文件夹的相关操作 + + /// + /// 获取指定目录下的所有文件 + /// + /// + /// + public static string[] GetFiles(string path) + { + return Directory.GetFiles(path); + } + + /// + /// 获取指定目录下的所有子目录 + /// + /// + /// + public static string[] GetDirectories(string path) + { + return Directory.GetDirectories(path); + } + + /// + /// 创建文件夹 + /// + /// + public static void CreateDirectory(string path) + { + Directory.CreateDirectory(path); + } + + /// + /// 删除指定目录下的所有子目录和文件 + /// + /// + public static void DeleteFiles(string path) + { + DirectoryInfo directory = new DirectoryInfo(path); + + directory.Delete(true); + } + + + #endregion + + } +} diff --git a/JinYuan.Helper/IniConfigHelper.cs b/JinYuan.Helper/IniConfigHelper.cs new file mode 100644 index 0000000..4d4c0e6 --- /dev/null +++ b/JinYuan.Helper/IniConfigHelper.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace JinYuan.Helper +{ + public class IniConfigHelper + { + /// + /// 文件路径 + /// + public static string iniFilePath = string.Empty; + + + #region API函数声明 + + [DllImport("kernel32")] + private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); + + //需要调用GetPrivateProfileString的重载 + [DllImport("kernel32", EntryPoint = "GetPrivateProfileString")] + private static extern long GetPrivateProfileString(string section, string key, + string def, StringBuilder retVal, int size, string filePath); + + [DllImport("kernel32", EntryPoint = "GetPrivateProfileString")] + private static extern uint GetPrivateProfileStringA(string section, string key, + string def, Byte[] retVal, int size, string filePath); + + #endregion + + /// + /// + /// + /// + /// + public static void CreateIniFile(string StartupPath, string AppName) + { + iniFilePath = StartupPath + AppName; + if (!Directory.Exists(StartupPath)) + { + Directory.CreateDirectory(StartupPath); + } + if (!File.Exists(iniFilePath)) + { + File.Create(iniFilePath).Close(); + } + } + + + #region 读取INI文件 + /// + /// 根据节点及Key的值返回数据 + /// + /// 节点 + /// 键 + /// 默认值 + /// 路径 + /// 返回值 + public static string ReadIniData(string Section, string Key, string NoText, string iniFilePath) + { + if (File.Exists(iniFilePath)) + { + StringBuilder stringBuilder = new StringBuilder(10240); + + GetPrivateProfileString(Section, Key, NoText, stringBuilder, 10240, iniFilePath); + + return stringBuilder.ToString(); + } + else + { + return string.Empty; + } + } + + + /// + /// 根据节点及Key的值返回数据 + /// + /// 节点 + /// 键 + /// 默认值 + /// 返回值 + public static string ReadIniData(string Section, string Key, string NoText) + { + return ReadIniData(Section, Key, NoText, iniFilePath); + } + + #endregion + + #region 写入Ini文件 + + /// + /// 根据节点及Key的值写入数据 + /// + /// 节点 + /// 键 + /// 值 + /// 路径 + /// 操作结果 + public static bool WriteIniData(string Section, string Key, string Value, string path) + { + long result = WritePrivateProfileString(Section, Key, Value, path); + + if (result == 0) + { + return false; + } + else + { + return true; + } + } + + /// + /// 根据节点及Key的值写入数据 + /// + /// 节点 + /// 键 + /// 值 + /// 操作结果 + public static bool WriteIniData(string Section, string Key, string Value) + { + return WriteIniData(Section, Key, Value, iniFilePath); + } + + #endregion + + #region 读取所有的Sections + + /// + /// 读取所有的Section + /// + /// 路径 + /// Section集合 + public static List ReadSections(string path) + { + byte[] buffer = new byte[65536]; + + uint length = GetPrivateProfileStringA(null, null, null, buffer, buffer.Length, path); + + int startIndex = 0; + + List sections = new List(); + + for (int i = 0; i < length; i++) + { + if (buffer[i] == 0) + { + sections.Add(Encoding.Default.GetString(buffer, startIndex, i - startIndex)); + startIndex = i + 1; + } + } + + return sections; + } + + /// + /// 读取所有的Section + /// + /// 路径 + /// Section集合 + public static List ReadSections() + { + byte[] buffer = new byte[65536]; + + uint length = GetPrivateProfileStringA(null, null, null, buffer, buffer.Length, iniFilePath); + + int startIndex = 0; + + List sections = new List(); + + for (int i = 0; i < length; i++) + { + if (buffer[i] == 0) + { + sections.Add(Encoding.Default.GetString(buffer, startIndex, i - startIndex)); + startIndex = i + 1; + } + } + + return sections; + } + + + + #endregion + + #region 根据某个Section读取所有的Keys + + /// + /// 根据某个Section读取所有的Keys + /// + /// 某个section + /// 路径 + /// key的集合 + public static List ReadKeys(string section, string path) + { + byte[] buffer = new byte[65536]; + + uint length = GetPrivateProfileStringA(section, null, null, buffer, buffer.Length, path); + + int startIndex = 0; + + List keys = new List(); + + for (int i = 0; i < length; i++) + { + if (buffer[i] == 0) + { + keys.Add(Encoding.Default.GetString(buffer, startIndex, i - startIndex)); + startIndex = i + 1; + } + } + + return keys; + + } + + /// + /// 根据某个Section读取所有的Keys + /// + /// 某个section + /// 路径 + /// key的集合 + public static List ReadKeys(string section) + { + byte[] buffer = new byte[65536]; + + uint length = GetPrivateProfileStringA(section, null, null, buffer, buffer.Length, iniFilePath); + + int startIndex = 0; + + List keys = new List(); + + for (int i = 0; i < length; i++) + { + if (buffer[i] == 0) + { + keys.Add(Encoding.Default.GetString(buffer, startIndex, i - startIndex)); + startIndex = i + 1; + } + } + + return keys; + + } + + #endregion + + } +} diff --git a/JinYuan.Helper/IniFileHelper.cs b/JinYuan.Helper/IniFileHelper.cs new file mode 100644 index 0000000..67298d2 --- /dev/null +++ b/JinYuan.Helper/IniFileHelper.cs @@ -0,0 +1,75 @@ +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; + +namespace JinYuan.Helper +{ + public class IniFileHelper + { + private static string iniFilePath = "Configure.ini"; + + [DllImport("kernel32")] + private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); + + [DllImport("kernel32")] + private static extern long GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); + + public static string ReadIniData(string Section, string Key) + { + try + { + if (File.Exists(iniFilePath)) + { + StringBuilder temp = new StringBuilder(1024); + GetPrivateProfileString(Section, Key, "", temp, 1024, iniFilePath); + return temp.ToString(); + } + MessageBox.Show("节点:" + Section + ",键名:" + Key + ":读取配置文件错误!"); + return null; + } + catch + { + throw; + } + } + + public static bool WriteIniData(string Section, string Key, string Value) + { + try + { + if (File.Exists(iniFilePath)) + { + if (WritePrivateProfileString(Section, Key, Value, iniFilePath) == 0L) + { + return false; + } + return true; + } + File.Create(iniFilePath).Close(); + if (WritePrivateProfileString(Section, Key, Value, iniFilePath) == 0L) + { + return false; + } + return true; + } + catch + { + throw; + } + } + + public static void CreateIniFile(string StartupPath, string AppName) + { + iniFilePath = StartupPath + AppName; + if (!Directory.Exists(StartupPath)) + { + Directory.CreateDirectory(StartupPath); + } + if (!File.Exists(iniFilePath)) + { + File.Create(iniFilePath).Close(); + } + } + } +} diff --git a/JinYuan.Helper/JinYuan.Helper.csproj b/JinYuan.Helper/JinYuan.Helper.csproj new file mode 100644 index 0000000..0a35936 --- /dev/null +++ b/JinYuan.Helper/JinYuan.Helper.csproj @@ -0,0 +1,175 @@ + + + + + + Debug + AnyCPU + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360} + Library + Properties + JinYuan.Helper + JinYuan.Helper + v4.8 + 512 + true + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\BouncyCastle.Cryptography.2.2.1\lib\net461\BouncyCastle.Cryptography.dll + + + ..\packages\CsvHelper.33.0.1\lib\net48\CsvHelper.dll + + + ..\packages\Enums.NET.4.0.1\lib\net45\Enums.NET.dll + + + ..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll + + + ..\packages\MathNet.Numerics.Signed.4.15.0\lib\net461\MathNet.Numerics.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll + + + ..\packages\Microsoft.IO.RecyclableMemoryStream.2.3.2\lib\net462\Microsoft.IO.RecyclableMemoryStream.dll + + + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NLog.6.0.2\lib\net46\NLog.dll + + + False + bin\Debug\PLCCommunication.dll + + + ..\packages\SixLabors.Fonts.1.0.0\lib\netstandard2.0\SixLabors.Fonts.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + + ..\packages\System.Configuration.ConfigurationManager.8.0.0\lib\net462\System.Configuration.ConfigurationManager.dll + + + + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + + ..\packages\System.Security.AccessControl.6.0.0\lib\net461\System.Security.AccessControl.dll + + + ..\packages\System.Security.Cryptography.Xml.6.0.1\lib\net461\System.Security.Cryptography.Xml.dll + + + ..\packages\System.Security.Permissions.6.0.0\lib\net461\System.Security.Permissions.dll + + + ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll + + + + ..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {4C0BCB84-5CD7-4846-8363-C4C10D46E391} + JinYuan.Models + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + \ No newline at end of file diff --git a/JinYuan.Helper/JsonHelper.cs b/JinYuan.Helper/JsonHelper.cs new file mode 100644 index 0000000..a22bc4a --- /dev/null +++ b/JinYuan.Helper/JsonHelper.cs @@ -0,0 +1,90 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Text; + +namespace JinYuan.Helper +{ + public class JsonHelper + { + /// + /// 使用Newtonsoft.json.dll对象序列化成Json字符串 + /// + /// + /// + /// + public static string EntityToJson(T t) + { + try + { + return JsonConvert.SerializeObject(t); + } + catch (Exception) + { + return string.Empty; + } + } + + /// + /// 使用Newtonsoft.json.dll 将Json字符串反序列化成对象 + /// + /// + /// + /// + public static T JsonToEntity(string json) + { + try + { + return (T)JsonConvert.DeserializeObject(json, typeof(T)); + } + catch (Exception) + { + return default(T); + } + } + + /// + /// 实体类转换成JSON字符串 + /// + /// + /// + /// + public static string EntityToJson2(T obj) + { + //序列化 + DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T)); + MemoryStream msObj = new MemoryStream(); + //将序列化之后的Json格式数据写入流中 + js.WriteObject(msObj, obj); + msObj.Position = 0; + //从0这个位置开始读取流中的数据 + StreamReader sr = new StreamReader(msObj, Encoding.Default); + string json = sr.ReadToEnd(); + sr.Close(); + msObj.Close(); + return json; + } + + + /// + /// JSON字符串转换成实体类 + /// + /// + /// + /// + public static T JsonToEntity2(string json) where T : class + { + //反序列化 + using (var ms = new MemoryStream(Encoding.Default.GetBytes(json))) + { + DataContractJsonSerializer deseralizer = new DataContractJsonSerializer(typeof(T)); + T model = (T)deseralizer.ReadObject(ms);// //反序列化ReadObject + return model; + } + } + + + + } +} diff --git a/JinYuan.Helper/LogHelper.cs b/JinYuan.Helper/LogHelper.cs new file mode 100644 index 0000000..9b67930 --- /dev/null +++ b/JinYuan.Helper/LogHelper.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +namespace JinYuan.Helper +{ + /// + /// 日志操作类 + /// + public class LogHelper + { + private static object singleLock = new object(); + + /// + /// log日志文件路径 + /// + public static string logFilePath = string.Empty; + + + public static LogHelper _instance = null; + public static LogHelper Instance + { + + get + { + if (_instance == null) + { + lock (singleLock) + { + if (_instance == null) + { + _instance = new LogHelper(); + } + } + } + return _instance; + } + + } + + + + + /// + /// 初始化 + /// + /// + public void InitLog(string configPath) + { + logFilePath = configPath; + if (!Directory.Exists(logFilePath)) + { + Directory.CreateDirectory(logFilePath); + } + //if (!File.Exists(logFilePath)) + //{ + // File.Create(logFilePath).Close(); + //} + } + + + /// + /// 写日志文件数据库日志文件 + /// + /// 消息 + public void WriteError(string message) + { + + AddLog(message, "Error"); + } + + public void WriteEX(Exception ex) + { + AddLog(ex.Message + "\r\n" + ex.InnerException + "\r\n" + ex.StackTrace + "\r\n" + ex.Source, "SysErrorLog"); + } + + public void WriteEX(string ErrorName, Exception ex) + { + AddLog(ErrorName + "\r\n" + ex.Message + "\r\n" + ex.InnerException + "\r\n" + ex.StackTrace + "\r\n" + ex.Source, "SysErrorLog"); + } + /// + /// 写日志文件数据库日志文件 + /// + /// 消息 + /// 日志存储目录名称 + public void WriteError(Exception ex, string direName) + { + AddLog(ex.Message + "\r\n" + ex.InnerException + "\r\n" + ex.StackTrace + "\r\n" + ex.Source, direName); + } + + /// + /// / + /// + /// + /// + public void WriteError(string message, string direName) + { + AddLog(message, direName); + } + /// + /// 写日志文件数据库日志文件 + /// + /// 消息 + public void WriteLog(string message) + { + + AddLog(message, "Info"); + } + /// + /// 写日志文件数据库日志文件 + /// + /// 消息 + /// 日志存储目录名称 + public void WriteLog(string message, string direName) + { + + AddLog(message, direName); + } + + /// + /// 写日志文件数据库日志文件 + /// + /// 消息 + /// 日志存储目录名称 + private void AddLog(string message, string direName) + { + string fileLog = logFilePath; + if (fileLog == "") + { + return; + } + try + { + var applicationName = direName; + //从宿主配置文件中获取日志文件全路径 + //所有的接口日志文件放在一个目录下面,跟web站点的目录分开 + //日志文件一天放一个,按日期分开 + + if (string.IsNullOrEmpty(applicationName)) + { + applicationName = "Log"; + } + string logFullPath = fileLog + applicationName; + + if (!Directory.Exists(logFullPath)) + { + Directory.CreateDirectory(logFullPath); + } + //只保留30天的日志 + var deletePath = $@"{logFullPath}\{DateTime.Now.AddDays(-30):yyyyMMddHH}.txt"; + + if (File.Exists(deletePath)) + { + File.Delete(deletePath); + } + + logFullPath = $@"{logFullPath}\{DateTime.Now:yyyyMMddHH}.txt"; + if (!File.Exists(logFullPath)) + { + using (var fs = new FileStream(logFullPath, FileMode.Create, FileAccess.Write)) + { + StreamWriter sw = new StreamWriter(fs); + sw.Close(); + fs.Close(); + } + } + + using (StreamWriter writer = new StreamWriter(logFullPath, true)) + { + writer.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + writer.WriteLine(message); + writer.WriteLine(Environment.NewLine); + + } + + } + catch + { + // ignored + } + } + + /// + /// 轴位置日志类 + /// + public class PrintMotorLog + { + private static readonly Thread WriteThread; + private static readonly Queue MsgQueue;//先进先出集合 + public static readonly object FileLock; + private static readonly string FilePath = "D:\\LOCAL\\轴位置修改记录(查看文件就复制到副本到桌面!!!)\\"; + static PrintMotorLog() + { + FileLock = new object();//文件锁 + + WriteThread = new Thread(WriteMsg); + MsgQueue = new Queue(); + WriteThread.Start(); + } + + public static void LogInfo(string BegionTime, string MotorDescribe, string IndxDescribe, string FrontIndx, string NewIndx) + { + Monitor.Enter(MsgQueue); + string strData = BegionTime + "," + + MotorDescribe + "," + + IndxDescribe + "," + + FrontIndx + "," + + NewIndx + ","; + MsgQueue.Enqueue(strData); + Monitor.Exit(MsgQueue); + } + private static void WriteMsg() + { + while (true) + { + Thread.Sleep(10); + if (MsgQueue.Count > 0) + { + Monitor.Enter(MsgQueue); + string msg = MsgQueue.Dequeue(); + Monitor.Exit(MsgQueue); + Monitor.Enter(FileLock); + if (!Directory.Exists(FilePath)) + { + Directory.CreateDirectory(FilePath); + } + string strFilename = FilePath + "轴位置修改_" + System.DateTime.Now.ToString("yyyyMMdd") + ".csv"; + //用默认编码和缓冲区大小,为指定的文件初始化 StreamWriter 类的一个新实例。 如果该文件存在,则可以将其覆盖或向其追加。 如果该文件不存在,则此构造函数将创建一个新文件。 + try + { + if (!File.Exists(strFilename)) + { + //文件标头 19 + string strProInfoFileHead = @"日期时间,轴描述,位置描述,位置修改前,当前位置"; + StreamWriter sw = new StreamWriter(strFilename, true, UnicodeEncoding.GetEncoding("GB2312")); + sw.WriteLine(strProInfoFileHead); + sw.Flush(); + sw.Close(); + sw.Dispose(); + } + StreamWriter se = new StreamWriter(strFilename, true, UnicodeEncoding.GetEncoding("GB2312")); + se.WriteLine(msg); + se.Flush(); + se.Close(); + se.Dispose(); + } + catch (Exception) + { + + + } + Monitor.Exit(FileLock); + if (GetFileSize(strFilename) > 1024 * 5) + { + CopyToBak(strFilename); + } + } + } + } + private static long GetFileSize(string fileName) + { + long strRe = 0; + if (File.Exists(fileName)) + { + Monitor.Enter(FileLock); + try + { + var myFs = new FileStream(fileName, FileMode.Open); + strRe = myFs.Length / 1024; + myFs.Close(); + myFs.Dispose(); + } + catch (Exception) + { + + + } + Monitor.Exit(FileLock); + } + return strRe; + } + + private static void CopyToBak(string sFileName) + { + int fileCount = 0; + string sBakName = ""; + Monitor.Enter(FileLock); + try + { + do + { + fileCount++; + sBakName = sFileName + "." + fileCount + ".BAK"; + } + while (File.Exists(sBakName)); + File.Copy(sFileName, sBakName); + File.Delete(sFileName); + } + catch (Exception) + { + + + } + Monitor.Exit(FileLock); + } + } + } +} diff --git a/JinYuan.Helper/Logger.cs b/JinYuan.Helper/Logger.cs new file mode 100644 index 0000000..b77da55 --- /dev/null +++ b/JinYuan.Helper/Logger.cs @@ -0,0 +1,63 @@ +using NLog; +using System; + + + +public class Logger +{ + + private static readonly NLog.Logger loginfo = LogManager.GetLogger("loginfo"); + private static readonly NLog.Logger logerror = LogManager.GetLogger("logerror"); + private static readonly NLog.Logger logmqtt = LogManager.GetLogger("logmqtt"); + private static readonly NLog.Logger logWHX = LogManager.GetLogger("logWHX"); + + private static readonly NLog.Logger logsInfo = LogManager.GetLogger("logsInfo"); + private static readonly NLog.Logger logsMEStIME = LogManager.GetLogger("logsMEStIME"); + private static readonly NLog.Logger logsSql = LogManager.GetLogger("logsSql"); + private static readonly NLog.Logger logsSysErrorLog = LogManager.GetLogger("logsSysErrorLog"); + private static readonly NLog.Logger logsSysErrorLogcn = LogManager.GetLogger("logsSysErrorLogcn"); + public static void WriteInfo(string info) + { + Console.WriteLine(info); + if (loginfo.IsInfoEnabled) + { + loginfo.Info(info); + } + } + + public static void WriteMqtt(string info) + { + Console.WriteLine(info); + if (logmqtt.IsInfoEnabled) + { + logmqtt.Info(info); + } + } + + public static void WriteError(string error) + { + Console.WriteLine(error); + if (logerror.IsErrorEnabled) + { + logerror.Error(error); + } + } + + public static void WriteError(string info, Exception ex) + { + Console.WriteLine(info); + if (logerror.IsErrorEnabled) + { + logerror.Error(info, ex); + } + } + public static void WriteWHX(string info) + { + Console.WriteLine(info); + if (logWHX.IsErrorEnabled) + { + logWHX.Error(info); + } + } +} + diff --git a/JinYuan.Helper/MockDataGenerator.cs b/JinYuan.Helper/MockDataGenerator.cs new file mode 100644 index 0000000..f578a69 --- /dev/null +++ b/JinYuan.Helper/MockDataGenerator.cs @@ -0,0 +1,101 @@ +using JinYuan.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace JinYuan.Helper +{ + public static class MockDataGenerator + { + public static readonly Random _random = new Random(); + + // 修改为与实际数据结构匹配的类 + public class ProdData + { + public string DisplayTime { get; set; } + public int ProdIn { get; set; } + public int ProdOut { get; set; } + public double OKRatio { get; set; } + } + + public class AlarmData + { + public string DataType { get; set; } + public int DataCount { get; set; } + } + + public class NGData + { + public string DataType { get; set; } + public int DataCount { get; set; } + } + + public static List Generate12HourData() + { + var result = new List(); + var random = new Random(); + + // 方法1:使用数组预定义顺序 + var timeSlots = new[] + { + "08:30", "09:30", "10:30", "11:30", "12:30", "13:30", "14:30", "15:30", "16:30", "17:30", + "18:30", "19:30", "20:30", "21:30", "22:30", "23:30", "00:30", "01:30", "02:30", "03:30", + "04:30", "05:30", "06:30", "07:30" + }; + + foreach (var timeSlot in timeSlots) + { + var prodIn = random.Next(800, 2000); + var prodOut = random.Next(700, prodIn); + var okRatio = Math.Round((double)prodOut / prodIn * 100, 2); + + result.Add(new Chart12HourData + { + DisplayTime = timeSlot, + ProdIn = prodIn, + ProdOut = prodOut, + OKRatio = okRatio.ToString("F2") + "%" + }); + } + + return result; // 不需要额外排序,因为已经按照需要的顺序生成 + } + + public static List GenerateAlarmTop10Data() + { + var alarmTypes = new[] + { + "设备故障", "原料异常", "温度超限", "压力异常", + "速度偏差", "位置错误", "通信中断", "电源故障", + "气压不足", "传感器异常" + }; + + return alarmTypes + .Select(type => new ChartDataType + { + DataType = type, + DataCount = _random.Next(5, 50) + }) + .OrderByDescending(x => x.DataCount) + .ToList(); + } + + public static List GenerateNGData() + { + var ngTypes = new[] + { + "尺寸超差", "表面划伤", "变形", "异物", + "色差", "气泡", "裂纹", "焊接不良" + }; + + return ngTypes + .Select(type => new ChartDataType + { + DataType = type, + DataCount = _random.Next(10, 100) + }) + .OrderByDescending(x => x.DataCount) + .ToList(); + } + } +} diff --git a/JinYuan.Helper/PLCAlarmParseHelper.cs b/JinYuan.Helper/PLCAlarmParseHelper.cs new file mode 100644 index 0000000..8458f58 --- /dev/null +++ b/JinYuan.Helper/PLCAlarmParseHelper.cs @@ -0,0 +1,232 @@ +using JinYuan.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace JinYuan.Helper +{ + public static class PLCAlarmParseHelper + { + /// + /// 三菱将报警地址值转成报警List + /// + /// PLC地址值,如100 + /// PLC读取出来的值 + /// PLC地址类型,默认值R + /// + public static List MelsecByte2Status(int plcAddrSuffix, byte[] byteData, char plcAddrPrefix = 'R') + { + var listAlarmStatus = new List(); + // byte[]转为二进制字符串表示 + string strResult = ""; + for (int i = 0; i < byteData.Length; i++) + { + string strTemp = System.Convert.ToString(byteData[i], 2); + strTemp = strTemp.PadLeft(8, '0').StrReverse(); + strResult += strTemp; + } + + for (int i = 0; i < strResult.Length; i++) + { + var plcByte = i % 16; + //如果是16的倍数地址+1 + if (plcByte % 16 == 0 && i != 0) + { + plcAddrSuffix++; + } + //将地址和状态添加到结果集 + listAlarmStatus.Add(new AlarmStatus() + { + PLCAdress = $"{plcAddrPrefix}{plcAddrSuffix}.{plcByte.ToString("X")}", + Status = strResult[i] == '1' + }); + //if (strResult[i] == '1') + // Console.WriteLine($"{plcAddrPrefix}{plcAddrSuffix}.{plcByte.ToString("X")}:{strResult[i]}"); + } + + return listAlarmStatus; + } + + + /// + /// 欧姆龙NX系列Ethernet/IP通讯时将报警地址值转成报警List {直接读取标签地址/无需高低位互换} + /// + /// PLC地址值,如100 + /// PLC读取出来的值 + /// PLC地址类型,默认值R + /// + public static List OmronEIPByte2Status(int plcAddrSuffix, List byteData, char plcAddrPrefix = 'W') + { + var listAlarmStatus = new List(); + // byte[]转为二进制字符串表示 + string strResult = ""; + for (int i = 0; i < byteData.Count; i++) + { + string strTemp = System.Convert.ToString(byteData[i], 2); + strTemp = strTemp.PadLeft(8, '0').StrReverse(); + strResult += strTemp; + } + + for (int i = 0; i < strResult.Length; i++) + { + var plcByte = i % 16; + //如果是16的倍数地址+1 + if (plcByte % 16 == 0 && i != 0) + { + plcAddrSuffix++; + } + //将地址和状态添加到结果集 + listAlarmStatus.Add(new AlarmStatus() + { + PLCAdress = $"{plcAddrPrefix}6100[{plcAddrSuffix}].B[{plcByte.ToString()}]", + Status = strResult[i] == '1' + }); + } + + return listAlarmStatus; + } + + + /// + /// 欧姆龙FINS通讯读取EM数据寄存器是时将报警地址值转成报警List + /// + /// PLC地址值,如100 + /// PLC读取出来的值 + /// PLC地址类型,默认值W + /// + public static List OmronFinsByte2Status(int plcAddrSuffix, byte[] byteData, char plcAddrPrefix = 'D') + { + var listAlarmStatus = new List(); + #region 取消 + // byte[]转为二进制字符串表示 + //byte[] revBytes = SWAPbyte(byteData); //字节高低位互换 + //string strResult = ""; + //for (int i = 0; i < revBytes.Length; i++) + //{ + // string strTemp = System.Convert.ToString(revBytes[i], 2); + // strTemp = strTemp.PadLeft(8, '0').StrReverse(); + // strResult += strTemp; + //} + + //for (int i = 0; i < strResult.Length; i++) + //{ + // var plcByte = i % 500; + // //如果是16的倍数地址+1 + // if (plcByte % 500 == 0 && i != 0) + // { + // plcAddrSuffix++; + // } + // //将地址和状态添加到结果集 + // listAlarmStatus.Add(new AlarmStatus() + // { + // PLCAdress = $"{plcAddrPrefix}{plcAddrSuffix}.{plcByte.ToString()}", + // Status = strResult[i] == '1' + // }); + // //if (strResult[i] == '1') + // // Console.WriteLine($"{plcAddrPrefix}{plcAddrSuffix}.{plcByte.ToString("X")}:{strResult[i]}"); + //} + + //将地址和状态添加到结果集 + //for (int i = 0; i < byteData.Length / 2; i++) + //{ + // listAlarmStatus.Add(new AlarmStatus() + // { + // PLCAdress = $"{plcAddrPrefix}{plcAddrSuffix + i}", + // Status = ShortLib.GetShortFromByteArray(byteData, (i * 2)) == 1, + // //Status = strResult[i] == '1' + // }); + //} + #endregion + int wordCount = byteData.Length / 2; // 16位整数数量 + + for (int i = 0; i < wordCount; i++) + { + int currentAddr = plcAddrSuffix + i; + int byteOffset = i * 2; + + // 组合字节为16位整数(大端序) + ushort wordValue = (ushort)( + (byteData[byteOffset] << 8) | + byteData[byteOffset + 1] + ); + + // 跳过0值(无报警) + if (wordValue == 0) continue; + + // 计算位地址(从1开始) + int bitPosition = wordValue; + string address = $"{plcAddrPrefix}{currentAddr}.{bitPosition}"; + + // 添加到报警列表(只添加实际触发的位) + listAlarmStatus.Add(new AlarmStatus() + { + PLCAdress = address, + Status = true // 只有触发的位才会被添加 + }); + } + return listAlarmStatus; + + } + + + /// + /// 欧姆龙FINS通讯读取W数据寄存器是时将报警地址值转成报警List + /// + /// PLC地址值,如100 + /// PLC读取出来的值 + /// PLC地址类型,默认值W + /// + //public static List OmronByte2Status(int plcAddrSuffix, byte[] byteData, char plcAddrPrefix = 'W') + //{ + // var listAlarmStatus = new List(); + + // var addrCount = byteData.Length / 2; + // // byte[]每个地址保存的都是bool值,只取双数index位 + // for (int i = 0; i < addrCount; i++) + // { + // //将地址和状态添加到结果集 + // listAlarmStatus.Add(new AlarmStatus() + // { + // PLCAdress = $"{plcAddrPrefix}{plcAddrSuffix + i}", + // Status = byteData[i * 2 + 1] == 1 + + // }); + // //if (byteData[i * 2 + 1] == 1) + // // Console.WriteLine($"原始数据 PLC地址:{plcAddrPrefix}{plcAddrSuffix + i} 报警值:{byteData[i * 2 + 1]}"); + // } + + // return listAlarmStatus; + //} + + + + + /// + /// 字符串反转 + /// + /// 需要反转字符串.Reverse() + /// + public static string StrReverse(this string str) + { + return new string(str.Reverse().ToArray()); + } + + + /// + ///byte字节高低位互换 + /// + /// + /// + public static byte[] SWAPbyte(byte[] data) + { + byte[] data2 = new byte[data.Length]; + for (int i = 0; i < data.Length; i += 2) + { + data2[i] = data[i + 1]; + data2[i + 1] = data[i]; + } + return data2; + } + } +} + diff --git a/JinYuan.Helper/Properties/AssemblyInfo.cs b/JinYuan.Helper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6d47b23 --- /dev/null +++ b/JinYuan.Helper/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.Helper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.Helper")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("258d0ab7-2b4f-4d8f-a3cd-7a8cb4a85360")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.Helper/ScanerHook.cs b/JinYuan.Helper/ScanerHook.cs new file mode 100644 index 0000000..a7cc54c --- /dev/null +++ b/JinYuan.Helper/ScanerHook.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace JinYuan.Helper +{ + public class ScanerHook + { + public delegate void ScanerDelegate(ScanerCodes codes); + public event ScanerDelegate ScanerEvent; + + //private const int WM_KEYDOWN = 0x100;//KEYDOWN + //private const int WM_KEYUP = 0x101;//KEYUP + //private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN + //private const int WM_SYSKEYUP = 0x105;//SYSKEYUP + //private static int HookProc(int nCode, Int32 wParam, IntPtr lParam); + private int hKeyboardHook = 0;//声明键盘钩子处理的初始值 + private ScanerCodes codes = new ScanerCodes();//13为键盘钩子 + //定义成静态,这样不会抛出回收异常 + private static HookProc hookproc; + delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + //设置钩子 + private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + //卸载钩子 + private static extern bool UnhookWindowsHookEx(int idHook); + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + //继续下个钩子 + private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam); + + [DllImport("user32", EntryPoint = "GetKeyNameText")] + private static extern int GetKeyNameText(int IParam, StringBuilder lpBuffer, int nSize); + [DllImport("user32", EntryPoint = "GetKeyboardState")] + //获取按键的状态 + private static extern int GetKeyboardState(byte[] pbKeyState); + [DllImport("user32", EntryPoint = "ToAscii")] + //ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符 + private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeySate, ref uint lpChar, int uFlags); + + //int VirtualKey //[in] 指定虚拟关键代码进行翻译。 + //int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压) + //byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如/果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。 + //byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。 + //uint fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. + + + + [DllImport("kernel32.dll")] + //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效 + public static extern IntPtr GetModuleHandle(string name); + public ScanerHook() + { + } + public bool Start() + { + if (hKeyboardHook == 0) + { + hookproc = new HookProc(KeyboardHookProc); + //GetModuleHandle 函数 替代 Marshal.GetHINSTANCE + //防止在 framework4.0中 注册钩子不成功 + IntPtr modulePtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName); + //WH_KEYBOARD_LL=13 + //全局钩子 WH_KEYBOARD_LL + // hKeyboardHook = SetWindowsHookEx(13, hookproc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0); + hKeyboardHook = SetWindowsHookEx(13, hookproc, modulePtr, 0); + } + return (hKeyboardHook != 0); + } + public bool Stop() + { + if (hKeyboardHook != 0) + { + bool retKeyboard = UnhookWindowsHookEx(hKeyboardHook); + hKeyboardHook = 0; + return retKeyboard; + + } + return true; + } + private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) + { + + + EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg)); + codes.Add(msg); + if (ScanerEvent != null && msg.message == 13 && msg.paramH > 0 && !string.IsNullOrEmpty(codes.Result)) + { + ScanerEvent(codes); + } + return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam); + } + public class ScanerCodes + { + private int ts = 100; // 指定输入间隔为300毫秒以内时为连续输入 + private List> _keys = new List>(); + private List _keydown = new List(); // 保存组合键状态 + private List _result = new List(); // 返回结果集 + private DateTime _last = DateTime.Now; + private byte[] _state = new byte[256]; + private string _key = string.Empty; + private string _cur = string.Empty; + public EventMsg Event + { + get + { + if (_keys.Count == 0) + { + return new EventMsg(); + } + else + { + return _keys[_keys.Count - 1][_keys[_keys.Count - 1].Count - 1]; + } + } + } + public List KeyDowns + { + get + { + return _keydown; + } + } + public DateTime LastInput + { + get + { + return _last; + } + } + public byte[] KeyboardState + { + get + { + return _state; + } + } + public int KeyDownCount + { + get + { + return _keydown.Count; + } + } + public string Result + { + get + { + if (_result.Count > 0) + { + return _result[_result.Count - 1].Trim(); + } + else + { + return null; + } + } + } + public string CurrentKey + { + get + { + return _key; + } + } + public string CurrentChar + { + get + { + return _cur; + } + } + public bool isShift + { + get + { + return _keydown.Contains(160); + } + } + public void Add(EventMsg msg) + { + #region 记录按键信息 + + // 首次按下按键 + if (_keys.Count == 0) + { + _keys.Add(new List()); + _keys[0].Add(msg); + _result.Add(string.Empty); + } + // 未释放其他按键时按下按键 + else if (_keydown.Count > 0) + { + _keys[_keys.Count - 1].Add(msg); + } + // 单位时间内按下按键 + else if (((TimeSpan)(DateTime.Now - _last)).TotalMilliseconds < ts) + { + _keys[_keys.Count - 1].Add(msg); + } + // 从新记录输入内容 + else + { + _keys.Add(new List()); + _keys[_keys.Count - 1].Add(msg); + _result.Add(string.Empty); + } + #endregion + _last = DateTime.Now; + #region 获取键盘状态 + // 记录正在按下的按键 + if (msg.paramH == 0 && !_keydown.Contains(msg.message)) + { + _keydown.Add(msg.message); + } + // 清除已松开的按键 + if (msg.paramH > 0 && _keydown.Contains(msg.message)) + { + _keydown.Remove(msg.message); + } + #endregion + #region 计算按键信息 + + int v = msg.message & 0xff; + int c = msg.paramL & 0xff; + StringBuilder strKeyName = new StringBuilder(500); + if (GetKeyNameText(c * 65536, strKeyName, 255) > 0) + { + _key = strKeyName.ToString().Trim(new char[] { ' ', '\0' }); + GetKeyboardState(_state); + if (_key.Length == 1 && msg.paramH == 0)// && msg.paramH == 0 + { + // 根据键盘状态和shift缓存判断输出字符 + _cur = ShiftChar(_key, isShift, _state).ToString(); + _result[_result.Count - 1] += _cur; + } + // 备选 + else + { + _cur = string.Empty; + } + } + #endregion + } + private char ShiftChar(string k, bool isShiftDown, byte[] state) + { + bool capslock = state[0x14] == 1; + bool numlock = state[0x90] == 1; + bool scrolllock = state[0x91] == 1; + bool shiftdown = state[0xa0] == 1; + char chr = (capslock ? k.ToUpper() : k.ToLower()).ToCharArray()[0]; + if (isShiftDown) + { + if (chr >= 'a' && chr <= 'z') + { + chr = (char)((int)chr - 32); + } + else if (chr >= 'A' && chr <= 'Z') + { + if (chr == 'Z') + { + string s = ""; + } + chr = (char)((int)chr + 32); + } + else + { + string s = "`1234567890-=[];',./"; + string u = "~!@#$%^&*()_+{}:\"<>?"; + if (s.IndexOf(chr) >= 0) + { + return (u.ToCharArray())[s.IndexOf(chr)]; + } + } + } + return chr; + } + } + + public struct EventMsg + { + public int message; + public int paramL; + public int paramH; + public int Time; + public int hwnd; + } + } +} diff --git a/JinYuan.Helper/SendDateMQTT.cs b/JinYuan.Helper/SendDateMQTT.cs new file mode 100644 index 0000000..a841d25 --- /dev/null +++ b/JinYuan.Helper/SendDateMQTT.cs @@ -0,0 +1,855 @@ +using JinYuan.Models; +using Newtonsoft.Json; +using PLCCommunication.MQTT; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace JinYuan.Helper +{ + public class MqttService : IDisposable + { + private readonly MqttClient _mqttClient; + private readonly object _syncLock = new object(); + private readonly MqttConfig _config; + public class MqttConfig + { + public string ServerAddress { get; set; } = "10.22.161.1"; + public int ServerPort { get; set; } = 2883; + public string ClientId { get; set; } = "601PWM01"; + //进出站主题 + public string TopicInOut { get; set; } = "EVE/60J/TrackInOut/601PWM01"; + //预测性维护数据主题 + public string TopicForecast { get; set; } = "EVE/60J/EQP/601PWM01"; + // 其他配置项... + } + + public MqttService(MqttConfig config) + { + _config = config; + _mqttClient = new MqttClient(new MqttConnectionOptions + { + ClientId = _config.ClientId, + IpAddress = _config.ServerAddress, + Port = _config.ServerPort, + Credentials = new MqttCredential("", "") // 无用户名密码 + }); + InitializeConnection(); + StartHeartbeat();//心跳检测 + } + + #region 长连接 + /// + /// 初始化长连接 + /// + private void InitializeConnection() + { + lock (_syncLock) + { + if (_mqttClient.IsConnected) return; + var result = _mqttClient.ConnectServer(); + if (result.IsSuccess) + { + Logger.WriteMqtt("MQTT 长连接建立成功"); + // 订阅需要的主题 + SubscribeTopics(); + } + else + { + Logger.WriteMqtt($"MQTT 长连接建立失败: {result.Message}"); + } + } + } + /// + /// 订阅主题 + /// + private void SubscribeTopics() + { + //_mqttClient.OnMqttMessageReceived += MqttMessageReceived; + + var topics = new[] { _config.TopicInOut, _config.TopicForecast }; + foreach (var topic in topics) + { + var result = _mqttClient.SubscribeMessage(topic); + if (result.IsSuccess) + { + Logger.WriteMqtt($"订阅主题成功: {topic}"); + } + else + { + Logger.WriteMqtt($"订阅主题失败: {topic}, 错误: {result.Message}"); + } + } + } + + /// + /// 消息接收处理 + /// + /// + /// + private void MqttMessageReceived(MqttClient client, MqttApplicationMessage message) + { + Logger.WriteMqtt($"收到消息: 主题[{message.Topic}], 内容[{Encoding.UTF8.GetString(message.Payload)}]"); + } + #endregion + + #region 发送消息 + /// + /// 发送进出站消息 + /// + /// + public void SendInOutMessage(string action) + { + try + { + lock (_syncLock) + { + if (!_mqttClient.IsConnected) + Reconnect(); + + var message = BuildInOutMessage(action); + var result = _mqttClient.PublishMessage(new MqttApplicationMessage + { + Topic = _config.TopicInOut, + Payload = Encoding.UTF8.GetBytes(message), + QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce, + Retain = false + }); + + if (result.IsSuccess) + { + Logger.WriteMqtt($"进出站消息发送成功 主题:{_config.TopicInOut}: {message}"); + } + else + { + Logger.WriteError($"进出站消息发送失败: {result.Message}"); + } + } + } + catch (Exception ex) + { + Logger.WriteError($"发送进出站消息异常: {ex.Message}", ex); + } + } + + /// + /// 发送预测数据 + /// + /// + public void SendForecastMessage(Predictability_BM data) + { + try + { + lock (_syncLock) + { + if (!_mqttClient.IsConnected) + { + Reconnect(); + } + + var message = BuildForecastMessage(data); + var result = _mqttClient.PublishMessage(new MqttApplicationMessage + { + Topic = _config.TopicForecast, + Payload = Encoding.UTF8.GetBytes(message), + QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce, + Retain = false + }); + + if (result.IsSuccess) + { + Logger.WriteInfo($"预测数据发送成功 主题:{_config.TopicForecast}: {message}"); + } + else + { + Logger.WriteError($"预测数据发送失败: {result.Message}"); + } + } + } + catch (Exception ex) + { + Logger.WriteError($"发送预测数据异常: {ex.Message}", ex); + } + } + + + #endregion + + #region 构建消息 + /// + /// 构建进出站消息 + /// + /// + /// + private string BuildInOutMessage(string action) + { + try + { + var message = new EnterandExit + { + bu_id = "EVE8BU", + district_id = "JM", + factory_id = "60J", + production_line_id = "601L", + work_center_id = "601PWE01", + device_name = "601PWM01", + action = action, + action_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + }; + + return JsonConvert.SerializeObject(message, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + catch (Exception ex) + { + Logger.WriteError($"构建进出站消息失败: {ex.Message}", ex); + return string.Empty; + } + } + + /// + /// 构建预测数据消息 + /// + /// + /// + public string BuildForecastMessage(Predictability_BM predictability) + { + try + { + CollectionUpload collectionUpload = new CollectionUpload() + { + bu_id = "EVE8BU", + district_id = "JM", + factory_id = "60J", + production_line_id = "601L", + production_processes_id = "", + work_center_id = "601PWE01", + station_id = "", + device_name = "601PWM01", + taglist = new List + { + new Collection + { + device_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + collection_items = new Dictionary + { + //扭矩 + {"Coating1_Torque1", predictability.Coating1_Torque1}, + {"Coating1_Torque2", predictability.Coating1_Torque2}, + {"Coating1_Torque3", predictability.Coating1_Torque3}, + {"Coating1_Torque4", predictability.Coating1_Torque4}, + {"Coating1_Torque5", predictability.Coating1_Torque5}, + {"Coating1_Torque6", predictability.Coating1_Torque6}, + {"Coating1_Torque7", predictability.Coating1_Torque7}, + {"Coating1_Torque8", predictability.Coating1_Torque8}, + {"Coating2_Torque1", predictability.Coating2_Torque1}, + {"Coating2_Torque2", predictability.Coating2_Torque2}, + {"Coating2_Torque3", predictability.Coating2_Torque3}, + {"Coating2_Torque4", predictability.Coating2_Torque4}, + {"Coating2_Torque5", predictability.Coating2_Torque5}, + {"Coating2_Torque6", predictability.Coating2_Torque6}, + {"Coating2_Torque7", predictability.Coating2_Torque7}, + {"Coating2_Torque8", predictability.Coating2_Torque8}, + {"Folding1_Torque1", predictability.Folding1_Torque1}, + {"Folding1_Torque2", predictability.Folding1_Torque2}, + {"Folding1_Torque3", predictability.Folding1_Torque3}, + {"Folding2_Torque1", predictability.Folding2_Torque1}, + {"Folding2_Torque2", predictability.Folding2_Torque2}, + {"Folding2_Torque3", predictability.Folding2_Torque3}, + //轴速度 + {"Coating1_AxisSpeed1", predictability.Coating1_AxisSpeed1}, + {"Coating1_AxisSpeed2", predictability.Coating1_AxisSpeed2}, + {"Coating1_AxisSpeed3", predictability.Coating1_AxisSpeed3}, + {"Coating1_AxisSpeed4", predictability.Coating1_AxisSpeed4}, + {"Coating1_AxisSpeed5", predictability.Coating1_AxisSpeed5}, + {"Coating1_AxisSpeed6", predictability.Coating1_AxisSpeed6}, + {"Coating1_AxisSpeed7", predictability.Coating1_AxisSpeed7}, + {"Coating1_AxisSpeed8", predictability.Coating1_AxisSpeed8}, + {"Coating2_AxisSpeed1", predictability.Coating2_AxisSpeed1}, + {"Coating2_AxisSpeed2", predictability.Coating2_AxisSpeed2}, + {"Coating2_AxisSpeed3", predictability.Coating2_AxisSpeed3}, + {"Coating2_AxisSpeed4", predictability.Coating2_AxisSpeed4}, + {"Coating2_AxisSpeed5", predictability.Coating2_AxisSpeed5}, + {"Coating2_AxisSpeed6", predictability.Coating2_AxisSpeed6}, + {"Coating2_AxisSpeed7", predictability.Coating2_AxisSpeed7}, + {"Coating2_AxisSpeed8", predictability.Coating2_AxisSpeed8}, + {"Folding1_AxisSpeed1", predictability.Folding1_AxisSpeed1}, + {"Folding1_AxisSpeed2", predictability.Folding1_AxisSpeed2}, + {"Folding1_AxisSpeed3", predictability.Folding1_AxisSpeed3}, + {"Folding2_AxisSpeed1", predictability.Folding2_AxisSpeed1}, + {"Folding2_AxisSpeed2", predictability.Folding2_AxisSpeed2}, + {"Folding2_AxisSpeed3", predictability.Folding2_AxisSpeed3}, + //轴位置 + {"Coating1_AxisPosition1", predictability.Coating1_AxisPosition1}, + {"Coating1_AxisPosition2", predictability.Coating1_AxisPosition2}, + {"Coating1_AxisPosition3", predictability.Coating1_AxisPosition3}, + {"Coating1_AxisPosition4", predictability.Coating1_AxisPosition4}, + {"Coating1_AxisPosition5", predictability.Coating1_AxisPosition5}, + {"Coating1_AxisPosition6", predictability.Coating1_AxisPosition6}, + {"Coating1_AxisPosition7", predictability.Coating1_AxisPosition7}, + {"Coating1_AxisPosition8", predictability.Coating1_AxisPosition8}, + {"Coating2_AxisPosition1", predictability.Coating2_AxisPosition1}, + {"Coating2_AxisPosition2", predictability.Coating2_AxisPosition2}, + {"Coating2_AxisPosition3", predictability.Coating2_AxisPosition3}, + {"Coating2_AxisPosition4", predictability.Coating2_AxisPosition4}, + {"Coating2_AxisPosition5", predictability.Coating2_AxisPosition5}, + {"Coating2_AxisPosition6", predictability.Coating2_AxisPosition6}, + {"Coating2_AxisPosition7", predictability.Coating2_AxisPosition7}, + {"Coating2_AxisPosition8", predictability.Coating2_AxisPosition8}, + {"Folding1_AxisPosition1", predictability.Folding1_AxisPosition1}, + {"Folding1_AxisPosition2", predictability.Folding1_AxisPosition2}, + {"Folding1_AxisPosition3", predictability.Folding1_AxisPosition3}, + {"Folding2_AxisPosition1", predictability.Folding2_AxisPosition1}, + {"Folding2_AxisPosition2", predictability.Folding2_AxisPosition2}, + {"Folding2_AxisPosition3", predictability.Folding2_AxisPosition3}, + //行程时间 + {"Coating1_Cylinder_TravelTime1", predictability.Coating1_Cylinder_TravelTime1}, + {"Coating1_Cylinder_TravelTime2", predictability.Coating1_Cylinder_TravelTime2}, + {"Coating1_Cylinder_TravelTime3", predictability.Coating1_Cylinder_TravelTime3}, + {"Coating1_Cylinder_TravelTime4", predictability.Coating1_Cylinder_TravelTime4}, + {"Coating1_Cylinder_TravelTime5", predictability.Coating1_Cylinder_TravelTime5}, + {"Coating1_Cylinder_TravelTime6", predictability.Coating1_Cylinder_TravelTime6}, + {"Coating1_Cylinder_TravelTime7", predictability.Coating1_Cylinder_TravelTime7}, + {"Coating1_Cylinder_TravelTime8", predictability.Coating1_Cylinder_TravelTime8}, + {"Coating1_Cylinder_TravelTime9", predictability.Coating1_Cylinder_TravelTime9}, + {"Coating1_Cylinder_TravelTime10", predictability.Coating1_Cylinder_TravelTime10}, + {"Coating1_Cylinder_TravelTime11", predictability.Coating1_Cylinder_TravelTime11}, + {"Coating1_Cylinder_TravelTime12", predictability.Coating1_Cylinder_TravelTime12}, + {"Coating1_Cylinder_TravelTime13", predictability.Coating1_Cylinder_TravelTime13}, + {"Coating1_Cylinder_TravelTime14", predictability.Coating1_Cylinder_TravelTime14}, + {"Coating2_Cylinder_TravelTime1", predictability.Coating2_Cylinder_TravelTime1}, + {"Coating2_Cylinder_TravelTime2", predictability.Coating2_Cylinder_TravelTime2}, + {"Coating2_Cylinder_TravelTime3", predictability.Coating2_Cylinder_TravelTime3}, + {"Coating2_Cylinder_TravelTime4", predictability.Coating2_Cylinder_TravelTime4}, + {"Coating2_Cylinder_TravelTime5", predictability.Coating2_Cylinder_TravelTime5}, + {"Coating2_Cylinder_TravelTime6", predictability.Coating2_Cylinder_TravelTime6}, + {"Coating2_Cylinder_TravelTime7", predictability.Coating2_Cylinder_TravelTime7}, + {"Coating2_Cylinder_TravelTime8", predictability.Coating2_Cylinder_TravelTime8}, + {"Coating2_Cylinder_TravelTime9", predictability.Coating2_Cylinder_TravelTime9}, + {"Coating2_Cylinder_TravelTime10", predictability.Coating2_Cylinder_TravelTime10}, + {"Coating2_Cylinder_TravelTime11", predictability.Coating2_Cylinder_TravelTime11}, + {"Coating2_Cylinder_TravelTime12", predictability.Coating2_Cylinder_TravelTime12}, + {"Coating2_Cylinder_TravelTime13", predictability.Coating2_Cylinder_TravelTime13}, + {"Coating2_Cylinder_TravelTime14", predictability.Coating2_Cylinder_TravelTime14}, + {"CornerCutting1_Cylinder_TravelTime1", predictability.CornerCutting1_Cylinder_TravelTime1}, + {"CornerCutting1_Cylinder_TravelTime2", predictability.CornerCutting1_Cylinder_TravelTime2}, + {"CornerCutting1_Cylinder_TravelTime3", predictability.CornerCutting1_Cylinder_TravelTime3}, + {"CornerCutting1_Cylinder_TravelTime4", predictability.CornerCutting1_Cylinder_TravelTime4}, + {"CornerCutting1_Cylinder_TravelTime5", predictability.CornerCutting1_Cylinder_TravelTime5}, + {"CornerCutting1_Cylinder_TravelTime6", predictability.CornerCutting1_Cylinder_TravelTime6}, + {"CornerCutting1_Cylinder_TravelTime7", predictability.CornerCutting1_Cylinder_TravelTime7}, + {"CornerCutting1_Cylinder_TravelTime8", predictability.CornerCutting1_Cylinder_TravelTime8}, + {"CornerCutting2_Cylinder_TravelTime1", predictability.CornerCutting2_Cylinder_TravelTime1}, + {"CornerCutting2_Cylinder_TravelTime2", predictability.CornerCutting2_Cylinder_TravelTime2}, + {"CornerCutting2_Cylinder_TravelTime3", predictability.CornerCutting2_Cylinder_TravelTime3}, + {"CornerCutting2_Cylinder_TravelTime4", predictability.CornerCutting2_Cylinder_TravelTime4}, + {"CornerCutting2_Cylinder_TravelTime5", predictability.CornerCutting2_Cylinder_TravelTime5}, + {"CornerCutting2_Cylinder_TravelTime6", predictability.CornerCutting2_Cylinder_TravelTime6}, + {"CornerCutting2_Cylinder_TravelTime7", predictability.CornerCutting2_Cylinder_TravelTime7}, + {"CornerCutting2_Cylinder_TravelTime8", predictability.CornerCutting2_Cylinder_TravelTime8}, + } + } + } + }; + // 根据实际数据结构调整 + return JsonConvert.SerializeObject(collectionUpload, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + catch (Exception ex) + { + Logger.WriteError($"构建预测数据消息失败: {ex.Message}", ex); + return string.Empty; + } + } + #endregion + + /// + /// 重新连接 + /// + private void Reconnect() + { + try + { + _mqttClient.ConnectClose(); + InitializeConnection(); + } + catch (Exception ex) + { + Logger.WriteError($"MQTT重连失败: {ex.Message}", ex); + } + } + #region 资源释放跟心跳检测 + private Timer _heartbeatTimer; + private bool _disposed = false; + + + // 心跳检测 + private void StartHeartbeat() + { + _heartbeatTimer = new Timer(state => + { + try + { + if (!_mqttClient.IsConnected) + { + Logger.WriteMqtt("检测到MQTT连接断开,尝试重连..."); + Reconnect(); + } + } + catch (Exception ex) + { + Logger.WriteError($"心跳检测异常: {ex.Message}", ex); + } + }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); // 每分钟检查一次 + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + _heartbeatTimer?.Dispose(); + _mqttClient?.ConnectClose(); + _mqttClient?.Dispose(); + } + + _disposed = true; + } + + ~MqttService() + { + Dispose(false); + } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } + /*public class SendDateMQTT + { + HslCommunication.MQTT.MqttClient mqttClientIN = null; + HslCommunication.MQTT.MqttClient mqttClientOUT = null; + HslCommunication.MQTT.MqttClient mqttClientForecast = null; + private static readonly object ObjectIN = new object(); + private static readonly object ObjectOUT = new object(); + private static readonly object ObjectForecast = new object(); + //10.22.160.144 + public string MQTTServerAddress = "10.22.161.1";//"10.22.161.1"; + public int MQTTServerPort = 2883;//2883 + public string ClientId = "601PWM01"; + + /// 进出站主题 + public string Topic = "EVE/60J/TrackInOut/601PWM01"; + /// CTPCTQ主题 + public string Topic1 = "EVE/60J/CTPCTQ/601PWM01"; + // 预测性维护数据主题 + public string Topic2 = "EVE/60J/EQP/601PWM01"; + + /// BU编码 + public string BU_id = "EVE8BU"; + /// 区域简称 + public string District_id = "JM"; + /// 工厂编码 + public string Factory_id = "60J"; + /// 工序编码 + public string Production_line_id = "601L"; + /// 工作中心编码 + public string Work_center_id = "601PWE01"; + /// 设备编码 + public string Device_name = "601PWM01"; + + /// + /// 发送Mqtt进站数据 + /// + /// + /// + /// + /// + public void EnterandExitSendMessgeIN() + { + try + { + + lock (ObjectIN) + { + if (mqttClientIN != null) { mqttClientIN.ConnectClose(); } + Connect(mqttClientIN, MQTTServerAddress, MQTTServerPort, "", ""); + SubscribeMessage(mqttClientIN, Topic); + PublishMessage(mqttClientIN, Topic, EnterandExitMessge("0")); + } + + + + } + catch (Exception ex) + { + Logger.WriteError($"发送进出站数据错误,{ex.Message}", ex); + //CommonMethods.AddLog(true, $"发送进出站数据错误,{ex.Message}"); + } + } + /// + /// 发送Mqtt出站数据 + /// + /// + /// + /// + /// + public void EnterandExitSendMessgeOUT() + { + try + { + + lock (ObjectOUT) + { + if (mqttClientOUT != null) { mqttClientOUT.ConnectClose(); } + Connect(mqttClientOUT, MQTTServerAddress, MQTTServerPort, "", ""); + SubscribeMessage(mqttClientOUT, Topic); + PublishMessage(mqttClientOUT, Topic, EnterandExitMessge("1")); + } + } + catch (Exception ex) + { + Logger.WriteError($"发送进出站数据错误,{ex.Message}", ex); + //CommonMethods.AddLog(true, $"发送进出站数据错误,{ex.Message}"); + } + } + /// + /// 发送采集项数据 + /// + /// + /// + /// + /// + public void CollectionSendMessgeForecast(Predictability_BM predictability) + { + try + { + + lock (ObjectForecast) + { + if (mqttClientForecast != null) { mqttClientForecast.ConnectClose(); } + Connect(mqttClientForecast, MQTTServerAddress, MQTTServerPort, "", ""); + SubscribeMessage(mqttClientForecast, Topic2); + PublishMessage(mqttClientForecast, Topic2, CollectionMessge(predictability)); + } + } + catch (Exception ex) + { + Logger.WriteError($"发送采集项数据错误,{ex.Message}", ex); + //CommonMethods.AddLog(false, $"发送采集项数据错误,{ex.Message}"); + } + } + + /// + /// 连接 + /// + /// + /// + /// + /// + /// + public void Connect(MqttClient mqttClient, string ip, int port, string name, string pwd, string clientId = "ClientId") + { + try + { + if (mqttClient != null) mqttClient.ConnectClose(); + + mqttClient = new MqttClient(new MqttConnectionOptions() + { + ClientId = clientId, + IpAddress = ip, + Port = port, + Credentials = new MqttCredential(name, pwd), // 设置了用户名和密码 + }); + + OperateResult connect = mqttClient.ConnectServer(); + if (connect.IsSuccess) + { + Logger.WriteMqtt("MQTT 连接服务器成功"); + } + else + { + Logger.WriteMqtt("MQTT 无法连接到服务器"); + } + + } + catch (Exception ex) + { + Logger.WriteError($"MQTT 无法连接到服务器: {ex.Message}"); + } + + + } + + /// + /// 发布信息 + /// + /// + public void PublishMessage(MqttClient mqttClient, string topic, string Message) + { + try + { + + OperateResult result = mqttClient.PublishMessage(new MqttApplicationMessage() + { + Topic = topic, // 主题 + QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce, // 消息等级 + Payload = Encoding.UTF8.GetBytes(Message), // 数据 + Retain = false, // 是否保留 + }); + if (result.IsSuccess) + { + Logger.WriteMqtt($"发送消息到主题 [{topic}]: {Message}"); + } + else + { + Logger.WriteMqtt($"发送消息到主题 [{topic}] 失败: {result.Message}"); + } + + } + catch (Exception ex) + { + Logger.WriteError($"MQTT 无法连接到服务器: {ex.Message}"); + } + } + + /// + /// 订阅主题 + /// + /// + public void SubscribeMessage(MqttClient mqttClient, string Topic) + { + try + { + + mqttClient.OnMqttMessageReceived += MqttClient_OnMqttMessageReceived; // 调用一次即可 + OperateResult Result = mqttClient.SubscribeMessage(Topic); // 订阅A的主题 + if (Result.IsSuccess) + { + Logger.WriteMqtt($"订阅成功[{Topic}]"); + } + else + { + Logger.WriteMqtt($"订阅失败[{Topic}]"); + } + + } + catch (Exception ex) + { + Logger.WriteError($"订阅失败[{ex.Message}]"); + } + } + + private static void MqttClient_OnMqttMessageReceived(MqttClient client, MqttApplicationMessage message) + { + Logger.WriteMqtt($"收到服务器信息[{message.ToString()}]"); + } + + /// + /// 拼接进出站json + /// + /// + /// + public string EnterandExitMessge(string action) + { + string messgeJson = string.Empty; + try + { + EnterandExit enterandExit = new EnterandExit() + { + bu_id = BU_id, + district_id = District_id, + factory_id = Factory_id, + production_line_id = Production_line_id, + production_processes_id = "", + work_center_id = Work_center_id, + station_id = "", + device_name = Device_name, + action = action, + action_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + + }; + var messageJson = JsonConvert.SerializeObject(enterandExit, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + messgeJson = messageJson; + } + catch (Exception ex) + { + Logger.WriteError($"方法:上传MQTTServer数据,上传失败: {ex.Message}", ex); + } + return messgeJson; + } + + /// + /// 拼接采集项数据 + /// + /// + /// + public string CollectionMessge(Predictability_BM predictability) + { + string messgejson = string.Empty; + try + { + CollectionUpload collectionUpload = new CollectionUpload() + { + bu_id = BU_id, + district_id = District_id, + factory_id = Factory_id, + production_line_id = Production_line_id, + production_processes_id = "", + work_center_id = Work_center_id, + station_id = "", + device_name = Device_name, + taglist = new List + { + new Collection + { + device_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + collection_items = new Dictionary + { + //扭矩 + {"Coating1_Torque1", predictability.Coating1_Torque1}, + {"Coating1_Torque2", predictability.Coating1_Torque2}, + {"Coating1_Torque3", predictability.Coating1_Torque3}, + {"Coating1_Torque4", predictability.Coating1_Torque4}, + {"Coating1_Torque5", predictability.Coating1_Torque5}, + {"Coating1_Torque6", predictability.Coating1_Torque6}, + {"Coating1_Torque7", predictability.Coating1_Torque7}, + {"Coating1_Torque8", predictability.Coating1_Torque8}, + {"Coating2_Torque1", predictability.Coating2_Torque1}, + {"Coating2_Torque2", predictability.Coating2_Torque2}, + {"Coating2_Torque3", predictability.Coating2_Torque3}, + {"Coating2_Torque4", predictability.Coating2_Torque4}, + {"Coating2_Torque5", predictability.Coating2_Torque5}, + {"Coating2_Torque6", predictability.Coating2_Torque6}, + {"Coating2_Torque7", predictability.Coating2_Torque7}, + {"Coating2_Torque8", predictability.Coating2_Torque8}, + {"Folding1_Torque1", predictability.Folding1_Torque1}, + {"Folding1_Torque2", predictability.Folding1_Torque2}, + {"Folding1_Torque3", predictability.Folding1_Torque3}, + {"Folding2_Torque1", predictability.Folding2_Torque1}, + {"Folding2_Torque2", predictability.Folding2_Torque2}, + {"Folding2_Torque3", predictability.Folding2_Torque3}, + //轴速度 + {"Coating1_AxisSpeed1", predictability.Coating1_AxisSpeed1}, + {"Coating1_AxisSpeed2", predictability.Coating1_AxisSpeed2}, + {"Coating1_AxisSpeed3", predictability.Coating1_AxisSpeed3}, + {"Coating1_AxisSpeed4", predictability.Coating1_AxisSpeed4}, + {"Coating1_AxisSpeed5", predictability.Coating1_AxisSpeed5}, + {"Coating1_AxisSpeed6", predictability.Coating1_AxisSpeed6}, + {"Coating1_AxisSpeed7", predictability.Coating1_AxisSpeed7}, + {"Coating1_AxisSpeed8", predictability.Coating1_AxisSpeed8}, + {"Coating2_AxisSpeed1", predictability.Coating2_AxisSpeed1}, + {"Coating2_AxisSpeed2", predictability.Coating2_AxisSpeed2}, + {"Coating2_AxisSpeed3", predictability.Coating2_AxisSpeed3}, + {"Coating2_AxisSpeed4", predictability.Coating2_AxisSpeed4}, + {"Coating2_AxisSpeed5", predictability.Coating2_AxisSpeed5}, + {"Coating2_AxisSpeed6", predictability.Coating2_AxisSpeed6}, + {"Coating2_AxisSpeed7", predictability.Coating2_AxisSpeed7}, + {"Coating2_AxisSpeed8", predictability.Coating2_AxisSpeed8}, + {"Folding1_AxisSpeed1", predictability.Folding1_AxisSpeed1}, + {"Folding1_AxisSpeed2", predictability.Folding1_AxisSpeed2}, + {"Folding1_AxisSpeed3", predictability.Folding1_AxisSpeed3}, + {"Folding2_AxisSpeed1", predictability.Folding2_AxisSpeed1}, + {"Folding2_AxisSpeed2", predictability.Folding2_AxisSpeed2}, + {"Folding2_AxisSpeed3", predictability.Folding2_AxisSpeed3}, + //轴位置 + {"Coating1_AxisPosition1", predictability.Coating1_AxisPosition1}, + {"Coating1_AxisPosition2", predictability.Coating1_AxisPosition2}, + {"Coating1_AxisPosition3", predictability.Coating1_AxisPosition3}, + {"Coating1_AxisPosition4", predictability.Coating1_AxisPosition4}, + {"Coating1_AxisPosition5", predictability.Coating1_AxisPosition5}, + {"Coating1_AxisPosition6", predictability.Coating1_AxisPosition6}, + {"Coating1_AxisPosition7", predictability.Coating1_AxisPosition7}, + {"Coating1_AxisPosition8", predictability.Coating1_AxisPosition8}, + {"Coating2_AxisPosition1", predictability.Coating2_AxisPosition1}, + {"Coating2_AxisPosition2", predictability.Coating2_AxisPosition2}, + {"Coating2_AxisPosition3", predictability.Coating2_AxisPosition3}, + {"Coating2_AxisPosition4", predictability.Coating2_AxisPosition4}, + {"Coating2_AxisPosition5", predictability.Coating2_AxisPosition5}, + {"Coating2_AxisPosition6", predictability.Coating2_AxisPosition6}, + {"Coating2_AxisPosition7", predictability.Coating2_AxisPosition7}, + {"Coating2_AxisPosition8", predictability.Coating2_AxisPosition8}, + {"Folding1_AxisPosition1", predictability.Folding1_AxisPosition1}, + {"Folding1_AxisPosition2", predictability.Folding1_AxisPosition2}, + {"Folding1_AxisPosition3", predictability.Folding1_AxisPosition3}, + {"Folding2_AxisPosition1", predictability.Folding2_AxisPosition1}, + {"Folding2_AxisPosition2", predictability.Folding2_AxisPosition2}, + {"Folding2_AxisPosition3", predictability.Folding2_AxisPosition3}, + //行程时间 + {"Coating1_Cylinder_TravelTime1", predictability.Coating1_Cylinder_TravelTime1}, + {"Coating1_Cylinder_TravelTime2", predictability.Coating1_Cylinder_TravelTime2}, + {"Coating1_Cylinder_TravelTime3", predictability.Coating1_Cylinder_TravelTime3}, + {"Coating1_Cylinder_TravelTime4", predictability.Coating1_Cylinder_TravelTime4}, + {"Coating1_Cylinder_TravelTime5", predictability.Coating1_Cylinder_TravelTime5}, + {"Coating1_Cylinder_TravelTime6", predictability.Coating1_Cylinder_TravelTime6}, + {"Coating1_Cylinder_TravelTime7", predictability.Coating1_Cylinder_TravelTime7}, + {"Coating1_Cylinder_TravelTime8", predictability.Coating1_Cylinder_TravelTime8}, + {"Coating1_Cylinder_TravelTime9", predictability.Coating1_Cylinder_TravelTime9}, + {"Coating1_Cylinder_TravelTime10", predictability.Coating1_Cylinder_TravelTime10}, + {"Coating1_Cylinder_TravelTime11", predictability.Coating1_Cylinder_TravelTime11}, + {"Coating1_Cylinder_TravelTime12", predictability.Coating1_Cylinder_TravelTime12}, + {"Coating1_Cylinder_TravelTime13", predictability.Coating1_Cylinder_TravelTime13}, + {"Coating1_Cylinder_TravelTime14", predictability.Coating1_Cylinder_TravelTime14}, + {"Coating2_Cylinder_TravelTime1", predictability.Coating2_Cylinder_TravelTime1}, + {"Coating2_Cylinder_TravelTime2", predictability.Coating2_Cylinder_TravelTime2}, + {"Coating2_Cylinder_TravelTime3", predictability.Coating2_Cylinder_TravelTime3}, + {"Coating2_Cylinder_TravelTime4", predictability.Coating2_Cylinder_TravelTime4}, + {"Coating2_Cylinder_TravelTime5", predictability.Coating2_Cylinder_TravelTime5}, + {"Coating2_Cylinder_TravelTime6", predictability.Coating2_Cylinder_TravelTime6}, + {"Coating2_Cylinder_TravelTime7", predictability.Coating2_Cylinder_TravelTime7}, + {"Coating2_Cylinder_TravelTime8", predictability.Coating2_Cylinder_TravelTime8}, + {"Coating2_Cylinder_TravelTime9", predictability.Coating2_Cylinder_TravelTime9}, + {"Coating2_Cylinder_TravelTime10", predictability.Coating2_Cylinder_TravelTime10}, + {"Coating2_Cylinder_TravelTime11", predictability.Coating2_Cylinder_TravelTime11}, + {"Coating2_Cylinder_TravelTime12", predictability.Coating2_Cylinder_TravelTime12}, + {"Coating2_Cylinder_TravelTime13", predictability.Coating2_Cylinder_TravelTime13}, + {"Coating2_Cylinder_TravelTime14", predictability.Coating2_Cylinder_TravelTime14}, + {"CornerCutting1_Cylinder_TravelTime1", predictability.CornerCutting1_Cylinder_TravelTime1}, + {"CornerCutting1_Cylinder_TravelTime2", predictability.CornerCutting1_Cylinder_TravelTime2}, + {"CornerCutting1_Cylinder_TravelTime3", predictability.CornerCutting1_Cylinder_TravelTime3}, + {"CornerCutting1_Cylinder_TravelTime4", predictability.CornerCutting1_Cylinder_TravelTime4}, + {"CornerCutting1_Cylinder_TravelTime5", predictability.CornerCutting1_Cylinder_TravelTime5}, + {"CornerCutting1_Cylinder_TravelTime6", predictability.CornerCutting1_Cylinder_TravelTime6}, + {"CornerCutting1_Cylinder_TravelTime7", predictability.CornerCutting1_Cylinder_TravelTime7}, + {"CornerCutting1_Cylinder_TravelTime8", predictability.CornerCutting1_Cylinder_TravelTime8}, + {"CornerCutting2_Cylinder_TravelTime1", predictability.CornerCutting2_Cylinder_TravelTime1}, + {"CornerCutting2_Cylinder_TravelTime2", predictability.CornerCutting2_Cylinder_TravelTime2}, + {"CornerCutting2_Cylinder_TravelTime3", predictability.CornerCutting2_Cylinder_TravelTime3}, + {"CornerCutting2_Cylinder_TravelTime4", predictability.CornerCutting2_Cylinder_TravelTime4}, + {"CornerCutting2_Cylinder_TravelTime5", predictability.CornerCutting2_Cylinder_TravelTime5}, + {"CornerCutting2_Cylinder_TravelTime6", predictability.CornerCutting2_Cylinder_TravelTime6}, + {"CornerCutting2_Cylinder_TravelTime7", predictability.CornerCutting2_Cylinder_TravelTime7}, + {"CornerCutting2_Cylinder_TravelTime8", predictability.CornerCutting2_Cylinder_TravelTime8}, + } + } + } + }; + var messageJson = JsonConvert.SerializeObject(collectionUpload, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + messgejson = messageJson; + } + catch (Exception ex) + { + Logger.WriteError($"生成Json数据失败: {ex.Message}", ex); + } + return messgejson; + } + }*/ +} diff --git a/JinYuan.Helper/StreamIOHelper.cs b/JinYuan.Helper/StreamIOHelper.cs new file mode 100644 index 0000000..a6a4df8 --- /dev/null +++ b/JinYuan.Helper/StreamIOHelper.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; + +namespace JinYuan.Helper +{ + /// + /// 流读写IO辅助类 + /// + public class StreamIOHelper + { + /// + /// 写入文件字节流 + /// + /// 待写入的流 + /// 写入的文件流 + /// 是否在操作后关闭流 + /// 是否写入成功:true:成功;false:失败 + public static bool WriteStreamBytes(Stream stream, byte[] bys, bool isCloseStream = false) + { + //确保文件支持写入 + if (stream == null || !stream.CanWrite) + { + return false; + } + + try + { + //单次写入的长度 + int perWriteByteLen = 1024 * 1024; + //单次读取的索引下标 + int startIndex = 0; + //写入的总长度 + int allLen = bys.Length; + while (startIndex < allLen && startIndex >= 0) + { + stream.Write(bys, startIndex, (startIndex > allLen - perWriteByteLen) ? allLen - startIndex : perWriteByteLen); + startIndex += perWriteByteLen; + } + stream.Flush(); + return true; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + "\t" + ex.StackTrace); + return false; + } + finally + { + if (isCloseStream) + { + CloseStream(stream); + } + } + } + + /// + /// 读取文件字节流 + /// 读取异常或者文件不存在时返回null; + /// + /// 读取的字节流 + /// 是否在操作后关闭流 + /// 读取到的文件字节流 + public static byte[] ReadStreamBytes(Stream stream, bool isCloseStream = false) + { + //检测是否支持读操作 + if (stream == null || !stream.CanRead || stream.Length == 0) + { + return null; + } + + try + { + byte[] resBytes = new byte[stream.Length]; + int allLen = (int)stream.Length; + //单次读取的长度,1024字节即1kb,1024*1024=1M + int perReadByteLen = 1024 * 1024; + //单次读取的索引下标 + int startIndex = 0; + //单次读取到的长度 + int readLen = 0; + while ((readLen = stream.Read(resBytes, startIndex, (startIndex > allLen - perReadByteLen) ? allLen - startIndex : perReadByteLen)) > 0) + { + startIndex += readLen; + } + if (startIndex == allLen) + { + return resBytes; + } + else + { + return ArrayHelper.GetSubArray(resBytes, 0, startIndex); + } + + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + "\t" + ex.StackTrace); + return null; + } + finally + { + if (isCloseStream) + { + CloseStream(stream); + } + } + } + + /// + /// 关闭流 + /// + /// + public static void CloseStream(Stream fileInfo) + { + try + { + if (fileInfo != null) + fileInfo.Dispose(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + "\t" + ex.StackTrace); + } + } + + } +} diff --git a/JinYuan.Helper/StringSecurityHelper.cs b/JinYuan.Helper/StringSecurityHelper.cs new file mode 100644 index 0000000..7071792 --- /dev/null +++ b/JinYuan.Helper/StringSecurityHelper.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace JinYuan.Helper +{ + /// + /// 字符串加密解密类 + /// + public class StringSecurityHelper + { + private static string md5Begin = "Hello"; + private static string md5End = "World"; + + #region SHA1 加密 + + /// + /// 使用SHA1加密字符串。 + /// + /// 输入字符串。 + /// 加密后的字符串。(40个字符) + public static string SHA1Encrypt(string inputString) + { + SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); + byte[] encryptedBytes = sha1.ComputeHash(Encoding.ASCII.GetBytes(inputString)); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < encryptedBytes.Length; i++) + { + sb.AppendFormat("{0:x2}", encryptedBytes[i]); + } + return sb.ToString(); + } + + #endregion + + #region DES 加密/解密 + + private static byte[] key = Encoding.ASCII.GetBytes("uiertysd"); + private static byte[] iv = Encoding.ASCII.GetBytes("99008855"); + + /// + /// DES加密。 + /// + /// 输入字符串。 + /// 加密后的字符串。 + public static string DESEncrypt(string inputString) + { + MemoryStream ms = null; + CryptoStream cs = null; + StreamWriter sw = null; + + DESCryptoServiceProvider des = new DESCryptoServiceProvider(); + try + { + ms = new MemoryStream(); + cs = new CryptoStream(ms, des.CreateEncryptor(key, iv), CryptoStreamMode.Write); + sw = new StreamWriter(cs); + sw.Write(inputString); + sw.Flush(); + cs.FlushFinalBlock(); + return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length); + } + finally + { + if (sw != null) sw.Close(); + if (cs != null) cs.Close(); + if (ms != null) ms.Close(); + } + } + + /// + /// DES解密。 + /// + /// 输入字符串。 + /// 解密后的字符串。 + public static string DESDecrypt(string inputString) + { + MemoryStream ms = null; + CryptoStream cs = null; + StreamReader sr = null; + + DESCryptoServiceProvider des = new DESCryptoServiceProvider(); + try + { + ms = new MemoryStream(Convert.FromBase64String(inputString)); + cs = new CryptoStream(ms, des.CreateDecryptor(key, iv), CryptoStreamMode.Read); + sr = new StreamReader(cs); + return sr.ReadToEnd(); + } + catch + { + return string.Empty; + } + finally + { + if (sr != null) sr.Close(); + if (cs != null) cs.Close(); + if (ms != null) ms.Close(); + } + } + + #endregion + + + /// + /// MD5加密 + /// + /// MD5加密前字符串 + /// MD5加密后字符串 + public static string MD5Encrypt(string str) + { + str = string.Concat(md5Begin, str, md5End); + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] fromData = Encoding.Unicode.GetBytes(str); + byte[] targetData = md5.ComputeHash(fromData); + string md5String = string.Empty; + foreach (var b in targetData) + md5String += b.ToString("x2"); + return md5String; + } + } +} diff --git a/JinYuan.Helper/TimedOperation.cs b/JinYuan.Helper/TimedOperation.cs new file mode 100644 index 0000000..e554558 --- /dev/null +++ b/JinYuan.Helper/TimedOperation.cs @@ -0,0 +1,36 @@ +using System; +using System.Diagnostics; +using System.Threading; + +namespace JinYuan.Helper +{ + /// + /// 操作计时功能 + /// + public class TimedOperation : IDisposable + { + private readonly Stopwatch _stopwatch; + private readonly string _operationName; + private readonly Action _onCompleted; + private bool _disposed = false; + + public TimedOperation(string operationName, Action onCompleted = null) + { + _stopwatch = Stopwatch.StartNew(); + _operationName = operationName; + _onCompleted = onCompleted; + } + + public long ElapsedMilliseconds => _stopwatch.ElapsedMilliseconds; + + public void Dispose() + { + if (!_disposed) + { + _stopwatch.Stop(); + _onCompleted?.Invoke(_stopwatch.ElapsedMilliseconds, _operationName); + _disposed = true; + } + } + } +} diff --git a/JinYuan.Helper/TimerReset.cs b/JinYuan.Helper/TimerReset.cs new file mode 100644 index 0000000..93b89ec --- /dev/null +++ b/JinYuan.Helper/TimerReset.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading; + +namespace JinYuan.Helper +{ + /// + /// 定时器重置时间间隔,定时器执行未超间隔则设置剩余时间后再次触发,超时则立即触发 + /// + public class TimerReset : IDisposable + { + private Timer timer; + private DateTime nextTime; + + /// + /// 使用using语句,在定时器TimerCallback中使用 + /// using语句块内为时间到时的执行代码,dispose计算使用的时间,来重设下次触发时间 + /// + /// 定时器 + /// 时间间隔 + public TimerReset(Timer tim, int ep) + { + timer = tim; + nextTime = DateTime.Now.AddMilliseconds(ep);//设置下次执行时间 + } + public void Dispose() + { + //执行完后,重新设置定时器下次执行时间. + TimeSpan timeout = nextTime.Subtract(DateTime.Now); + if (timeout < TimeSpan.Zero) + { + timeout = TimeSpan.Zero; + } + + timer.Change(timeout, Timeout.InfiniteTimeSpan); + } + } +} diff --git a/JinYuan.Helper/TxtHelper.cs b/JinYuan.Helper/TxtHelper.cs new file mode 100644 index 0000000..c77733b --- /dev/null +++ b/JinYuan.Helper/TxtHelper.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; + +namespace JinYuan.Helper +{ + public class TxtHelper + { + static ReaderWriterLockSlim sucessLogWriteLockSlim = new ReaderWriterLockSlim(); + + /// + /// 写入TEXT文本 + /// + /// 文件名 + /// 内容 + /// 保存结果 + public static bool WriteTxt(string fullName, string content) + { + FileStream fs = null; + StreamWriter sw = null; + + try + { + string directory = fullName.Substring(0, fullName.LastIndexOf('\\')); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + sucessLogWriteLockSlim.EnterWriteLock();//加锁防止抢占 + if (!File.Exists(fullName)) + { + fs = new FileStream(fullName, FileMode.Create, FileAccess.Write); + sw = new StreamWriter(fs, Encoding.UTF8); + } + else + { + fs = new FileStream(fullName, FileMode.Append, FileAccess.Write); + sw = new StreamWriter(fs, Encoding.UTF8); + } + + sw.WriteLine(content); + + sw.Close(); + fs.Close(); + + return true; + } + catch (Exception ex) + { + sw?.Close(); + fs?.Close(); + + } + finally + { + sucessLogWriteLockSlim.ExitWriteLock(); + } + + return false; + } + + } +} diff --git a/JinYuan.Helper/XmlHelper.cs b/JinYuan.Helper/XmlHelper.cs new file mode 100644 index 0000000..f2d012e --- /dev/null +++ b/JinYuan.Helper/XmlHelper.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Xml.Serialization; + +namespace JinYuan.Helper +{ + /// + /// 序列化辅助类 + /// + public class XmlHelper + { + + /// + /// 二进制方式的序列化 + /// + /// 类型 + /// 序列化对象 + /// 序列化后的内存 + public static Stream BinarySerialize(T obj) + { + MemoryStream serMs = new MemoryStream(); + IFormatter iBinaryFormatter = new BinaryFormatter(); + iBinaryFormatter.Serialize(serMs, obj); + if (serMs.Length > 0) + serMs.Position = 0; + return serMs; + } + + /// + /// 二进制方式的反序列化 + /// + /// 类型 + /// 待序列化的内存 + /// 反序列化后的对象 + public static T BinaryDeserializer(Stream ms) where T : class + { + T res = default(T); + if (ms.Length > 0) + ms.Position = 0; + IFormatter iBinaryFormatter = new BinaryFormatter(); + res = iBinaryFormatter.Deserialize(ms) as T; + return res; + } + + /// + /// Xml方式的序列化 + /// + /// 类型 + /// 序列化对象 + /// 序列化后的内存 + public static Stream XmlSerialize(T obj) + { + MemoryStream serMs = new MemoryStream(); + XmlSerializer ser = new XmlSerializer(obj.GetType()); + try + { + ser.Serialize(serMs, obj); + if (serMs.Length > 0) + serMs.Position = 0; + } + catch (Exception ex) + { + //LogHelper.Current.WriteEx(string.Format("序列化对象异常:{0}", obj.ToString()), ex); + return null; + } + + return serMs; + } + + /// + /// Xml方式的序列化 + /// + /// + /// + public static Stream XmlSerializeObj(object obj) + { + MemoryStream serMs = new MemoryStream(); + XmlSerializer ser = new XmlSerializer(obj.GetType()); + ser.Serialize(serMs, obj); + if (serMs.Length > 0) + serMs.Position = 0; + return serMs; + } + + /// + /// Xml方式的反序列化 + /// + /// 类型 + /// 待序列化的内存 + /// 反序列化后的对象 + public static T XmlDeserializer(Stream ms) where T : class + { + T res = default(T); + if (ms.Length > 0) + ms.Position = 0; + XmlSerializer ser = new XmlSerializer(typeof(T)); + res = ser.Deserialize(ms) as T; + return res; + } + + /// + /// 将List集合保存成XML文档 + /// + /// + /// + /// + public static bool SaveListToXML(List lstT, string filePath) + { + try + { + FileInfo fInfo = new FileInfo(filePath); + if (!fInfo.Directory.Exists) + { + fInfo.Directory.Create(); + } + Stream stream = XmlSerialize(lstT); + if (stream != null) + { + byte[] bs = StreamIOHelper.ReadStreamBytes(stream); + using (FileStream fs = new FileStream(filePath, FileMode.Create)) + { + fs.Write(bs, 0, bs.Length); + } + stream.Close(); + return true; + } + else + { + return false; + } + + } + catch (Exception ex) + { + //LogHelper.Current.WriteEx("将List保存成XML文档发生异常", ex, EnumLogType.Error); + return false; + } + } + + + /// + /// 读取XML信息成List集合 + /// + public static List ReadXMLToList(string filePath) + { + try + { + FileInfo fInfo = new FileInfo(filePath); + if (!fInfo.Directory.Exists) + { + fInfo.Directory.Create(); + } + using (FileStream fs = new FileStream(filePath, FileMode.Open)) + { + var crList = XmlDeserializer>(fs); + return crList; + } + } + catch (Exception ex) + { + //LogHelper.Current.WriteEx("读取XML转换成List异常", ex, EnumLogType.Error); + return null; + } + } + + /// + /// 将类的实例保存成XML文档 + /// + /// + /// + /// + /// + public static bool SaveModelToXML(T t, string filePath) where T : class + { + try + { + FileInfo fInfo = new FileInfo(filePath); + if (!fInfo.Directory.Exists) + { + fInfo.Directory.Create(); + } + using (FileStream fs = new FileStream(filePath, FileMode.Create)) + { + using (Stream stream = XmlSerialize(t)) + { + byte[] bs = StreamIOHelper.ReadStreamBytes(stream); + fs.Write(bs, 0, bs.Length); + } + } + return true; + } + catch (Exception ex) + { + //LogHelper.Current.WriteEx("将Class保存成XML文档发生异常", ex, EnumLogType.Error); + return false; + } + } + + /// + /// 将XML文档中数据读取到类的实例中 + /// + /// + /// + /// + public static T ReadXMLToModel(string filePath) where T : class + { + try + { + FileInfo fInfo = new FileInfo(filePath); + if (!fInfo.Directory.Exists) + { + fInfo.Directory.Create(); + } + using (FileStream fs = new FileStream(filePath, FileMode.Open)) + { + T model = XmlDeserializer(fs); + return model; + } + } + catch (Exception ex) + { + //LogHelper.Current.WriteEx("读取XML转换成实例异常", ex, EnumLogType.Error); + return default(T); + } + } + } +} diff --git a/JinYuan.Helper/app.config b/JinYuan.Helper/app.config new file mode 100644 index 0000000..a2625f6 --- /dev/null +++ b/JinYuan.Helper/app.config @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JinYuan.Helper/packages.config b/JinYuan.Helper/packages.config new file mode 100644 index 0000000..daf59d1 --- /dev/null +++ b/JinYuan.Helper/packages.config @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JinYuan.MES/Enums/MesResType.cs b/JinYuan.MES/Enums/MesResType.cs new file mode 100644 index 0000000..1f630b1 --- /dev/null +++ b/JinYuan.MES/Enums/MesResType.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace JinYuan.MES.Enums +{ + /// + /// + /// + public enum MesResType + { + [Description("停线")] + A = 1, + [Description("排出")] + B = 2, + [Description("警示")] + C = 3, + [Description("OK值")] + D = 4, + [Description("未知的结果")] + UnKnow = 99999 + } +} diff --git a/JinYuan.MES/Enums/MesUploadType.cs b/JinYuan.MES/Enums/MesUploadType.cs new file mode 100644 index 0000000..932dcba --- /dev/null +++ b/JinYuan.MES/Enums/MesUploadType.cs @@ -0,0 +1,28 @@ +using System.ComponentModel; + +namespace JinYuan.MES.Enums +{ + /// + /// MES上传的三种类型 + /// + public enum MesUploadType + { + /// + /// 单进整出 + /// + [Description("DZ")] + DZ = 1, + /// + /// 整进整出 + /// + [Description("ZZ")] + ZZ = 2, + /// + /// 单进单出 + /// + [Description("DD")] + DD = 3, + + } +} + diff --git a/JinYuan.MES/IMes.cs b/JinYuan.MES/IMes.cs new file mode 100644 index 0000000..ae6c89c --- /dev/null +++ b/JinYuan.MES/IMes.cs @@ -0,0 +1,147 @@ +using JinYuan.MES.Enums; +using JinYuan.MES.Models; +using JinYuan.Models; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace JinYuan.MES +{ + /// + /// MES接口 + /// + public interface IMes + { + /// + /// 登录接口 + /// + Task<(bool Success, string Message, string MesUserLevel)> LoginAsync(string url, string siteCode, string lineCode, string equipNum, string userName, string passWord); + + Task<(bool Success, string Message)> LoginAsync(string url, string siteCode, string lineCode, string equipNum, string UserCardID); + + /// + /// 设备参数设定值请求接口 + /// + Task<(ParamReturnData Data, string Mesage)> GetParamSetRequestAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName); + + /// + /// 参数设定值变更接口 + /// + Task<(bool Success, string ResJson)> ParamChangeAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List paramChangeItems); + + /// + /// 电芯档位获取 + /// + Task<(bool Success, List materialGrades)> QueryGradeAsync(string url, string siteCode, string lineCode, string equipNum, string recordDate, string qty, string materialCode, string userName, List listCode); + /// + /// 料盘信息获取 + /// + Task<(bool Success, string mesMessage, MesResType mesResType, TrayInfo trayInfo)> QueryMesTrayInfosAsync(string url, string siteCode, string lineCode, string equipNum, string recordDate, string containerCode, string materialCode, string userName); + + //Task<(bool Success, string mesMessage, MesResType mesResType, BatteryInfo trayInfo)> QueryMesGradeInfosAsync(string url, string siteCode, string lineCode, string equipNum, string recordDate, string containerCode, string materialCode, string userName); + + /// + /// 料框码与电池解绑 + /// + Task<(bool Success, string mesMessage)> UnbindTrayInfosAsync(string url, string equipNum, string trayCode); + + /// + /// 半成品电池绑定(装箱) + /// + Task<(bool success, string mesMessage, MesResType mesResType, List materialPackInfos)> PackLoadAsync(string url, string siteCode, string lineCode, string equipNum, string ContainerCode, int capacity, string grade, string materialCode, List cellDataVOList); + + /// + /// 成品电池绑定(装箱) + /// + Task<(bool success, string mesMessage, MesResType mesResType, List materialPackInfos)> PackLoadFinishAsync(string url, string siteCode, string lineCode, string equipNum, string ContainerCode, int capacity, string grade, string materialCode, List cellDataVOList); + /// + /// 箱唛信息获取 + /// + //Task<(bool success, string mesMessage, MesResType mesResType, List cartonTagInfos)> QueryCartonAsync(string url, string siteCode, string lineCode, string equipNum, string containerCode); + + /// + /// 栈板信息获取 + /// + //Task<(bool success, string mesMessage, MesResType mesResType, List palletTagInfos)> QueryPalletAsync(string url, string siteCode, string lineCode, string equipNum, string containerCode); + + /// + /// 客户标签与系统标签绑定 + /// + //Task<(bool success, string mesMessage, MesResType mesResType)> BindingAsync(string url, string siteCode, string lineCode, string equipNum, string containerCode, string palletCode, string custcartonCode, string custpalletCode, List custcarton, List custpallet); + + ///// + ///// 复投单个上传(只上传条码,不上传卷芯码) + ///// + //Task<(bool Success, string MesMessage, MesResType MesResType)> SingleFTCellInStationAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, string BarCode); + + ///// + ///// 电芯进站接口(多个) + ///// + //Task<(bool Success, List MesMessage, List MesResType)> ManyCellInStationAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List listBar); + + //Task<(bool Success, List MesMessage, List MesResType, List CellCode)> ManyCellInStationAsync1(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List listBar); + + ///// + ///// 电芯出站接口(多个) + ///// + //Task<(bool Success, List MesMessage, List MesResType)> OutboundInformationsAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List listBar); + + ///// + ///// 组装出站(单电池) + ///// + ///// + ///// + ///// + ///// + ///// + ///// + ///// + ///// + ///// + ///// + //Task<(bool Success, string Mesage, MesResType MesResType)> SingleCellInAndOutStationAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, BGearEntity m, int type, string materialLotCodeLocator); + + + ///// + ///// 原材料上传 + ///// + ///// + ///// + ///// + ///// + ///// + ///// + ///// + //Task<(bool Success, string MesMessage, MesResType MesResType)> RawMaterialStationAsync(string url, string MaterialCode, string equipNum, string BarCode); + ///// + ///// 产品过程加工参数接口 + ///// + //Task<(bool Success, string ResJson)> ProductProcessParamAsync(string url, string siteCode, string userName, string equipNum, string lineCode, string materialCode, MesUploadType unloadType, List productProcessParam); + + /// + /// 产品结果加工参数接口 + /// + //Task<(bool Success, string ResJson)> ProducResultParamAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List batteryInfos, MesUploadType unloadType, string insertTime); + Task ProducResultParamAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, string containerCode, string palletId, List batteryInfos, MesUploadType unloadType); + + /// + /// 设备运行状态接口 + /// + Task<(bool Success, string ResJson)> UploadEquStatusAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, string guid, string statusCode, List faultCodes); + + /// + /// 设备报警接口 + /// + Task<(bool Success, string Mesage)> UploadEquAlarmAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List alarmObj, string guid); + + /// + /// 能耗数据上传 + /// + Task<(bool Success, string Mesage)> UploadEquEnergyAsync(string url, string siteCode, string lineCode, string equipNum, string userName, List electricMeterNum, List wattrs); + + /// + /// 风速仪数据上传 + /// + Task<(bool Success, string Mesage)> UploadDeviceCollectDataAsync(string url, string equipNum, List antiDustAirSpeedNum, List collectData); + } +} diff --git a/JinYuan.MES/JinYuan.MES.csproj b/JinYuan.MES/JinYuan.MES.csproj new file mode 100644 index 0000000..80aec84 --- /dev/null +++ b/JinYuan.MES/JinYuan.MES.csproj @@ -0,0 +1,92 @@ + + + + + Debug + AnyCPU + {530B6426-08E7-461C-91DC-787F876620FC} + Library + Properties + JinYuan.MES + JinYuan.MES + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\JinYuan.VirtualDataLibrary\obj\Debug\JinYuan.VirtualDataLibrary.dll + + + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360} + JinYuan.Helper + + + {4C0BCB84-5CD7-4846-8363-C4C10D46E391} + JinYuan.Models + + + + + + + + \ No newline at end of file diff --git a/JinYuan.MES/MESApiHelper.cs b/JinYuan.MES/MESApiHelper.cs new file mode 100644 index 0000000..bf54fc0 --- /dev/null +++ b/JinYuan.MES/MESApiHelper.cs @@ -0,0 +1,200 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.MES +{ + public static class MESApiHelper + { + private static readonly HttpClient _httpClient; + private static string _appId; + private static string _appKey; + private static string _token; + private static DateTime _tokenExpireTime; + + private const string TOKEN_URL = "https://example.com/api/oauth/token"; // Token 获取地址 + + static MESApiHelper() + { + _httpClient = new HttpClient(); + _httpClient.Timeout = TimeSpan.FromSeconds(10); // 设置默认超时 + } + + /// + /// 初始化 AppId 和 AppKey + /// + /// + /// + public static void Initialize(string appId, string appKey) + { + _appId = appId; + _appKey = appKey; + } + + /// + /// 确保 Token 有效 + /// + private static async Task EnsureTokenValidAsync() + { + if (string.IsNullOrEmpty(_token) || DateTime.Now >= _tokenExpireTime) + { + await RefreshTokenAsync(); + } + } + + /// + /// 刷新 Token + /// + private static async Task RefreshTokenAsync() + { + var tokenRequest = new + { + appId = _appId, + appKey = _appKey + }; + + var response = await SendRequestAsync(TOKEN_URL, HttpMethod.Post, tokenRequest, false); + + if (response != null && response.Success) + { + _token = response.Token; + _tokenExpireTime = DateTime.Now.AddSeconds(response.Expire); + } + else + { + throw new Exception("获取 Token 失败"); + } + } + + /// + /// 发送 HTTP 请求 + /// + /// 返回类型 + /// 请求地址 + /// HTTP 方法 + /// 请求数据 + /// 是否需要认证 + /// + public static async Task SendRequestAsync(string url, HttpMethod method, object data = null, bool requiresAuth = true) + { + if (requiresAuth) + { + await EnsureTokenValidAsync(); + } + + using (var request = new HttpRequestMessage(method, url)) + { + if (requiresAuth) + { + request.Headers.Add("Authorization", $"Bearer {_token}"); + } + + if (data != null) + { + var json = JsonConvert.SerializeObject(data); + request.Content = new StringContent(json, Encoding.UTF8, "application/json"); + } + + var response = await _httpClient.SendAsync(request); + var content = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) + { + throw new HttpRequestException($"请求失败: {response.StatusCode}, {content}"); + } + + return JsonConvert.DeserializeObject(content); + } + } + + /// + /// 发送 HTTP 请求并返回字符串 + /// + /// 请求地址 + /// HTTP 方法 + /// 请求数据 + /// 是否需要认证 + /// + public static async Task SendRequestStringAsync(string url, HttpMethod method, string data = null, bool requiresAuth = true) + { + if (requiresAuth) + { + await EnsureTokenValidAsync(); + } + + using (var request = new HttpRequestMessage(method, url)) + { + if (requiresAuth) + { + request.Headers.Add("Authorization", $"Bearer {_token}"); + } + + if (data != null) + { + if (method == HttpMethod.Get) + { + //// GET 请求 + //var query = QueryStringBuilder(data); + url = url + "/" + data; + request.RequestUri = new Uri(url); + } + else + { + request.Content = new StringContent(data, Encoding.UTF8, "application/json"); + } + } + try + { + var response = await _httpClient.SendAsync(request); + var content = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) + { + throw new HttpRequestException($"请求失败: {response.StatusCode}, {content}"); + } + + return content; + } + catch (TaskCanceledException ex) + { + Debug.WriteLine($"【超时异常】请求被取消: {ex.Message},通常是服务端无响应/超时"); + throw; + } + catch (Exception ex) + { + Debug.WriteLine($"【请求异常】{ex.Message}"); + throw; + } + + } + } + + private static string QueryStringBuilder(object obj) + { + var properties = obj.GetType().GetProperties(); + var keyValuePairs = properties + .Where(p => p.GetValue(obj) != null) + .Select(p => $"{Uri.EscapeDataString(p.Name)}={Uri.EscapeDataString(p.GetValue(obj).ToString())}"); + + return string.Join("&", keyValuePairs); + } + } + + + + /// + /// Token 响应模型 + /// + public class TokenResponse + { + public bool Success { get; set; } + public string Token { get; set; } + public int Expire { get; set; } + } + +} diff --git a/JinYuan.MES/MesDataProcess.cs b/JinYuan.MES/MesDataProcess.cs new file mode 100644 index 0000000..dded582 --- /dev/null +++ b/JinYuan.MES/MesDataProcess.cs @@ -0,0 +1,2194 @@ +using JinYuan.Helper; +using JinYuan.MES.Enums; +using JinYuan.MES.Models; +using JinYuan.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Runtime.Remoting.Messaging; +using System.Threading; +using System.Threading.Tasks; +using static System.Runtime.CompilerServices.RuntimeHelpers; + +namespace JinYuan.MES +{ + public class MesDataProcess : IMes + { + + #region 1、登录验证 + + /// 账号密码登录(异步方法) + /// + /// API地址 + /// 站点代码 + /// 线体代码 + /// 设备编号 + /// 用户名 + /// 密码 + /// 用户卡ID + /// 返回结果(是否成功、消息) userCardID = UserCardID + public async Task<(bool Success, string Message, string MesUserLevel)> LoginAsync(string url, string siteCode, string lineCode, string equipNum, string userName, string passWord) + { + bool res = false; // 操作结果 + string resJson = ""; // 日志信息 + string message = ""; // 消息 + string mesUserName = "";//mes返回登陆权限 + + try + { + // 创建请求模型 + var model = new LoginEntity + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + userName = userName, + passWord = passWord, + }; + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postData = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postData, false); + + // 记录请求结束时间 + sw.Stop(); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用员工权限校验接口:{url},请求数据为:{postData},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\员工权限校验\{nowDate.ToString("HH")}.txt", resJson); + return (res, message, mesUserName); + } + + // 解析返回结果 + var res1 = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (res1 != null && res1.success && string.IsNullOrEmpty(res1.code) && string.IsNullOrEmpty(res1.message)) + { + //mes登陆权限赋值 + //if (res1.rows[0].username == userName) { mesUserName = res1.rows[0].permissionLevel; } + if (res1.rows[0] == userName) { mesUserName = res1.rows[0]; } + res = true; + message = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用员工权限校验接口:{url},请求数据为:{postData}\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\员工权限校验\{nowDate.ToString("HH")}.txt", resJson); + } + else + { + // 如果操作失败,记录日志 + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + message = res1?.message ?? "未知错误"; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用员工权限校验接口:{url},请求数据为:{postData}\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\员工权限校验\{nowDate.ToString("HH")}.txt", resJson); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = "调用员工权限校验接口发生异常"; + resJson = $"调用员工权限校验接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("调用员工权限校验接口", ex); + } + + // 返回结果 + return (res, message, mesUserName); + } + + /// + /// 刷卡登录 + /// + /// + /// + /// + /// + /// + /// + public async Task<(bool Success, string Message)> LoginAsync(string url, string siteCode, string lineCode, string equipNum, string UserCardID) + { + bool res = false; // 操作结果 + string resJson = ""; // 日志信息 + string message = ""; // 消息 + + try + { + // 创建请求模型 + var model = new LoginEntity + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + userCardID = UserCardID, + + }; + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postData = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postData, false); + + // 记录请求结束时间 + sw.Stop(); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用员工权限校验接口:{url},请求数据为:{postData},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\员工权限校验\{nowDate.ToString("HH")}.txt", resJson); + return (res, message); + } + + // 解析返回结果 + var res1 = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (res1 != null && res1.success && string.IsNullOrEmpty(res1.code) && string.IsNullOrEmpty(res1.message)) + { + res = true; + message = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用员工权限校验接口:{url},请求数据为:{postData}\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\员工权限校验\{nowDate.ToString("HH")}.txt", resJson); + } + else + { + // 如果操作失败,记录日志 + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + message = res1?.message ?? "未知错误"; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用员工权限校验接口:{url},请求数据为:{postData}\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\员工权限校验\{nowDate.ToString("HH")}.txt", resJson); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = "调用员工权限校验接口发生异常"; + resJson = $"调用员工权限校验接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("调用员工权限校验接口", ex); + } + + // 返回结果 + return (res, message); + } + #endregion + + #region 2、获取MES参数请求 + /// + /// 获取MES参数请求 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public async Task<(ParamReturnData Data, string Mesage)> GetParamSetRequestAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName) + { + string resJson = ""; + string mesage = ""; // 用于存储消息 + + try + { + var model = new + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + materialCode = materialCode, + userName = userName + }; + + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + var sw = new Stopwatch(); + sw.Start(); + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + + sw.Stop(); + + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备参数设定值请求接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备参数设定值请求\{nowDate.ToString("HH")}.txt", resJson); + return (null, mesage); + } + + var res1 = ReturnMesMsg(result); + if (res1.success) + { + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备参数设定值请求接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备参数设定值请求\{nowDate.ToString("HH")}.txt", resJson); + } + else + { + var resData = res1 == null ? "" : result; + mesage = "MES返回结果为空"; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备参数设定值请求接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备参数设定值请求\{nowDate.ToString("HH")}.txt", resJson); + } + return (res1, mesage); + } + catch (Exception ex) + { + mesage = $"设备参数设定值请求接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("设备参数设定值请求接口", ex); + return (null, mesage); + } + } + #endregion + + #region 3、参数变更请求 + /// + /// 参数变更请求 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public async Task ParamChange(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List paramChangeItems) + { + bool res = false; + string resJson = ""; + try + { + var model = new ParamChange + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + materialCode = materialCode, + userName = userName, + }; + + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + var sw = new Stopwatch(); + sw.Start(); + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + sw.Stop(); + + + var resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用参数设定值变更接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\MesLogs\{nowDate.ToString("yyyyMMdd")}\参数设定值变更\{nowDate.ToString("HH")}.txt", resJson); + + } + catch (Exception ex) + { + resJson = $"参数设定值变更接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("参数设定值变更接口", ex); + } + + return res; + + } + #endregion + + #region 根据料框码获取电池型号、电池条码等数据 + /// + /// 根据料框码获取电池型号、电池条码等数据 + /// + /// API地址 /api/public/equip/auto/gradequery + /// 工厂代码 + /// 产线编号 + /// 设备编号 + /// 记录时间 + /// 数量 + /// 托盘码 + /// 物料代码 + /// 操作人 + /// 电芯信息列表 + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool Success, string mesMessage, MesResType mesResType, TrayInfo trayInfo)> QueryMesTrayInfosAsync(string url, string siteCode, string lineCode, string equipNum, string recordDate, string containerCode, string materialCode, string userName) + { + bool success = false; // 操作结果 + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + TrayInfo trayInfo = new TrayInfo(); + + try + { + // 序列化请求数据 + var nowDate = DateTime.Now; + + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync($"{url}", HttpMethod.Get, containerCode, false); + + // 记录请求结束时间 + sw.Stop(); + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + LogHelper.Instance.WriteLog($"查询料盘信息PC<=>MES耗时:{outTime}ms,料框码:{containerCode}", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用查询料盘信息接口:{url}/{containerCode},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\查询料盘信息\{nowDate:HH}.txt", requestLog); + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", resJson); + message = "MES接口返回空结果"; + return (success, message, mesResType, trayInfo); + } + + // 解析返回结果 + var mesResponse = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (mesResponse != null && mesResponse.code == 200 && mesResponse.data != null) + { + success = true; + ProcessTrayResponse(mesResponse, ref message, ref mesResType, ref trayInfo); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", resJson); + if (success && mesResType == MesResType.D) + { + message += $"查询料盘信息成功,共获取 {trayInfo.cellList.Count} 个电池信息"; + //CommonMethods.AddDataMonitorLog(0, message); + //return (success, message, mesResType, trayInfo); + } + else + { + message += $"查询料盘信息失败"; + //return (success, message, mesResType, trayInfo); + } + } + else + { + // 如果操作失败,记录日志 + //var resData = res1 == null ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", resJson); + // 如果操作失败 + message += mesResponse?.msg ?? "MES接口返回失败状态"; + //mesResType = GetMesResType(mesResponse?.category); + //CommonMethods.AddDataMonitorLog(1, $"查询电芯档位失败:{message}"); + //return (success, message, mesResType, trayInfo); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = $"查询料盘信息接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("查询料盘信息接口", ex); + } + + // 返回结果 + return (success, message, mesResType, trayInfo); + } + + /// + /// 料盘信息查询返回数据处理 + /// + /// + /// + /// + /// + private void ProcessTrayResponse(MesResponseTray res, ref string mesMessage, ref MesResType mesResType, ref TrayInfo trayInfo) + { + if (res != null) + { + trayInfo = res.data ?? new TrayInfo(); + mesMessage = res.msg; + if (res.code == 200) + { + mesResType = MesResType.D; + mesMessage = "MES料盘信息查询成功 "; + } + else + { + mesResType = MesResType.B; + //mesMessage = "MES料盘信息查询失败 "; + } + } + else + { + mesMessage = "响应数据为空"; + mesResType = MesResType.B; + } + } + + #endregion + + #region 电芯档位获取 + /// + /// 电芯档位获取 + /// + /// API地址 /api/public/equip/auto/gradequery + /// 工厂代码 + /// 产线编号 + /// 设备编号 + /// 记录时间 + /// 数量 + /// 托盘码 + /// 物料代码 + /// 操作人 + /// 电芯信息列表 + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool Success, List materialGrades)> QueryGradeAsync(string url, string siteCode, string lineCode, string equipNum, string recordDate, string qty, string materialCode, string userName, List listCode) + { + bool success = false; // 操作结果 + string rawJson = ""; + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + List materialGrades = new List(); + + try + { + // 创建请求模型 + var model = new QueryGradeParam + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + recordDate = recordDate, + qty = qty, + materialCode = materialCode, + actionType = "IN", + userName = userName, + batteryTrayBindVOList = listCode + }; + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + LogHelper.Instance.WriteLog($"查询电芯档位PC<=>MES耗时:{outTime}ms,电芯码:{string.Join(",", listCode)}", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\查询电芯档位\{nowDate:HH}.txt", requestLog); + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + string resData = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", resData); + message = "MES接口返回空结果"; + return (success, materialGrades); + } + + // 解析返回结果 + var mesResponse = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (mesResponse != null && mesResponse.success) + { + success = true; + ProcessGradeResponse(mesResponse, listCode, ref message, ref materialGrades); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", resJson); + if (success) + { + message = $"查询电芯档位成功,共获取 {materialGrades.Count} 个档位信息"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", message); + return (success, materialGrades); + } + else + { + return (success, materialGrades); + } + } + else + { + // 如果操作失败,记录日志 + var resData = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用查询电芯档位接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\查询电芯档位\{nowDate.ToString("HH")}.txt", result); + + return (success, materialGrades); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = $"查询电芯档位接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("查询电芯档位接口", ex); + } + + // 返回结果 + return (success, materialGrades); + } + + /// + /// 电芯档位查询返回数据处理 + /// + /// + /// + /// + /// + private void ProcessGradeResponse(MesResponseGrade res, List barCodes, ref string mesMessage, ref List materialGrades) + { + if (res != null) + { + materialGrades = res.rows ?? new List(); + + if (res.success) + { + // 检查数据完整性 + if (materialGrades.Count != res.total) + { + mesMessage = $"数据数量不匹配:返回{materialGrades.Count}条,总数{res.total}"; + } + + // 检查条码匹配 + var requestBarcodes = barCodes.Select(b => b.identification).ToHashSet(); + var responseBarcodes = materialGrades.Select(m => m.identification).ToHashSet(); + + var unmatchedBarcodes = requestBarcodes.Except(responseBarcodes).ToList(); + + if (unmatchedBarcodes.Any()) + { + mesMessage = $"存在 {unmatchedBarcodes.Count} 个未匹配的条码"; + } + } + + } + else + { + mesMessage = "响应数据为空"; + } + } + #endregion + + /// + /// 将MES返回的category转换为MesResType + /// + private MesResType GetMesResType(string category) + { + if (string.IsNullOrEmpty(category)) + return MesResType.B; + + switch (category.ToUpper()) + { + case "A": + return MesResType.A; // 停线 + case "B": + return MesResType.B; // 排出 + case "C": + return MesResType.C; // 忽略(需警示) + case "D": + return MesResType.D; // 成功 + default: + return MesResType.B; // 默认排出 + } + } + + #region 解绑所有料框码 + /// + /// 料框码与电池解绑 + /// + public async Task<(bool Success, string mesMessage)> UnbindTrayInfosAsync(string url, string equipNum, string trayCode) + { + bool success = false; // 操作结果 + string rawJson = ""; // 日志信息 + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + + try + { + if (string.IsNullOrEmpty(trayCode)) + { + message = "料框码为空"; + return (success, message); + } + + // 创建请求模型 + var model = new unbindParam + { + equipNum = equipNum, + trayCode = trayCode, + }; + var postcontent = JsonConvert.SerializeObject(model); + // 序列化请求数据 + var nowDate = DateTime.Now; + + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + rawJson = result; + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + //LogHelper.Instance.WriteLog($"进站PC<=>MES上传耗时:{outTime}ms,电芯码:{listBar[0]},{listBar[1]},{listBar[2]},{listBar[3]}", "MESTime"); + LogHelper.Instance.WriteLog($"解绑料框码PC<=>MES耗时:{outTime}ms,料框码:{trayCode}", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用解绑料框码接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\调用解绑料框码接口\{nowDate:HH}.txt", requestLog); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用卡板电芯信息上传(装箱)接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + //return (res, mesMessage, mesResType, materialPackInfos); + message = "MES接口返回空结果"; + return (success, message); + } + + // 解析返回结果 + var response = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (response != null && response.flag) + { + success = true; + return (success, response.msg); + } + else + { + string msg = response == null? $"{result}": response.msg; + return (false, msg); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + //resJson = $"卡板电芯信息上传(装箱)接口发生异常:{ex.Message}"; + //LogHelper.Instance.WriteEX("卡板电芯信息上传(装箱)接口", ex); + + // 捕获异常并记录日志 + message = $"解绑料框码接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("解绑料框码", ex); + return (success, message);//MesResult>.Fail(message, MesResType.B, rawJson); + } + + } + + #endregion + + #region 卡板电芯信息上传(装箱) + /// + /// 半成品电池绑定(装箱) + /// + /// API地址 /api/public/equip/auto/pack + /// 工厂代码 + /// 设备编号 + /// 卡板码(箱唛号) + /// 档位 + /// 电芯信息 + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool success, string mesMessage, MesResType mesResType, List materialPackInfos)> PackLoadAsync(string url, string siteCode, string lineCode, string equipNum, string ContainerCode, int capacity, string grade, string materialCode, List cellDataVOList) + { + bool success = false; // 操作结果 + string rawJson = ""; // 日志信息 + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + List materialPackInfos = new List(); + + try + { + // 参数验证 + if (cellDataVOList == null || !cellDataVOList.Any()) + { + message = "电池信息列表为空"; + return (success, message, mesResType, materialPackInfos); + } + + if (string.IsNullOrEmpty(ContainerCode)) + { + message = "容器码为空"; + return (success, message, mesResType, materialPackInfos); + } + + ContainerInfo containerInfo = new ContainerInfo + { + containerCode = ContainerCode, + productDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + //containerTypeCode = "XM_BCP", + packQty = capacity, + groupNum = "1", + //supplierCode= "EVEDL", + materialName = "MB36-0.5P-V1.1 电芯注液半成品", + materialCode = materialCode, + batteryInfos = cellDataVOList, + }; + + List containerBarcodeInfos = new List + { }; + + containerBarcodeInfos.Add(containerInfo); + + // 创建请求模型 + var model = new PackParam + { + siteCode = siteCode, + lineCode = lineCode, + containerBarcodeInfos = containerBarcodeInfos, + equipNum = equipNum, + ContainerCode = ContainerCode, + capacity = capacity, + grade = grade, + materialCode = materialCode, + cellDataVOList = cellDataVOList + }; + + List barcodeList = cellDataVOList.Select(BatteryInfo => BatteryInfo.identification).ToList(); + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + rawJson = result; + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + //LogHelper.Instance.WriteLog($"进站PC<=>MES上传耗时:{outTime}ms,电芯码:{listBar[0]},{listBar[1]},{listBar[2]},{listBar[3]}", "MESTime"); + LogHelper.Instance.WriteLog($"半成品电池绑定PC<=>MES耗时:{outTime}ms,电芯码:{string.Join(",", barcodeList)}", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用半成品电池绑定接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\半成品电池绑定\{nowDate:HH}.txt", requestLog); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用卡板电芯信息上传(装箱)接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + //return (res, mesMessage, mesResType, materialPackInfos); + message = "MES接口返回空结果"; + return (success, message, mesResType, materialPackInfos); + } + + // 解析返回结果 + var response = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (response != null && response.success) + { + success = true; + ProcessPackResponse(response, barcodeList, cellDataVOList, ref message, ref mesResType, ref materialPackInfos); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用卡板电芯信息上传(装箱)接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + //if (success && mesResType == MesResType.D) + { + //message = $"卡板电芯信息上传成功,共处理 {materialPackInfos?.Count ?? 0} 个电芯"; + return (success, message, mesResType, materialPackInfos); + } + //else + //{ + // return (success, message, mesResType, materialPackInfos); + //} + } + else + { + // 如果操作失败,记录日志 + //var resData = res1 == null ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用卡板电芯信息上传(装箱)接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + // 如果操作失败 + message = response?.message ?? "MES接口返回失败状态"; + mesResType = MesResType.C;//GetMesResType(response?.category); + return (success, message, mesResType, materialPackInfos);//MesResult>.Fail(message, mesResType, rawJson); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + //resJson = $"卡板电芯信息上传(装箱)接口发生异常:{ex.Message}"; + //LogHelper.Instance.WriteEX("卡板电芯信息上传(装箱)接口", ex); + + // 捕获异常并记录日志 + message = $"半成品电池绑定接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("半成品电池绑定接口", ex); + return (success, message, mesResType, materialPackInfos);//MesResult>.Fail(message, MesResType.B, rawJson); + } + + // 返回结果 + //return (success, message, mesResType, materialPackInfos); + } + + /// + /// 卡板电芯信息上传(装箱)返回数据处理 + /// + /// + /// + /// + /// + private void ProcessPackResponse(MesResponsePack response, List barcodeList, List cellDataVOList, ref string message, ref MesResType mesResType, ref List materialPackInfos) + { + if (response != null) + { + //materialPackInfos = new List(); + message = response.message; + if (response.success) + { + mesResType = MesResType.D; + //message = "卡板电芯信息上传成功"; + + //// 检查数据完整性 + //if (materialPackInfos.Count != cellDataVOList.Count) + //{ + // message = $"返回数据数量不匹配:请求{cellDataVOList.Count}个,返回{materialPackInfos.Count}个"; + // mesResType = MesResType.B; + // return; + //} + + //// 检查条码匹配 + //var responseBarcodes = materialPackInfos.Select(m => m.identification).ToHashSet(); + //var unmatchedBarcodes = barcodeList.Except(responseBarcodes).ToList(); + + //if (unmatchedBarcodes.Any()) + //{ + // message = $"存在 {unmatchedBarcodes.Count} 个未匹配的条码"; + // mesResType = MesResType.B; + // return; + //} + + //// 检查绑定失败的条码 + //var failedBarcodes = materialPackInfos + // .Where(m => !m.packResult) + // .Select(m => m.identification) + // .ToList(); + + //if (failedBarcodes.Any()) + //{ + // message = $"存在 {failedBarcodes.Count} 个绑定失败的电芯"; + // mesResType = MesResType.B; + // return; + //} + } + else + { + mesResType = MesResType.C; //GetMesResType(response.category); + } + } + else + { + message = "响应数据为空"; + mesResType = MesResType.B; + } + } + + + /// + /// 成品电池绑定 + /// + /// API地址 /api/public/equip/auto/pack + /// 工厂代码 + /// 设备编号 + /// 卡板码(箱唛号) + /// 档位 + /// 电芯信息 + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool success, string mesMessage, MesResType mesResType, List materialPackInfos)> PackLoadFinishAsync(string url, string siteCode, string lineCode, string equipNum, string ContainerCode, int capacity, string grade, string materialCode, List cellDataVOList) + { + bool success = false; // 操作结果 + string rawJson = ""; // 日志信息 + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + List materialPackInfos = new List(); + + try + { + // 参数验证 + if (cellDataVOList == null || !cellDataVOList.Any()) + { + message = "电池信息列表为空"; + return (success, message, mesResType, materialPackInfos); + } + + if (string.IsNullOrEmpty(ContainerCode)) + { + message = "容器码为空"; + return (success, message, mesResType, materialPackInfos); + } + + ContainerInfo containerInfo = new ContainerInfo + { + containerCode = ContainerCode, + productDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + //containerTypeCode = "XM_BCP", + packQty = capacity, + groupNum = "1", + //supplierCode = "EVEDL", + materialName = "MB36-0.5P-V1.1 电池成品", + materialCode = materialCode, + batteryInfos = cellDataVOList, + }; + + List containerBarcodeInfos = new List(){ }; + + containerBarcodeInfos.Add(containerInfo); + + // 创建请求模型 + var model = new FinishPackParam + { + siteCode = siteCode, + lineCode = lineCode, + containerBarcodeInfos = containerBarcodeInfos, + equipCode = equipNum, + outerContainerCode = ContainerCode + }; + + List barcodeList = cellDataVOList.Select(BatteryInfo => BatteryInfo.identification).ToList(); + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + rawJson = result; + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + //LogHelper.Instance.WriteLog($"进站PC<=>MES上传耗时:{outTime}ms,电芯码:{listBar[0]},{listBar[1]},{listBar[2]},{listBar[3]}", "MESTime"); + LogHelper.Instance.WriteLog($"成品电池绑定(装箱)PC<=>MES耗时:{outTime}ms,电芯码:{string.Join(",", barcodeList)}", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用成品电池绑定接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\成品电池绑定\{nowDate:HH}.txt", requestLog); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用成品电池绑定接口:{url},请求数据为:{JsonConvert.SerializeObject(model)},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\成品电池绑定\{nowDate.ToString("HH")}.txt", resJson); + message = "MES接口返回空结果"; + return (success, message, mesResType, materialPackInfos); + + } + + // 解析返回结果 + var response = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (response != null && response.success) + { + success = true; + ProcessFinishPackResponse(response, barcodeList, cellDataVOList, ref message, ref mesResType, ref materialPackInfos); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用卡板电芯信息上传(装箱)接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + if (success && mesResType == MesResType.D) + { + message = $"卡板电芯信息上传成功,共处理 {materialPackInfos?.Count ?? 0} 个电芯"; + } + else + { + //return (success, message, mesResType, materialPackInfos); + } + } + else + { + // 如果操作失败,记录日志 + //var resData = res1 == null ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用卡板电芯信息上传(装箱)接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + // 如果操作失败 + message = response?.message ?? "MES接口返回失败状态"; + mesResType = GetMesResType(response?.category); + //return (success, message, mesResType, materialPackInfos);//MesResult>.Fail(message, mesResType, rawJson); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = $"卡板电芯信息上传(装箱)接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("卡板电芯信息上传(装箱)接口", ex); + //return (success, message, mesResType, materialPackInfos);//MesResult>.Fail(message, MesResType.B, rawJson); + } + + // 返回结果 + return (success, message, mesResType, materialPackInfos); + } + + /// + /// 成品电池绑定返回数据处理 + /// + /// + /// + /// + /// + private void ProcessFinishPackResponse(MesResponseFinishPack response, List barcodeList, List cellDataVOList, ref string message, ref MesResType mesResType, ref List materialPackInfos) + { + if (response != null) + { + materialPackInfos = response.rows ?? new List(); + message = response.message; + if (response.success) + { + mesResType = MesResType.D; + message = "卡板电芯信息上传成功"; + + // 检查数据完整性 + if (materialPackInfos.Count != cellDataVOList.Count) + { + message = $"返回数据数量不匹配:请求{cellDataVOList.Count}个,返回{materialPackInfos.Count}个"; + mesResType = MesResType.B; + return; + } + + // 检查条码匹配 + var responseBarcodes = materialPackInfos.Select(m => m.identification).ToHashSet(); + var unmatchedBarcodes = barcodeList.Except(responseBarcodes).ToList(); + + if (unmatchedBarcodes.Any()) + { + message = $"存在 {unmatchedBarcodes.Count} 个未匹配的条码"; + mesResType = MesResType.B; + return; + } + + // 检查绑定失败的条码 + var failedBarcodes = materialPackInfos + .Where(m => !m.packResult) + .Select(m => m.identification) + .ToList(); + + if (failedBarcodes.Any()) + { + message = $"存在 {failedBarcodes.Count} 个绑定失败的电芯"; + mesResType = MesResType.B; + return; + } + } + else + { + mesResType = GetMesResType(response.category); + } + } + else + { + message = "响应数据为空"; + mesResType = MesResType.B; + } + } + + #endregion + + #region 箱唛信息获取 + /// + /// 箱唛信息获取 + /// + /// API地址 /api/public/equip/auto/cartonquery + /// 工厂代码 + /// 产线编号 + /// 设备编号 + /// 卡板码(箱唛号) + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool success, string mesMessage, MesResType mesResType, List cartonTagInfos)> QueryCartonAsync(string url, string siteCode, string lineCode, string equipNum, string containerCode) + { + bool success = false; // 操作结果 + string rawJson = ""; // + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + List cartonTagInfos = new List(); + + try + { + // 参数验证 + if (string.IsNullOrEmpty(containerCode)) + { + message = "容器码为空"; + return (success, message, mesResType, cartonTagInfos); + } + + // 创建请求模型 + var model = new QueryCartonPalletParam + { + siteCode = siteCode, + equipNum = equipNum, + lineCode = lineCode, + containerCode = containerCode + }; + + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + rawJson = result; + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + //LogHelper.Instance.WriteLog($"进站PC<=>MES上传耗时:{outTime}ms,电芯码:{listBar[0]},{listBar[1]},{listBar[2]},{listBar[3]}", "MESTime"); + LogHelper.Instance.WriteLog($"箱唛信息获取PC<=>MES耗时:{outTime}ms", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用箱唛信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\箱唛信息获取\{nowDate:HH}.txt", requestLog); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用箱唛信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\箱唛信息获取\{nowDate.ToString("HH")}.txt", resJson); + //return (success, mesMessage, mesResType, cartonTagInfos); + message = "MES接口返回空结果"; + return (success, message, mesResType, cartonTagInfos); + } + + // 解析返回结果 + var response = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (response != null && response.success) + { + success = true; + ProcessCartonResponse(response, ref message, ref mesResType, ref cartonTagInfos); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用箱唛信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\箱唛信息获取\{nowDate.ToString("HH")}.txt", resJson); + if (success && mesResType == MesResType.D) + { + message = $"箱唛信息获取成功,共获取 {cartonTagInfos?.Count ?? 0} 个标签信息"; + return (success, message, mesResType, cartonTagInfos); + } + else + { + return (success, message, mesResType, cartonTagInfos); + } + } + else + { + //// 如果操作失败,记录日志 + //var resData = response == null ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用箱唛信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\箱唛信息获取\{nowDate.ToString("HH")}.txt", resJson); + // 如果操作失败 + message = response?.message ?? "MES接口返回失败状态"; + mesResType = GetMesResType(response?.category); + return (success, message, mesResType, cartonTagInfos);//MesResult>.Fail(message, mesResType, rawJson); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = $"箱唛信息获取接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("箱唛信息获取接口", ex); + } + + // 返回结果 + return (success, message, mesResType, cartonTagInfos); + } + + /// + /// 箱唛信息获取返回数据处理 + /// + /// + /// + /// + /// + private void ProcessCartonResponse(MesResponseCarton response, ref string message, ref MesResType mesResType, ref List cartonTagInfos) + { + if (response != null) + { + cartonTagInfos = response.rows ?? new List(); + message = response.message; + if (response.success) + { + mesResType = MesResType.D; + message = "MES箱唛信息获取成功 "; + // 检查数据完整性 + if (cartonTagInfos.Count == 0) + { + message = "未获取到箱唛标签信息"; + mesResType = MesResType.B; + } + } + else + { + mesResType = GetMesResType(response.category); + } + } + else + { + message = "响应数据为空"; + mesResType = MesResType.B; + } + } + #endregion + + #region 栈板获取 + /// + /// 栈板信息获取 + /// + /// API地址 /api/public/equip/auto/palletquery + /// 工厂代码 + /// 产线编号 + /// 设备编号 + /// 卡板码(箱唛号) + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool success, string mesMessage, MesResType mesResType, List palletTagInfos)> QueryPalletAsync(string url, string siteCode, string lineCode, string equipNum, string containerCode) + { + bool success = false; // 操作结果 + string rawJson = ""; // 日志信息 + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + List palletTagInfos = new List(); + + try + { + // 参数验证 + if (string.IsNullOrEmpty(containerCode)) + { + message = "容器码为空"; + return (success, message, mesResType, palletTagInfos); + } + + // 创建请求模型 + var model = new QueryCartonPalletParam + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + containerCode = containerCode + }; + + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + rawJson = result; + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + //LogHelper.Instance.WriteLog($"进站PC<=>MES上传耗时:{outTime}ms,电芯码:{listBar[0]},{listBar[1]},{listBar[2]},{listBar[3]}", "MESTime"); + LogHelper.Instance.WriteLog($"栈板信息获取PC<=>MES耗时:{outTime}ms", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用栈板信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\栈板信息获取\{nowDate:HH}.txt", requestLog); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用栈板信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\栈板信息获取\{nowDate.ToString("HH")}.txt", resJson); + //return (res, mesMessage, mesResType, palletTagInfos); + message = "MES接口返回空结果"; + //return MesResult>.Fail(message, MesResType.B, rawJson); + return (success, message, mesResType, palletTagInfos); + } + + // 解析返回结果 + var response = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (response != null && response.success) + { + success = true; + ProcessPalletResponse(response, ref message, ref mesResType, ref palletTagInfos); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用栈板信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\栈板信息获取\{nowDate.ToString("HH")}.txt", resJson); + + if (success && mesResType == MesResType.D) + { + message = $"栈板信息获取成功,共获取 {palletTagInfos?.Count ?? 0} 个标签信息"; + //return MesResult>.Ok(palletTagInfos ?? new List(), message, rawJson); + return (success, message, mesResType, palletTagInfos); + } + else + { + //return MesResult>.Fail(message, mesResType, rawJson); + return (success, message, mesResType, palletTagInfos); + } + } + else + { + //// 如果操作失败,记录日志 + //var resData = res1 == null ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用栈板信息获取接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\栈板信息获取\{nowDate.ToString("HH")}.txt", resJson); + // 如果操作失败 + message = response?.message ?? "MES接口返回失败状态"; + mesResType = GetMesResType(response?.category); + //return MesResult>.Fail(message, mesResType, rawJson); + } + } + catch (Exception ex) + { + // 捕获异常并记录日志 + message = $"栈板信息获取接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("栈板信息获取接口", ex); + } + + // 返回结果 + return (success, message, mesResType, palletTagInfos); + } + + /// + /// 栈板信息获取返回数据处理 + /// + /// + /// + /// + /// + private void ProcessPalletResponse(MesResponsePallet response, ref string message, ref MesResType mesResType, ref List palletTagInfos) + { + if (response != null) + { + palletTagInfos = response.rows ?? new List(); + message = response.message; + if (response.success) + { + mesResType = MesResType.D; + message = "MES栈板信息获取成功 "; + if (response.success) + { + mesResType = MesResType.D; + message = "栈板信息获取成功"; + + // 检查数据完整性 + if (palletTagInfos.Count == 0) + { + message = "未获取到栈板标签信息"; + mesResType = MesResType.B; + } + } + else + { + mesResType = GetMesResType(response.category); + } + } + } + else + { + message = "响应数据为空"; + mesResType = MesResType.B; + } + } + #endregion + + #region 客户标签与系统标签绑定 + /// + /// 客户标签与系统标签绑定 + /// + /// API地址 /api/public/equip/auto/ + /// 工厂代码 + /// 产线编号 + /// 设备编号 + /// 卡板码(箱唛号) + /// 栈板码 + /// 客户箱唛码 + /// 客户栈板码 + /// 客户箱唛信息 + /// 客户栈板信息 + /// 返回结果(是否成功、消息列表、响应类型列表) + public async Task<(bool success, string mesMessage, MesResType mesResType)> BindingAsync(string url, string siteCode, string lineCode, string equipNum, string containerCode, string palletCode, string custcartonCode, string custpalletCode, List custcarton, List custpallet) + { + bool success = false; // 操作结果 + string rawJson = ""; // 日志信息 + string message = ""; // 消息列表 + MesResType mesResType = MesResType.C; + + try + { + // 参数验证 + if (string.IsNullOrEmpty(containerCode)) + { + message = "容器码为空"; + return (success, message, mesResType); + } + + // 创建请求模型 + var model = new BindingParam + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + containerCode = containerCode, + palletCode = palletCode, + custcartonCode = custcartonCode, + custpalletCode = custpalletCode, + custcarton = custcarton, + custpallet = custpallet + }; + + // 序列化请求数据 + var nowDate = DateTime.Now; + var postcontent = JsonConvert.SerializeObject(model); + + // 记录请求开始时间 + var sw = Stopwatch.StartNew(); + + // 调用异步API + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + // 记录请求结束时间 + sw.Stop(); + rawJson = result; + + // 如果请求耗时超过1秒,记录日志 + long outTime = sw.ElapsedMilliseconds; + if (outTime > 1000) + { + //LogHelper.Instance.WriteLog($"进站PC<=>MES上传耗时:{outTime}ms,电芯码:{listBar[0]},{listBar[1]},{listBar[2]},{listBar[3]}", "MESTime"); + LogHelper.Instance.WriteLog($"客户标签与系统标签绑定PC<=>MES耗时:{outTime}ms", "MESTime"); + } + + // 记录请求日志 + string requestLog = $"{nowDate:yyyy-MM-dd HH:mm:ss.fff}:调用客户标签与系统标签绑定接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds):yyyy-MM-dd HH:mm:ss.fff}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate:yyyyMMdd}\客户标签与系统标签绑定\{nowDate:HH}.txt", requestLog); + + // 如果返回结果为空,记录日志并返回 + if (string.IsNullOrEmpty(result)) + { + //string resData = result == "" ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用客户标签与系统标签绑定接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\客户标签与系统标签绑定\{nowDate.ToString("HH")}.txt", resJson); + //return (res, mesMessage, mesResType); + message = "MES接口返回空结果"; + //return MesResult.Fail(message, MesResType.B, rawJson); + return (success, message, mesResType); + } + + // 解析返回结果 + var response = JsonConvert.DeserializeObject(result); + + // 如果操作成功 + if (response != null && response.success) + { + success = true; + ProcessBindingResponse(response, ref message, ref mesResType); // 处理返回结果 + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用客户标签与系统标签绑定接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{result}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\卡板电芯信息上传(装箱)\{nowDate.ToString("HH")}.txt", resJson); + if (success && mesResType == MesResType.D) + { + message = "客户标签与系统标签绑定成功"; + //return MesResult.Ok(true, message, rawJson); + return (success, message, mesResType); + } + else + { + //return MesResult.Fail(message, mesResType, rawJson); + return (success, message, mesResType); + } + } + else + { + //// 如果操作失败,记录日志 + //var resData = res1 == null ? "" : result; + //resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用客户标签与系统标签绑定接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + //TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\客户标签与系统标签绑定\{nowDate.ToString("HH")}.txt", resJson); + // 如果操作失败 + message = response?.message ?? "MES接口返回失败状态"; + //mesResType = GetMesResType(response?.category); + //return MesResult.Fail(message, mesResType, rawJson); + return (success, message, mesResType); + } + } + catch (Exception ex) + { + //// 捕获异常并记录日志 + //resJson = $"客户标签与系统标签绑定接口发生异常:{ex.Message}"; + //LogHelper.Instance.WriteLog($"客户标签与系统标签绑定接口{ex}"); + // 捕获异常并记录日志 + message = $"客户标签与系统标签绑定接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("客户标签与系统标签绑定接口", ex); + //return MesResult.Fail(message, MesResType.B, rawJson); + return (success, message, mesResType); + } + + // 返回结果 + //return (res, mesMessage, mesResType); + } + + /// + /// 客户标签与系统标签绑定返回数据处理 + /// + /// + /// + /// + /// + private void ProcessBindingResponse(MesResponse response, ref string message, ref MesResType mesResType) + { + if (response != null) + { + message = response.message; + if (response.success) + { + mesResType = MesResType.D; + message = "MES客户标签与系统标签绑定成功"; + } + else + { + //mesResType = GetMesResType(response.category); + } + } + else + { + message = "响应数据为空"; + mesResType = MesResType.B; + } + } + #endregion + + /// + /// 产品结果加工参数接口 + /// + public async Task ProducResultParamAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, string containerCode, string palletId, List batteryInfos, MesUploadType unloadType) + { + var nowDate = DateTime.Now; + bool res = false; + string resJson = ""; + #region 结果上传MES + try + { + + string sNowDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff"); + + var model = new ProductResultParameters + { + equipNum = equipNum, + type = unloadType.ToString(), + payload = "" + }; + + switch (unloadType) + { + case MesUploadType.DZ: + var payload1 = new Payload1 + { + siteCode = siteCode, + lineCode = lineCode, + userName = userName, + materialCode = materialCode, + carCode = "", + collection = "JS", //BL 补录, JS 及时上传 + recordDate = sNowDate, + qty = batteryInfos.Count, + containerCode = containerCode, + }; + + var Items = new List(); + foreach(var battery in batteryInfos) + { + IdentificationListItem item = new IdentificationListItem() + { + identification = battery.identification, + qualityStatus = "Y", //m.CSBYHOUTSTATIONJUDGMENTRESULT, + tagDataVOList = GetTagDataVOList(battery, containerCode, palletId, sNowDate) + }; + Items.Add(item); + } + + payload1.identificationList = Items; + model.payload = JsonConvert.SerializeObject(payload1); + break; + + } + + + var postcontent = JsonConvert.SerializeObject(model); + var sw = new Stopwatch(); + sw.Start(); + //string result = MESApiHelper.WepPostAPIAsync(url, postcontent); + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + sw.Stop(); + + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用产品结果加工参数接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\产品结果加工参数\{nowDate.ToString("HH")}.txt", resJson); + return res; + } + + + var res1 = ReturnMesMsg(result); + if (!res1.success) + { + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + //Mesage = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用产品结果加工参数接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\产品结果加工参数\{nowDate.ToString("HH")}.txt", resJson); + } + else + { + res = true; + //Mesage = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用产品结果加工参数接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\产品结果加工参数\{nowDate.ToString("HH")}.txt", resJson); + } + + } + catch (Exception ex) + { + resJson = $"产品结果加工参数接口发生异常:{ex.Message}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\产品结果加工参数\{nowDate.ToString("HH")}.txt", resJson); + } + #endregion + return res; + } + + private List GetTagDataVOList(BatteryInfo m, string containerId, string palletId, string insertTime) + { + List datavolist = new List(); + + // 托盘号 + datavolist.Add(new TagDataVOListItem() + { + tagCode = "TRAY_NUMBER_DBJJG", + tagValue = containerId, + tagTime = insertTime, + tagCalculateResult = "", + tagRemark = "托盘号" + }); + // 栈板号 + datavolist.Add(new TagDataVOListItem() + { + tagCode = "PALLET_NUMBER_DBJJG", + tagValue = palletId, + tagTime = insertTime, + tagCalculateResult = "", + tagRemark = "栈板号" + }); + // 电池位置 + datavolist.Add(new TagDataVOListItem() + { + tagCode = "BATTERY_LOCATION_DBJJG", + tagValue = m.locationRow, + tagTime = insertTime, + tagCalculateResult = "", + tagRemark = "电池位置" + }); + // 设备编码 + datavolist.Add(new TagDataVOListItem() + { + tagCode = "TOP_COVER_CODE_DBJJG", + tagValue = "", + tagTime = insertTime, + tagCalculateResult = "", + tagRemark = "电芯顶盖码" + }); + + return datavolist; + } + + + #region 12、设备状态 + /// + /// 设备状态 + /// + /// API URL + /// 站点代码 + /// 生产线代码 + /// 设备编号 + /// 物料代码 + /// 用户名 + /// 唯一标识 + /// 状态代码 + /// 故障代码列表 + /// 返回操作结果和消息 + public async Task<(bool Success, string ResJson)> UploadEquStatusAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, string guid, string statusCode, List faultCodes) + { + bool res = false; + string resJson = ""; + + try + { + DateTime nowDate = DateTime.Now; + string sNowDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"); + + var parameters = new EqpStatusParam + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + materialCode = materialCode, + userName = userName, + seatId = "", + recordDate = sNowDate, + statusCode = statusCode.ToString(), + uploadTime = sNowDate, + guid = guid + }; + + // 设置故障代码列表 + parameters.faultCodeList = faultCodes; + + var postcontent = JsonConvert.SerializeObject(parameters); + var sw = Stopwatch.StartNew(); + + // 异步调用 + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + sw.Stop(); + + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{sNowDate}:调用设备运行状态接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备运行状态\{nowDate.ToString("HH")}.txt", resJson); + return (res, resJson); + } + + var res1 = ReturnMesMsg(result); + if (!res1.success) + { + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + resJson = $"{sNowDate}:调用设备运行状态接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备运行状态\{nowDate.ToString("HH")}.txt", resJson); + } + else + { + res = true; + resJson = $"{sNowDate}:调用设备运行状态接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备运行状态\{nowDate.ToString("HH")}.txt", resJson); + } + } + catch (Exception ex) + { + resJson = $"设备运行状态接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("设备运行状态接口", ex); + } + + return (res, resJson); + } + #endregion + + #region 13、设备报警上传接口 + /// + /// 设备报警上传接口 + /// + /// API URL + /// 站点代码 + /// 生产线代码 + /// 设备编号 + /// 物料代码 + /// 用户名 + /// 报警数据列表 + /// 唯一标识 + /// 返回操作结果和消息 + public async Task<(bool Success, string Mesage)> UploadEquAlarmAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List alarmObj, string guid) + { + bool res = false; + string resJson = ""; + string mesage = ""; // 用于存储消息 + + try + { + var nowDate = DateTime.Now; + + if (alarmObj.Count > 0) + { + Console.WriteLine($"{nowDate}: 开始处理报警数据,数量:{alarmObj.Count}"); + + var model = new UploadAlarmParam + { + siteCode = siteCode, + lineCode = lineCode, + equipNum = equipNum, + materialCode = materialCode, + userName = userName, + recordDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"), + guid = guid, + seatId = "" + }; + + model.alarmLineList = new List(); + for (int j = 0; j < alarmObj.Count; j++) + { + AlarmLineListItem alarmList = new AlarmLineListItem + { + alarmEndTime = System.Convert.ToString(alarmObj[j].EndTime), + alarmType = alarmObj[j].AlarmType, + alarmName = alarmObj[j].AlarmContent, + alarmStartTime = System.Convert.ToString(alarmObj[j].StartTime), + faultCode = alarmObj[j].AlarmCode + }; + model.alarmLineList.Add(alarmList); + + Console.WriteLine($"{nowDate}: 添加报警数据 - 报警类型:{alarmObj[j].AlarmType}, 报警内容:{alarmObj[j].AlarmContent}"); + } + + var postcontent = JsonConvert.SerializeObject(model); + Console.WriteLine($"{nowDate}: 请求数据已序列化:{postcontent}"); + + var sw = Stopwatch.StartNew(); + Console.WriteLine($"{nowDate}: 开始调用设备报警信息接口"); + + // 异步调用 + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + sw.Stop(); + Console.WriteLine($"{nowDate}: 接口调用完成,耗时:{sw.ElapsedMilliseconds}ms"); + + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备报警信息接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\报警信息\{nowDate.ToString("HH")}.txt", resJson); + Console.WriteLine($"{nowDate}: 接口返回结果为空"); + return (res, mesage); + } + + var res1 = ReturnMesMsg(result); + if (!res1.success) + { + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + mesage = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备报警信息接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\报警信息\{nowDate.ToString("HH")}.txt", resJson); + Console.WriteLine($"{nowDate}: 接口调用失败,消息:{mesage}"); + } + else + { + res = true; + mesage = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备报警信息接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\报警信息\{nowDate.ToString("HH")}.txt", resJson); + Console.WriteLine($"{nowDate}: 接口调用成功,消息:{mesage}"); + } + } + else + { + Console.WriteLine($"{nowDate}: 报警数据为空,无需处理"); + } + } + catch (Exception ex) + { + resJson = $"调用设备报警信息接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("调用设备报警信息接口", ex); + Console.WriteLine($"{DateTime.Now}: 发生异常:{ex.Message}"); + } + + return (res, mesage); + } + #endregion + + #region 14、上传设备能耗数据 + /// + /// 上传设备能耗数据 + /// + /// API URL + /// 站点代码 + /// 生产线代码 + /// 设备编号 + /// 用户名 + /// 电表编号列表 + /// 能耗数据列表 + /// 返回操作结果和日志信息 + public async Task<(bool Success, string Mesage)> UploadEquEnergyAsync(string url, string siteCode, string lineCode, string equipNum, string userName, List electricMeterNum, List wattrs) + { + bool res = false; + string mesage = ""; + + try + { + var nowDate = DateTime.Now; + Console.WriteLine($"{nowDate}: 开始处理设备能耗数据"); + + // 序列化请求数据 + var postcontent = JsonConvert.SerializeObject(wattrs); + Console.WriteLine($"{nowDate}: 请求数据已序列化:{postcontent}"); + + var sw = Stopwatch.StartNew(); + Console.WriteLine($"{nowDate}: 开始调用设备能耗信息接口"); + + // 异步调用 + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + sw.Stop(); + Console.WriteLine($"{nowDate}: 接口调用完成,耗时:{sw.ElapsedMilliseconds}ms"); + + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + mesage = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备能耗信息接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备能耗信息\{nowDate.ToString("HH")}.txt", mesage); + Console.WriteLine($"{nowDate}: 接口返回结果为空"); + return (res, mesage); + } + + var res1 = ReturnMesMsg(result); + if (!res1.success) + { + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + mesage = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备能耗信息接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备能耗信息\{nowDate.ToString("HH")}.txt", mesage); + Console.WriteLine($"{nowDate}: 接口调用失败,返回结果:{resData}"); + } + else + { + res = true; + mesage = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用设备能耗信息接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\设备能耗信息\{nowDate.ToString("HH")}.txt", mesage); + Console.WriteLine($"{nowDate}: 接口调用成功,返回结果:{result}"); + } + } + catch (Exception ex) + { + mesage = $"调用设备能耗信息接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("调用设备能耗信息接口", ex); + Console.WriteLine($"{DateTime.Now}: 发生异常:{ex.Message}"); + } + + return (res, mesage); + } + #endregion + + #region 15、风速仪数据上传至MES + /// + /// 风速仪数据上传至MES + /// + /// API URL + /// 设备编号 + /// 风速仪编号列表 + /// 采集数据列表 + /// 返回操作结果和消息 + public async Task<(bool Success, string Mesage)> UploadDeviceCollectDataAsync(string url, string equipNum, List antiDustAirSpeedNum, List collectData) + { + bool res = false; + string resJson = ""; + string mesage = ""; // 用于存储消息 + + try + { + if (collectData == null || collectData.Count == 0) + { + mesage = "采集数据为空,无需处理"; + Console.WriteLine($"{DateTime.Now}: {mesage}"); + return (res, mesage); + } + + var nowDate = DateTime.Now; + Console.WriteLine($"{nowDate}: 开始处理风速仪数据"); + + // 创建请求模型 + UploadDeviceCollectData uploadDevice = new UploadDeviceCollectData + { + appid = "e1012966a936170c6fcab98e24042d10", + device_code = equipNum, + collect_time = GetUnixTimestamp() + }; + + // 填充采集数据 + List list = new List(); + for (int i = 0; i < collectData.Count; i++) + { + Collect_code_value_list _Value_List = new Collect_code_value_list + { + target_code = 5, + target_value = collectData[i].ToString(), + target_value_tag = antiDustAirSpeedNum[i] + }; + list.Add(_Value_List); + + Console.WriteLine($"{nowDate}: 添加采集数据 - 风速仪编号:{antiDustAirSpeedNum[i]}, 采集值:{collectData[i]}"); + } + uploadDevice.collect_code_value_list = list; + + // 序列化请求数据 + string postcontent = JsonConvert.SerializeObject(uploadDevice); + Console.WriteLine($"{nowDate}: 请求数据已序列化:{postcontent}"); + + var sw = Stopwatch.StartNew(); + Console.WriteLine($"{nowDate}: 开始调用风速接口"); + + // 异步调用 + string result = await MESApiHelper.SendRequestStringAsync(url, HttpMethod.Post, postcontent, false); + + sw.Stop(); + Console.WriteLine($"{nowDate}: 接口调用完成,耗时:{sw.ElapsedMilliseconds}ms"); + + if (string.IsNullOrEmpty(result)) + { + string resData = result == "" ? "" : result; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用风速接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\风速信息\{nowDate.ToString("HH")}.txt", resJson); + mesage = "接口返回结果为空"; + Console.WriteLine($"{nowDate}: {mesage}"); + return (res, mesage); + } + + var res1 = ReturnMesMsg(result); + if (!res1.success) + { + var resData = res1 == null ? "" : JsonConvert.SerializeObject(res1); + mesage = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用风速接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{resData}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\风速信息\{nowDate.ToString("HH")}.txt", resJson); + Console.WriteLine($"{nowDate}: 接口调用失败,消息:{mesage}"); + } + else + { + res = true; + mesage = res1.message; + resJson = $"{nowDate.ToString("yyyy-MM-dd HH:mm:ss.fff")}:调用风速接口:{url},请求数据为:{postcontent},\n{nowDate.AddMilliseconds(sw.ElapsedMilliseconds).ToString("yyyy-MM-dd HH:mm:ss.fff")}:接口耗时:{sw.ElapsedMilliseconds}ms,返回结果:{JsonConvert.SerializeObject(result)}"; + TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{nowDate.ToString("yyyyMMdd")}\风速信息\{nowDate.ToString("HH")}.txt", resJson); + Console.WriteLine($"{nowDate}: 接口调用成功,消息:{mesage}"); + } + } + catch (Exception ex) + { + resJson = $"调用风速接口发生异常:{ex.Message}"; + LogHelper.Instance.WriteEX("调用风速接口", ex); + Console.WriteLine($"{DateTime.Now}: 发生异常:{ex.Message}"); + } + + return (res, mesage); + } + #endregion + + + /// + /// 序列化各类返回 + /// + /// + /// + /// + private T ReturnMesMsg(string ret) + { + + try + { + return JsonConvert.DeserializeObject(ret); + } + catch (System.Exception ex) + { + return default(T); + } + } + + public List GetMesType(int Num) + { + List mesResTypes = new List(); + for (int i = 0; i < Num; i++) + { + mesResTypes.Add(MesResType.B); + } + return mesResTypes; + } + + + public List GetListString(int Num, string str) + { + List mesResTypes = new List(); + for (int i = 0; i < Num; i++) + { + mesResTypes.Add(str); + } + return mesResTypes; + } + + + /// + ///本地时间为Unix时间戳 + /// + /// + public static long GetUnixTimestamp() + { + return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000; + } + + public Task<(bool Success, string ResJson)> ParamChangeAsync(string url, string siteCode, string lineCode, string equipNum, string materialCode, string userName, List paramChangeItems) + { + throw new NotImplementedException(); + } + + + + //#endregion + } +} diff --git a/JinYuan.MES/Models/BatteryInfo.cs b/JinYuan.MES/Models/BatteryInfo.cs new file mode 100644 index 0000000..ec3bc76 --- /dev/null +++ b/JinYuan.MES/Models/BatteryInfo.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using System.Security.Cryptography; + +namespace JinYuan.MES.Models +{ + + /// + /// 卡板电芯信息上传(装箱)接口参数类 + /// + public class PackParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + public string outerContainerCode { get; set; } + public string outerContainerTypeCode { get; set; } + public List containerBarcodeInfos { get; set; } + /// + /// 卡板码(箱唛号) + /// + public string ContainerCode { get; set; } + public int capacity { get; set; } + /// + /// 档位 + /// + public string grade { get; set; } + public string materialCode { get; set; } + /// + /// 电芯信息列表 + /// + public List cellDataVOList { get; set; } + }; + + + /// + /// 卡板电芯信息上传(装箱)接口参数类 + /// + public class FinishPackParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipCode { get; set; } + public string outerContainerCode { get; set; } //外箱号 + //public string outerContainerTypeCode { get; set; } + public List containerBarcodeInfos { get; set; } + + }; + + + public class ContainerInfo + { + /// + /// 卡板码(箱唛号) + /// + public string containerCode { get; set; } // 内箱号 + public string rohs { get; } = "RoSH Label"; // 环境标识 + public string productDate { get; set; } // 生产 日期 + public string containerTypeCode { get; } = "XM_BZCPGD"; // 容器类型 + public int packQty { get; set; } // 包装数量 + //public string productionType { get; set; } + public string groupNum { get; set; } // 组号 + public string customerName { get; set; } + public string customerCode { get; set; } //客户代码 + public string supplierCode { get; } = "EVEDL"; // 供应商 + public string batchQty { get; set; } // 批数量 + public string grade { get; set; } //档位 + public string customerOrder { get; set; } // 客户订单号 + public string soNum { get; set; } + public string materialName { get; set; } // 物料名称 + public string materialCode { get; set; } //物料编码 + public string voltage { get; set; } // 电压 + public string inresistance { get; set; } // 内阻 + public string capacity { get; set; } //容量 + public string remark { get; set; } + public List batteryInfos { get; set; } + } + + + public class BatteryInfo + { + //电芯条码 + public string identification { get; set; } + + //电芯条码位置 + public string locationRow { get; set; } + } +} diff --git a/JinYuan.MES/Models/BindingParam.cs b/JinYuan.MES/Models/BindingParam.cs new file mode 100644 index 0000000..563c968 --- /dev/null +++ b/JinYuan.MES/Models/BindingParam.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + + /// + /// 客户标签与系统标签绑定 + /// + public class BindingParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 卡板码 + /// + public string containerCode { get; set; } + /// + /// 栈板码 + /// + public string palletCode { get; set; } + /// + /// 客户箱唛码 + /// + public string custcartonCode { get; set; } + /// + /// 客户栈板码 + /// + public string custpalletCode { get; set; } + /// + /// 客户箱唛信息 + /// + public List custcarton { get; set; } + /// + /// 客户栈板信息 + /// + public List custpallet { get; set; } + }; + +} diff --git a/JinYuan.MES/Models/CartonParam.cs b/JinYuan.MES/Models/CartonParam.cs new file mode 100644 index 0000000..fbf868a --- /dev/null +++ b/JinYuan.MES/Models/CartonParam.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + + /// + /// 箱唛/栈板信息获取接口参数类 + /// + public class QueryCartonPalletParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 卡板码 + /// + public string containerCode { get; set; } + }; + +} diff --git a/JinYuan.MES/Models/EqpStatusParam.cs b/JinYuan.MES/Models/EqpStatusParam.cs new file mode 100644 index 0000000..1e2f0af --- /dev/null +++ b/JinYuan.MES/Models/EqpStatusParam.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + /// + /// 设备状态上传接口参数类 + /// + public class EqpStatusParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 物料编码 + /// + public string materialCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// 库位ID + /// + public string seatId { get; set; } + /// + /// 采集时间 + /// + public string recordDate { get; set; } + /// + /// 设备状态 。Run:(正常运行)、Alert:(故障调试)、Idle:(闲置待机)、Maintain(停止运行) + /// + public string statusCode { get; set; } + /// + /// 状态变更时间 + /// + public string uploadTime { get; set; } + /// + /// 唯一标识符号 + /// + public string guid { get; set; } + /// + /// 故障代码数组 + /// + public List faultCodeList { get; set; } + } + + public class FaultCodeList + { + /// + /// 故障代码 + /// + public string faultCode { get; set; } + } +} diff --git a/JinYuan.MES/Models/GetOCVShift.cs b/JinYuan.MES/Models/GetOCVShift.cs new file mode 100644 index 0000000..bd4d51b --- /dev/null +++ b/JinYuan.MES/Models/GetOCVShift.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.MES.Models +{ + internal class GetOCVShift + { + /// + /// 站点编码 + /// + public string siteCode { get; set; } + /// + /// 产线编码 + /// + public string lineCode { get; set; } + /// + /// 设备编码 + /// + public string equipNum { get; set; } + /// + /// 采集时间 + /// + public string recordDate { get; set; } + /// + /// 传入条码的个数 + /// + public string qty { get; set; } + /// + /// 托盘码 + /// + public string containerCode { get; set; } + /// + /// 物料编码 + /// + public string materialCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// 条码数组 + /// + public List materiallotCodeList { get; set; } + } +} diff --git a/JinYuan.MES/Models/LoginEnyity.cs b/JinYuan.MES/Models/LoginEnyity.cs new file mode 100644 index 0000000..dc6aeff --- /dev/null +++ b/JinYuan.MES/Models/LoginEnyity.cs @@ -0,0 +1,33 @@ +namespace JinYuan.MES.Models +{ + /// + /// 登录 + /// + public class LoginEntity + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// 员工密码 + /// + public string passWord { get; set; } + /// + /// 刷卡员工账号 + /// + public string userCardID { get; set; } + } +} diff --git a/JinYuan.MES/Models/ManyCellInStation.cs b/JinYuan.MES/Models/ManyCellInStation.cs new file mode 100644 index 0000000..288dd3b --- /dev/null +++ b/JinYuan.MES/Models/ManyCellInStation.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + + /// + /// 多个电池进站 + /// + public class ManyCellInStation + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 物料编码 + /// + public string materialCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + + /// + /// 产品类型 + /// + public string productType { get; set; } + /// + /// 电芯条码 + /// + // public List identificationList { get; set; } + public string identification { get; set; } + /// + /// 容器条码 + /// + public List containerCodeList { get; set; } + } + +} diff --git a/JinYuan.MES/Models/ManyCellOutStation.cs b/JinYuan.MES/Models/ManyCellOutStation.cs new file mode 100644 index 0000000..afb66c7 --- /dev/null +++ b/JinYuan.MES/Models/ManyCellOutStation.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + + /// + /// 多个电池出站 × + /// + public class ManyCellOutStation + { + /// + /// + /// + public string siteCode { get; set; } + /// + /// + /// + public string lineCode { get; set; } + /// + /// + /// + public string equipNum { get; set; } + /// + /// + /// + public string materialCode { get; set; } + /// + /// + /// + public string userName { get; set; } + /// + /// 产品类型 + /// + public string productType { get; set; } + /// + /// 完工数 + /// + public string completeQty { get; set; } + /// + /// 托盘码 + /// + public string containerCode { get; set; } + /// + /// 1:通用出站;2:合芯出站;3:虚拟码替换出站;4:追溯标识替换出站;5:合芯有顶盖出站 + /// + public int type { get; set; } + + /// + /// 条码数组 + /// + public List identiftyList { get; set; } + + } + + + public class identiftyList + { + + /// + /// 产品条码 + /// + public string identification { get; set; } + /// + /// 原材料信息 + /// + public List materialLotList = new List(); + /// + /// 原材料条码 + /// + public string materialLotCode { get; set; } + /// + /// 原材料上料位置 + /// + public string materialLotCodeLocator { get; set; } + /// + /// 质量状态 + /// + public string qualityStatus { get; set; } + /// + /// 关联条码 + /// + public string qrCode { get; set; } + /// + /// NG编码 + /// + public List ngCode = new List(); + /// + /// NG错误信息 + /// + public string ngMessage = ""; + + } + + +} diff --git a/JinYuan.MES/Models/MaterialLot.cs b/JinYuan.MES/Models/MaterialLot.cs new file mode 100644 index 0000000..154fac4 --- /dev/null +++ b/JinYuan.MES/Models/MaterialLot.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + + /// + /// 查询电芯档位接口参数类 + /// + public class QueryTrayParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 记录时间 + /// + public string recordDate { get; set; } + /// + /// 数量 + /// + public string qty { get; set; } + /// + /// 托盘码 + /// + public string containerCode { get; set; } + + /// + /// 物料代码 + /// + public string materialCode { get; set; } + /// + /// 操作人 + /// + // public List identificationList { get; set; } + public string userName { get; set; } + + /// + /// 电芯信息列表 + /// + public List listCode { get; set; } + }; + + + public class MaterialLot + { + //电芯条码 + public string identification { get; set; } + + public string locationBat { get; set; } + } + + + /// + /// 查询电芯档位接口参数类 + /// + public class QueryGradeParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 记录时间 + /// + public string recordDate { get; set; } + /// + /// 数量 + /// + public string qty { get; set; } + + /// + /// 物料代码 + /// + public string materialCode { get; set; } + /// + /// 操作人 + /// + public string userName { get; set; } + + public string actionType { get; set; } // 进站"IN", 出站"OUT" + /// + /// 电芯信息列表 + /// + public List batteryTrayBindVOList { get; set; } + }; +} diff --git a/JinYuan.MES/Models/MesResponse.cs b/JinYuan.MES/Models/MesResponse.cs new file mode 100644 index 0000000..ad4da0a --- /dev/null +++ b/JinYuan.MES/Models/MesResponse.cs @@ -0,0 +1,396 @@ +using System; +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + /// + /// 执行结果 + /// + public class MesResponse + { + /// + /// 错误代码 错误代码,成功不返回 + /// + public string code { get; set; } + /// + /// 数据处理消息 成功不返回 + /// + public string message { get; set; } + /// + /// 成功标识 false失败 true 成功 + /// + public bool success { get; set; } + } + + #region 获取料盘信息 + public class TrayInfo_old + { + /// + /// 料框码 + /// + public string trayID { get; set; } + /// + /// 电芯条码 + /// + public List identifications { get; set; } + + /// + /// 返回电池型号 + /// + public string model { get; set; } + /// + /// 返回电芯档位 + /// + public string grade { get; set; } + /// + /// 返回电芯二级档位 + /// + public string moreGrade { get; set; } + /// + /// 产线id + /// + public string lineNo { get; set; } + } + + public class Cell + { + /// + /// 电芯条码 + /// + public string cellNo { get; set; } + + public int channel { get; set; } + } + + public class TrayInfo + { + /// + /// 料框码 + /// + public string trayNo { get; set; } + /// + /// 电芯条码 + /// + public List cellList { get; set; } + + /// + /// 返回电池型号 + /// + public string productCode { get; set; } + /// + /// 返回电芯档位 + /// + public string grade { get; set; } + /// + /// 返回电芯二级档位 + /// + public string moreGrade { get; set; } + /// + /// 产线id + /// + //public string lineNo { get; set; } + } + #endregion + + #region 料盘信息 + public class MesResponseTray + { + /// + /// 返回料盘信息 + /// + public TrayInfo data { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功 + /// + //public bool success { get; set; } + /// + /// 返回错误代码:成功200,错误204 + /// + public int code { get; set; } + /// + /// 返回报错消息类型:A:停线、B:排出、C:忽略(需警示) + /// + //public string category { get; set; } + /// + /// 返回失败原因 + /// + //public string message { get; set; } + public string msg { get; set; } + /// + /// 绑定电芯数量 + /// + //public int total { get; set; } + } + #endregion + + #region 档位查询反馈 + public class MesResponseGrade + { + /// + /// 返回电芯档位参数 + /// + public List rows { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功 + /// + public bool success { get; set; } + /// + /// 绑定电芯数量 + /// + public int total { get; set; } + } + + public class MaterialGrade + { + /// + /// 电芯条码 + /// + public string identification { get; set; } + /// + /// 返回电芯档位 + /// + public string grade { get; set; } + + } + #endregion + + + #region 卡板电芯信息上传(装箱)反馈 + public class MesResponsePack + { + /// + /// 返回电芯档位参数 + /// + //public List rows { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功,整盘绑定无问题允许放行:true;箱唛还没完全绑定成功:false + /// + public bool success { get; set; } + /// + /// 返回错误代码:成功200,错误204 + /// + public string code { get; set; } + /// + /// 返回报错消息类型:A:停线、B:排出、C:忽略(需警示) + /// + //public string category { get; set; } + /// + /// 返回失败原因 + /// + public string message { get; set; } + + /// + /// 返回绑定电芯数量 + /// + //public string total { get; set; } + } + + public class MaterialPackInfo + { + /// + /// 电芯条码 + /// + public string identification { get; set; } + /// + /// 返回电芯条码位置 + /// + public string locationRow { get; set; } + /// + /// 返回条码是否已成功绑定该卡板:电芯绑定成功:true;电芯需排出:false + /// + public bool packResult { get; set; } + /// + /// 返回条码绑定失败原因 + /// + public string packFalseReason { get; set; } + + } + + + public class MesResponseFinishPack + { + /// + /// 返回电芯档位参数 + /// + public List rows { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功,整盘绑定无问题允许放行:true;箱唛还没完全绑定成功:false + /// + public bool success { get; set; } + /// + /// 返回错误代码:成功200,错误204 + /// + public string code { get; set; } + /// + /// 返回报错消息类型:A:停线、B:排出、C:忽略(需警示) + /// + public string category { get; set; } + /// + /// 返回失败原因 + /// + public string message { get; set; } + + /// + /// 返回绑定电芯数量 + /// + public string total { get; set; } + } + #endregion + + + #region 获取箱唛信息 + public class MesResponseCarton + { + /// + /// 返回箱唛信息参数 + /// + public List rows { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功,整盘绑定无问题允许放行:true;箱唛还没完全绑定成功:false + /// + public bool success { get; set; } + /// + /// 返回错误代码:成功200,错误204 + /// + public string code { get; set; } + /// + /// 返回报错消息类型:A:停线、B:排出、C:忽略(需警示) + /// + public string category { get; set; } + /// + /// 返回失败原因 + /// + public string message { get; set; } + } + + public class TagInfo + { + /// + /// 箱唛信息参数代码 + /// + public string tagCode { get; set; } + /// + /// 箱唛信息参数值 + /// + public string tagValue { get; set; } + } + + #endregion + + + #region 获取栈板信息 + public class MesResponsePallet + { + /// + /// 返回栈板信息参数 + /// + public List rows { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功,整盘绑定无问题允许放行:true;箱唛还没完全绑定成功:false + /// + public bool success { get; set; } + /// + /// 返回错误代码:成功200,错误204 + /// + public string code { get; set; } + /// + /// 返回栈板码 + /// + public string palletCode { get; set; } + /// + /// 返回报错消息类型:A:停线、B:排出、C:忽略(需警示) + /// + public string category { get; set; } + /// + /// 返回失败原因 + /// + public string message { get; set; } + } + #endregion + + + #region 员工校验反馈 + public class MesResponseLogin + { + /// + /// 返回参数 + /// + // public List rows { get; set; } + public List rows { get; set; } + /// + /// 错误代码 错误代码,成功不返回 + /// + public string code { get; set; } + /// + /// MES信息返回成功标识 false失败 true 成功 + /// + public bool success { get; set; } + /// + /// 数据处理消息 成功不返回 + /// + public string message { get; set; } + /// + /// 报错消息类型 A=停线,B=排出,C=忽略(需警示) + /// + public string category { get; set; } + /// + /// 返回参数条数 + /// + public int total { get; set; } + } + public class RowsItemLogin + { + /// + /// 用户名 + /// + public string username { get; set; } + /// + /// 用户名权限 + /// + public string permissionLevel { get; set; } + } + #endregion + + /// + /// 执行结果Entity,带返回值 + /// + /// + public class RequestResult : MesResponse + { + public T Result { get; set; } + } + + + /// + /// 执行结果List,带返回值 + /// + /// + public class RequestResultList : MesResponse + { + public List Result { get; set; } + } + + + #region 解绑料框码 + public class unBindMesResponse + { + /// + /// 错误代码 错误代码,成功不返回 + /// + public string code { get; set; } + /// + /// 数据处理消息 成功不返回 + /// + public string msg { get; set; } + /// + /// 成功标识 false失败 true 成功 + /// + public bool flag { get; set; } + + /// + /// 数据处理消息 + /// + public string data { get; set; } + } + #endregion +} diff --git a/JinYuan.MES/Models/ParamChange.cs b/JinYuan.MES/Models/ParamChange.cs new file mode 100644 index 0000000..44bf8f0 --- /dev/null +++ b/JinYuan.MES/Models/ParamChange.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + /// + /// 设备参数设定值变更 + /// + public class ParamChange + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 物料编码 + /// + public string materialCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// 变更时间 + /// + public string changeTime { get; set; } + /// + /// 数据组编码 + /// + public string tagGroupCode { get; set; } + /// + /// 数据组描述 + /// + public string tagGroupDescription { get; set; } + /// + /// 数据项数组 + /// + public List tagList { get; set; } + } + public class TagListItem + { + /// + /// 数据项编码 + /// + public string tagCode { get; set; } + /// + /// 变更前计量单位 + /// + public string unitBefore { get; set; } + /// + /// 变更前标准值 + /// + public string standardValueBefore { get; set; } + /// + /// 变更前符合值 + /// + public string trueValueBefore { get; set; } + /// + /// 变更前不符合值 + /// + public string falseValueBefore { get; set; } + /// + /// 变更前最小值 + /// + public int minValueBefore { get; set; } + /// + /// 变更前最大值 + /// + public int maxValueBefore { get; set; } + /// + /// 变更后计量单位 + /// + public string unitAfter { get; set; } + /// + /// 变更后标准值 + /// + public string standardValueAfter { get; set; } + /// + /// 变更后符合值 + /// + public string trueValueAfter { get; set; } + /// + /// 变更后不符合值 + /// + public string falseValueAfter { get; set; } + /// + /// 变更后最小值 + /// + public int minValueAfter { get; set; } + /// + /// 变更后最大值 + /// + public int maxValueAfter { get; set; } + } +} diff --git a/JinYuan.MES/Models/ParamReturnData.cs b/JinYuan.MES/Models/ParamReturnData.cs new file mode 100644 index 0000000..46c7f53 --- /dev/null +++ b/JinYuan.MES/Models/ParamReturnData.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + /// + /// 设备参数设定值返回 + /// + public class ParamReturnData + { + /// + /// 返回参数 + /// + public List rows { get; set; } + /// + /// 成功标识 + /// + public bool success { get; set; } + /// + /// 返回参数条数 + /// + public int total { get; set; } + } + + + /// + /// 返回参数项 + /// + public class RowsItem + { + /// + /// 数据组编码 + /// + public string tagGroupCode { get; set; } + /// + /// 配方0002 + /// + public string tagGroupDescription { get; set; } + /// + /// 数据组描述 + /// + public List tagList { get; set; } + } + + /// + /// 数据组描述 + /// + public class ReturnDataTagListItem + { + /// + /// + /// + public string tagCode { get; set; } + /// + /// 真空度设定值 + /// + public string tagDescription { get; set; } + /// + /// + /// + public string valueType { get; set; } + /// + /// + /// + public string unit { get; set; } + /// + /// + /// + public string standardValue { get; set; } + /// + /// + /// + public string trueValue { get; set; } + /// + /// + /// + public string falseValue { get; set; } + /// + /// + /// + public string minValue { get; set; } + /// + /// + /// + public string maxValue { get; set; } + /// + /// + /// + public string tagRemark { get; set; } + } +} diff --git a/JinYuan.MES/Models/ProductProcessParam.cs b/JinYuan.MES/Models/ProductProcessParam.cs new file mode 100644 index 0000000..e7345e6 --- /dev/null +++ b/JinYuan.MES/Models/ProductProcessParam.cs @@ -0,0 +1,9 @@ +namespace JinYuan.MES.Models +{ + /// + /// 产品过程加工参数 + /// + public class ProductProcessParam + { + } +} diff --git a/JinYuan.MES/Models/ProductResultParameters.cs b/JinYuan.MES/Models/ProductResultParameters.cs new file mode 100644 index 0000000..a8121fa --- /dev/null +++ b/JinYuan.MES/Models/ProductResultParameters.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + /// + /// 结果加工参数 + /// + public class ProductResultParameters + { + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 类型单进整出:DZ 整进整出:ZZ 单进单出:DD 未传时默认按照ZZ进行数据解析 + /// + public string type { get; set; } + /// + /// 设备数据 + /// + public string payload { get; set; } + } + + /// + /// 单进整出 + /// + public class Payload1 + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// 物料编码 工单产成品物料号 + /// + public string materialCode { get; set; } + /// + /// 小车号 装载电池的小车编号 + /// + public string carCode { get; set; } + /// + /// 补录 是否属于补录数据(BL=补录,JS=及时上传) + /// + public string collection { get; set; } + /// + /// 采集时间 数据的采集时间 + /// + public string recordDate { get; set; } + /// + /// 条码数量 传入条码的个数 + /// + public int qty { get; set; } + /// + /// RFID托杯码 + /// + public string containerCode { get; set; } + /// + /// 条码数组 + /// + + public List identificationList { get; set; } + //public List tagDataVOList { get; set; } + } + + public class IdentificationListItem + { + /// /// + /// 条码 + /// + public string identification { get; set; } + /// + /// 质量状态 各产品所有参数的整体判断结果(Y/N) + /// + public string qualityStatus { get; set; } + /// + /// 采集数组 + /// + public List tagDataVOList { get; set; } + } + + + + public class TagDataVOListItem + { + /// + /// 设备每个采集项规定的编号 + /// + public string tagCode { get; set; } + /// + /// 采集值 + /// + public string tagValue { get; set; } + /// + /// 采集项采集时间 + /// + public string tagTime { get; set; } + /// + /// 各产品所有参数的整体判断结果(Y/N) + /// + public string tagCalculateResult { get; set; } + /// + /// 采集项描述 + /// + public string tagRemark { get; set; } + } +} diff --git a/JinYuan.MES/Models/SingleCellInStation.cs b/JinYuan.MES/Models/SingleCellInStation.cs new file mode 100644 index 0000000..075e473 --- /dev/null +++ b/JinYuan.MES/Models/SingleCellInStation.cs @@ -0,0 +1,38 @@ +namespace JinYuan.MES.Models +{ + /// + /// 单个电池进站 + /// + public class SingleCellInStation + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 物料编码 + /// + public string materialCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// + /// + public string identification { get; set; } + /// + /// + /// + public string productType { get; set; } + } + +} diff --git a/JinYuan.MES/Models/SingleCellOutStation.cs b/JinYuan.MES/Models/SingleCellOutStation.cs new file mode 100644 index 0000000..92d12e7 --- /dev/null +++ b/JinYuan.MES/Models/SingleCellOutStation.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + + + public class MaterialLotListItem + { + /// + /// + /// + public string materialLotCode { get; set; } + /// + /// + /// + public string materialLotCodeLocator { get; set; } + } + + public class IdentiftyListItem + { + /// + /// 条码 + /// + public string identification { get; set; } + /// + /// 质量状态 + /// + public string qualityStatus { get; set; } + /// + /// 关联条码 + /// + public string qrCode { get; set; } + /// + /// NG2信息,NG1信息 + /// + public string ngMessage { get; set; } + /// + /// + /// + public List ngCode { get; set; } + /// + /// + /// + public List materialLotList { get; set; } + } + + public class SingleCellOutStation + { + /// + /// + /// + public string siteCode { get; set; } + /// + /// + /// + public string lineCode { get; set; } + /// + /// + /// + public string equipNum { get; set; } + /// + /// + /// + public string userName { get; set; } + /// + /// + /// + public string productType { get; set; } + + public string completeQty { get; set; } + + public string materialCode { get; set; } + + /// + /// + /// + public string containerCode { get; set; } + + public string type { get; set; } + + + + public List identiftyList { get; set; } = new List(); + } + + //public class AssembleLineList + //{ + // public string identification { get; set; } + + // public string qualityStatus{ get; set; } + + // public string qrCode { get; set; } + + // public List ngCode { get; set;} = new List(); + + // public string ngMessage { get; set; } + //} + +} diff --git a/JinYuan.MES/Models/UploadAlarmParam.cs b/JinYuan.MES/Models/UploadAlarmParam.cs new file mode 100644 index 0000000..39b1fdf --- /dev/null +++ b/JinYuan.MES/Models/UploadAlarmParam.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + /// + /// 报警数据上传接口参数类 + /// + public class UploadAlarmParam + { + /// + /// 工厂代码 + /// + public string siteCode { get; set; } + /// + /// 产线编号 + /// + public string lineCode { get; set; } + /// + /// 设备编号 + /// + public string equipNum { get; set; } + /// + /// 物料编码 + /// + public string materialCode { get; set; } + /// + /// 员工账号 + /// + public string userName { get; set; } + /// + /// 采集时间 + /// + public string recordDate { get; set; } + /// + /// 唯一标识符号 + /// + public string guid { get; set; } + /// + /// 库位ID 库位ID,化成段用 + /// + public string seatId { get; set; } + /// + /// 报警数组 + /// + public List alarmLineList { get; set; } + } + + + /// + /// 报警数组 + /// + public class AlarmLineListItem + { + /// + /// 报警消除时间 + /// + public string alarmEndTime { get; set; } + /// + /// 报警类型 + /// + public string alarmType { get; set; } + /// + /// 报警名称 + /// + public string alarmName { get; set; } + /// + /// 报警开始时间 + /// + public string alarmStartTime { get; set; } + /// + /// 故障代码 + /// + public string faultCode { get; set; } + } +} diff --git a/JinYuan.MES/Models/UploadDeviceCollectData.cs b/JinYuan.MES/Models/UploadDeviceCollectData.cs new file mode 100644 index 0000000..9d454f1 --- /dev/null +++ b/JinYuan.MES/Models/UploadDeviceCollectData.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; + +namespace JinYuan.MES.Models +{ + internal class UploadDeviceCollectData + { + /// + /// 应用id,对应不同系统对接 + /// + public string appid { get; set; } + /// + /// 采集指标类型和具体值的集合 + /// + public List collect_code_value_list { get; set; } + /// + /// 采集时间,unix时间戳,整数类型 + /// + public long collect_time { get; set; } + /// + /// 设备编号 + /// + public string device_code { get; set; } + } + public class Collect_code_value_list + { + /// + /// 指标类型,1 温度 2湿度 3露点 4粉尘 5风速,整数类型 + /// + public int target_code { get; set; } + /// + /// 指标对应采集值,若是某个指标或某个指标的某个值未采集到,则传N + /// + public string target_value { get; set; } + /// + /// 风速仪标签,风速仪值对应target_value + /// + public string target_value_tag { get; set; } + } + + + public class UploadDeviceCollectDataResult + { + /// + /// + /// + public int status { get; set; } + /// + /// + /// + public Data data { get; set; } + /// + /// + /// + public string message { get; set; } + } + + public class Data + { + } +} diff --git a/JinYuan.MES/Models/VdaGetData.cs b/JinYuan.MES/Models/VdaGetData.cs new file mode 100644 index 0000000..a7ed3c3 --- /dev/null +++ b/JinYuan.MES/Models/VdaGetData.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.MES.Models +{ + public class VdaGetData + { + /// + /// 所属仓库 + /// + public string warehouseCode { get; set; } + /// + /// 货主 + /// + public string customerCode { get; set; } + public string labelTemplateCode { get; set; } + public List codeDataList { get; set; } + } + + public class CodeData + { + public string trayLabel { get; set; } + } +} diff --git a/JinYuan.MES/Models/WattrMeter.cs b/JinYuan.MES/Models/WattrMeter.cs new file mode 100644 index 0000000..ab4fb21 --- /dev/null +++ b/JinYuan.MES/Models/WattrMeter.cs @@ -0,0 +1,111 @@ +namespace JinYuan.MES.Models +{ + public class WattrMeter + { + + /// + /// 工厂代码 + /// + public System.String siteCode { get; set; } + + /// + /// 产线编号 + /// + public System.String lineCode { get; set; } + + /// + /// 设备编号 + /// + public System.String equipNum { get; set; } + + /// + /// 电表编号 + /// + public System.String electricMeterNum { get; set; } + + /// + /// 员工账号 + /// + public System.String userName { get; set; } + + /// + /// 工序编号 + /// + public System.String specName { get; set; } + + /// + /// 采集时间 + /// + public System.String recordDate { get; set; } + + /// + /// 有功电能(累计电能)KWH + /// + public System.Decimal? accumulatedElectricity { get; set; } + + /// + /// A相电压 V + /// + public System.Decimal? phaseVoltageA { get; set; } + + /// + /// B相电压 V + /// + public System.Decimal? phaseVoltageB { get; set; } + + /// + /// C相电压 V + /// + public System.Decimal? phaseVoltageC { get; set; } + + /// + /// A相电流 + /// + public System.Decimal? phaseCurrentA { get; set; } + + /// + /// B相电流 + /// + public System.Decimal? phaseCurrentB { get; set; } + + /// + /// C相电流 + /// + public System.Decimal? phaseCurrentC { get; set; } + + /// + /// A相功率 + /// + public System.Decimal? phasePowerA { get; set; } + + /// + /// B相功率 + /// + public System.Decimal? phasePowerB { get; set; } + + /// + /// C相功率 + /// + public System.Decimal? phasePowerC { get; set; } + + /// + /// 总有功功率 + /// + public System.Decimal? activePower { get; set; } + + /// + /// 总功率因数 + /// + public System.Decimal? powerFactor { get; set; } + + /// + /// 电流变比 + /// + public System.Decimal? pt { get; set; } + + /// + /// 电压变比 + /// + public System.Decimal? ct { get; set; } + } +} diff --git a/JinYuan.MES/Models/WmsUpload.cs b/JinYuan.MES/Models/WmsUpload.cs new file mode 100644 index 0000000..a1301ea --- /dev/null +++ b/JinYuan.MES/Models/WmsUpload.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.MES.Models +{ + public class WmsUpload + { + /// + /// 所属仓库 + /// + public string warehouseCode { get; set; } + /// + /// 货主 + /// + public string customerCode { get; set; } + /// + /// 设备编码 + /// + public string equipmentCode { get; set; } + /// + /// 设备名称 + /// + public string equipmentName { get; set; } + /// + /// 底托(卡板) + /// + public string trayLabel { get; set; } + /// + /// 详细信息 + /// + public List innerBoxLabelList { get; set; } + } + + public class InnerBoxLabelInfo + { + /// + /// 外箱标签(宝马层托)托盘码 + /// + public string outerBoxLabel { get; set; } + /// + /// 内箱标签,电芯码 + /// + public string innerBoxLabel { get; set; } + /// + /// 质检结果,N-良品 Y-不良品 + /// + public string iqcState { get; set; } + /// + /// 电芯位置,G11需传该字段 + /// + public string batteriesLocation { get; set; } + } +} diff --git a/JinYuan.MES/Models/unbindParam.cs b/JinYuan.MES/Models/unbindParam.cs new file mode 100644 index 0000000..a2123fe --- /dev/null +++ b/JinYuan.MES/Models/unbindParam.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.MES.Models +{ + public class unbindParam + { + /// + /// 设备编码 + /// + public string equipNum { get; set; } + + /// + /// 料框码 + /// + public string trayCode { get; set; } + } +} diff --git a/JinYuan.MES/Properties/AssemblyInfo.cs b/JinYuan.MES/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..01e120f --- /dev/null +++ b/JinYuan.MES/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.MES")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.MES")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("530b6426-08e7-461c-91dc-787f876620fc")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.MES/app.config b/JinYuan.MES/app.config new file mode 100644 index 0000000..b20d2b2 --- /dev/null +++ b/JinYuan.MES/app.config @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JinYuan.MES/packages.config b/JinYuan.MES/packages.config new file mode 100644 index 0000000..e46d5a8 --- /dev/null +++ b/JinYuan.MES/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/JinYuan.Models/AGearEntity.cs b/JinYuan.Models/AGearEntity.cs new file mode 100644 index 0000000..166d3f3 --- /dev/null +++ b/JinYuan.Models/AGearEntity.cs @@ -0,0 +1,77 @@ +using JinYuan.Models.HelperAttribute; +using PLCCommunication; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace JinYuan.Models +{ + /// + /// 电芯进站 + /// + public class AGearEntity + { + /// + /// 时间 + /// + [DataGridViewColumn(Name = "InTestTime")] + public DateTime Time { get; set; } + /// + /// 电池码 + /// + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "InBarCode")] + public string BarCode { get; set; } + + /// + /// 电芯在托盘位置号 + /// + [DataGridViewColumn(Name = "Location")] + public string Location { get; set; } + + /// + /// 托盘码 + /// + [DataGridViewColumn(Name = "InVassoioID")] + public string TrayID { get; set; } + + /// + /// 电池型号 + /// + [DataGridViewColumn(Name = "InModelName")] + public string Model { get; set; } + + /// + /// 一级电芯档位 + /// + [DataGridViewColumn(Name = "InGrade")] + public string Grade { get; set; } + /// + /// 二级电芯档位 + /// + [DataGridViewColumn(Name = "InMoreGrade")] + public string MoreGrade { get; set; } + + /// + /// 工位号 + /// + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "GongWei")] + public string GongWei { get; set; } + + /// + /// 结果 + /// + [DataGridViewColumn(Name = "InResult")] + public string Result { get; set; } + /// + /// 备注 + /// + [DataGridViewColumn(Name = "InRemark")] + public string Remark { get; set; } + } +} diff --git a/JinYuan.Models/Alarm/AlarmData.cs b/JinYuan.Models/Alarm/AlarmData.cs new file mode 100644 index 0000000..ae4293d --- /dev/null +++ b/JinYuan.Models/Alarm/AlarmData.cs @@ -0,0 +1,83 @@ +using CsvHelper.Configuration.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 工位报警数据 + /// + public class AlarmData + { + /// + /// 报警唯一标识符 + /// + public string AlarmGuid { get; set; } + + /// + /// 报警地址 + /// + public string PLCAdress { get; set; } + + /// + /// 报警内容 + /// + public string AlarmContent { get; set; } + + /// + /// 报警代码 + /// + public string AlarmCode { get; set; } + + /// + /// 报警类型 停机报警/非停机报警 + /// + public string AlarmType { get; set; } + + /// + /// 报警开始时间 + /// + public System.String StartTime { get; set; } + + /// + /// 报警消除时间 + /// + public System.String EndTime { get; set; } + + /// + /// 报警描述 + /// + public string AlarmDesc { get; set; } + + /// + /// 报警状态 传1或0,1是开始报警,0结束报警 + /// + public string AlarmState { get; set; } + + /// + /// 更新状态 + /// + public int Flag { get; set; } + } + + public class AlarmCSVData + { + + /// + /// 报警开始时间 + /// + [Name("报警时间")] + public string StartTime { get; set; } + + /// + /// 报警内容 + /// + /// + [Name("报警内容")] + public string AlarmContent { get; set; } + + } +} diff --git a/JinYuan.Models/Alarm/AlarmStatus.cs b/JinYuan.Models/Alarm/AlarmStatus.cs new file mode 100644 index 0000000..641ee78 --- /dev/null +++ b/JinYuan.Models/Alarm/AlarmStatus.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + public class AlarmStatus + { + /// + /// 报警地址 + /// + public string PLCAdress { get; set; } + + /// + /// 报警状态 + /// + public bool Status { get; set; } + } +} diff --git a/JinYuan.Models/AlarmCountEntry.cs b/JinYuan.Models/AlarmCountEntry.cs new file mode 100644 index 0000000..dc761b9 --- /dev/null +++ b/JinYuan.Models/AlarmCountEntry.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + public class AlarmCountEntry + { + /// + /// PLC地址 + /// + public string PLCAdress { get; set; } + + /// + /// 报警内容 + /// + public string AlarmContent { get; set; } + + /// + /// 报警次数 + /// + public int AlarmCount { get; set; } + /// + /// 班次 + /// + public string Class { get; set; } + /// + /// 更新时间 + /// + public DateTime AlarmTime { get; set; } + } +} diff --git a/JinYuan.Models/AlarmForm.cs b/JinYuan.Models/AlarmForm.cs new file mode 100644 index 0000000..536c679 --- /dev/null +++ b/JinYuan.Models/AlarmForm.cs @@ -0,0 +1,47 @@ +using CsvHelper.Configuration.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 报警表单数据 + /// + public class AlarmForm + { + /// + /// 报警地址 + /// + [Name("寄存器地址")] + public string PLCAdress { get; set; } + /// + /// 中语报警内容 + /// + [Name("中语报警信息")] + public string AlarmContent { get; set; } + /// + /// 报警代码 + /// + [Name("故障代码")] + public string AlarmCode { get; set; } + /// + /// 英语报警内容 + /// + [Name("英语报警信息")] + public string EnAlarmContent { get; set; } + /// + /// 匈牙利语报警内容 + /// + [Name("匈牙利语报警信息")] + public string HuAlarmContent { get; set; } + /// + /// 马来语报警内容 + /// + [Name("马来语报警信息")] + public string MsAlarmContent { get; set; } + } + +} diff --git a/JinYuan.Models/AxleLog.cs b/JinYuan.Models/AxleLog.cs new file mode 100644 index 0000000..a6156ba --- /dev/null +++ b/JinYuan.Models/AxleLog.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 电机位置记录 + /// + public class AxleLog + { + private string _m_AxleDscribe;//轴描述 + private string _m_AxleLocation;//位置描述 + private string _m_AxleAddress;//PLC地址 + + /// + /// 描述 + /// + public string m_AxleDscribe + { + get { return _m_AxleDscribe; } + set { _m_AxleDscribe = value; } + } + + /// + /// 位置描述 + /// + public string m_AxleLocation + { + get { return _m_AxleLocation; } + set { _m_AxleLocation = value; } + } + /// + /// 地址 + /// + public string m_AxleAddress + { + get { return _m_AxleAddress; } + set { _m_AxleAddress = value; } + } + } +} diff --git a/JinYuan.Models/BGearEntity.cs b/JinYuan.Models/BGearEntity.cs new file mode 100644 index 0000000..61f4348 --- /dev/null +++ b/JinYuan.Models/BGearEntity.cs @@ -0,0 +1,71 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; +using System.Collections.Generic; +using System.Xml.Linq; +using static System.Net.Mime.MediaTypeNames; + +namespace JinYuan.Models +{ + /// + /// 组盘出站工位 + /// + public class BGearEntity + { + /// + /// 测试时间 + /// + [DataGridViewColumn(Name = "OutTestTime")] + public string TestTime { get; set; } + + /// + /// 托盘码 + /// + [DataGridViewColumn(Name = "OutVassoioID")] + public string VassoioID { get; set; } + + /// + /// 叠盘工位号 + /// + [DataGridViewColumn(Name = "OutGongWei")] + public string GongWei { get; set; } + + /// + /// 叠盘层数 + /// + [DataGridViewColumn(Name = "OutStackingLayer")] + public int StackingLayer { get; set; } + + /// + /// 电芯等级 + /// + [DataGridViewColumn(Name = "OutQty")] + public string Qty { get; set; } + + + /// + /// 电芯数量 + /// + [DataGridViewColumn(Name = "OutTotal")] + public int Total { get; set; } + + /// + /// 电芯成功绑定数量 + /// + [DataGridViewColumn(Name = "OutSuccTotal")] + public int OutSuccTotal { get; set; } + + /// + /// 装箱结果 + /// + [DataGridViewColumn(Name = "OutResult")] + public string Result { get; set; } + + /// + /// 备注 + /// + [DataGridViewColumn(Name = "OutRemark")] + public string Remark { get; set; } + + + } +} diff --git a/JinYuan.Models/BGearEntity2.cs b/JinYuan.Models/BGearEntity2.cs new file mode 100644 index 0000000..9641f19 --- /dev/null +++ b/JinYuan.Models/BGearEntity2.cs @@ -0,0 +1,306 @@ +using JinYuan.Models.HelperAttribute; + +namespace JinYuan.Models +{ + /// + /// + /// + public class BGearEntity2 + { + /// + /// + /// + //public BGearEntity() + //{ + //} + + /// + /// 通道号 + /// + [DataGridViewColumn(Name = "OutChannelNo")] + [DataGridColumnAttribute("ChannelNo")] + + public string ChannelNo { get; set; } + /// + /// 时间 + /// + [DataGridViewColumn(Name = "OutTestTime")] + [DataGridColumnAttribute("TestTime")] + + public string TestTime { get; set; } + /// + /// 物料编码 + /// + [DataGridColumnAttribute("FrmHistory_dgv_Main_MaterialCode")] + + public string MaterialCode { get; set; } + /// + /// RFID托杯码 + /// + //[DataGridViewColumn(Name = "OutRFID")] + + public string RFID { get; set; } + /// + /// 电芯码 + /// + [DataGridViewColumn(Name = "OutBarCode")] + [DataGridColumnAttribute("BarCode")] + + public string BarCode { get; set; } + + /// + /// 离子风速 + /// + [DataGridViewColumn(Name = "OutWindSpeed")] + [DataGridColumnAttribute("WindSpeed")] + + public string WindSpeed { get; set; } + /// + /// 离子风清洁设备号 + /// + [DataGridViewColumn(Name = "OutWindDeviceNum")] + [DataGridColumnAttribute("WindDeviceNum")] + public string WindDeviceNum { get; set; } + + /// + /// 端面检测设备号1 + /// + [DataGridViewColumn(Name = "OutCCDFaceTestDeviceNum1")] + public string CCDFaceTestDeviceNum1 { get; set; } + /// + /// 端面检测设备号2 + /// + [DataGridViewColumn(Name = "OutCCDFaceTestDeviceNum2")] + public string CCDFaceTestDeviceNum2 { get; set; } + /// + /// 端面检测设备号3 + /// + [DataGridViewColumn(Name = "OutCCDFaceTestDeviceNum3")] + public string CCDFaceTestDeviceNum3 { get; set; } + /// + /// 端面检测设备号4 + /// + [DataGridViewColumn(Name = "OutCCDFaceTestDeviceNum4")] + public string CCDFaceTestDeviceNum4 { get; set; } + + /// + /// 柱面检测设备号1 + /// + [DataGridViewColumn(Name = "OutCCDCylinderTestDeviceNum1")] + public string CCDCylinderTestDeviceNum1 { get; set; } + /// + /// 柱面检测设备号2 + /// + [DataGridViewColumn(Name = "OutCCDCylinderTestDeviceNum2")] + public string CCDCylinderTestDeviceNum2 { get; set; } + /// + /// 柱面检测设备号3 + /// + [DataGridViewColumn(Name = "OutCCDCylinderTestDeviceNum3")] + public string CCDCylinderTestDeviceNum3 { get; set; } + + /// + /// 负极焊接区2D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDNegativeTerminalWeldingZone2DInspectionResult")] + public string CCDNegativeTerminalWeldingZone2DInspectionResult { get; set; } + + + /// + /// 负极焊接区2D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDNegativeTerminalWeldingZone2DInspectionNGReasons")] + public string CCDNegativeTerminalWeldingZone2DInspectionNGReasons { get; set; } + + + /// + /// 盖板2D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDCoverPlate2DInspectionResult")] + public string CCDCoverPlate2DInspectionResult { get; set; } + ///// + ///// 正极柱检测结果 + ///// + //[DataGridViewColumn(Name = "OutCCDPosCylinderTestResult")] + //public string CCDPosCylinderTestResult { get; set; } + ///// + ///// 负极柱检测结果 + ///// + //[DataGridViewColumn(Name = "OutCCDNegCylinderTestResult")] + //public string CCDNegCylinderTestResult { get; set; } + + + /// + /// 盖板2D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDCoverPlate2DInspectionNGReasons")] + public string CCDCoverPlate2DInspectionNGReasons { get; set; } + + /// + /// 负极焊接区2.5D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDNegativeTerminalWeldingZone25DInspectionResult")] + public string CCDNegativeTerminalWeldingZone25DInspectionResult { get; set; } + + + /// + /// 负极焊接区2.5D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDNegativeTerminalWeldingZone25DInspectionNGReasons")] + public string CCDNegativeTerminalWeldingZone25DInspectionNGReasons { get; set; } + + + /// + /// 盖板2.5D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDCoverPlate25DInspectionResult")] + public string CCDCoverPlate25DInspectionResult { get; set; } + + + /// + /// 盖板2.5D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDCoverPlate25DInspectionNGReasons")] + public string CCDCoverPlate25DInspectionNGReasons { get; set; } + + + /// + /// 极柱2D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDTerminalPost2DInspectionResult")] + public string CCDTerminalPost2DInspectionResult { get; set; } + + + /// + /// 极柱2D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDTerminalPost2DInspectionNGReasons")] + public string CCDTerminalPost2DInspectionNGReasons { get; set; } + + + /// + /// 极柱3D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDTerminalPost3DInspectionResult")] + public string CCDTerminalPost3DInspectionResult { get; set; } + + + /// + /// 极柱3D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDTerminalPost3DInspectionNGReasons")] + public string CCDTerminalPost3DInspectionNGReasons { get; set; } + + + + /// + /// 密封钉2D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDSealingNail2DInspectionResult")] + public string CCDSealingNail2DInspectionResult { get; set; } + + + /// + /// 密封钉2D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDSealingNail2DInspectionNGReasons")] + public string CCDSealingNail2DInspectionNGReasons { get; set; } + + + /// + /// 密封钉3D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDSealingNail3DInspectionResult")] + public string CCDSealingNail3DInspectionResult { get; set; } + + + /// + /// 密封钉3D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDSealingNail3DInspectionNGReasons")] + public string CCDSealingNail3DInspectionNGReasons { get; set; } + + + /// + /// 上部R角2.5D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDTopFillet25DInspectionResult")] + public string CCDTopFillet25DInspectionResult { get; set; } + + + /// + /// 上部R角2.5D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDTopFillet25DInspectionNGReasons")] + public string CCDTopFillet25DInspectionNGReasons { get; set; } + + + /// + /// 底部R角2.5D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDBottomFillet25DInspectionResult")] + public string CCDBottomFillet25DInspectionResult { get; set; } + + + /// + /// 底部R角2.5D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDBottomFillet25DInspectionNGReasons")] + public string CCDBottomFillet25DInspectionNGReasons { get; set; } + + + /// + /// 柱面2.5D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDCylindricalSurface25DInspectionResult")] + public string CCDCylindricalSurface25DInspectionResult { get; set; } + + + /// + /// 柱面2.5D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDCylindricalSurface25DInspectionNGReasons")] + public string CCDCylindricalSurface25DInspectionNGReasons { get; set; } + + + /// + /// 柱面3D检测结果 + /// + [DataGridViewColumn(Name = "OutCCDCylindricalSurface3DInspectionResult")] + public string CCDCylindricalSurface3DInspectionResult { get; set; } + + + /// + /// 柱面3D检测NG原因 + /// + [DataGridViewColumn(Name = "OutCCDCylindricalSurface3DInspectionNGReasons")] + public string CCDCylindricalSurface3DInspectionNGReasons { get; set; } + + + /// + /// 综合结果 + /// + [DataGridViewColumn(Name = "OutResult")] + public string Result { get; set; } + /// + /// NG详情 + /// + [DataGridViewColumn(Name = "OutInfo")] + public string Info { get; set; } + /// + /// 备注 + /// + [DataGridViewColumn(Name = "OutRemark")] + public string Remark { get; set; } + /// + /// 出站是否上传MES + /// + [DataGridViewColumn(Name = "OutFlag")] + public string Flag { get; set; } + /// + /// 结果数据是否上传MES + /// + public string Flag1 { get; set; } + + } +} diff --git a/JinYuan.Models/BatteryEntity.cs b/JinYuan.Models/BatteryEntity.cs new file mode 100644 index 0000000..f316458 --- /dev/null +++ b/JinYuan.Models/BatteryEntity.cs @@ -0,0 +1,57 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; + +namespace JinYuan.Models +{ + /// + /// 电芯满箱出站 + /// + public class BatteryEntity + { + /// + /// 电芯条码 + /// + //[SugarColumn(IsIgnore = true)] //不存储到数据库 + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "identification")] + public string identification { get; set; } + /// + /// 电芯条码位置 + /// + //[SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "location")] + public string location { get; set; } + + /// + /// 电芯等级 + /// + [DataGridViewColumn(Name = "grade")] + public string grade { get; set; } + /// + /// 卡板码(箱唛号) + /// + [DataGridViewColumn(Name = "containerCode")] + public string containerCode { get; set; } + /// + /// 条码是否已成功绑定该卡板 + /// + [DataGridViewColumn(Name = "packResult")] + public bool packResult { get; set; } + /// + /// 条码绑定失败原因 + /// + [DataGridViewColumn(Name = "packFalseReason")] + public string packFalseReason { get; set; } + /// + /// 条码绑定时间 + /// + [DataGridViewColumn(Name = "packTime")] + public string packTime { get; set; } + + /// + /// 出站类型 + /// + //[DataGridViewColumn(Name = "outStationType")] + public int outStationType { get; set; } + } +} diff --git a/JinYuan.Models/BatteryReplace.cs b/JinYuan.Models/BatteryReplace.cs new file mode 100644 index 0000000..67e03c3 --- /dev/null +++ b/JinYuan.Models/BatteryReplace.cs @@ -0,0 +1,70 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace JinYuan.Models +{ + /// + /// 电芯替换 + /// + public class BatteryReplace + { + /// + /// 时间 + /// + [DataGridViewColumn(Name = "TestTime")] + public DateTime ReplaceTime { get; set; } + /// + /// 替换后的电池码 + /// + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "NewBarCode")] + public string NewBarCode { get; set; } + + /// + /// 替换前的电池码 + /// + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "OldBarCode")] + public string OldBarCode { get; set; } + + /// + /// 电芯在托盘位置号 + /// + [DataGridViewColumn(Name = "Location")] + public string Location { get; set; } + + + + /// + /// 托盘码 + /// + [DataGridViewColumn(Name = "VassoioID")] + public string VassoioID { get; set; } + + /// + /// 托盘工位号 + /// + [DataGridViewColumn(Name = "GongWei")] + public string GongWei { get; set; } + + /// + /// 电芯档位 + /// + [DataGridViewColumn(Name = "Grade")] + public string Grade { get; set; } + + + /// + /// 备注 + /// + [DataGridViewColumn(Name = "Remark")] + public string Remark { get; set; } + } +} diff --git a/JinYuan.Models/BatteryStatus.cs b/JinYuan.Models/BatteryStatus.cs new file mode 100644 index 0000000..73a3acf --- /dev/null +++ b/JinYuan.Models/BatteryStatus.cs @@ -0,0 +1,16 @@ + + +namespace JinYuan.Models +{ + public class BatteryStatus + { + public string batteryId { get; set; } + + public int status { get; set; } + + public string location { get; set; } + + public string Container { get; set; } + + } +} diff --git a/JinYuan.Models/CGearEntity.cs b/JinYuan.Models/CGearEntity.cs new file mode 100644 index 0000000..ec9b36d --- /dev/null +++ b/JinYuan.Models/CGearEntity.cs @@ -0,0 +1,53 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace JinYuan.Models +{ + /// + /// 抽检工位 + /// + public class CGearEntity + { + /// + /// 时间 + /// + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "ReTestTime")] + public string TestTime { get; set; } + + /// + /// 电池条码 + /// + [DataGridViewColumn(Name = "ReBarCode")] + public string BarCode { get; set; } + + /// + /// 托盘码 + /// + [DataGridViewColumn(Name = "ReVassoioID")] + public string VassoioID { get; set; } + + /// + /// 托盘位置号 + /// + [DataGridViewColumn(Name = "ReLocationNum")] + public string LocationNum { get; set; } + + /// + /// 结果 + /// + [DataGridViewColumn(Name = "ReResult")] + public string Result { get; set; } + /// + /// 备注 + /// + [DataGridViewColumn(Name = "ReRemark")] + public string Remark { get; set; } + } +} diff --git a/JinYuan.Models/CPKModel.cs b/JinYuan.Models/CPKModel.cs new file mode 100644 index 0000000..5e7b922 --- /dev/null +++ b/JinYuan.Models/CPKModel.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + + + +namespace JinYuan.Models +{ + //子组大小:这个与计算内的CPK值又非常打的关系,即是分组的样本个数,数据的分组在此处需要说明的是,必须 + //是根据实际情况来填写,比如每次抽样为5个,那么子组大小为5个,我们不能随心所欲的任意填写这个值,否则 + //将没有实际意义。 + //上规格:用户录入的上规格值 + //目标值:用户输入的目标值,即期望达到的中心值 + //下规格:用户输入的下规格值 + + + public class CPKModel + { + /// + /// 总样本数 。参与分析的数据的个数 + /// + public int TotalNumber { get; set; } + /// + /// 图表类型 .说明进行分析的控制图的类型,此处为XR控制图 + /// + public string ChartType { get; set; } + /// + /// 平均值 所有样本数据的平均值 + /// + public double MeanVlaue { get; set; } + /// + /// 最大值 所有样本的最大值 + /// + public double MaxValue { get; set; } + /// + /// 最小值 + /// + public double MinValue { get; set; } + + /// + /// 正的3倍标准差线 + /// + public double Pos3Sigma { get; set; } + /// + /// 负的3倍标准差线 + /// + public double Neg3Sigma { get; set; } + /// + /// 组内标准差值 + /// + public double GroupSTDEV { get; set; } + /// + /// 整体标准差值 + /// + public double WholeSTDEV { get; set; } + + /// + /// 组内CPK值 工序能力指数,与规格值及上述标准差值相关联 + /// + public double GroupCPK { get; set; } + /// + /// 整体CPK值 工序能力指数,与规格值及上述标准差值相关联 + /// + public double WholeCPK { get; set; } + + /// + /// 组内CP值 Cp值是衡量过程满足产品品质标准的成都,也叫制程精密度,Cp值越大,表示过程变异越小,过程能力越差 + /// + public double GroupCP { get; set; } + /// + /// 整体CP值 Cp值是衡量过程满足产品品质标准的成都,也叫制程精密度,Cp值越大,表示过程变异越小,过程能力越差 + /// + public double WholeCP { get; set; } + + /// + /// 组内CPL值 相对应于下规格的工序能力值; + /// + public double GroupCPL { get; set; } + /// + /// 整体CPL值 相对应于下规格的工序能力值; + /// + public double WholeCPL { get; set; } + + /// + /// 组内CPU值 相对应于上规格的工序能力值; + /// + public double GroupCPU { get; set; } + /// + /// 整体CPU值 相对应于上规格的工序能力值; + /// + public double WholeCPU { get; set; } + + /// + /// 组内PPM + public double GroupPPM_LSL { get; set; } + /// + /// 整体PPM + public double WholePPM_LSL { get; set; } + + /// + /// 实际检测PPM + public double MeasuredPPM_LSL { get; set; } + + /// + /// 组内PPM + public double GroupPPM_USL { get; set; } + /// + /// 整体PPM + public double WholePPM_USL { get; set; } + /// + /// 实际检测PPM + public double MeasuredPPM_USL { get; set; } + /// + /// 组内PPM Total值,预测的总的不合格品数 + /// + public double GroupPPM_Total { get; set; } + /// + /// 整体PPM + public double WholePPM_Total { get; set; } + + /// + /// 实际检测PPM + public double MeasuredPPM_Total { get; set; } + + /// + /// 制程准确度,值越小越好 + /// + public double CA { get; set; } + + + } +} diff --git a/JinYuan.Models/CTPCTQDate.cs b/JinYuan.Models/CTPCTQDate.cs new file mode 100644 index 0000000..e4e45de --- /dev/null +++ b/JinYuan.Models/CTPCTQDate.cs @@ -0,0 +1,228 @@ +using System.Collections.Generic; + +namespace JinYuan.Models +{ + + + /// + /// 进出站上传数据 + /// + public class EnterandExit + { + /// + /// BU编码 + /// + public string bu_id; + /// + /// 区域简称 + /// + public string district_id; + /// + /// 工厂编码 + /// + public string factory_id; + /// + /// 产线编码 + /// + public string production_line_id; + /// + /// 工序编码 + /// + public string production_processes_id; + /// + /// 工作中心编码 + /// + public string work_center_id; + /// + /// 工站 + /// + public string station_id; + /// + /// 设备编码 + /// + public string device_name; + /// + /// 进出站标识 + /// + public string action; + /// + /// 动作时间(进出站) + /// + public string action_time; + } + + public class CollectionUpload + { + /// + /// BU编码 + /// + public string bu_id; + /// + /// 区域简称 + /// + public string district_id; + /// + /// 工厂编码 + /// + public string factory_id; + /// + /// 产线编码 + /// + public string production_line_id; + /// + /// 工序编码 + /// + public string production_processes_id; + /// + /// 工作中心编码 + /// + public string work_center_id; + /// + /// 工站 + /// + public string station_id; + /// + /// 设备编码 + /// + public string device_name; + /// + /// 采集项数据列表 + /// + public List taglist { get; set; } + + } + + public class Collection + { + /// + /// 时间 + /// + public string device_time { get; set; } + /// + /// 采集项键值对 + /// + public Dictionary collection_items { get; set; } + } + + #region 预测性数据采集项对象 + public class Predictability_BM + { + //------------------------------------------------------------------------扭矩 扭矩 扭矩 扭矩 + public string Coating1_Torque1 { get; set; } + public string Coating1_Torque2 { get; set; } + public string Coating1_Torque3 { get; set; } + public string Coating1_Torque4 { get; set; } + public string Coating1_Torque5 { get; set; } + public string Coating1_Torque6 { get; set; } + public string Coating1_Torque7 { get; set; } + public string Coating1_Torque8 { get; set; } + public string Coating2_Torque1 { get; set; } + public string Coating2_Torque2 { get; set; } + public string Coating2_Torque3 { get; set; } + public string Coating2_Torque4 { get; set; } + public string Coating2_Torque5 { get; set; } + public string Coating2_Torque6 { get; set; } + public string Coating2_Torque7 { get; set; } + public string Coating2_Torque8 { get; set; } + public string Folding1_Torque1 { get; set; } + public string Folding1_Torque2 { get; set; } + public string Folding1_Torque3 { get; set; } + public string Folding2_Torque1 { get; set; } + public string Folding2_Torque2 { get; set; } + public string Folding2_Torque3 { get; set; } + //------------------------------------------------------------------------轴速度 轴速度 轴速度 轴速度 + public string Coating1_AxisSpeed1 { get; set; } + public string Coating1_AxisSpeed2 { get; set; } + public string Coating1_AxisSpeed3 { get; set; } + public string Coating1_AxisSpeed4 { get; set; } + public string Coating1_AxisSpeed5 { get; set; } + public string Coating1_AxisSpeed6 { get; set; } + public string Coating1_AxisSpeed7 { get; set; } + public string Coating1_AxisSpeed8 { get; set; } + public string Coating2_AxisSpeed1 { get; set; } + public string Coating2_AxisSpeed2 { get; set; } + public string Coating2_AxisSpeed3 { get; set; } + public string Coating2_AxisSpeed4 { get; set; } + public string Coating2_AxisSpeed5 { get; set; } + public string Coating2_AxisSpeed6 { get; set; } + public string Coating2_AxisSpeed7 { get; set; } + public string Coating2_AxisSpeed8 { get; set; } + public string Folding1_AxisSpeed1 { get; set; } + public string Folding1_AxisSpeed2 { get; set; } + public string Folding1_AxisSpeed3 { get; set; } + public string Folding2_AxisSpeed1 { get; set; } + public string Folding2_AxisSpeed2 { get; set; } + public string Folding2_AxisSpeed3 { get; set; } + + //------------------------------------------------------------------------轴位置 轴位置 轴位置 轴位置 + public string Coating1_AxisPosition1 { get; set; } + public string Coating1_AxisPosition2 { get; set; } + public string Coating1_AxisPosition3 { get; set; } + public string Coating1_AxisPosition4 { get; set; } + public string Coating1_AxisPosition5 { get; set; } + public string Coating1_AxisPosition6 { get; set; } + public string Coating1_AxisPosition7 { get; set; } + public string Coating1_AxisPosition8 { get; set; } + public string Coating2_AxisPosition1 { get; set; } + public string Coating2_AxisPosition2 { get; set; } + public string Coating2_AxisPosition3 { get; set; } + public string Coating2_AxisPosition4 { get; set; } + public string Coating2_AxisPosition5 { get; set; } + public string Coating2_AxisPosition6 { get; set; } + public string Coating2_AxisPosition7 { get; set; } + public string Coating2_AxisPosition8 { get; set; } + public string Folding1_AxisPosition1 { get; set; } + public string Folding1_AxisPosition2 { get; set; } + public string Folding1_AxisPosition3 { get; set; } + public string Folding2_AxisPosition1 { get; set; } + public string Folding2_AxisPosition2 { get; set; } + public string Folding2_AxisPosition3 { get; set; } + //------------------------------------------------------------------------行程时间 行程时间 行程时间 行程时间 + public string Coating1_Cylinder_TravelTime1 { get; set; } + public string Coating1_Cylinder_TravelTime2 { get; set; } + public string Coating1_Cylinder_TravelTime3 { get; set; } + public string Coating1_Cylinder_TravelTime4 { get; set; } + public string Coating1_Cylinder_TravelTime5 { get; set; } + public string Coating1_Cylinder_TravelTime6 { get; set; } + public string Coating1_Cylinder_TravelTime7 { get; set; } + public string Coating1_Cylinder_TravelTime8 { get; set; } + public string Coating1_Cylinder_TravelTime9 { get; set; } + public string Coating1_Cylinder_TravelTime10 { get; set; } + public string Coating1_Cylinder_TravelTime11 { get; set; } + public string Coating1_Cylinder_TravelTime12 { get; set; } + public string Coating1_Cylinder_TravelTime13 { get; set; } + public string Coating1_Cylinder_TravelTime14 { get; set; } + public string Coating2_Cylinder_TravelTime1 { get; set; } + public string Coating2_Cylinder_TravelTime2 { get; set; } + public string Coating2_Cylinder_TravelTime3 { get; set; } + public string Coating2_Cylinder_TravelTime4 { get; set; } + public string Coating2_Cylinder_TravelTime5 { get; set; } + public string Coating2_Cylinder_TravelTime6 { get; set; } + public string Coating2_Cylinder_TravelTime7 { get; set; } + public string Coating2_Cylinder_TravelTime8 { get; set; } + public string Coating2_Cylinder_TravelTime9 { get; set; } + public string Coating2_Cylinder_TravelTime10 { get; set; } + public string Coating2_Cylinder_TravelTime11 { get; set; } + public string Coating2_Cylinder_TravelTime12 { get; set; } + public string Coating2_Cylinder_TravelTime13 { get; set; } + public string Coating2_Cylinder_TravelTime14 { get; set; } + public string CornerCutting1_Cylinder_TravelTime1 { get; set; } + public string CornerCutting1_Cylinder_TravelTime2 { get; set; } + public string CornerCutting1_Cylinder_TravelTime3 { get; set; } + public string CornerCutting1_Cylinder_TravelTime4 { get; set; } + public string CornerCutting1_Cylinder_TravelTime5 { get; set; } + public string CornerCutting1_Cylinder_TravelTime6 { get; set; } + public string CornerCutting1_Cylinder_TravelTime7 { get; set; } + public string CornerCutting1_Cylinder_TravelTime8 { get; set; } + public string CornerCutting2_Cylinder_TravelTime1 { get; set; } + public string CornerCutting2_Cylinder_TravelTime2 { get; set; } + public string CornerCutting2_Cylinder_TravelTime3 { get; set; } + public string CornerCutting2_Cylinder_TravelTime4 { get; set; } + public string CornerCutting2_Cylinder_TravelTime5 { get; set; } + public string CornerCutting2_Cylinder_TravelTime6 { get; set; } + public string CornerCutting2_Cylinder_TravelTime7 { get; set; } + public string CornerCutting2_Cylinder_TravelTime8 { get; set; } + + } + #endregion +} diff --git a/JinYuan.Models/CapSize.cs b/JinYuan.Models/CapSize.cs new file mode 100644 index 0000000..017f549 --- /dev/null +++ b/JinYuan.Models/CapSize.cs @@ -0,0 +1,26 @@ +using System; + + +namespace JinYuan.Models +{ + public class BoxSize + { + public int layers { get; set; } + public int rowsPerLayer { get; set; } + public int colsPerLayer { get; set; } + + public BoxSize() { } + + public BoxSize(int layers, int rowsPerLayer, int colsPerLayer) + { + this.layers = layers; + this.rowsPerLayer = rowsPerLayer; + this.colsPerLayer = colsPerLayer; + } + + public int getBoxSize() + { + return layers * rowsPerLayer * colsPerLayer; + } + } +} diff --git a/JinYuan.Models/Chart12HourData.cs b/JinYuan.Models/Chart12HourData.cs new file mode 100644 index 0000000..5e78da3 --- /dev/null +++ b/JinYuan.Models/Chart12HourData.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 24小时统计表数据 + /// + public class Chart12HourData + { + /// + /// 优率 + /// + public string DisplayTime { get; set; } + /// + /// 产出数 + /// + public int ProdIn { set; get; } + /// + /// 投入数 + /// + public int ProdOut { set; get; } + /// + /// 不良数量 + /// + public int ProdNg { set; get; } + /// + /// 优率 + /// + public string OKRatio { get; set; } + } +} diff --git a/JinYuan.Models/ChartDataType.cs b/JinYuan.Models/ChartDataType.cs new file mode 100644 index 0000000..7bc9a2c --- /dev/null +++ b/JinYuan.Models/ChartDataType.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 不良統計 + /// + public class ChartDataType + { + /// + /// 數據類型 + /// + public string DataType { get; set; } + /// + /// 數量 + /// + public int DataCount { get; set; } + } +} diff --git a/JinYuan.Models/DGearEntity.cs b/JinYuan.Models/DGearEntity.cs new file mode 100644 index 0000000..070a442 --- /dev/null +++ b/JinYuan.Models/DGearEntity.cs @@ -0,0 +1,64 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; +using System.Collections.Generic; +using static System.Net.Mime.MediaTypeNames; + +namespace JinYuan.Models +{ + /// + /// 底托卡板绑定工位(上传WMS) + /// + public class DGearEntity + { + + /// + /// 层数 + /// + //[SugarColumn(IsIgnore = true)] //不存储到数据库 + [DataGridViewColumn(Name = "DtChannelNo")] + public string ChannelNo { get; set; } + + /// + /// 托盘位置号 + /// + [DataGridViewColumn(Name = "DtLocationNum")] + public string LocationNum { get; set; } + + /// + /// 托盘码 + /// + [DataGridViewColumn(Name = "DtVassoioID")] + public string VassoioID { get; set; } + + /// + /// 时间 + /// + [SugarColumn(IsPrimaryKey = true)] + [DataGridViewColumn(Name = "DtTestTime")] + public string TestTime { get; set; } + + /// + /// 电池码 + /// + [DataGridViewColumn(Name = "DtBarCode")] + public string BarCode { get; set; } + + /// + /// 底托卡板码 + /// + [DataGridViewColumn(Name = "DtCardBarcode")] + public string CardBarcode { get; set; } + + + /// + /// 结果 + /// + [DataGridViewColumn(Name = "DtResult")] + public string Result { get; set; } + /// + /// 备注 + /// + [DataGridViewColumn(Name = "DtRemark")] + public string Remark { get; set; } + } +} diff --git a/JinYuan.Models/DataTurnover.cs b/JinYuan.Models/DataTurnover.cs new file mode 100644 index 0000000..b7c2621 --- /dev/null +++ b/JinYuan.Models/DataTurnover.cs @@ -0,0 +1,66 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace JinYuan.Models +{ + /// + /// 组盘临时表 + /// + public class DataTurnover + { + + /// + /// 时间 + /// + //[SugarColumn(IsPrimaryKey = true)] + public System.DateTime? Time { get; set; } + + /// + /// 电池码 + /// + [SugarColumn(IsPrimaryKey = true)] + public string identification { get; set; } + + /// + /// 托盘码 + /// + public string containerCode { get; set; } + + /// + /// 设备编码 + /// + public string equipNum { get; set; } + + /// + /// 电芯位置号 + /// + //public string Location { get; set; } + + + /// + /// 托盘位置号 + /// + //public string Grade { get; set; } + + /// + /// 装箱次数 + /// + //public string PackNum { get; set; } + + /// + /// 装箱时间 + /// + //public string PackTime { get; set; } + + /// + /// 信息 + /// + public string Message { get; set; } + } +} diff --git a/JinYuan.Models/DeviceOEE.cs b/JinYuan.Models/DeviceOEE.cs new file mode 100644 index 0000000..b0edaa6 --- /dev/null +++ b/JinYuan.Models/DeviceOEE.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + + /// + /// 设备综合效率 + /// + public class DeviceOEE + { + /// + /// 生产总数 + /// + public int TotalQty { set; get; } + /// + /// 良品数 + /// + public int ProOKQty { set; get; } + /// + /// 良率 + /// + public double YieldRate { set; get; } + /// + /// 稼动率 + /// + public double UtilizationRate { set; get; } + /// + /// PPM + /// + public int PPM { set; get; } + /// + /// 风速仪器 + /// + public List listWindSpeed { set; get; } + /// + /// 报警 + /// + public List ListAlarmData { set; get; } + + /// + /// 不良统计 + /// + public List ListNGData { set; get; } + } + + + + + + public class Hour12Data + { + /// + /// 12小时产能 + /// + public List chart12HourDatas { set; get; } + } + + public class List12HourData + { + public List dataTime { set; get; } + public List dataTotal { set; get; } + public List dataOk { set; get; } + public List dataLV { set; get; } + } +} diff --git a/JinYuan.Models/EGearEntity.cs b/JinYuan.Models/EGearEntity.cs new file mode 100644 index 0000000..958a346 --- /dev/null +++ b/JinYuan.Models/EGearEntity.cs @@ -0,0 +1,40 @@ +using JinYuan.Models.HelperAttribute; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace JinYuan.Models +{ + /// + /// 卡板码打印工位 + /// + public class EGearEntity + { + /// + /// 测试时间 + /// + [DataGridViewColumn(Name = "TestTime")] + public string TestTime { get; set; } + + /// + /// 托盘码 + /// + [DataGridViewColumn(Name = "CardBarcode")] + public string CardBarcode { get; set; } + + /// + /// 综合结果 + /// + [DataGridViewColumn(Name = "Result")] + public string Result { get; set; } + + /// + /// 备注 + /// + [DataGridViewColumn(Name = "Remark")] + public string Remark { get; set; } + } +} diff --git a/JinYuan.Models/ElectricEnergy.cs b/JinYuan.Models/ElectricEnergy.cs new file mode 100644 index 0000000..b0e7593 --- /dev/null +++ b/JinYuan.Models/ElectricEnergy.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 智能电表 + /// + public class ElectricEnergy + { + + /// + /// 有功电能(累计电能)KWH + /// + public System.Decimal? AccumulatedElectricity { get; set; } + + /// + /// A相电压 V + /// + public System.Decimal? PhaseVoltageA { get; set; } + + /// + /// B相电压 + /// + public System.Decimal? PhaseVoltageB { get; set; } + + /// + /// C相电压 + /// + public System.Decimal? PhaseVoltageC { get; set; } + + /// + /// A相电流 + /// + public System.Decimal? PhaseCurrentA { get; set; } + + /// + /// B相电流 + /// + public System.Decimal? PhaseCurrentB { get; set; } + + /// + /// C相电流 + /// + public System.Decimal? PhaseCurrentC { get; set; } + + /// + /// A相功率 + /// + public System.Decimal? PhasePowerA { get; set; } + + /// + /// B相功率 + /// + public System.Decimal? PhasePowerB { get; set; } + + /// + /// C相功率 + /// + public System.Decimal? PhasePowerC { get; set; } + + /// + /// 总有功功率 + /// + public System.Decimal? ActivePower { get; set; } + + /// + /// 总功率因数 + /// + public System.Decimal? PowerFactor { get; set; } + + /// + /// 电压变比 + /// + public System.Decimal? pt { get; set; } + + /// + /// 电流变比 + /// + public System.Decimal? ct { get; set; } + } +} diff --git a/JinYuan.Models/HelperAttribute/AnnotationUtils.cs b/JinYuan.Models/HelperAttribute/AnnotationUtils.cs new file mode 100644 index 0000000..7d71a4c --- /dev/null +++ b/JinYuan.Models/HelperAttribute/AnnotationUtils.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models.HelperAttribute +{ + public static class AnnotationUtils + { + public static List GetPropertiesWithAnnotation(Type type) where T : Attribute + { + var properties = type.GetProperties().Where(p => p.GetCustomAttributes(typeof(T), true).Length > 0).ToList(); + return properties; + } + + /// + /// 获取当前类的DataGridViewColumn + /// + /// + /// + public static List GetDataGridViewColumns(this object obj) + { + Type typeObj = obj.GetType(); + var properties = AnnotationUtils.GetPropertiesWithAnnotation(typeObj); + + List list = new List(); + foreach (var property in properties) + { + DataGridViewColumn attribute = property.GetCustomAttribute(); + //数据源名称 + attribute.DataPropertyName = property.Name; + list.Add(attribute); + } + + return list; + } + + } +} diff --git a/JinYuan.Models/HelperAttribute/DataGridColumnAttribute.cs b/JinYuan.Models/HelperAttribute/DataGridColumnAttribute.cs new file mode 100644 index 0000000..a705178 --- /dev/null +++ b/JinYuan.Models/HelperAttribute/DataGridColumnAttribute.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models.HelperAttribute +{ + /// + /// 数据表格列映射特性(支持字段/属性) + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] + public sealed class DataGridColumnAttribute : Attribute + { + /// + /// 目标列名(默认使用成员名) + /// + public string ColumnName { get; set; } + + /// + /// 列数据类型(默认使用成员类型) + /// + public Type ColumnType { get; set; } + + public DataGridColumnAttribute() { } + + public DataGridColumnAttribute(string columnName) => ColumnName = columnName; + } +} diff --git a/JinYuan.Models/HelperAttribute/DataGridViewColumn.cs b/JinYuan.Models/HelperAttribute/DataGridViewColumn.cs new file mode 100644 index 0000000..811363f --- /dev/null +++ b/JinYuan.Models/HelperAttribute/DataGridViewColumn.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models.HelperAttribute +{ + public class DataGridViewColumn : Attribute + { + public string HeaderText { get; set; } + public string Name { get; set; } + public string DataPropertyName { get; set; } + } +} diff --git a/JinYuan.Models/HelperAttribute/DataTableMapper.cs b/JinYuan.Models/HelperAttribute/DataTableMapper.cs new file mode 100644 index 0000000..222c3b3 --- /dev/null +++ b/JinYuan.Models/HelperAttribute/DataTableMapper.cs @@ -0,0 +1,155 @@ +using JinYuan.Models.HelperAttribute; +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; + + + +/// +/// DataTable 映射工具 +/// +/// +/// DataTable 映射工具 +/// +public static class DataTableMapper +{ + /// + /// 实体类型转换为 DataTable 结构(含注解解析) + /// + public static DataTable ToSchema(Type type) + { + var dt = new DataTable(type.Name); + var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance); + + foreach (var member in members) + { + var prop = member as PropertyInfo; + var field = member as FieldInfo; + if ((prop != null && !prop.CanRead) || (field == null && prop == null)) continue; + + var attr = member.GetCustomAttribute(); + var colName = attr != null ? attr.ColumnName : member.Name; + var colType = attr != null && attr.ColumnType != null ? attr.ColumnType : + (prop != null ? prop.PropertyType : field.FieldType); + + var column = dt.Columns.Add(colName, colType); + column.AllowDBNull = !(colType.GetTypeInfo().IsValueType && + !colType.GetTypeInfo().IsGenericType); + } + return dt; + } + + /// + /// 实体集合转换为 DataTable(含注解映射) + /// 使用: var dt = DataTableMapper.ToDataTable (employees, typeof (Employee)); + /// + public static DataTable ToDataTable(this IEnumerable entities, Type type) + { + var dt = ToSchema(type); + if (entities == null) return dt; + + foreach (var entity in entities) + { + var row = dt.NewRow(); + FillDataRow(entity, row, type); + dt.Rows.Add(row); + } + return dt; + } + + private static void FillDataRow(object entity, DataRow row, Type type) + { + foreach (DataColumn column in row.Table.Columns) + { + MemberInfo member = null; + foreach (var m in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)) + { + var attr = m.GetCustomAttribute(); + var mName = attr != null ? attr.ColumnName : m.Name; + if (string.Equals(mName, column.ColumnName, StringComparison.OrdinalIgnoreCase)) + { + member = m; + break; + } + } + + if (member == null) continue; + + object value; + if (member is PropertyInfo prop) + { + value = prop.GetValue(entity); + } + else if (member is FieldInfo field) + { + value = field.GetValue(entity); + } + else + { + continue; + } + + row[column] = value ?? DBNull.Value; + } + } + + /// + /// DataTable 转换为 List + /// 使用案例: var employeeList = dt.ToList(); + /// + public static List ToList(this DataTable dt) where T : new() + { + var list = new List(); + var type = typeof(T); + var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance); + + foreach (DataRow row in dt.Rows) + { + var item = new T(); + foreach (var member in members) + { + var prop = member as PropertyInfo; + var field = member as FieldInfo; + if ((prop != null && !prop.CanWrite) || (field == null && prop == null)) continue; + + var attr = member.GetCustomAttribute(); + var colName = attr != null ? attr.ColumnName : member.Name; + if (dt.Columns.Contains(colName)) + { + var value = row[colName]; + if (value != DBNull.Value) + { + if (prop != null) + { + prop.SetValue(item, Convert.ChangeType(value, prop.PropertyType)); + } + else if (field != null) + { + field.SetValue(item, Convert.ChangeType(value, field.FieldType)); + } + } + } + } + list.Add(item); + } + return list; + } + + /// + /// 循环获取当前 DataTable 的列名称,通过自定义的获取名称方法获取新的列名并替换 + /// + /// 要处理的 DataTable + /// 自定义的获取新列名的方法 + /// 列名替换后的 DataTable + public static DataTable ReplaceColumnNamesWithCustomMethod(this DataTable dt, Func GetNewColumnName) + { + for (int i = 0; i < dt.Columns.Count; i++) + { + string originalColumnName = dt.Columns[i].ColumnName; + string newColumnName = GetNewColumnName(originalColumnName); + dt.Columns[i].ColumnName = newColumnName; + } + return dt; + } +} \ No newline at end of file diff --git a/JinYuan.Models/Hourprod.cs b/JinYuan.Models/Hourprod.cs new file mode 100644 index 0000000..d2f9504 --- /dev/null +++ b/JinYuan.Models/Hourprod.cs @@ -0,0 +1,52 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 24小时产能 + /// + public class Hourprod + { + /// + /// 日期 + /// + [SugarColumn(IsPrimaryKey = true)] + public System.String FDate { get; set; } + + /// + /// 小时 + /// + [SugarColumn(IsPrimaryKey = true)] + public System.Int32 FHour { get; set; } + + /// + /// 投入数 + /// + public System.Int32 ProdIn { get; set; } + + /// + /// 产出数 + /// + public System.Int32 ProdOut { get; set; } + + /// + /// 时间 + /// + public System.DateTime? TestTime { get; set; } + + /// + /// PPM + /// + public System.Int32 Ppm { get; set; } + + /// + /// 稼动率 + /// + public System.Decimal JiaDL { get; set; } + } +} diff --git a/JinYuan.Models/JinYuan.Models.csproj b/JinYuan.Models/JinYuan.Models.csproj new file mode 100644 index 0000000..2f74d2a --- /dev/null +++ b/JinYuan.Models/JinYuan.Models.csproj @@ -0,0 +1,141 @@ + + + + + Debug + AnyCPU + {4C0BCB84-5CD7-4846-8363-C4C10D46E391} + Library + Properties + JinYuan.Models + JinYuan.Models + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\CsvHelper.33.0.1\lib\net48\CsvHelper.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll + + + ..\packages\MiniExcel.1.36.1\lib\net45\MiniExcel.dll + + + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + ..\LargeSquareOne\Lib\PLCCommunication.dll + + + ..\packages\SqlSugar.5.1.4.199\lib\SqlSugar.dll + + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + + + ..\packages\System.Memory.4.5.0\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JinYuan.Models/MotorLog.cs b/JinYuan.Models/MotorLog.cs new file mode 100644 index 0000000..7f6173d --- /dev/null +++ b/JinYuan.Models/MotorLog.cs @@ -0,0 +1,39 @@ +namespace JinYuan.Models +{ + + /// + /// 轴位置记录 + /// + public class MotorLog + { + private string _m_MotorDscribe;//轴描述 + private string _m_MotorLocation;//位置描述 + private string _m_MotorAddress;//PLC地址 + + /// + /// 描述 + /// + public string m_MotorDscribe + { + get { return _m_MotorDscribe; } + set { _m_MotorDscribe = value; } + } + + /// + /// 位置描述 + /// + public string m_MotorLocation + { + get { return _m_MotorLocation; } + set { _m_MotorLocation = value; } + } + /// + /// 地址 + /// + public string m_MotorAddress + { + get { return _m_MotorAddress; } + set { _m_MotorAddress = value; } + } + } +} diff --git a/JinYuan.Models/NgCodeEntity.cs b/JinYuan.Models/NgCodeEntity.cs new file mode 100644 index 0000000..e4edff4 --- /dev/null +++ b/JinYuan.Models/NgCodeEntity.cs @@ -0,0 +1,22 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; + +namespace JinYuan.Models +{ + /// + /// ngCode实体类 + /// + public class NgCodeEntity + { + /// + /// 编码 + /// + public string ngCode { get; set; } + /// + /// 不良信息 + /// + public string ngMessage { get; set; } + + + } +} diff --git a/JinYuan.Models/PlcDevice.cs b/JinYuan.Models/PlcDevice.cs new file mode 100644 index 0000000..24ffa42 --- /dev/null +++ b/JinYuan.Models/PlcDevice.cs @@ -0,0 +1,201 @@ +using MiniExcelLibs.Attributes; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 通信设备实体类 + /// + public class PlcDevice + { + /// + /// PLC编号 + /// + public int PlcNum { get; set; } + /// + /// IP地址 + /// + public string IPAddress { get; set; } + /// + /// 端口 + /// + public int Port { get; set; } + + /// + /// PLC类型 + /// + public string PLCType { get; set; } + /// + /// 是否启用 + /// + public bool IsActive { get; set; } + /// + /// 心跳地址 + /// + public string HeartBeat { get; set; } + /// + /// 是否启用心跳消息 + /// + public bool IsHeartBeat { get; set; } + /// + /// 链接成功标志 + /// + public bool IsConnected { get; set; } + /// + /// 是否是首次连接 + /// + public bool IsFirstConnect { get; set; } = true; + + /// + /// 重连周期 + /// + + public int ReConnectTime { get; set; } = 2000; + + /// + /// 休眠时间 + /// + + public int SleepTime { get; set; } = 10; + + /// + /// 大小端 + /// + [JsonIgnore] + public int DataFormat { get; set; } = 0; + /// + /// 出错次数 + /// + public int ErrorTimes { get; set; } + + /// + /// 容错次数 + /// + public int AllowErrorTimes { get; set; } = 3; + + /// + /// 多线程取消源标志位 + /// + public CancellationTokenSource Cts { get; set; } + /// + /// 通信组集合 + /// + public List GroupList { get; set; } = new List(); + } + + + public class PlcGroup + { + /// + /// PLC编号 + /// + public int PlcNum { get; set; } + /// + ///通信组名称 + /// + public string GroupName { get; set; } + /// + /// 起始地址 + /// + public string Start { get; set; } + /// + /// 长度 + /// + public ushort Length { get; set; } + /// + /// 是否为触发读取 + /// + public bool IsTiggerRead { get; set; } + + /// + /// 是否需要反馈结果到PLC + /// + public bool IsFeedbackPlc { get; set; } + + /// + /// 是否启用 + /// + public bool IsActive { get; set; } + /// + /// 备注说明 + /// + public string Remark { get; set; } + /// + /// 机架号,对于物流线需要带线号,对于组盘机只要子架号 + /// + public string StationName { get; set; } + /// + /// 变量集合 + /// + [ExcelIgnore] + public List VarList { get; set; } + } + + /// + /// 变量属性类 + /// + public class PlcVariable + { + /// + /// PLC编号 + /// + public int PlcNum { get; set; } + /// + /// 变量名称 + /// + public string VarName { get; set; } + + /// + /// 变量地址 + /// + public string VarAddress { get; set; } + /// + /// 起始索引 + /// + public string Start { get; set; } + /// + /// 数据类型 + /// + public string DataType { get; set; } + /// + /// 偏移或长度 + /// + public int OffsetOrLength { get; set; } + /// + /// 所属通信组名称 + /// + public string GroupName { get; set; } + /// + /// 机架号,对于物流线需要带线号,对于组盘机只要子架号 + /// + public string StationName { get; set; } + } + + + public class PlcStates + { + // ... 现有的属性 ... + public short OldStatus { get; set; } + public int StatusCount { get; set; } + public string GuidAlarm { get; set; } + public List Status { get; set; } + } + + // 串口配置类 + public class SerialPortConfig + { + public bool IsActive { get; set; } + public string PortName { get; set; } + public int BaudRate { get; set; } + public string DeviceName { get; set; } + public SerialPort serialPort { get; set; } + public bool IsConnected { get; set; } + } +} diff --git a/JinYuan.Models/Properties/AssemblyInfo.cs b/JinYuan.Models/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f08f0e6 --- /dev/null +++ b/JinYuan.Models/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.Models")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.Models")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("4c0bcb84-5cd7-4846-8363-c4c10d46e391")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.Models/SysConfig/BTWConfig.cs b/JinYuan.Models/SysConfig/BTWConfig.cs new file mode 100644 index 0000000..100e76b --- /dev/null +++ b/JinYuan.Models/SysConfig/BTWConfig.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace JinYuan.Models +{ + public class BTWConfig + { + /// + /// 是否连接打印机服务器 + /// + public bool IsConnectPrinter; + /// + /// 箱唛码模板路径 + /// + public string containerBTWPath; + + /// + /// 栈板码模板路径 + /// + public string palletBTWPath; + + /// + /// printerName + /// + public string printerName; + } +} diff --git a/JinYuan.Models/SysConfig/CartainerConfig.cs b/JinYuan.Models/SysConfig/CartainerConfig.cs new file mode 100644 index 0000000..1f3bbb5 --- /dev/null +++ b/JinYuan.Models/SysConfig/CartainerConfig.cs @@ -0,0 +1,88 @@ +//using Newtonsoft.Json; +//using System; +//using System.Collections.Generic; +//using System.Diagnostics; +//using System.Threading; + +//namespace JinYuan.Models +//{ +// /// +// /// 卡板ID及档位类 +// /// +// public class CartainerConfig +// { + +// /// +// /// 卡板ID及档位映射字典 +// /// +// public Dictionary CartainerGrade { get; set; } = new Dictionary(); + +// /// +// /// 默认卡板ID +// /// +// public string DefaultCartainerId { get; set; } = ""; + +// /// +// /// 是否启用卡板验证 +// /// +// public bool EnableCartainerValidation { get; set; } = true; +// /// +// /// 根据卡板ID获取档位 +// /// +// /// 卡板ID +// /// 档位信息 +// public string GetGrade(string cartainerId) +// { +// if (CartainerGrade.ContainsKey(cartainerId)) +// { +// return CartainerGrade[cartainerId]; +// } +// return string.Empty; +// } + +// /// +// /// 添加或更新卡板档位 +// /// +// /// 卡板ID +// /// 档位 +// public void AddOrUpdateCartainer(string cartainerId, string grade) +// { +// if (CartainerGrade.ContainsKey(cartainerId)) +// { +// CartainerGrade[cartainerId] = grade; +// } +// else +// { +// CartainerGrade.Add(cartainerId, grade); +// } +// } + +// /// +// /// 移除卡板 +// /// +// /// 卡板ID +// /// 是否成功移除 +// public bool RemoveCartainer(string cartainerId) +// { +// return CartainerGrade.Remove(cartainerId); +// } + +// /// +// /// 清空所有卡板数据 +// /// +// public void ClearAll() +// { +// CartainerGrade.Clear(); +// } + +// /// +// /// 验证卡板ID是否存在 +// /// +// /// 卡板ID +// /// 是否存在 +// public bool ContainsCartainer(string cartainerId) +// { +// return CartainerGrade.ContainsKey(cartainerId); +// } +// } +//} diff --git a/JinYuan.Models/SysConfig/Device.cs b/JinYuan.Models/SysConfig/Device.cs new file mode 100644 index 0000000..8b1b3ef --- /dev/null +++ b/JinYuan.Models/SysConfig/Device.cs @@ -0,0 +1,317 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; + +namespace JinYuan.Models +{ + /// + /// 通信设备实体类 + /// + public class Device + { + /// + /// IP地址 + /// + public string IPAddress { get; set; } + /// + /// 端口 + /// + public int Port { get; set; } + + /// + /// PLC类型 + /// + public string PLCType { get; set; } + /// + /// 当前设备的连接状态 + /// + + public bool IsConnected { get; set; } + + /// + /// 是否是首次连接 + /// + + public bool IsFirstConnect { get; set; } = true; + + /// + /// 重连周期 + /// + + public int ReConnectTime { get; set; } = 2000; + + /// + /// 休眠时间 + /// + + public int SleepTime { get; set; } = 10; + + /// + /// 大小端 + /// + [JsonIgnore] + public int DataFormat { get; set; } = 0; + /// + /// 出错次数 + /// + public int ErrorTimes { get; set; } + + /// + /// 容错次数 + /// + public int AllowErrorTimes { get; set; } = 3; + + /// + /// 多线程取消源标志位 + /// + public CancellationTokenSource Cts { get; set; } + + /// + /// 计时器 + /// + + public Stopwatch Stopwatch { get; set; } + + /// + /// 所有归档变量的集合 + /// + + public List StoreVarList { get; set; } = new List(); + + /// + /// 按工位读取 + /// + + public List WorkVarList { get; set; } = new List(); + /// + /// 通信组集合 + /// + public List GroupList { get; set; } = new List(); + /// + /// 所有变量的集合 + /// + public List VarList { get; set; } = new List(); + + /// + /// 所有变量名称与值的集合 + /// + public Dictionary CurrentValue { get; set; } = new Dictionary(); + + /// + /// 定义报警触发和消除事件 + /// + //public event Action AlarmTrigEvent; + + /// + /// 变量初始化 + /// + public void Init() + { + foreach (var gp in GroupList) + { + + if (gp.IsTiggerRead) + { + WorkVarList.Add(gp); + } + foreach (var variable in gp.VarList) + { + if (!gp.IsTiggerRead) + { + VarList.Add(variable); + + + if (CurrentValue.ContainsKey(variable.VarName)) + { + CurrentValue[variable.VarName] = "NA"; + } + else + { + CurrentValue.Add(variable.VarName, "NA"); + } + } + + } + } + } + + + + + /// + /// 索引器,通过键名获取到数据 + /// + /// + /// + [JsonIgnore] + public object this[string key] + { + get + { + if (CurrentValue.ContainsKey(key)) + { + return CurrentValue[key]; + } + else + { + return null; + } + } + } + + /// + /// 实时更新 + /// + /// + public void Update(Variable variable) + { + //更新处理 + if (CurrentValue.ContainsKey(variable.VarName)) + { + CurrentValue[variable.VarName] = variable.VarValue; + } + else + { + CurrentValue.Add(variable.VarName, variable.VarValue); + } + + //报警处理 + if (variable.HighAlarmEnable || variable.LowAlarmEnable) + { + float compareValue = 0.0f; + + if (variable.DataType.ToLower() == "bool") + { + compareValue = Convert.ToBoolean(variable.VarValue) ? 1.0f : 0.0f; + } + else + { + compareValue = Convert.ToSingle(variable.VarValue); + } + + int compareResult = 0; + //高报警时,触发事件 + if (variable.HighAlarmEnable) + { + compareResult = Compare(compareValue, variable.HighAlarmValue, variable.HighAlarmCacheValue, true); + + if (compareResult != 0) + { + //通过事件做通知 + + OnAlarmAckEvent(variable, new AlarmEventArgs() + { + Name = variable.VarName, + CurrentValue = variable.VarValue.ToString(), + SetValue = variable.HighAlarmValue.ToString(), + AlarmNote = variable.HighAlarmNote, + IsTrigger = compareResult == 1 + }); + } + + variable.HighAlarmCacheValue = compareValue; + } + else + { + compareResult = Compare(compareValue, variable.LowAlarmValue, variable.LowAlarmCacheValue, false); + + if (compareResult != 0) + { + //通过事件做通知 + + OnAlarmAckEvent(variable, new AlarmEventArgs() + { + Name = variable.VarName, + CurrentValue = variable.VarValue.ToString(), + SetValue = variable.LowAlarmValue.ToString(), + AlarmNote = variable.LowAlarmNote, + IsTrigger = compareResult == 1 + }); + + } + variable.LowAlarmCacheValue = compareValue; + } + } + } + + /// + /// 报警触发的事件 + /// + //public event AlarmTriggerEventDelegate AlarmTriggerEvent; + + /// + /// 触发事件 + /// + /// + /// + private void OnAlarmAckEvent(object sender, AlarmEventArgs e) + { + //AlarmTriggerEvent?.Invoke(sender, e); + } + + /// + /// 报警比较 + /// + /// 当前值 + /// 设置值 + /// 缓存值 + /// 上升沿还是下降沿 + /// 比较结果,1表示触发,-1表示消除,0表示无变化 + private int Compare(float current, float set, float last, bool isPositive) + { + if (isPositive) + { + if (current >= set && last < set) + { + return 1; + } + if (current < set && last >= set) + { + return -1; + } + } + else + { + if (current <= set && last > set) + { + return 1; + } + if (current > set && last <= set) + { + return -1; + } + } + return 0; + } + } + + public class AlarmEventArgs : EventArgs + { + /// + /// 变量名称 + /// + public string Name { get; set; } + + /// + /// 当前值 + /// + public string CurrentValue { get; set; } + + /// + /// 报警说明 + /// + public string AlarmNote { get; set; } + + /// + /// 报警设定值 + /// + public string SetValue { get; set; } + + /// + /// 是否为触发 + /// + public bool IsTrigger { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/Enum.cs b/JinYuan.Models/SysConfig/Enum.cs new file mode 100644 index 0000000..0698d68 --- /dev/null +++ b/JinYuan.Models/SysConfig/Enum.cs @@ -0,0 +1,18 @@ +namespace JinYuan.Models +{ + /// + /// 所有窗体枚举,小于临界窗体的为固定窗体,不执行关闭 + /// + public enum FormNames + { + 集中监控, + 数据监控, + 日志报警, + 临界窗体, + 电池状况, + 数据追溯, + 参数设置, + 系统设置, + 用户管理 + } +} diff --git a/JinYuan.Models/SysConfig/FDConfig.cs b/JinYuan.Models/SysConfig/FDConfig.cs new file mode 100644 index 0000000..69481a2 --- /dev/null +++ b/JinYuan.Models/SysConfig/FDConfig.cs @@ -0,0 +1,36 @@ +using SqlSugar; + +namespace JinYuan.Models +{ + public class FDConfig + { + /// + /// 编号 + /// + + public int FdNum { get; set; } + /// + /// OK拉带类型1 + /// + public string Grade1 { get; set; } + /// + /// OK拉带类型2 + /// + public string Grade2 { get; set; } + /// + /// OK拉带类型3 + /// + public string Grade3 { get; set; } + /// + /// 是否开启分档 + /// + public bool IsFDActive { get; set; } + /// + ///是否激活NG电池不分类排出 + /// + + //public bool IsNGActive { get; set; } + + + } +} diff --git a/JinYuan.Models/SysConfig/FDConfigMapping.cs b/JinYuan.Models/SysConfig/FDConfigMapping.cs new file mode 100644 index 0000000..bf1dd25 --- /dev/null +++ b/JinYuan.Models/SysConfig/FDConfigMapping.cs @@ -0,0 +1,18 @@ +using SqlSugar; + +namespace JinYuan.Models +{ + public class FDConfigMapping + { + /// + /// 编号 + /// + public int FDNum { get; set; } + /// + /// 分档类型 + /// + public string FDName { get; set; } + + public string ModelType { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/Group.cs b/JinYuan.Models/SysConfig/Group.cs new file mode 100644 index 0000000..c1286ed --- /dev/null +++ b/JinYuan.Models/SysConfig/Group.cs @@ -0,0 +1,47 @@ +using MiniExcelLibs.Attributes; +using System.Collections.Generic; + +namespace JinYuan.Models +{ + /// + /// 通信组实体类 + /// + public class Group + { + /// + ///通信组名称 + /// + public string GroupName { get; set; } + /// + /// 起始地址 + /// + public string Start { get; set; } + /// + /// 长度 + /// + public ushort Length { get; set; } + /// + /// 是否为触发读取 + /// + public bool IsTiggerRead { get; set; } + + /// + /// 是否需要反馈结果到PLC + /// + public bool IsFeedbackPlc { get; set; } + + /// + /// 是否启用 + /// + public bool IsActive { get; set; } + /// + /// 备注说明 + /// + public string Remark { get; set; } + /// + /// 变量集合 + /// + [ExcelIgnore] + public List VarList { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/PLCConfig.cs b/JinYuan.Models/SysConfig/PLCConfig.cs new file mode 100644 index 0000000..4af9511 --- /dev/null +++ b/JinYuan.Models/SysConfig/PLCConfig.cs @@ -0,0 +1,43 @@ +namespace JinYuan.Models +{ + public class PLCConfig + { + /// + /// PLC编号 + /// + + public int PlcNum { get; set; } + /// + /// PLC类型 + /// + public string PLCType { get; set; } + /// + /// IP地址 + /// + public string IPAddress { get; set; } + /// + /// 端口号 + /// + public string Port { get; set; } + /// + /// 心跳地址 + /// + + public string HeartBeat { get; set; } + /// + /// 是否启用心跳 + /// + + public bool IsHeartBeat { get; set; } + /// + ///PLC是否激活 + /// + + public bool IsActive { get; set; } + /// + /// 备注 + /// + public string Remark { get; set; } + + } +} diff --git a/JinYuan.Models/SysConfig/PLCGroupVariable.cs b/JinYuan.Models/SysConfig/PLCGroupVariable.cs new file mode 100644 index 0000000..463bb11 --- /dev/null +++ b/JinYuan.Models/SysConfig/PLCGroupVariable.cs @@ -0,0 +1,19 @@ +namespace JinYuan.Models +{ + public class PLCGroupVariable : Variable + { + /// + /// 变量名称 + /// + public int ArrayStart { get; set; } + + /// + /// 电池数量 + /// + public int CellSum { get; set; } + /// + /// 电池名称 + /// + public string BTName { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/ParamBase.cs b/JinYuan.Models/SysConfig/ParamBase.cs new file mode 100644 index 0000000..a7261e3 --- /dev/null +++ b/JinYuan.Models/SysConfig/ParamBase.cs @@ -0,0 +1,33 @@ +using SqlSugar; + +namespace JinYuan.Models +{ + /// + /// + /// + public class ParamBase + { + /// + /// + /// + public ParamBase() + { + } + + /// + /// 序号 + /// + public System.Int32? fNo { get; set; } + + /// + /// 参数名称 + /// + [SugarColumn(IsPrimaryKey = true)] + public System.String ParaName { get; set; } + + /// + /// 备注 + /// + public System.String Remark { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/ParamList.cs b/JinYuan.Models/SysConfig/ParamList.cs new file mode 100644 index 0000000..ef67072 --- /dev/null +++ b/JinYuan.Models/SysConfig/ParamList.cs @@ -0,0 +1,42 @@ +using SqlSugar; + +namespace JinYuan.Models +{ + public class ParamList + { + /// + /// + /// + [SugarColumn(IsPrimaryKey = true)] + public System.String ModelName { get; set; } + + /// + /// + /// + [SugarColumn(IsPrimaryKey = true)] + public System.String ParaName { get; set; } + + /// + /// + /// + public System.String ParaValueMin { get; set; } + /// + /// + /// + public System.String ParaValueMax { get; set; } + /// + /// + /// + public System.String Uint { get; set; } + + /// + /// + /// + public System.String Remark { get; set; } + + /// + /// + /// + public System.DateTime? UpdateTime { get; set; } = System.DateTime.Now; + } +} diff --git a/JinYuan.Models/SysConfig/PlcGroupConfig.cs b/JinYuan.Models/SysConfig/PlcGroupConfig.cs new file mode 100644 index 0000000..e78f56a --- /dev/null +++ b/JinYuan.Models/SysConfig/PlcGroupConfig.cs @@ -0,0 +1,128 @@ +namespace JinYuan.Models +{ + public class PlcGroupConfig + { + /// + /// PLC编号 + /// + private int _plcNum; + public int PlcNum + { + get => _plcNum; + set + { + if (_plcNum == value) return; + _plcNum = value; + + } + } + + /// + /// 通信组 + /// + private string _groupName; + public string GroupName + { + get => _groupName; + set + { + if (_groupName == value) return; + _groupName = value; + + } + } + + /// + /// 通信组起始地址 + /// + private string _start; + public string Start + { + get => _start; + set + { + if (_start == value) return; + _start = value; + + } + } + + private int _length; + + public int Length + { + get => _length; + set + { + if (_length == value) return; + _length = value; + + } + } + + + private bool _isTiggerRead; + /// + /// 是否触发读取 + /// + public bool IsTiggerRead + { + get => _isTiggerRead; + set + { + if (_isTiggerRead == value) return; + _isTiggerRead = value; + + } + } + + + private bool _isFeedbackPlc; + /// + ///是否有返回PLC + /// + public bool IsFeedbackPlc + { + get => _isFeedbackPlc; + set + { + if (_isFeedbackPlc == value) return; + _isFeedbackPlc = value; + + } + } + + private bool _isActive; + /// + /// 是否激活 + /// + public bool IsActive + { + get => _isActive; + set + { + if (_isActive == value) return; + _isActive = value; + + } + } + + private string _remark; + /// + /// 备注 + /// + public string Remark + { + get => _remark; + set + { + if (_remark == value) return; + _remark = value; + + } + + } + + + } +} diff --git a/JinYuan.Models/SysConfig/ProductModel.cs b/JinYuan.Models/SysConfig/ProductModel.cs new file mode 100644 index 0000000..a6aff95 --- /dev/null +++ b/JinYuan.Models/SysConfig/ProductModel.cs @@ -0,0 +1,21 @@ +using SqlSugar; + +namespace JinYuan.Models +{ + public class ProductModel + { + /// + /// + /// + [SugarColumn(IsPrimaryKey = true)] + public System.String ModelName { get; set; } + /// + /// 物料编码 + /// + public System.String MaterialCode { get; set; } + /// + /// + /// + public System.String Remark { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/ProductModelParam.cs b/JinYuan.Models/SysConfig/ProductModelParam.cs new file mode 100644 index 0000000..69433c3 --- /dev/null +++ b/JinYuan.Models/SysConfig/ProductModelParam.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models +{ + /// + /// 产品型号参数范围 + /// + public class ProductModelParam + { + /// + /// OCV内阻最大值 + /// + public decimal OcvIrMax { set; get; } + /// + /// OCV内阻最小值 + /// + public decimal OcvIrMin { set; get; } + + /// + /// OCV电压最大值 + /// + public decimal OcvVoltageMax { set; get; } + /// + /// OCV电压最小值 + /// + public decimal OcvVoltageMin { set; get; } + + /// + /// OCV静置时间最大值 + /// + public decimal OcvTimeMax { set; get; } + /// + /// OCV静置时间最小值 + /// + public decimal OcvTimeMin { set; get; } + + + /// + /// 常数A + /// + public decimal CoefficientA { get; set; } + /// + ///常数B + /// + public decimal ExponentB { get; set; } + + } +} diff --git a/JinYuan.Models/SysConfig/SysAdmin.cs b/JinYuan.Models/SysConfig/SysAdmin.cs new file mode 100644 index 0000000..068c4df --- /dev/null +++ b/JinYuan.Models/SysConfig/SysAdmin.cs @@ -0,0 +1,24 @@ +using SqlSugar; + +namespace JinYuan.Models +{ + /// + /// 登录实体类型 + /// + public class SysAdmin + { + [SugarColumn(IsPrimaryKey = true, IsIgnore = true)] + public int LoginId { get; set; } + public string LoginName { get; set; } + public string LoginPwd { get; set; } + public string LoginUid { get; set; } + public string LoginLevel { get; set; } + public bool SystemLog { get; set; } + public bool CpkData { get; set; } + public bool HistoryData { get; set; } + public bool ParamSet { get; set; } + public bool SystemSet { get; set; } + public bool UserManage { get; set; } + + } +} diff --git a/JinYuan.Models/SysConfig/SysConfig.cs b/JinYuan.Models/SysConfig/SysConfig.cs new file mode 100644 index 0000000..4d4866f --- /dev/null +++ b/JinYuan.Models/SysConfig/SysConfig.cs @@ -0,0 +1,88 @@ +namespace JinYuan.Models +{ + public class SysConfig + { + /// + /// 开机自动启动 + /// + public bool AutoStart { get; set; } + /// + ///启动自动登录 + /// + public bool AutoLogin { get; set; } + /// + ///无操作自动锁屏 + /// + public bool AutoLock { get; set; } + /// + ///锁屏间隙时间,单位是分钟 + /// + public int LockPeriod { get; set; } + + /// + ///无操作自动锁屏 + /// + public bool AutoQieHuanM { get; set; } + /// + ///锁屏间隙时间,单位是分钟 + /// + public int QieHuanMPeriod { get; set; } + /// + /// 调试模式 + /// + public bool IsDebugMode { get; set; } + /// + ///曲线显示数量 + /// + public int ShowSeriesCount { get; set; } + /// + /// 开启刷卡模式 + /// + public bool SwipeCardMode { get; set; } + /// + /// MES/非MES模式切换 + /// + public bool MesModeSwitching { get; set; } + /// + /// 成品电池/半成品电池绑盘 + /// + public bool FinishSwitching { get; set; } + /// + /// 切屏 + /// + public bool ScreenCutting { get; set; } + /// + /// 获取MES参数 + /// + public bool GetMesParam { get; set; } + + /// + /// 线程耗时日志保存 + /// + public bool SaveThreadTime { get; set; } + + /// + /// 开启无卷芯码进出站一体模式 + /// + public bool NoRollCodeMode { get; set; } + + /// + /// 开启物流线分拣模式 + /// + public bool WuLiu { get; set; } + + /// + /// 工位号 + /// + public string GongWei { get; set; } + /// + /// 生产线号 + /// + public string LineNo { get; set; } + /// + /// 机架号 + /// + public string StationNo { get; set; } + + } +} diff --git a/JinYuan.Models/SysConfig/SysLog.cs b/JinYuan.Models/SysConfig/SysLog.cs new file mode 100644 index 0000000..d1c82d1 --- /dev/null +++ b/JinYuan.Models/SysConfig/SysLog.cs @@ -0,0 +1,38 @@ +namespace JinYuan.Models +{ + public class SysLog + { + /// + /// 插入时间 + /// + public string InsertTime { get; set; } + /// + /// 报警类型 + /// + public string LogType { get; set; } + /// + /// 日志信息 + /// + public string Note { get; set; } + /// + /// 操作人员 + /// + public string Operater { get; set; } + /// + /// 变量名称 + /// + public string VarName { get; set; } + /// + /// 报警设置值 + /// + public string AlarmSet { get; set; } + /// + /// 报警值 + /// + public string AlarmValue { get; set; } + /// + /// 报警类型 + /// + public string AlarmType { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/Variable.cs b/JinYuan.Models/SysConfig/Variable.cs new file mode 100644 index 0000000..3bdcb52 --- /dev/null +++ b/JinYuan.Models/SysConfig/Variable.cs @@ -0,0 +1,103 @@ +using MiniExcelLibs.Attributes; + +namespace JinYuan.Models +{ + /// + /// 变量属性类 + /// + public class Variable + { + /// + /// 变量名称 + /// + public string VarName { get; set; } + + /// + /// 变量地址 + /// + public string VarAddress { get; set; } + /// + /// 起始索引 + /// + public string Start { get; set; } + /// + /// 数据类型 + /// + public string DataType { get; set; } + /// + /// 偏移或长度 + /// + public int OffsetOrLenght { get; set; } + /// + /// 所属通信组名称 + /// + public string GroupName { get; set; } + /// + /// 备注说明 + /// + public string Remark { get; set; } + /// + /// 是否上升沿报警 + /// + public bool PosAlarm { get; set; } + /// + /// 是否下降沿报警 + /// + public bool NegAlarm { get; set; } + /// + /// 转换系数 + /// + public float Scale { get; set; } = 1.0f; + /// + /// 偏移值 + /// + public float Offset { get; set; } = 0.0f; + + /// + /// 变量的值 + /// + [ExcelIgnore] + public object VarValue { get; set; } + + /// + /// 高报警启用 + /// + public bool HighAlarmEnable { get; set; } + + /// + /// 高报警设定值 + /// + public float HighAlarmValue { get; set; } + + /// + /// 高报警说明 + /// + public string HighAlarmNote { get; set; } + + /// + /// 高报警缓存值 + /// + [ExcelIgnore] + public float HighAlarmCacheValue { get; set; } + /// + /// 低报警启用 + /// + public bool LowAlarmEnable { get; set; } + + /// + /// 低报警设定值 + /// + public float LowAlarmValue { get; set; } + + /// + /// 低报警说明 + /// + public string LowAlarmNote { get; set; } + + /// + /// 低报警缓存值 + /// + [ExcelIgnore] + public float LowAlarmCacheValue { get; set; } + } +} diff --git a/JinYuan.Models/SysConfig/VariableConfig.cs b/JinYuan.Models/SysConfig/VariableConfig.cs new file mode 100644 index 0000000..1e0407e --- /dev/null +++ b/JinYuan.Models/SysConfig/VariableConfig.cs @@ -0,0 +1,121 @@ +namespace JinYuan.Models +{ + // 变量配置模型 + public class VariableConfig + { + + public string _varName; + + public string VarName + { + get => _varName; + set + { + if (_varName == value) return; + _varName = value; + + } + } + + public string _varAddress; + public string VarAddress + { + get => _varAddress; + set + { + if (_varAddress == value) return; + _varAddress = value; + + } + } + + public string _start; + public string Start + { + get => _start; + set + { + if (_start == value) return; + _start = value; + + } + } + + + public string _dataType; + public string DataType + { + get => _dataType; + set + { + if (_dataType == value) return; + _dataType = value; + + } + } + + + public int _offsetOrLength; + public int OffsetOrLength + { + get => _offsetOrLength; + set + { + if (_offsetOrLength == value) return; + _offsetOrLength = value; + + } + } + /// + /// PLC编号 + /// + private int _plcNum; + public int PlcNum + { + get => _plcNum; + set + { + if (_plcNum == value) return; + _plcNum = value; + + } + } + /// + /// 通信组 + /// + private string _groupName; + public string GroupName + { + get => _groupName; + set + { + if (_groupName == value) return; + _groupName = value; + + } + } + private string _remark; + public string Remark + { + get => _remark; + set + { + if (_remark == value) return; + _remark = value; + + } + + } + private string _stationName; + public string StationName + { + get => _stationName; + set + { + if (_stationName == value) return; + _stationName = value; + } + } + + } +} diff --git a/JinYuan.Models/TrayEntity.cs b/JinYuan.Models/TrayEntity.cs new file mode 100644 index 0000000..d376e38 --- /dev/null +++ b/JinYuan.Models/TrayEntity.cs @@ -0,0 +1,84 @@ +using JinYuan.Models.HelperAttribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using static System.Net.Mime.MediaTypeNames; + + +namespace JinYuan.Models +{ + public class TrayEntity + { + /// + /// 料框码(对应数据库TrayID字段) + /// + //[SugarColumn(ColumnName = "TrayID")] + [DataGridViewColumn(Name = "trayID")] + public string trayID { get; set; } + /// + /// 电池型号(对应数据库Model字段) + /// + //[SugarColumn(ColumnName = "Model")] + [DataGridViewColumn(Name = "model")] + public string model { get; set; } + + /// + /// 电池一级档位(对应数据库Grade字段) + /// + //[SugarColumn(ColumnName = "Grade")] + [DataGridViewColumn(Name = "grade")] + public string grade { get; set; } + + /// + /// 电池二级档位(对应数据库MoreGrade字段) + /// + //[SugarColumn(ColumnName = "MoreGrade")] + [DataGridViewColumn(Name = "moreGrade")] + public string moreGrade { get; set; } + + /// + /// 线体号(对应数据库LineNo字段) + /// + //[SugarColumn(ColumnName = "LineNo")] + [DataGridViewColumn(Name = "lineNo")] + public string lineNo { get; set; } + + /// + /// 备注(对应数据库Remark字段) + /// + //[SugarColumn(ColumnName = "Remark")] + [DataGridViewColumn(Name = "Remark")] + public string Remark { get; set; } + + /// + /// 进站时间(对应数据库Time字段) + /// + //[SugarColumn(ColumnName = "Time")] + [DataGridViewColumn(Name = "Time")] + public DateTime Time { get; set; } + + /// + /// 电池个数(对应数据库Count字段) + /// + //[SugarColumn(ColumnName = "Count")] + [DataGridViewColumn(Name = "Count")] + public int Count { get; set; } + + /// + /// 机架号(对应数据库GongWei字段) + /// + //[SugarColumn(ColumnName = "GongWei")] + [DataGridViewColumn(Name = "GongWei")] + public string GongWei { get; set; } + + /// + /// 结果(对应数据库Result字段) + /// + //[SugarColumn(ColumnName = "Result")] + [DataGridViewColumn(Name = "Result")] + public string Result { get; set; } + + } +} + diff --git a/JinYuan.Models/app.config b/JinYuan.Models/app.config new file mode 100644 index 0000000..90f0655 --- /dev/null +++ b/JinYuan.Models/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/JinYuan.Models/packages.config b/JinYuan.Models/packages.config new file mode 100644 index 0000000..c068d60 --- /dev/null +++ b/JinYuan.Models/packages.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JinYuan.VirtualDataLibrary/CommonMethods.cs b/JinYuan.VirtualDataLibrary/CommonMethods.cs new file mode 100644 index 0000000..736c498 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/CommonMethods.cs @@ -0,0 +1,990 @@ +using HML; +using JinYuan.DAL; +using JinYuan.Helper; +using JinYuan.MES; +using JinYuan.MES.Models; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary.Utlis; +using MiniExcelLibs; +using PLC; +using PLC.PLCAlarm; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Windows.Forms; +using System.Xml.Linq; + +namespace JinYuan.VirtualDataLibrary +{ + public class CommonMethods + { + public static readonly object SyncRoot = new object(); + + /// + /// 本地数据库 + /// + public static ISugarHelper db = new SQLSugarService(); + /// + /// 远程服务段数据库 + /// + public static ISugarHelper dbServer = new SQLSugarService(); + /// + /// 全局的PLC链接 + /// + public static List plcDevices; + /// + /// plc状态 + /// + public static readonly Dictionary> plcStatuses = new Dictionary>(); + /// + /// 报警 + /// + public static AlarmManager alarmManager = new AlarmManager(); + /// + /// MES接口 + /// + public static IMes hbgMes = new MesDataProcess(); + /// + /// 参数 + /// + public static ProductModelParam parRange = new ProductModelParam(); + /// + /// 全局钩子 + /// + public static ScanerHook listener = new ScanerHook(); + + /// + /// 创建个全局焊接功率队列数据存储 + /// + public static List> QWeldingPowerData = new List>(); + + /// + /// 创建个全局入壳推力队列数据存储 + /// + public static List> QPlanenessData = new List>(); + + /// + /// 创建全局的登录对象 + /// + public static SysAdmin currentAdmin = null; + /// + /// 创建全局的登录对象 + /// + public static List listNgCodeEntity = new List(); + /// + /// 登录是否成功 + /// + public static bool IsLoginOk = false; + + //创建一个全局的配置对象 + public static SysConfig sysConfig = new SysConfig(); + + public static int InvadTime; + /// + /// 智能电表 + /// + public static List listElectricEnergy = new List(); + + /// + /// 电能表 + /// + public static EnergyMeterHelper energyMeter = new EnergyMeterHelper(); + + /// + ///是否开启刷新 + /// + public static bool isRefreshTimerWeeding = false; + + /// + /// SQL语句 + /// + public static DBSQL dBSQL { get; } = new DBSQL(); + + public static M_DBCtrl m_DBCtrl { get; } = new M_DBCtrl(); + + /// + /// MES配置文件类 + /// + public static MesConfig mesConfig = new MesConfig(); + + /// + /// 打印模板配置文件类 + /// + public static BTWConfig btwConfig = new BTWConfig(); + + ///创建一个全局的连接状态 + public static bool connectState = false; + + /// + /// 滴答次数 + /// + public static int tickCount = 0; + /// + /// QIEHUAN + /// + public static int tickHomeCount = 0; + + /// + /// 报警信息 + /// + public static string SlideAlarmText = "当前无报警"; + /// + /// 退出 + /// + public static bool IsExit = false; + /// + /// 是否登出账户 + /// + public static bool LoginOut = false; + /// + /// 是否上传MES + /// + public static bool IsUpMes { get; set; } + /// + /// 是否运行 + /// + public static bool IsRun { get; set; } = false; + /// + /// 上一次设备状态 + /// + public static int DeviceStatus = 0; + /// + /// 上一次Guid + /// + public static string DeviceGuid = ""; + /// + ///第一次读取 + /// + public static bool IsFirst = false; + /// + /// 焊接功率波形图显示条数 + /// + public static int ChatLineCount = 3; + /// + /// 员工号 + /// + public static string strWorker { get; set; } + /// + /// 是否开启智能电表 + /// + public static bool IsStartZNDB { get; set; } = false; + /// + /// 白夜班 + /// + public static string strClass { get; set; } = "白班"; + /// + /// 时间变更 + /// + public static string ChangeClassTime { get; set; } = "20:30:00"; + /// + /// 设备状态 + /// + public static List Statues { get; set; } + + /// + /// 服务器链接状态 + /// + public static bool EMCStatues { get; set; } + + #region 小时产能 + /// + /// 上个时间点的总数 + /// + public static int LastTotalNum { get; set; } = 0; + /// + /// 上个时间点良品数 + /// + public static int LastOkNum { get; set; } = 0; + /// + /// 上一次重置计数的时间 + /// + public static string LastResetTime { get; set; } + /// + /// 上一次的小时 + /// + public static int LastHour { get; set; } + #endregion + + /// + /// + /// + public static List ListOmronGroups { get; set; } + + /// + /// 12小时产能 + /// + public static List Lst_Prod12HourData = new List(); + /// + /// 不良选项(检测项不良) + /// + public static List Lst_DefectTypeQty = new List(); + + /// + /// PLC报警前10项 + /// + public static List Lst_AlarmTop10_Qty = new List(); + /// + /// 参数项设置 + /// + public static List paramlists { get; set; } + + /// + /// 线程控制 + /// + public static ManualResetEvent ResetEventRecv = new ManualResetEvent(true); + + + #region 计数项 + /// + /// 生产总数 + /// + public static float TotalQty = 0; + + public static float ProOKQty = 0; + + public static float Ppm = 0; + + public static double JiaDL = 0.0; + + public static List AntiDustAirSpeed = new List(); + /// + /// PLC开机/运行时间 + /// + public static List PlcOpenAndRunTime = new List(); + /// + /// PLC开机/运行时间地址 + /// + public static List PlcOpenAndRunTimeAdress = new List { "D50", "D52", "D54", "D56", "D58", "D60" }; + public static int ProdGaoRFIDNgQty = 0;//高托杯 绑定卷心码 + public static int ProdDiRFIDNgQty = 0;//低托杯 绑定钢壳码 + + public static int ProdGangKeRFIDNgQty = 0;//钢壳托杯 绑定出站钢壳码 + public static int ProdJuanBarNgQty = 0; + public static int ProdGangKeBarNgQty = 0; + + public static int ProdRuKeTuiliNgQty = 0; + public static int ProdCCDNgQty = 0; + public static int ProdMesOutNGQty = 0; + #endregion + + #region 配置信息 + /// + /// 错误日志路径 + /// + public static string strErrorLogspath = "D:\\APILog\\Logs\\ErrorLogs"; + + public static string strSystemLogspath = "D:\\APILog\\Logs\\SystemLogs"; + public static string strAlarmLogspath = "D:\\APILog\\Logs\\AlarmLogs"; + + public static string strsqlLogspath = ""; + /// + /// 删除路径 + /// + public static string strDeletepath = ""; + /// + /// 能耗保存路径 + /// + public static string strWattrMeterpath = "D:\\APILog\\Logs\\智能电表数据"; + /// + /// MES路径日志 + /// + public static string strMesLogspath = "D:\\APILog\\Logs\\MesLogs"; + /// + /// 主界面下列表绑定数据 + /// + public static DropDownListPlusItemCollection DropDownItemList = new DropDownListPlusItemCollection(); + + /// + /// 设备状态信息路径 + /// + public static string strDeviceStatusPath = System.Windows.Forms.Application.StartupPath + "\\Config\\DeviceStatus.cfg"; + + + /// + /// PLC读取寄存器配置文件路径 + /// + public static string ConfigPath = Path.Combine(System.Windows.Forms.Application.StartupPath, "ini\\PlcConfig.ini"); + /// + /// 系统程序配置文件路径 + /// + //public static string iniFilePath = Path.Combine(System.Windows.Forms.Application.StartupPath, "ini\\Configure.ini"); + + public static string xmlFilePath = Path.Combine(System.Windows.Forms.Application.StartupPath, "Config\\Configure.xml"); + /// + /// 配置文件字典 + /// + public static Dictionary> Configxml = new Dictionary>(); + + + #region 读取配置文件 + + // 读取 XML 配置文件 + public static Dictionary> ReadXmlConfig(string filePath) + { + var config = new Dictionary>(); + if (!File.Exists(filePath)) + { + MessageBox.Show($"配置文件不存在:{filePath}\n请检查Config文件夹是否存在,且包含Configure.xml文件"); + return config; + } + + XDocument xmlDoc = XDocument.Load(filePath); + + foreach (var sectionElement in xmlDoc.Root.Elements()) + { + string sectionName = sectionElement.Name.LocalName; + config[sectionName] = new Dictionary(); + + foreach (var keyElement in sectionElement.Elements()) + { + string key = keyElement.Name.LocalName; + string value = keyElement.Value; + config[sectionName][key] = value; + } + } + + return config; + } + + // 获取配置值 + public static string GetConfigValue(Dictionary> config, string section, string key, string defaultValue) + { + if (config.ContainsKey(section) && config[section].ContainsKey(key)) + { + return config[section][key]; + } + return defaultValue; + } + + + // 写入 XML 文件 + public static void WriteXmlFile(Dictionary> config, string filePath) + { + XDocument xmlDoc = new XDocument(new XElement("Configuration")); + + foreach (var section in config) + { + var sectionElement = new XElement(section.Key); + foreach (var keyValue in section.Value) + { + sectionElement.Add(new XElement(keyValue.Key, keyValue.Value)); + } + xmlDoc.Root.Add(sectionElement); + } + xmlDoc.Save(filePath); + } + + /// + /// 单个配置数据保存 + /// + /// + /// + /// + public static void UpdateConfig(string INFO, string Type, string value) + { + // 更新 Configxml 中的 SteelshellCount + CommonMethods.Configxml[INFO][Type] = value; + + // 将更新后的 Configxml 写入文件 + CommonMethods.WriteXmlFile(CommonMethods.Configxml, CommonMethods.xmlFilePath); + } + + + /// + ///读取配置文件 + /// + public static SysConfig GetSysConfig() + { + try + { + // 读取配置项 + string line_gongwei = GetConfigValue(Configxml, "CONFIG_INFO", "EquipNo", "1-1"); + + // 安全拆分EquipNo + string[] gongweis = !string.IsNullOrWhiteSpace(line_gongwei) ? line_gongwei.Split('-') : new string[0]; + + // 安全获取LineNo + string lineNo = gongweis.Length >= 1 && !string.IsNullOrWhiteSpace(gongweis[0]) ? gongweis[0].Trim() : "1"; + // 安全获取StationNo + string stationNo = gongweis.Length >= 2 && !string.IsNullOrWhiteSpace(gongweis[1]) ? gongweis[1].Trim() : "1"; + + #region 系统配置文件 + return sysConfig = new SysConfig + { + AutoStart = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "AutoStart", "true")), + AutoLogin = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "AutoLogin", "true")), + AutoLock = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "AutoLockScreen", "false")), + LockPeriod = Convert.ToInt32(GetConfigValue(Configxml, "CONFIG_INFO", "LockIntervalTime", "0")), + AutoQieHuanM = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "AutoSwitchMonitor", "false")), + QieHuanMPeriod = Convert.ToInt32(GetConfigValue(Configxml, "CONFIG_INFO", "SwitchMonitorInterval", "0")), + ShowSeriesCount = Convert.ToInt32(GetConfigValue(Configxml, "CONFIG_INFO", "CurveDisplayCount", "0")), + SwipeCardMode = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "EnableCardMode", "false")), + MesModeSwitching = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "MESModeSwitch", "false")), + FinishSwitching = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "FinishSwitch", "false")), + GetMesParam = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "FetchMESParams", "false")), + SaveThreadTime = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "SaveThreadTimeLog", "false")), + IsDebugMode = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "IsDebugMode", "true")), + WuLiu = Convert.ToBoolean(GetConfigValue(Configxml, "CONFIG_INFO", "WuLiu", "false")), + GongWei = string.IsNullOrWhiteSpace(line_gongwei) ? "1-1" : line_gongwei, + LineNo = lineNo, + StationNo = stationNo + }; + #endregion + } + catch (Exception) + { + return sysConfig = null; + } + } + + /// + /// 获取MES配置文件 + /// + public static MesConfig GetMesConfig() + { + try + { + #region MES配置文件 + return mesConfig = new MesConfig + { + siteCode = GetConfigValue(Configxml, "MES_CONFIG", "SiteCode", "57M"), + lineCode = GetConfigValue(Configxml, "MES_CONFIG", "LineCode", "PW-571"), + equipNum = GetConfigValue(Configxml, "MES_CONFIG", "EquipNum", "571VIM01"), + CustomerPartNum = GetConfigValue(Configxml, "MES_CONFIG", "CustomerPartNum", "491VIM01"), + MESURLAddressIP = GetConfigValue(Configxml, "MES_CONFIG", "MESIp", "10.100.111.81"), + MESURLAddressPort = GetConfigValue(Configxml, "MES_CONFIG", "MESPort", "80"), + EmployeeAuthCheck = GetConfigValue(Configxml, "MES_CONFIG", "EmployeeAuthCheck", "571VIM01"), + DeviceParamRequest = GetConfigValue(Configxml, "MES_CONFIG", "DeviceParamRequest", "571VIM01"), + DeviceParamChange = GetConfigValue(Configxml, "MES_CONFIG", "DeviceParamChange", "491581VIM01VIM01"), + DeviceAlarm = GetConfigValue(Configxml, "MES_CONFIG", "DeviceAlarm", "581VIM01"), + DeviceStatus = GetConfigValue(Configxml, "MES_CONFIG", "DeviceStatus", "581VIM01"), + EnergyConsumption = GetConfigValue(Configxml, "MES_CONFIG", "EnergyConsumption", "581VIM01"), + Anemometer = GetConfigValue(Configxml, "MES_CONFIG", "Anemometer", "581VIM01"), + queryTrayUrl = GetConfigValue(Configxml, "MES_CONFIG", "QueryTrayUrl", ""), + queryGradeUrl = GetConfigValue(Configxml, "MES_CONFIG", "QueryGradeUrl", ""), + upResultParamUrl = GetConfigValue(Configxml, "MES_CONFIG", "UpResultParamUrl", ""), + packLoadUrl = GetConfigValue(Configxml, "MES_CONFIG", "PackLoadUrl", ""), + finishedPackUrl = GetConfigValue(Configxml, "MES_CONFIG", "finishedPackUrl", ""), + unbindTrayUrl = GetConfigValue(Configxml, "MES_CONFIG", "unBindTrayUrl", ""), + packLayers = int.Parse(GetConfigValue(Configxml, "MES_CONFIG", "PackLayers", "4")), + rowsPerLayer = int.Parse(GetConfigValue(Configxml, "MES_CONFIG", "RowsPerLayer", "5")), + colsPerLayer = int.Parse(GetConfigValue(Configxml, "MES_CONFIG", "ColsPerLayer", "12")), + }; + + #endregion + } + catch (Exception) + { + return mesConfig = null; + } + } + + public static List fdConfigs; + public static FDConfig curFdConfig; //垛位分档信息 + public static List FDConfigMappings { get; set; } = new List(); + public static FDConfigMapping CurrentFDConfig { get; set; } + public static void LoadFDConfig() + { + FDConfig fdconfig = null; + string FdConfigFilePath = CommonMethods.FdConfigFilePath; //Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config/FdConfig.xlsx"); + + if (File.Exists(FdConfigFilePath)) + { + using (var stream = File.OpenRead(FdConfigFilePath)) + { + var devices = MiniExcel.Query(stream).ToList(); + CommonMethods.fdConfigs = devices.Select(device => new FDConfig + { + FdNum = device.FdNum, + Grade1 = device.Grade1, + Grade2 = device.Grade2, + Grade3 = device.Grade3, + IsFDActive = device.IsFDActive, + }).ToList(); + CommonMethods.curFdConfig = CommonMethods.fdConfigs[CommonMethods.fdConfigs.Count - 1]; + } + } + } + + /// + /// 加载分档配置 + /// + public static void LoadFDConfigMappings() + { + try + { + string fdConfigPath = CommonMethods.FdConfigMappingPath;//Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", "fd_config.xlsx"); + if (File.Exists(fdConfigPath)) + { + FDConfigMappings = MiniExcel.Query(fdConfigPath).ToList(); + } + else + { + FDConfigMappings = new List(); + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"加载分档配置失败:{ex.Message}", "SysErrorLog"); + FDConfigMappings = new List(); + } + } + + /// + /// 根据机架号获取分档配置 + /// + public static string GetFDConfigByStation(int stationNo) + { + if (stationNo == 1) + return curFdConfig.Grade1; + else if(stationNo == 2) + return curFdConfig.Grade2; + else if (stationNo == 3) + return curFdConfig.Grade3; + return ""; + } + + /// + /// 将电池等级转换成下发PLC的等级编号 + /// + /// + /// + public static int GetGradeNo(string strGrade) + { + if (string.IsNullOrEmpty(strGrade)) return 99; + if (strGrade == "NG" || strGrade == "拦截") + return 99; + if (strGrade == "不设置") + return 90; + var config = FDConfigMappings?.FirstOrDefault(x => x.FDName == strGrade); + return config != null ? (short)config.FDNum : 99; + } + + public static List FDGradeTypes = new List(); + + public static void LoadFDGradeTypes() + { + try + { + string fdConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", "FdConfigMapping.xlsx"); + if (File.Exists(fdConfigPath)) + { + var configs = MiniExcel.Query(fdConfigPath).ToList(); + var types = configs.Select(x => x.FDName).Distinct().ToList(); + + // 确保包含 "不设置" 和 "NG" + if (!types.Contains("不设置")) + types.Insert(0, "不设置"); + if (!types.Contains("NG")) + types.Add("NG"); + + FDGradeTypes = types; + } + else + { + FDGradeTypes = new List { "不设置", "NG" }; + } + } + catch (Exception ex) + { + Console.WriteLine($"LoadFDGradeTypes error: {ex.Message}"); + FDGradeTypes = new List { "不设置", "NG" }; + } + } + + public static List GetValidGrades() + { + List grades = new List(); + if (curFdConfig != null) + { + if (curFdConfig.Grade1 != null && curFdConfig.Grade1 != "NG" && curFdConfig.Grade1 != "不设置") + { + grades.Add(curFdConfig.Grade1); + } + if (curFdConfig.Grade2 != null && curFdConfig.Grade2 != "NG" && curFdConfig.Grade2 != "不设置") + { + grades.Add(curFdConfig.Grade2); + } + if (curFdConfig.Grade3 != null && curFdConfig.Grade3 != "NG" && curFdConfig.Grade3 != "不设置") + { + grades.Add(curFdConfig.Grade3); + } + grades = grades.Distinct().ToList(); + } + return grades; + } + + /// + /// 获取BTW配置文件 + /// + public static BTWConfig GetBtwConfig() + { + try + { + #region 打印模板路径配置文件 + return btwConfig = new BTWConfig + { + containerBTWPath = GetConfigValue(Configxml, "BTW_CONFIG", "ContainerBTWPath", ""), + printerName = GetConfigValue(Configxml, "BTW_CONFIG", "PrinterName", ""), + }; + #endregion + } + catch (Exception) + { + return btwConfig = null; + } + } + + #endregion + + public static string deviceConfigPath = Application.StartupPath + "\\Config\\Device.xlsx"; + public static string groupConfigPath = Application.StartupPath + "\\Config\\Group.xlsx"; + public static string variableConfigPath = Application.StartupPath + "\\Config\\Variable.xlsx"; + public static string FdConfigFilePath = Application.StartupPath + "\\Config\\FdConfig.xlsx"; + public static string FdConfigMappingPath = Application.StartupPath + "\\Config\\FdConfigMapping.xlsx"; + + + #region 保存配置文件 + /// + /// 保存启动自动登录 + /// + /// + /// + public static bool SaveAutoStart(bool value) + { + Configxml["CONFIG_INFO"]["AutoStart"] = value.ToString(); // 修改自动登录为 True + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + /// + /// 保存开机自动启动 + /// + /// + /// + public static bool SaveAutoLogin(bool value) + { + Configxml["CONFIG_INFO"]["AutoLogin"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 保存无操作自动锁屏 + /// + /// + /// + public static bool SaveAutoLock(bool value) + { + Configxml["CONFIG_INFO"]["AutoLockScreen"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 保存锁屏间隔时间 + /// + /// + /// + public static bool SaveLockPeriod(int value) + { + Configxml["CONFIG_INFO"]["LockIntervalTime"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + + /// + /// 保存无操作自动切换监控界面 + /// + /// + /// + public static bool SaveAutoQieHuanM(bool value) + { + Configxml["CONFIG_INFO"]["AutoSwitchMonitor"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + + /// + /// 保存无操作自动切换监控界面 + /// + /// + /// + public static bool SaveIsDebug(bool value) + { + Configxml["CONFIG_INFO"]["IsDebugMode"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 保存物流线分拣 + /// + /// + /// + public static bool SaveWuLiu(bool value) + { + Configxml["CONFIG_INFO"]["WuLiu"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 保存切换监控界面间隔时间 + /// + /// + /// + public static bool SaveQieHuanMPeriod(int value) + { + Configxml["CONFIG_INFO"]["SwitchMonitorInterval"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 保存曲线显示数量 + /// + /// + /// + public static bool SaveShowSeriesCount(int value) + { + Configxml["CONFIG_INFO"]["CurveDisplayCount"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 开启刷卡模式 + /// + /// + /// + public static bool SaveSwipeCardMode(bool value) + { + Configxml["CONFIG_INFO"]["EnableCardMode"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + /// + /// MES/非MES模式 + /// + /// + /// + public static bool SaveOpenMesModel(bool value) + { + Configxml["CONFIG_INFO"]["MESModeSwitch"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 成品/半成品切换 + /// + /// + /// + public static bool SaveFinishSwitch(bool value) + { + Configxml["CONFIG_INFO"]["FinishSwitch"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + /// + /// 保存机架号 + /// + /// + /// + public static bool SaveEquipNo(string value) + { + Configxml["CONFIG_INFO"]["EquipNo"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + + /// + /// 获取MES参数 + /// + /// + /// + public static bool SaveGetMesParam(bool value) + { + Configxml["CONFIG_INFO"]["FetchMESParams"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + + /// + /// 保存线程耗时操作 + /// + /// + /// + public static bool SaveSaveThreadTime(bool value) + { + Configxml["CONFIG_INFO"]["SaveThreadTimeLog"] = value.ToString(); + WriteXmlFile(Configxml, xmlFilePath); + return true; + } + #endregion + + #endregion + + #region 委托信息 + //创建委托 + // 数据监视委托 + public static Action AddDataMonitorDelegate; + /// + /// 系统日志 + /// + public static Action AddLogDelegate; + /// + /// 操作日志 + /// + public static Action AddOPLogDelegate; + /// + /// 报警日志 + /// + public static Action AddAlarmDelegate; + /// + /// 显示报警信息 + /// + public static Action ShowAlarmDelegate; + /// + /// 参数更新 + /// + public static Action ChangeParamDelegate; + /// + /// + /// + public static Action AddHomeDelegate; + + /// + /// 显示组盘信息 + /// + public static Action> ShowFeedingDelegate; + /// + /// 显示组盘抽检信息 + /// + public static Action> ShowReFeedingDelegate; + /// + /// 显示叠盘数据 + /// + public static Action> ShowBlankingDelegate; + /// + /// 显示底托拉板绑定信息 + /// + public static Action> ShowMaterialDelegate; + /// + /// 显示料框码进站信息 + /// + public static Action> ShowTrayDataDelegate; + /// + /// 电池状态委托 + /// + public static Action> ShowBatteryStatusDelegate; + /// + /// 满层后,展示电池二维码 + /// + //public static Action> ShowBatteryQRCoderDelegate; + /// + /// 档位NG原因委托 + /// + public static Action> ShowBatteryNGRsnDelegate; + /// + /// 显示电池替换信息 + /// + public static Action> ShowBatteryReplaceDelegate; + /// + /// 显示卡板打印信息 + /// + public static Action> ShowLabellingMachineDelegate; + + /// + /// 数据监视委托 + /// + /// + /// + public static void AddDataMonitorLog(int type, string info) + { + //调用委托 + if (AddDataMonitorDelegate != null) + { + AddDataMonitorDelegate(type, info); + } + } + + /// + /// 写入系统日志 + /// + /// 是否为错误信息 + /// 日志信息 + public static void AddLog(bool isError, string info) + { + //调用委托 + if (AddLogDelegate != null) + { + AddLogDelegate(isError, info); + } + } + /// + /// 写入操作日志 + /// + /// + /// + public static void AddOPLog(bool isError, string info) + { + //调用委托 + if (AddLogDelegate != null) + { + AddOPLogDelegate(isError, info); + } + } + + public static void AddAlarmLog(SysLog sysLog) + { + //调用委托 + if (AddAlarmDelegate != null) + { + AddAlarmDelegate(sysLog); + } + } + + /// + /// 显示报警日志 + /// + /// + public static void ShowAlarmLog(string info) + { + //调用委托 + if (ShowAlarmDelegate != null) + { + ShowAlarmDelegate(info); + } + } + + public static void ChangeParamData() + { + //调用委托 + if (ChangeParamDelegate != null) + { + ChangeParamDelegate(); + } + } + #endregion + + /// + /// PLC变量集合 + /// KEY = VarAddress + /// + public static ConcurrentDictionary PLCVariable = new ConcurrentDictionary(); + + // 打印机 + /// + /// zebra + /// + public static BartenderPrinter containerPrint; + + } +} diff --git a/JinYuan.VirtualDataLibrary/DBSQL.cs b/JinYuan.VirtualDataLibrary/DBSQL.cs new file mode 100644 index 0000000..0df754e --- /dev/null +++ b/JinYuan.VirtualDataLibrary/DBSQL.cs @@ -0,0 +1,730 @@ +using JinYuan.Helper; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.VirtualDataLibrary +{ + public class DBSQL + { + + /// + /// 获取PLC换型参数绑定值 + /// + /// + /// + public string GetPlcParamSql(string modelName) + { + string strSql = $@"SELECT + '{modelName}' AS `ModelName`, + `pb`.`PLCAddress`, + `pc`.`PLCValue`, + `pc`.`UpdateTime`, + `pb`.`PLCRemark`, + `pb`.`OrderNum` + FROM + `Plcconfigbase` `pb` + LEFT JOIN + (SELECT * FROM `Plcconfig` WHERE `ModelName` = '{modelName}') `pc` + ON + `pb`.`PLCAddress` = `pc`.`PLCAddress` + ORDER BY + `pb`.`OrderNum`"; + + return strSql; + } + + /// + /// 获取产品型号参数 + /// + /// + /// + public string GetParamSql(string strModelType) + { + string strSql = $@"SELECT + `pb`.`ParaName`, + '{strModelType}' AS `ModelName`, + `pl`.`ParaValueMin`, + `pl`.`ParaValueMax`, + `pl`.`Uint`, + `pb`.`Remark`, + `pl`.`UpdateTime` + FROM + `Parambase` `pb` + LEFT JOIN + (SELECT * FROM `ParamList` WHERE `ModelName` = '{strModelType}') `pl` + ON + `pb`.`ParaName` = `pl`.`ParaName` + ORDER BY + `pb`.`fNo` ASC"; + + return strSql; + } + + + /// + /// 获取产品型号列表 + /// + /// + /// + public string GetProdTypeSql(string strProdType = "") + { + string strSql = @"SELECT * FROM ProductModel "; + if (strProdType != "") + { + strSql += string.Format(" where ModelName='{0}'", strProdType); + } + strSql += " order by ModelName"; + return strSql; + } + + + /// + /// 获取产品型号 + /// + /// + /// + public string GetProductParaByProdModel(string strModelType) + { + string strSql = $@"SELECT + `pb`.`ParaName`, + '{strModelType}' AS `ModelName`, + `pl`.`ParaValueMin`, + `pl`.`ParaValueMax`, + `pl`.`Uint`, + `pb`.`Remark`, + `pl`.`UpdateTime` + FROM + `Parambase` `pb` + LEFT JOIN + (SELECT * FROM `Paramlist` WHERE `ModelName` = '{strModelType}') `pl` + ON + `pb`.`ParaName` = `pl`.`ParaName` + ORDER BY + `pb`.`fNo` ASC"; + + return strSql; + } + + + public string GetPLCConfigBases() + { + string strSql = string.Format(@"SELECT * FROM `Plcconfigbase` ORDER BY `OrderNum`"); + + return strSql; + } + + + public string GetSysAdminSql() + { + string strSql = string.Format(@"SELECT + `LoginId`, + `LoginName`, + `LoginPwd`, + `LoginUid`, + `LoginLevel`, + `SystemLog`, + `CpkData`, + `HistoryData`, + `ParamSet`, + `SystemSet`, + `UserManage` + FROM + `SysAdmin`"); + + return strSql; + } + + /// + /// 查询历史数据 + /// + /// + /// + /// + /// + public string SelectHostData(int type, string strRfid, string strBarCode, string strDate1, string strDate2) + { + Dictionary outTypes = new Dictionary() + { + { 3, 1 }, + { 4, 2 } + }; + string strSql = string.Empty; + if (type == 0) + { + strSql = @"SELECT + DATE_FORMAT(`Time`, '%Y-%m-%d %H:%i:%s') AS `TestTime`, + `BarCode`, + `Location` AS `CellPosition`, + `TrayID` AS `RFID`, + `Model`, + `Grade` AS `CellGrade`, + `Gongwei`, + `Result`, + `Remark` + FROM + `AGearEntity` + WHERE + `Time` >= '" + strDate1 + "' AND `Time` <= '" + strDate2 + "'"; + + // 2. 安全拼接查询条件:参数化+CONCAT函数 + if (!string.IsNullOrEmpty(strRfid)) + { + strSql += " AND `TrayID` LIKE '%" + strRfid + "%'"; + } + + if (!string.IsNullOrEmpty(strBarCode)) + { + strSql += " AND `BarCode` LIKE '%" + strBarCode + "%'"; + } + } + else if (type == 1) //装箱或者强制出站 + { + strSql = @"SELECT + `identification` AS `BarCode`, + DATE_FORMAT(`packTime`, '%Y-%m-%d %H:%i:%s') AS `TestTime`, + `location` AS `CellPosition`, + `grade` AS `CellGrade`, + `containerCode` AS `ContainerCode`, + `packResult` AS `PackResult`, + `packFalseReason` AS `PackFailReason`, + CASE + WHEN `outStationType` = 1 THEN '满箱出站' + ELSE '强制出站' + END AS `OutStationType` + FROM + `BatteryEntity` + WHERE + `packTime` >= '" + strDate1 + "' and `packTime` <= '" + strDate2 + "' "; + + + // 安全拼接查询条件:参数化+CONCAT函数, + if (!string.IsNullOrEmpty(strRfid)) + { + strSql += " AND `containerCode` LIKE '%" + strRfid + "%'"; + } + + if (!string.IsNullOrEmpty(strBarCode)) + { + strSql += " AND `identification` LIKE '%" + strBarCode + "%'"; + } + } + else if (type == 2)//电芯替换 + { + strSql = @"SELECT + DATE_FORMAT(`ReplaceTime`, '%Y-%m-%d %H:%i:%s') AS `TestTime`, + `NewBarCode`, + `OldBarCode`, + `Location` AS `CellPosition`, + `VassoioID` AS `ContainerCode`, + `GongWei` AS `Gongwei`, + `Grade` AS `CellGrade`, + `Remark` + FROM + `BatteryReplace` + WHERE + `ReplaceTime` >= '" + strDate1 + "' and `ReplaceTime` <= '" + strDate2 + "' "; + + if (!string.IsNullOrEmpty(strRfid)) + { + strSql += " AND `VassoioID` LIKE '%" + strRfid + "%'"; + } + + if (!string.IsNullOrEmpty(strBarCode)) + { + string safeRfid = strRfid?.Replace("'", "''") ?? ""; + string safeBarCode = strBarCode?.Replace("'", "''") ?? ""; + + + strSql += $" AND (`NewBarCode` LIKE '%{safeRfid}%' OR `OldBarCode` LIKE '%{safeBarCode}%')"; + } + } + else + { + LogHelper.Instance.WriteError($"不支持的查询类型:{type}", "DataErrorLog"); + } + + return strSql; + } + + + /// + /// 查询报警历史数据 + /// + /// + /// + /// + /// + public string SelectHostAlarmData(string start, string end, int alarmType) + { + string strSql = ""; + switch (alarmType) + { + case 1: + strSql = @"SELECT + DATE_FORMAT(`AlarmTime`, '%Y-%m-%d %H:%i:%s') AS `AlarmTime`, + `PLCAdress`, + `AlarmContent`, + `AlarmCount`, + `Class` + FROM + `AlarmCountEntry` + WHERE + `AlarmTime` >= '" + start + "' AND `AlarmTime` <= '" + end + $"' AND `Class` = '{CommonMethods.strClass}'"; + break; + case 2: + strSql = @"SELECT + DATE_FORMAT(`AlarmTime`, '%Y-%m-%d %H:%i:%s') AS `AlarmTime`, + `PLCAdress`, + `AlarmContent`, + `AlarmCount`, + `Class` + FROM + `AlarmCountEntry` + WHERE + `AlarmTime` >= '" + start + "' AND `AlarmTime` <= '" + end + $"' AND `Class` = '{CommonMethods.strClass}'"; + break; + default: + case 0: + strSql = @"SELECT + DATE_FORMAT(`AlarmTime`, '%Y-%m-%d %H:%i:%s') AS `AlarmTime`, + `PLCAdress`, + `AlarmContent`, + `AlarmCount`, + `Class` + FROM + `AlarmCountEntry` + WHERE + `AlarmTime` >= '" + start + "' AND `AlarmTime` <= '" + end + "'"; + break; + } + #region 旧 + //if (alarmType == "全天") + //{ + // strSql = @"SELECT + // DATE_FORMAT(`AlarmTime`, '%Y-%m-%d %H:%i:%s') AS `AlarmTime`, + // `PLCAdress`, + // `AlarmContent`, + // `AlarmCount`, + // `Class` + // FROM + // `AlarmCountEntry` + // WHERE + // `AlarmTime` >= '" + start + "' AND `AlarmTime` <= '" + end + "'"; + //} + //else if (alarmType == "白班") + //{ + // strSql = @"SELECT + // DATE_FORMAT(`AlarmTime`, '%Y-%m-%d %H:%i:%s') AS `AlarmTime`, + // `PLCAdress`, + // `AlarmContent`, + // `AlarmCount`, + // `Class` + // FROM + // `AlarmCountEntry` + // WHERE + // `AlarmTime` >= '" + start + "' AND `AlarmTime` <= '" + end + "' AND `Class` = '白班'"; + //} + //else + //{ + // strSql = @"SELECT + // DATE_FORMAT(`AlarmTime`, '%Y-%m-%d %H:%i:%s') AS `AlarmTime`, + // `PLCAdress`, + // `AlarmContent`, + // `AlarmCount`, + // `Class` + // FROM + // `AlarmCountEntry` + // WHERE + // `AlarmTime` >= '" + start + "' AND `AlarmTime` <= '" + end + "' AND `Class` = '夜班'"; + //} + #endregion + return strSql; + } + + /// + /// 按日统计 + /// + /// + /// + /// + public string GetStaticByDay(string startDateTime, string endDateTime) + { + string strSql = $@"SELECT + DATE_FORMAT(`TestTime`, '%Y-%m-%d %H:00:00') AS `Day`, + `ProdIn`, + `ProdOut`, + `Ppm`, + CONCAT(CAST(ROUND(`JiaDL` * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN `ProdIn` > 0 THEN ROUND(COALESCE(`ProdOut`, 0) / COALESCE(`ProdIn`, 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{startDateTime}' AND '{endDateTime}' + GROUP BY + `TestTime`, `ProdOut`, `ProdIn`, `Ppm`, `JiaDL` + UNION ALL + SELECT + 'Total' AS `Day`, + SUM(`ProdIn`) AS ProdIn, + SUM(`ProdOut`) AS ProdOut, + AVG(`Ppm`) AS Ppm, + CONCAT(CAST(ROUND(AVG(`JiaDL`) * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN SUM(`ProdIn`) > 0 THEN ROUND(COALESCE(SUM(`ProdOut`), 0) / COALESCE(SUM(`ProdIn`), 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{startDateTime}' AND '{endDateTime}'"; + + return strSql; + } + + /// + /// 按周查询 + /// + /// + /// + /// + public string GetStaticByWeek(string startDateTime, string endDateTime) + { + string strSql = $@"SELECT + DATE_FORMAT(`TestTime`, '%Y-%m') AS `Week`, + SUM(`ProdIn`) AS ProdIn, + SUM(`ProdOut`) AS ProdOut, + AVG(`Ppm`) AS Ppm, + CONCAT(CAST(ROUND(`JiaDL` * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN SUM(`ProdIn`) > 0 THEN ROUND(COALESCE(SUM(`ProdOut`), 0) / COALESCE(SUM(`ProdIn`), 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{startDateTime}' AND '{endDateTime}' + GROUP BY + DATE_FORMAT(`TestTime`, '%Y-%m'), `JiaDL` + UNION ALL + SELECT + 'Total' AS `Week`, + SUM(`ProdIn`) AS ProdIn, + SUM(`ProdOut`) AS ProdOut, + AVG(`Ppm`) AS Ppm, + CONCAT(CAST(ROUND(AVG(`JiaDL`) * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN SUM(`ProdIn`) > 0 THEN ROUND(COALESCE(SUM(`ProdOut`), 0) / COALESCE(SUM(`ProdIn`), 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{startDateTime}' AND '{endDateTime}'"; + + return strSql; + } + + + /// + /// 按月查询 + /// + /// + /// + /// + public string GetStaticByMonth(string startDateTime, string endDateTime) + { + string strSql = $@"SELECT + DATE_FORMAT(`TestTime`, '%Y-%m') AS `Month`, + SUM(`ProdIn`) AS ProdIn, + SUM(`ProdOut`) AS ProdOut, + AVG(`Ppm`) AS Ppm, + CONCAT(CAST(ROUND(`JiaDL` * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN SUM(`ProdIn`) > 0 THEN ROUND(COALESCE(SUM(`ProdOut`), 0) / COALESCE(SUM(`ProdIn`), 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{startDateTime}' AND '{endDateTime}' + GROUP BY + DATE_FORMAT(`TestTime`, '%Y-%m'), `JiaDL` + UNION ALL + SELECT + 'Total' AS `Month`, + SUM(`ProdIn`) AS ProdIn, + SUM(`ProdOut`) AS ProdOut, + AVG(`Ppm`) AS Ppm, + CONCAT(CAST(ROUND(AVG(`JiaDL`) * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN SUM(`ProdIn`) > 0 THEN ROUND(COALESCE(SUM(`ProdOut`), 0) / COALESCE(SUM(`ProdIn`), 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{startDateTime}' AND '{endDateTime}'"; + + return strSql; + } + + /// + /// 按班次统计 + /// + /// + /// + /// + /// + public string GetStaticByShift(DateTime dateTime, int shift, string changeShiftTime) + { + string sDateTime1 = string.Empty; + string sDateTime2 = string.Empty; + if (shift == 0)// 白班 + { + DateTime sTempDateTime = Convert.ToDateTime($"{dateTime.ToString("yyyy-MM-dd")} {changeShiftTime}"); + + sDateTime1 = sTempDateTime.AddHours(-12).ToString("yyyy-MM-dd HH:mm:ss"); + sDateTime2 = sTempDateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + else + { + sDateTime1 = $"{dateTime.ToString("yyyy-MM-dd")} {changeShiftTime}"; + sDateTime2 = Convert.ToDateTime(sDateTime1).AddHours(12).ToString("yyyy-MM-dd HH:mm:ss"); + } + + string strsql = $@"SELECT + DATE_FORMAT(`TestTime`, '%Y-%m-%d %H:00:00') AS `TestTime`, + `ProdIn`, + `ProdOut`, + `Ppm`, + CONCAT(CAST(ROUND(`JiaDL` * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN `ProdIn` > 0 THEN ROUND(COALESCE(`ProdOut`, 0) / COALESCE(`ProdIn`, 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{sDateTime1}' AND '{sDateTime2}' + GROUP BY + `TestTime`, `ProdOut`, `ProdIn`, `Ppm`, `JiaDL` + UNION ALL + SELECT + 'Total' AS `Time`, + SUM(`ProdIn`) AS ProdIn, + SUM(`ProdOut`) AS ProdOut, + AVG(`Ppm`) AS Ppm, + CONCAT(CAST(ROUND(AVG(`JiaDL`) * 100, 1) AS CHAR(10)), '%') AS `JiaDL`, + CONCAT(CAST( + CASE + WHEN SUM(`ProdIn`) > 0 THEN ROUND(COALESCE(SUM(`ProdOut`), 0) / COALESCE(SUM(`ProdIn`), 0) * 100, 2) + ELSE 0 + END AS CHAR(10)), '%') AS `Prod` + FROM + `Hourprod` + WHERE + `TestTime` BETWEEN '{sDateTime1}' AND '{sDateTime2}'"; + + return strsql; + } + /// + /// 获取进站信息 + /// + /// + public string GetInTime(string strBarCode) + { + string strSql = $@"SELECT TestTime + ,BarCode + ,Result + ,Remark + FROM AGearEntity + WHERE BarCode = '{strBarCode}' + ORDER BY TestTime ASC"; + + return strSql; + } + + /// + /// 获取最新的数据 + /// + /// + public string GetStatic(string strDateTime) + { + + string strsql = $@" SELECT [FDate] + ,[FHour] + ,[ProdIn] + ,[ProdOut] + ,[TestTime] + FROM [dbo].[Hourprod] where FDate='{strDateTime}' order by TestTime desc"; + return strsql; + } + + /// + /// 根据条码查询是否存在 + /// + /// + /// + public string GetBarcode(string barCode) + { + string strSql = $@"SELECT EXISTS( + SELECT 1 + FROM `CGearEntity` + WHERE BarCode = '{barCode}') AS barcode_exists"; + return strSql; + } + + /// 根据条码获取进站时间最新的一条数据 + /// + /// + /// + public string GetInStationTop1Sql(string barCode) + { + string strSql = $@"SELECT + `ChannelNo`, + `TestTime`, + `RFID`, + `BarCode`, + `Result`, + `Remark`, + `Flag` + FROM + `AGearEntity` + WHERE `BarCode` = '{barCode}' ORDER BY `TestTime` DESC + LIMIT 1"; + return strSql; + } + + /// + /// 获取表头注释 按照设计顺序 + /// + /// + public string GetSqlFields(string tableName) + { + string strSql = $@"SELECT + COLUMN_NAME, + PLC.DataType, + COLUMN_COMMENT + FROM + INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_SCHEMA = 'largesquareone' AND TABLE_NAME = '{tableName}' + ORDER BY + ORDINAL_POSITION;"; + return strSql; + } + + + + /// + /// 根据档位获取当前档位中的所有电芯数据 + /// + /// + /// + public string GetGradeBatterySql(string grade) + { + string strSql = $@"SELECT + `identification`, + `locationBat`, + `grade`, + `innerContainerCode`, + `packResult`, + `packFalseReason` + FROM + `BatteryEntity` + WHERE `grade` = '{grade}' ORDER BY `TestTime` DESC"; + return strSql; + } + } + + public class M_DBCtrl + { + /// --本机数据库表名 + /// + /// + //public string machineInSQLTable = "agearentity"; + public string machineOutSQLTable = "bgearentity"; + + private string[] headerTextOut; + /// + /// 出站数据库表头 + /// + public string[] HeaderTextOut + { + get { return headerTextOut; } + set { headerTextOut = value; } + } + + /// 查询SQL数据库中的数据,并以string数组列表形式返回 + /// + /// + /// + /// 所查询到的数据,null表示不存在 + public List SQLAllDataSearchToStrArrList(string strSql) + { + List strResArrList = new List(); + List strResList = new List(); + try + { + DataTable dt = CommonMethods.db.QueryDataTable(strSql); + if (dt != null) + { + for (int i = 0; i < dt.Rows.Count; i++) + { + for (int j = 0; j < dt.Columns.Count; j++) + { + string resRow = dt.Rows[i][j].ToString(); + strResList.Add(resRow); + } + string[] strResArr = strResList.ToArray(); + strResList.Clear(); + strResArrList.Add(strResArr); + } + } + } + catch (Exception e) + { + return strResArrList = new List(); + } + return strResArrList; + } + + /// 根据下标在返回的数据库表信息 集合中获取相应数据 + /// index 0:字段 2:中文注释 1:变量类型int\char等 + /// + /// liststring[]类型的集合 + /// string[] 的下标 + /// + public String[] HeaderTextAssignment(List SqlList, int index) + { + string[] headStringlist = new string[SqlList.Count]; + // int i = 0; + try + { + for (int i = 0; i < SqlList.Count; i++) + { + headStringlist[i] = SqlList[i][index]; + } + } + catch (Exception) + { + } + return headStringlist; + } + } +} diff --git a/JinYuan.VirtualDataLibrary/DelegateLib.cs b/JinYuan.VirtualDataLibrary/DelegateLib.cs new file mode 100644 index 0000000..02df4dc --- /dev/null +++ b/JinYuan.VirtualDataLibrary/DelegateLib.cs @@ -0,0 +1,47 @@ + +using JinYuan.Models; +using PLCCommunication; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.VirtualDataLibrary +{ + + public delegate void dgStationFunction(JYResult bArrays, object plcModel); + + /// + /// 显示上料信息 + /// + /// + /// + //public delegate void dgShowFeeding(List list); + /// + /// 显示下料信息 + /// + /// + /// + //public delegate void dgShowBlanking(List list); + /// + /// 设备综合效率 + /// + /// + public delegate void DGShow12HourData(DeviceOEE device12Hour); + + /// + /// 设备综合效率 + /// + /// + public delegate void DGShowAlarmData(DeviceOEE deviceAlarm); + + + /// + /// 焊机功率 + /// Welding machine power + /// + public delegate void DGShowWeldingPowerData(List DataList); + + +} diff --git a/JinYuan.VirtualDataLibrary/JinYuan.VirtualDataLibrary.csproj b/JinYuan.VirtualDataLibrary/JinYuan.VirtualDataLibrary.csproj new file mode 100644 index 0000000..b2be763 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/JinYuan.VirtualDataLibrary.csproj @@ -0,0 +1,118 @@ + + + + + Debug + AnyCPU + {2AB7E380-7795-448A-933C-0F6A081B5E7E} + Library + Properties + JinYuan.VirtualDataLibrary + JinYuan.VirtualDataLibrary + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\Libs\HML.dll + + + False + ..\Libs\PLCCommunication.dll + + + False + ..\Libs\2016\Seagull.BarTender.Print.dll + + + ..\packages\MiniExcel.1.36.1\lib\net45\MiniExcel.dll + + + + + + + + + + + + + + + + + + + Form + + + MsgshowTip.cs + + + + True + True + Resources.resx + + + + + + {114aa012-29c9-418c-a2d6-3173c5341f51} + JinYuan.DAL + + + {258d0ab7-2b4f-4d8f-a3cd-7a8cb4a85360} + JinYuan.Helper + + + {530b6426-08e7-461c-91dc-787f876620fc} + JinYuan.MES + + + {4c0bcb84-5cd7-4846-8363-c4c10d46e391} + JinYuan.Models + + + {486aecd0-c2bf-43c5-b7d7-88e565ade4b7} + PLC + + + + + + + + MsgshowTip.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + \ No newline at end of file diff --git a/JinYuan.VirtualDataLibrary/MesConfig.cs b/JinYuan.VirtualDataLibrary/MesConfig.cs new file mode 100644 index 0000000..3241df6 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/MesConfig.cs @@ -0,0 +1,430 @@ +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using MiniExcelLibs; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +namespace JinYuan.VirtualDataLibrary +{ + public class MesConfig + { + /// + /// 工厂代码 + /// + public string siteCode = ""; + /// + /// 产线编号 + /// + public string lineCode = ""; + /// + /// 设备编号 + /// + public string equipNum = ""; + /// + /// 客户料号 + /// + public string CustomerPartNum = ""; + /// MES密码 + /// + public string mesPwd = ""; + /// + /// MES账户 + /// + public string mesUserName = ""; + + + + /// + /// 将电池等级转换成下发PLC的等级编号 + /// + /// + /// + public static string GetLocGrade(int stationNo, FDConfig fdconfig) + { + string grade = ""; + switch (stationNo) + { + case 1: + grade = fdconfig.Grade1; + break; + case 2: + grade = fdconfig.Grade2; + break; + case 3: + grade = fdconfig.Grade3; + break; + } + return grade; + } + // 组盘PLC 机架-工位对应的寄存器 + public Dictionary> gw_loc_plcAddr = + new Dictionary>() + { + // 机架1:loc1-loc3 对应PLC地址段D21600-D21602 + { + 1, new Dictionary() + { + {1, "D21600"}, + {2, "D21601"}, + {3, "D21602"} + } + }, + // 机架2:loc1-loc3 对应PLC地址段D23600-D23602 + { + 2, new Dictionary() + { + {1, "D23600"}, + {2, "D23601"}, + {3, "D23602"} + } + }, + // 机架3:loc1-loc3 对应PLC地址段D25600-D25602 + { + 3, new Dictionary() + { + {1, "D25600"}, + {2, "D25601"}, + {3, "D25602"} + } + } + }; + + //// 电池等级,PLC等级关系 + //private static Dictionary gradeDic = new Dictionary() + //{ + // { "V1", 1 }, + // { "A", 2 }, + // { "A-", 3 }, + // { "B", 4 }, + // { "NG", 0}, + // { "不设置", 0}, + //}; + + //public static List GetGrades() + //{ + // var validGradeKeys = gradeDic.Keys.ToList(); + // return validGradeKeys; + //} + + + /// + /// 将电池等级转换成下发PLC的等级编号 + /// + /// + /// + //public int GetGradeNo(string strGrade) + //{ + // if (gradeDic.TryGetValue(strGrade, out int result)) + // { + // return result; // 键存在,返回对应值 + // } + // // 键不存在,返回0 + // return 0; + //} + + /// + /// 电表编号 + /// + public List electricMeterNum = new List(); + + /// + /// 风速仪个数 + /// + public int AntiDustAirSpeedCount = 0; + /// + /// 风速仪编号 + /// + public List listAntiDustAirSpeedNum = new List(); + + /// + /// 权限 + /// + public string userLevel = ""; + /// + /// mes返回权限 + /// + public string mesUserLevel = ""; + /// + /// 物料编码 + /// + public string MaterialCode = ""; + /// + /// 生产型号 + /// + public string ModelName = ""; + // 产品型号转plc值 + private Dictionary modelMapping = new Dictionary() + { + { "LF350S", 1 }, //MB36 + { "LF314", 2 }, //MB31 + { "LF628", 3 }, //MB56 + { "LF668", 3 }, //MB56 + { "MB36", 1 }, //MB36 + { "MB31", 2 }, //MB31 + { "MB56", 3 }, //MB56 + }; + + /// + /// 将电池型号转换成下发PLC的型号编号 + /// + /// + /// + public int GetModel(string modelName) + { + if (modelMapping.TryGetValue(modelName, out int result)) + { + return result; // 键存在,返回对应值 + } + // 键不存在,返回0 + return 0; + } + + // 物流线各工位,生产型号写PLC地址 + private Dictionary modelPLCAddr_Mapping = new Dictionary() + { + { "2-1", "D2009" }, + { "2-2", "D2109" }, + { "2-3", "D2209" }, + { "1-1", "D2309" }, + { "1-2", "D2409" }, + { "1-3", "D2509" } + }; + + public string GetWuliuModelAddr() + { + if (modelPLCAddr_Mapping.TryGetValue(CommonMethods.sysConfig.GongWei, out string plcAdrr)) + { + return plcAdrr; // 键存在,返回对应值 + } + // 键不存在,返回"" + return ""; + } + + // 物流线各工位,等级写PLC地址 + private Dictionary> gradePLCAddr_Mapping = new Dictionary>() + { + { "2-1", new Dictionary {{1, "D2006"}, {2, "D2007"}, {3, "D2008"}} }, + { "2-2", new Dictionary {{1, "D2106"}, {2, "D2107"}, {3, "D2108"}} }, + { "2-3", new Dictionary {{1, "D2206"}, {2, "D2207"}, {3, "D2208"}} }, + { "1-1", new Dictionary {{1, "D2306"}, {2, "D2307"}, {3, "D2308"}} }, + { "1-2", new Dictionary {{1, "D2406"}, {2, "D2407"}, {3, "D2408"}} }, + { "1-3", new Dictionary {{1, "D2506"}, {2, "D2507"}, {3, "D2508"}} } + }; + + public Dictionary GetWuliuGradeAddr() + { + if (gradePLCAddr_Mapping.TryGetValue(CommonMethods.sysConfig.GongWei, out Dictionary plc_addrs)) + { + return plc_addrs; + } + return new Dictionary(); + } + + // PLC触摸屏用户名称与权限 + private Dictionary> userPLCAddr_Mapping = new Dictionary>() + { + { "1-1", new Dictionary {{"user", "D22"}, {"right", "D21"}} }, + { "1-2", new Dictionary {{"user", "D22"}, {"right", "D21"}} }, + { "1-3", new Dictionary {{"user", "D22"}, {"right", "D21"}} }, + { "2-1", new Dictionary {{"user", "D22"}, {"right", "D21"}} }, + { "2-2", new Dictionary {{"user", "D22"}, {"right", "D21"}} }, + { "2-3", new Dictionary {{"user", "D22"}, {"right", "D21"}} }, + }; + + public Dictionary GetHMIUserRightAddr() + { + if (userPLCAddr_Mapping.TryGetValue(CommonMethods.sysConfig.GongWei, out Dictionary plc_addrs)) + { + return plc_addrs; + } + return new Dictionary(); + } + + + /// + /// 是否上传MES + /// + public bool isUpMes = false; + /// + /// MES接口URL地址中的IP地址 + /// + public string MESURLAddressIP = "10.100.111.81"; + /// + /// MES接口URL地址中的端口号 + /// + public string MESURLAddressPort = "80"; + /// + /// 是否连接MES + /// + public bool isConnected = false; + /// + /// 是否刷卡? + /// + public bool Isshuaka = false; + /// + /// 是否登录成功? + /// + public bool IsLoginOK = false; + /// + /// 是否登录MES成功? + /// + public bool IsLoginMesOK = false; + /// + /// 获取MES参数 + /// + public bool IsMesParam = false; + /// + /// MES超时 + /// + public long MesOutTime = 0; + /// + /// 焊接点个数 + /// + public int weldNum = 0; + /// + /// 是否2个电表(此功能仅适用于908-6负极焊接两台设备共用一台敢接机只有一个电表) + /// + public bool IsTwoDianBiao = false; + /// + /// 电表编号 + /// + public string ElectricMeterNum = ""; + /// + /// 除尘风速 + /// + public decimal antiDustAirSpeed = 0; + + /// + /// 电机旋转速度 + /// + public decimal dianjiXzSpeed = 0; + /// + /// 设备状态上传时间 + /// + public int EquStatuasTime = 0; + /// + /// 获取服务器数据 + /// + public bool IsGet_Server = true; + /// + /// 生成假数据 + /// + public bool IsDebug = true; + /// + /// 钢壳码计数 + /// + public int SteelshellCount = 0; + ///// + ///// 每个档位最大电芯数量 + ///// + //public int maxBatteriesPerGrade = 240; + + /// + /// 电芯装箱层数 + /// + public int packLayers = 4; + /// + /// 电芯装箱每层行数 + /// + public int rowsPerLayer = 5; + /// + /// 电芯装箱每层列数 + /// + public int colsPerLayer = 12; + /// + /// 卡板托盘计数 + /// + public int CoreCount = 0; + /// + /// 卡板托盘生成时间 + /// + public string CardTime = ""; + /// + /// 卡板码是否发送成功 + /// + public bool CardSuccess = false; + /// + /// 原材料上料位置 + /// + public string materialLotCodeLocator = ""; + /// + /// 存储服务器IP地址 + /// + public string RotueServerIP = "192.168.2.108"; + /// + /// 员工权限校验 + /// + public string EmployeeAuthCheck = "http://10.100.111.81/core/api/public/equipment/base/user/permission/verify"; + ///// + ///// 原材料投入信息 + ///// + //public string MaterialInputInfo = "http://10.100.111.81/core/api/public/raw/material/input/un/first/process"; + /// + /// 设备参数设定值请求 + /// + public string DeviceParamRequest = "http://10.100.111.81/core/api/public/param/setting/request"; + /// + /// 设备参数设定值变更 + /// + public string DeviceParamChange = "http://10.100.111.81/core/api/public/param/setting/change"; + + /// + /// 料盘信息获取 + /// + public string queryTrayUrl = "http://10.22.160.9/prod-api/produce/trayQuery/trayComposeInfo"; + + public string queryGradeUrl = "http://10.22.160.141:8080/core/api/public/equip/auto/gradequery"; + public string upResultParamUrl = "http://10.22.160.3/core/api/public/process/param/new/result"; + /// + /// 解绑料框码 + /// + public string unbindTrayUrl = "http://10.22.160.9/prod-api/api/fms/mp/unbindWholeTray"; + + /// + /// 半成品电池绑盘 + /// + public string packLoadUrl = "http://10.54.50.1:8082/core/api/public/equip/auto/pack/load"; + + /// + /// 成品电池绑盘 + /// + public string finishedPackUrl = "http://10.54.50.1:8082/core/api/public/equip/auto/pack/load"; + /// + /// 设备报警信息 + /// + public string DeviceAlarm = "http://10.100.111.81/core/api/public/equipment/alarm/currency"; + /// + /// 设备运行状态 + /// + public string DeviceStatus = "http://10.100.111.81/core/api/public/eve/pm/eqm/run/status/operation"; + /// + /// 能耗数据 + /// + public string EnergyConsumption = "http://10.100.111.81/core/api/public/eve/pm/energy/consumption/collection/submit"; + /// + /// 设备风速接口 + /// + public string Anemometer = "https://iot.eveportal.com:9470/eve_api/ems/iot/upload_device_collect_data"; + + ///// + ///// 进出站一体模式× + ///// + //public string InAndOutStationMesUrl = "http://10.17.96.73/core/api/public/14j/out/station/process/turn-in-out"; + + /// + /// appId + /// + public string AppID = "e36ef900320d442f850913e2ebc1d7a1"; + /// + /// AppKey + /// + public string AppKey = "8279ce76217245f48c0cc495c09124a3"; + /// + /// 获取TOKEN + /// + public string GetTokenUrl = "https://esb.evebattery.com:13502/gateway/ewms-eu/openapi/oauth/token"; + } +} diff --git a/JinYuan.VirtualDataLibrary/MsgshowTip.Designer.cs b/JinYuan.VirtualDataLibrary/MsgshowTip.Designer.cs new file mode 100644 index 0000000..cdda500 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/MsgshowTip.Designer.cs @@ -0,0 +1,89 @@ +namespace JinYuan.VirtualDataLibrary +{ + partial class MsgshowTip + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label1 = new System.Windows.Forms.Label(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.Image = global::JinYuan.VirtualDataLibrary.Properties.Resources.感叹号提示_块红色; + this.pictureBox1.Location = new System.Drawing.Point(6, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(87, 80); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("微软雅黑", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.label1.ForeColor = System.Drawing.Color.Red; + this.label1.Location = new System.Drawing.Point(95, 29); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(345, 28); + this.label1.TabIndex = 1; + this.label1.Text = "与PLC链接断开,请检查通讯线路!"; + // + // timer1 + // + this.timer1.Interval = 500; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // MsgshowTip + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Yellow; + this.ClientSize = new System.Drawing.Size(434, 84); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "MsgshowTip"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "MsgshowTip"; + this.Load += new System.EventHandler(this.MsgshowTip_Load); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Timer timer1; + } +} \ No newline at end of file diff --git a/JinYuan.VirtualDataLibrary/MsgshowTip.cs b/JinYuan.VirtualDataLibrary/MsgshowTip.cs new file mode 100644 index 0000000..319c15e --- /dev/null +++ b/JinYuan.VirtualDataLibrary/MsgshowTip.cs @@ -0,0 +1,115 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace JinYuan.VirtualDataLibrary +{ + public partial class MsgshowTip : Form + { + /// + /// 图标和文本之间的间距(像素) + /// + const int IconTextSpacing = 3; + /// + /// 显示文字 + /// + string _tipText; + /// + /// 提示图标 + /// + public Image TipIcon { get; set; } + + /// + /// 提示文本 + /// + public string TipText + { + get { return _tipText ?? string.Empty; } + set { _tipText = value; } + } + + public MsgshowTip(string Msg) + { + //双缓冲。有必要 + SetStyle(ControlStyles.UserPaint, true); + DoubleBuffered = true; + InitializeComponent(); + this._tipText = Msg; + } + + private void MsgshowTip_Load(object sender, EventArgs e) + { + //ProcessClientSize(); + ProcessLocation(); + label1.Text = _tipText; + timer1.Enabled = true; + } + + /// + /// 根据图标和文字处理窗体尺寸 + /// + private void ProcessClientSize() + { + Size size = Size.Empty; + if (TipIcon != null) + { + size += TipIcon.Size; + } + if (TipText.Length != 0) + { + if (TipIcon != null) + { + size.Width += IconTextSpacing;//图标与文字的间距 + } + var textSize = TextRenderer.MeasureText(TipText, this.Font); + size.Width += textSize.Width; + if (size.Height < textSize.Height) { size.Height = textSize.Height; } + } + this.ClientSize = size + Padding.Size; + } + private int x, y; //显示的坐标变量 + + private void timer1_Tick(object sender, EventArgs e) + { + this.Close(); + } + + private void ProcessLocation() + { + + #region 弹窗显示在屏幕中间 + this.y = (Screen.PrimaryScreen.Bounds.Height - 30 - this.Height) / 2; + this.x = (Screen.PrimaryScreen.Bounds.Width - 10 - this.Width) / 2; + this.Location = new Point(this.x, this.y); + #endregion + + #region 弹窗显示在屏幕右下角 + //this.x = Screen.PrimaryScreen.WorkingArea.Width - this.Width + 15; + //this.y = Screen.PrimaryScreen.WorkingArea.Height - this.Height * i - 5 * i; + //this.Location = new Point(this.x, this.y); + #endregion + + #region 弹窗跟随鼠标位置 + //var p = BasePoint; + //p.X -= Screen.PrimaryScreen.WorkingArea.Width - this.Width - 1000;//Screen.PrimaryScreen.WorkingArea.Width-this.Width / 2; + + ////横向处理。距离屏幕左右两边太近时的处理 + //int screenWidth; + //if (p.X < 10) + //{ + // p.X = 10; + //} + //else if (p.X + this.Width > (screenWidth = Screen.PrimaryScreen.Bounds.Width) - 10) + //{ + // p.X = screenWidth - 10 - this.Width; + //} + + ////纵向处理。在鼠标上方显示 + //p.Y -= this.Height + 20; + + //this.Location = p; + #endregion + } + + } +} diff --git a/JinYuan.VirtualDataLibrary/MsgshowTip.resx b/JinYuan.VirtualDataLibrary/MsgshowTip.resx new file mode 100644 index 0000000..1f666f2 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/MsgshowTip.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/JinYuan.VirtualDataLibrary/Properties/AssemblyInfo.cs b/JinYuan.VirtualDataLibrary/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a8452d0 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("JinYuan.VirtualDataLibrary")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JinYuan.VirtualDataLibrary")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("2ab7e380-7795-448a-933c-0f6a081b5e7e")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JinYuan.VirtualDataLibrary/Properties/Resources.Designer.cs b/JinYuan.VirtualDataLibrary/Properties/Resources.Designer.cs new file mode 100644 index 0000000..f8bac29 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace JinYuan.VirtualDataLibrary.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("JinYuan.VirtualDataLibrary.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 感叹号提示_块红色 { + get { + object obj = ResourceManager.GetObject("感叹号提示-块红色", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JinYuan.VirtualDataLibrary/Properties/Resources.resx b/JinYuan.VirtualDataLibrary/Properties/Resources.resx new file mode 100644 index 0000000..23cf1b4 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\感叹号提示-块红色.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JinYuan.VirtualDataLibrary/Resources/感叹号提示-块红色.png b/JinYuan.VirtualDataLibrary/Resources/感叹号提示-块红色.png new file mode 100644 index 0000000..eef6632 Binary files /dev/null and b/JinYuan.VirtualDataLibrary/Resources/感叹号提示-块红色.png differ diff --git a/JinYuan.VirtualDataLibrary/Utlis/BartenderPrinter.cs b/JinYuan.VirtualDataLibrary/Utlis/BartenderPrinter.cs new file mode 100644 index 0000000..7c667e6 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/Utlis/BartenderPrinter.cs @@ -0,0 +1,271 @@ +using JinYuan.Helper; +using Seagull.BarTender.Print; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace JinYuan.VirtualDataLibrary.Utlis +{ + public class BartenderPrinter + { + LabelFormatDocument print; + Engine engine; + string PrinterName; + string PrintLabelType; + + /// + /// 初始化打印机 + /// + /// 打印机名称通过该名称指定打印机 + /// 打印机类型 + public BartenderPrinter(string PrinterName, string PrintLabelType) + { + this.PrinterName = PrinterName; + this.PrintLabelType = PrintLabelType; + engine = new Engine(true); + } + + public BartenderPrinter(string PrinterName) + { + this.PrinterName = PrinterName; + engine = new Engine(true); + } + + + public string[] read(string path) + { + try + { + LabelFormatDocument print; + + + //System.Diagnostics.Process.Start("ExpLore", path); + + + print = engine.Documents.Open(path); + //print.PrintSetup.PrinterName = "Microsoft Print to PDF"; + //print.PrintSetup.PrinterName = "TSC MX340F"; + XmlDocument xml = new XmlDocument(); + xml.LoadXml(print.SubStrings.XML); + //string s = print.SubStrings.XML; + //获取XML中SubStrings/SubString + XmlNodeList nodeList = xml.SelectNodes("SubStrings/SubString"); + string[] printColumns = new string[print.SubStrings.Count]; + int count = 0; + foreach (XmlNode node in nodeList) + { + printColumns[count] = node.Attributes["Name"].Value; + count++; + } + //获取栏位 + return printColumns; + } + catch (Exception ex) + { + throw new Exception(ex.ToString()); + } + } + + /// + /// 执行打印 + /// + /// 文件地址 + /// 字段栏位映射,key BTname ,value BTValue + /// + public bool write(string path, string jobName, Dictionary printValue) + { + try + { + print = engine.Documents.Open(path); + //print.PrintSetup.PrinterName = "Microsoft Print to PDF"; + //print.PrintSetup.PrinterName = "TSC MX340"; + //print.PrintSetup.PrinterName = "TSC TTP-346MU"; + print.PrintSetup.PrinterName = this.PrinterName; + foreach (var oneItem in printValue) + { + print.SubStrings.SetSubString(oneItem.Key, oneItem.Value); + //log.Debug("[" + oneItem.Key + "]=" + oneItem.Value); + } + //Thread.Sleep(100); + + Result result = print.Print(jobName); //print.Print("Label Print"); + + return result == Result.Success ? true : false; + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + return false; + } + } + + /// + /// 读取btw檔 并确认各栏位是否能对应的到 + /// + /// + /// + /// + /// + /// + public string LoadColumns(string FileId, string Path, DataTable SourceDataTable, DataTable DtPrintColumn) + { + try + { + string msg = ""; + + string[] btwColumns = read(Path); + for (int i = 0; i < btwColumns.Length; i++)//版面欄位數量 + { + bool flag = false; + foreach (DataColumn dc in SourceDataTable.Columns)//資料庫欄位數量 + { + if (btwColumns[i] == dc.ColumnName) + { + flag = true; + } + } + + if (flag == false) + { + if (msg == "") { msg = btwColumns[i]; } + else { msg += "," + btwColumns[i]; } + } + } + + if (msg == "") + { + DataTable dt = DtPrintColumn; + string Id = FileId; + + DataRow[] drAry = dt.Select(" Id='" + Id + "'"); + for (int j = 0; j < drAry.Length; j++) + { + dt.Rows.Remove(drAry[j]); + } + dt.AcceptChanges(); + + DataRow drNew; + for (int j = 0; j < btwColumns.Length; j++) + { + drNew = dt.NewRow(); + drNew["Id"] = Id; + drNew["Value"] = btwColumns[j]; + dt.Rows.Add(drNew); + } + dt.AcceptChanges(); + } + + return msg; + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + return ex.ToString(); + } + } + + // 列印 Reel或Box或Carton标签 + // 偵測非同步處理 + public bool PrintLabel(DataRow dr) + { + try + { + string Id = ""; + string fileIdColumnName = ""; + string filePathColumnName = ""; + if (dr == null) + { + LogHelper.Instance.WriteError("DataRow is NULL"); + return false; + } + DataTable columnDT = new DataTable(); + if (PrintLabelType == "Box") + { + fileIdColumnName = "FileId"; + filePathColumnName = "Path"; + + } + else if (PrintLabelType == "Reel") + { + fileIdColumnName = "ReelFileId"; + filePathColumnName = "ReelFilePath"; + + } + else if (PrintLabelType == "Carton") + { + fileIdColumnName = "FileId"; + filePathColumnName = "Path"; + + } + else if (PrintLabelType == "Carton2") + { + fileIdColumnName = "FileId2"; + filePathColumnName = "Path2"; + } + else + { + LogHelper.Instance.WriteError("PrintLabelType =" + PrintLabelType); + return false; + } + + Id = dr[fileIdColumnName].ToString(); + + DataRow[] drAry = columnDT.Select("id='" + Id + "'"); + + Dictionary printValue = new Dictionary(); + + for (int i = 0; i < drAry.Length; i++) + { + string column = drAry[i][1].ToString(); + + printValue.Add(column, dr[column].ToString().TrimEnd()); + + } + bool writeResult = write(dr[filePathColumnName].ToString(), PrintLabelType, printValue); + return writeResult; + + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + throw ex; + } + } + + //列印 Interior Label 或 Outer Label + public bool PrintSimpleLabel(string chrCkdh, string jobname, string FilePath) + { + try + { + Dictionary printValue = new Dictionary(); + printValue.Add("chrCkdh", chrCkdh.TrimEnd()); + bool writeResult = write(FilePath, jobname, printValue); + return writeResult; + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + throw ex; + } + } + + public bool Close() + { + try + { + engine.Dispose(); + + return true; + } + catch (Exception ex) + { + LogHelper.Instance.WriteEX(ex); + return false; + } + } + } +} diff --git a/JinYuan.VirtualDataLibrary/app.config b/JinYuan.VirtualDataLibrary/app.config new file mode 100644 index 0000000..1ee22f7 --- /dev/null +++ b/JinYuan.VirtualDataLibrary/app.config @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Language/2025_01_08_09_12.xlsx b/Language/2025_01_08_09_12.xlsx new file mode 100644 index 0000000..486bfe4 Binary files /dev/null and b/Language/2025_01_08_09_12.xlsx differ diff --git a/Language/Language.7z b/Language/Language.7z new file mode 100644 index 0000000..bb04309 Binary files /dev/null and b/Language/Language.7z differ diff --git a/Language/Language.csproj b/Language/Language.csproj new file mode 100644 index 0000000..b968b51 --- /dev/null +++ b/Language/Language.csproj @@ -0,0 +1,139 @@ + + + + + Debug + AnyCPU + {292A5C9C-7A82-4D25-A885-DDCEDC93F03C} + Library + Properties + Language + Language + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\AntdUI.1.8.4\lib\net48\AntdUI.dll + + + ..\packages\BouncyCastle.Cryptography.2.3.1\lib\net461\BouncyCastle.Cryptography.dll + + + ..\packages\Google.Protobuf.3.26.1\lib\net45\Google.Protobuf.dll + + + ..\packages\K4os.Compression.LZ4.1.3.8\lib\net462\K4os.Compression.LZ4.dll + + + ..\packages\K4os.Compression.LZ4.Streams.1.3.8\lib\net462\K4os.Compression.LZ4.Streams.dll + + + ..\packages\K4os.Hash.xxHash.1.0.8\lib\net462\K4os.Hash.xxHash.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + ..\packages\System.Configuration.ConfigurationManager.8.0.0\lib\net462\System.Configuration.ConfigurationManager.dll + + + + + ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.IO.Pipelines.9.0.0\lib\net462\System.IO.Pipelines.dll + + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + ..\packages\ZstdSharp.Port.0.8.4\lib\net462\ZstdSharp.dll + + + + + + True + True + Languages.resx + PreserveNewest + + + + + + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + + + + + + + {1bb7ed33-d2cb-4cdd-ab39-f7f9ae948ca2} + JinYuan.ControlLib + + + + \ No newline at end of file diff --git a/Language/LanguageManager.cs b/Language/LanguageManager.cs new file mode 100644 index 0000000..239a3c8 --- /dev/null +++ b/Language/LanguageManager.cs @@ -0,0 +1,1118 @@ +using AntdUI; +using JinYuan.ControlLib; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Resources; +using System.Threading; +using System.Windows.Forms; + + +namespace Language +{ + /// + /// 全局语言管理器 UpperComputerSystem.Language.MsgResources + /// + public static class LanguageManager + { + public static ResourceManager rm = new ResourceManager("Language.Languages", typeof(LanguageManager).Assembly); + private static CultureInfo currentCulture = CultureInfo.CurrentUICulture; + public static event EventHandler LanguageChanged; + public static string LanguageCode = "zh";//默认中文 + + private static Dictionary translationCache = new Dictionary(); + + static LanguageManager() + { + // 在静态构造函数中加载保存的语言设置 + LoadSavedLanguage(); + } + + public static void ChangeLanguage(string languageCode) + { + LanguageCode = languageCode; + currentCulture = new CultureInfo(languageCode); + Thread.CurrentThread.CurrentUICulture = currentCulture; + translationCache.Clear(); + SaveLanguagePreference(languageCode); + LanguageChanged?.Invoke(null, EventArgs.Empty); + + } + + public static string GetString(string key) + { + if (translationCache.TryGetValue(key, out string cachedResult)) + { + return cachedResult; + } + + string result = rm.GetString(key, currentCulture); + if (result != null) + { + translationCache[key] = result; + } + return result ?? key; + } + + + // 新增:GetLocalizedString 方法,支持带参数的本地化字符串 + public static string GetLocalizedString(string key, params object[] args) + { + string value = GetString(key); + return args.Length > 0 ? string.Format(value, args) : value; + } + + // 新增:获取本地化的星期名称数组 + public static string[] WeekNames + { + get + { + return new string[] + { + GetString("Sunday"), + GetString("Monday"), + GetString("Tuesday"), + GetString("Wednesday"), + GetString("Thursday"), + GetString("Friday"), + GetString("Saturday") + }; + } + } + + + public static void LoadLanguageResource(string resourcePath) + { + ResourceManager newRm = new ResourceManager(resourcePath, typeof(LanguageManager).Assembly); + rm = newRm; + translationCache.Clear(); + LanguageChanged?.Invoke(null, EventArgs.Empty); + } + + // 新增:保存语言偏好 + private static void SaveLanguagePreference(string languageCode) + { + try + { + var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + var settings = configFile.AppSettings.Settings; + if (settings["PreferredLanguage"] == null) + { + settings.Add("PreferredLanguage", languageCode); + } + else + { + settings["PreferredLanguage"].Value = languageCode; + } + configFile.Save(ConfigurationSaveMode.Modified); + ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name); + } + catch (ConfigurationErrorsException ex) + { + Console.WriteLine($"Error writing app settings: {ex.Message}"); + // 考虑记录错误或通知用户 + } + catch (IOException ex) + { + Console.WriteLine($"Error accessing configuration file: {ex.Message}"); + // 考虑记录错误或通知用户 + } + } + + // 新增:加载保存的语言设置 + private static void LoadSavedLanguage() + { + try + { + string savedLanguage = ConfigurationManager.AppSettings["PreferredLanguage"]; + if (!string.IsNullOrEmpty(savedLanguage)) + { + ChangeLanguage(savedLanguage); + } + } + catch (ConfigurationErrorsException ex) + { + Console.WriteLine($"Error reading app settings: {ex.Message}"); + // 考虑记录错误或使用默认语言 + } + } + + // 新增:获取当前语言代码 + public static string GetCurrentLanguage() + { + return currentCulture.Name; + } + + } + + /// + /// 窗口控件翻译 + /// + public class MultiLanguageForm : AntdUI.Window + { + public MultiLanguageForm() + { + LanguageManager.LanguageChanged += OnLanguageChanged; + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + UpdateUILanguage(); + } + + protected virtual void OnLanguageChanged(object sender, EventArgs e) + { + UpdateUILanguage(); + } + + protected virtual void UpdateUILanguage() + { + UpdateControlsText(this); + } + + protected void UpdateControlsText(Control control) + { + UpdateControlProperties(control); + + foreach (Control childControl in control.Controls) + { + UpdateControlsText(childControl); + } + } + + + + protected void UpdateControlProperties(Control control) + { + string formName = this.Name; + string controlName = control.Name; + if (!string.IsNullOrEmpty(control.Name)) + { + // 更新 Text 属性 + UpdateProperty(control, "Text", formName, controlName, "_Text"); + if (control is NaviButton2 naviButton) + { + UpdateControlText(control, formName); + } + else if (control is TButton tButton) + { + UpdateControlText(control, formName); + } + + + // 处理特定类型的控件 + else if (control is AntdUI.Button antdButton) + { + UpdateProperty(antdButton, "Text", formName, controlName, "_Text"); + } + else if (control is AntdUI.Label label) + { + UpdateProperty(label, "Text", formName, controlName, "_Text"); + } + else if (control is AntdUI.Input antdInput) + { + UpdateProperty(antdInput, "PlaceholderText", formName, controlName, "_Placeholder"); + } + else if (control is AntdUI.Steps steps) + { + UpdateStepsTitle(steps, formName, controlName); + } + else if (control is StatusStrip status) + { + UpdateStatusStripItems(status, formName); + } + else if (control is AntdUI.PageHeader antdWindowBar) + { + UpdateProperty(antdWindowBar, "Text", formName, controlName, "_Text"); + } + else if (control is AntdUI.Table antdTable) + { + UpdateTableColumns(antdTable, formName, controlName); + } + + else if (control is TitleTime titleTime) + { + UpdateProperty(titleTime, "TitleName", formName, controlName, "_TitleName"); + } + else if (control is Title title) + { + UpdateProperty(title, "TitleName", formName, controlName, "_TitleName"); + } + else if (control is LongTitleStyle2 longTitleStyle) + { + UpdateProperty(longTitleStyle, "TitleName", formName, controlName, "_TitleName"); + } + + if (control is DataGridView dgv) + { + UpdateDataGridViewLanguage(dgv, formName); + } + + if (control is ListView listView) + { + UpdateListViewLanguage(listView, formName); + } + + if (control is UCElectricityMeterV) // 假设 EyMaterH1 是您自定义控件的类型 + { + LocalizeCustomControl(control, formName); + } + // 可以在这里添加更多特定控件类型的处理 + + // 更新控件的 ToolTipText 属性 + //else if (control is SidebarNavigation antdSidebarNavigation) + //{ + // UpdateSidebarNavigationItems(antdSidebarNavigation, formName); + //} + + //else if (control is CustomComboBox antdCustomComboBox) + //{ + // UpdateProperty(antdCustomComboBox, "WatermarkText", formName, controlName, "_WatermarkText"); + //} + + //else if (control is CustomGroupBox antdCustomGroupBox) + //{ + // UpdateProperty(antdCustomGroupBox, "Text", formName, controlName, "_Text"); + //} + // 添加 CustomDataGridView 的处理 + //else if (control is CustomDataGridView dataGridView) + //{ + // UpdateDataGridViewColumns(dataGridView, formName, controlName); + //} + } + } + + + protected void UpdateControlText(Control control, string formName) + { + string baseResourceKey = $"{formName}_{control.Name}"; + + // 尝试更新 Text 属性 + //string textKey = $"{baseResourceKey}_Text"; + //string translatedText = LanguageManager.GetString(textKey); + //if (translatedText != textKey) // 如果找到了翻译 + //{ + // control.Text = translatedText; + //} + + // 尝试更新 TitleName 属性 + string titleNameKey = $"{baseResourceKey}_TitleName"; + string translatedTitleName = LanguageManager.GetString(titleNameKey); + if (translatedTitleName != titleNameKey) // 如果找到了翻译 + { + + //control.Text = translatedText; + var titleNameProperty = control.GetType().GetProperty("TitleName"); + if (titleNameProperty != null && titleNameProperty.CanWrite) + { + titleNameProperty.SetValue(control, translatedTitleName); + } + } + } + + + /// + /// Winform 默认DataGridView控件 + /// + /// + /// + protected void UpdateDataGridViewLanguage(DataGridView dgv, string formName) + { + foreach (DataGridViewColumn column in dgv.Columns) + { + if (!string.IsNullOrEmpty(column.Name)) + { + string resourceKey = $"{formName}_{dgv.Name}_{column.Name}Header"; + string translatedHeader = LanguageManager.GetString(resourceKey); + if (translatedHeader != resourceKey) // 如果找到了翻译 + { + column.HeaderText = translatedHeader; + } + } + } + } + + + /// + /// 电表控件 + /// + /// + protected void LocalizeCustomControl(Control control, string formName) + { + Type controlType = control.GetType(); + PropertyInfo[] properties = controlType.GetProperties(); + + if (formName == "FrmMonitor") + { + foreach (PropertyInfo property in properties) + { + if (property.PropertyType == typeof(string) && property.Name.StartsWith("Text")) + { + string propertyName = property.Name; + string key = $"{formName}_{control.Name}_{propertyName}"; + string localizedText = LanguageManager.GetString(key); + + if (!string.IsNullOrEmpty(localizedText)) + { + property.SetValue(control, localizedText); + } + } + } + } + } + + protected void UpdateListViewLanguage(ListView listView, string formName) + { + //foreach (ColumnHeader column in listView.Columns) + //{ + // string key = $"{formName}_{listView.Name}_{column.Name}_Text"; + // string localizedText = LanguageManager.GetString(key); + // if (!string.IsNullOrEmpty(localizedText)) + // { + // column.Text = localizedText; + // } + //} + if (formName != "FrmMain") + { + for (int i = 0; i < listView.Columns.Count; i++) + { + string key = $"{formName}_{listView.Name}_Column{i}_Text"; + string localizedText = LanguageManager.GetString(key); + if (!string.IsNullOrEmpty(localizedText)) + { + listView.Columns[i].Text = localizedText; + } + } + } + } + + + /// + /// 更新 DataGridView 的列标题 + /// + private void UpdateDataGridViewColumns(CustomDataGridView dataGridView, string formName, string controlName) + { + try + { + foreach (DataGridViewColumn column in dataGridView.Columns) + { + // 构建语言键:窗体名_控件名_Column_列名 + //CommunicationEditForm_groupTable_Column_PlcNum + string languageKey = $"{formName}_{controlName}_Column_{column.Name}"; + + // 获取翻译后的列标题 + string translatedHeader = LanguageManager.GetString(languageKey); + + // 如果找到翻译,则更新列标题 + if (!string.IsNullOrEmpty(translatedHeader) && translatedHeader != languageKey) + { + column.HeaderText = translatedHeader; + } + } + + // 如果需要翻译行标题(RowHeaders) + if (dataGridView.RowHeadersVisible) + { + string rowHeaderKey = $"{formName}_{controlName}_RowHeader"; + string translatedRowHeader = LanguageManager.GetString(rowHeaderKey); + if (!string.IsNullOrEmpty(translatedRowHeader) && translatedRowHeader != rowHeaderKey) + { + dataGridView.RowHeadersDefaultCellStyle.Format = translatedRowHeader; + } + } + } + catch (Exception ex) + { + Debug.WriteLine($"Error updating DataGridView columns: {ex.Message}"); + } + } + + /// + /// + /// + /// + /// + /// + private void UpdateStepsTitle(AntdUI.Steps steps, string formName, string controlName) + { + if (steps.Items != null) + { + foreach (var item in steps.Items) + { + + ///格式 MainForm_mySteps_Item_Title = "姓名" + + string resourceKey = $"{formName}_{controlName}_{item.Name}_Title"; + string translatedTitle = LanguageManager.GetString(resourceKey); + if (translatedTitle != resourceKey) + { + item.Title = translatedTitle; + } + } + // 强制表格重新加载布局以应用新的标题 + steps.Invalidate(); + } + } + + + + /// + /// Updates the text and tooltips of status strip items based on the current language settings. + /// + /// The status strip control to update + /// The name of the form containing the status strip + public void UpdateStatusStripItems(StatusStrip statusStrip, string formName) + { + if (statusStrip == null || string.IsNullOrEmpty(formName)) + return; + + try + { + //FrmMain_StatusStrip_Status_Text = "就绪" + //FrmMain_StatusStrip_Progress_Text = "进度" + //FrmMain_StatusStrip_MenuButton_Text = "选项" + //FrmMain_StatusStrip_MenuButton_Option1_Text = "选项1" + //FrmMain_StatusStrip_MenuButton_Option2_Text = "选项2" + + foreach (ToolStripItem item in statusStrip.Items) + { + UpdateStatusStripItem(item, formName); + } + + // Force a redraw of the status strip + statusStrip.Invalidate(); + } + catch (Exception ex) + { + //Logger.LogError($"Error updating status strip: {ex.Message}", ex); + } + } + + /// + /// Updates text for a single status strip item + /// + private void UpdateStatusStripItem(ToolStripItem item, string formName) + { + if (item?.Name == null) return; + + // Update Text + string textResourceKey = BuildResourceKey(formName, item.Name.ToString(), "Text"); + string translatedText = LanguageManager.GetString(textResourceKey); + if (!string.Equals(translatedText, textResourceKey, StringComparison.Ordinal)) + { + item.Text = translatedText; + } + + // Handle nested items in dropdown buttons + if (item is ToolStripDropDownButton dropDown) + { + UpdateDropDownItems(dropDown, formName); + } + } + + /// + /// Updates text for dropdown items + /// + private void UpdateDropDownItems(ToolStripDropDownButton dropDown, string formName) + { + foreach (ToolStripItem dropDownItem in dropDown.DropDownItems) + { + if (dropDownItem?.Tag != null) + { + string itemResourceKey = BuildResourceKey(formName, + $"{dropDown.Tag}_{dropDownItem.Tag}", "Text"); + string translatedItemText = LanguageManager.GetString(itemResourceKey); + + if (!string.Equals(translatedItemText, itemResourceKey, + StringComparison.Ordinal)) + { + dropDownItem.Text = translatedItemText; + } + } + } + } + + /// + /// Builds the resource key for language lookup + /// + private string BuildResourceKey(string formName, string tag, string propertyName) + { + return $"{formName}_StatusStrip_{tag}_{propertyName}"; + } + + /// + /// Table控件 + /// + /// + /// + /// + private void UpdateTableColumns(AntdUI.Table table, string formName, string controlName) + { + if (table.Columns != null) + { + foreach (var column in table.Columns) + { + + ///格式 MainForm_myTable_ColumnName_Title = "姓名" + + string resourceKey = $"{formName}_{controlName}_{column.Key}_Title"; + string translatedTitle = LanguageManager.GetString(resourceKey); + if (translatedTitle != resourceKey) + { + column.Title = translatedTitle; + } + } + // 强制表格重新加载布局以应用新的标题 + table.LoadLayout(); + } + } + + + + /// + /// 侧边导航栏 + /// + /// + /// + private void UpdateSidebarNavigationItems(SidebarNavigation sidebarNavigation, string formName) + { + foreach (var item in sidebarNavigation.GetItems()) + { + //资源文件内部Key格式如下 + //FrmMain_SidebarItem_Home_Text = "Home" + //FrmMain_SidebarItem_Statistics_Text = "Statistics" + //FrmMain_SidebarItem_Search_Text = "Search" + //FrmMain_SidebarItem_Recipe_Text = "Recipe" + //FrmMain_SidebarItem_User_Text = "User" + //FrmMain_SidebarItem_Settings_Text = "Settings" + + string resourceKey = $"{formName}_SidebarItem_{item.Tag}_Text"; + string translatedText = LanguageManager.GetString(resourceKey); + if (translatedText != resourceKey) + { + item.Text = translatedText; + sidebarNavigation.UpdateButtonText(item.Tag, translatedText); + // 查找对应的按钮并更新工具提示 + var button = sidebarNavigation.Controls.OfType() + .FirstOrDefault(b => b.Tag == item); + if (button != null) + { + //sidebarNavigation.UpdateItemToolTip(button, translatedText); + } + } + } + // 强制 SidebarNavigation 重新绘制以显示更新后的文本 + sidebarNavigation.Invalidate(); + } + + + private void UpdateProperty(object control, string propertyName, string formName, string controlName, string suffix) + { + string resourceKey = $"{formName}_{controlName}{suffix}"; + string translatedValue = LanguageManager.GetString(resourceKey); + if (translatedValue != resourceKey) + { + var property = control.GetType().GetProperty(propertyName); + if (property != null && property.CanWrite) + { + property.SetValue(control, translatedValue); + } + } + } + + + protected override void Dispose(bool disposing) + { + if (disposing) + { + LanguageManager.LanguageChanged -= OnLanguageChanged; + } + base.Dispose(disposing); + } + } + + /// + /// UserControl控件翻译 + /// + public class MultiLanguageUserControl : UserControl + { + public MultiLanguageUserControl() + { + LanguageManager.LanguageChanged += OnLanguageChanged; + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + UpdateUILanguage(); + } + + protected virtual void OnLanguageChanged(object sender, EventArgs e) + { + UpdateUILanguage(); + } + + protected virtual void UpdateUILanguage() + { + UpdateControlsText(this); + } + + protected void UpdateControlsText(Control control) + { + UpdateControlProperties(control); + + foreach (Control childControl in control.Controls) + { + UpdateControlsText(childControl); + } + + + } + + protected void UpdateControlProperties(Control control) + { + string userControlName = this.Name; + string controlName = control.Name; + + // 更新 Text 属性 + UpdateProperty(control, "Text", userControlName, controlName, "_Text"); + + // 处理特定类型的控件 + if (control is AntdUI.Button antdButton) + { + UpdateProperty(antdButton, "Text", userControlName, controlName, "_Text"); + } + else if (control is AntdUI.Label label) + { + + UpdateProperty(label, "Text", userControlName, controlName, "_Text"); + } + else if (control is AntdUI.Input antdInput) + { + UpdateProperty(antdInput, "PlaceholderText", userControlName, controlName, "_Placeholder"); + } + + else if (control is AntdUI.Tabs antdtabs) + { + UpdateTabsLanguage(antdtabs, userControlName); + } + else if (control is AntdUI.Table antdTable) + { + UpdateTableColumns(antdTable, userControlName, controlName); + } + + else if (control is SidebarNavigation antdSidebarNavigation) + { + UpdateProperty(antdSidebarNavigation, "Text", userControlName, controlName, "_Text"); + } + else if (control is CustomComboBox antdCustomComboBox) + { + UpdateProperty(antdCustomComboBox, "WatermarkText", userControlName, controlName, "_WatermarkText"); + } + else if (control is CustomGroupBox antdCustomGroupBox) + { + UpdateProperty(antdCustomGroupBox, "Text", userControlName, controlName, "_Text"); + } + + // 添加 CustomDataGridView 的处理 + else if (control is CustomDataGridView dataGridView) + { + UpdateDataGridViewColumns(dataGridView, userControlName, controlName); + } + // 可以在这里添加更多特定控件类型的处理 + } + + + /// + /// 更新 DataGridView 的列标题 + /// + private void UpdateDataGridViewColumns(CustomDataGridView dataGridView, string userControlName, string controlName) + { + try + { + foreach (DataGridViewColumn column in dataGridView.Columns) + { + // 构建语言键:窗体名_控件名_Column_列名 + string languageKey = $"{userControlName}_{controlName}_Column_{column.Name}"; + + // 获取翻译后的列标题 + string translatedHeader = LanguageManager.GetString(languageKey); + + // 如果找到翻译,则更新列标题 + if (!string.IsNullOrEmpty(translatedHeader) && translatedHeader != languageKey) + { + column.HeaderText = translatedHeader; + } + } + + // 如果需要翻译行标题(RowHeaders) + if (dataGridView.RowHeadersVisible) + { + string rowHeaderKey = $"{userControlName}_{controlName}_RowHeader"; + string translatedRowHeader = LanguageManager.GetString(rowHeaderKey); + if (!string.IsNullOrEmpty(translatedRowHeader) && translatedRowHeader != rowHeaderKey) + { + dataGridView.RowHeadersDefaultCellStyle.Format = translatedRowHeader; + } + } + } + catch (Exception ex) + { + Debug.WriteLine($"Error updating DataGridView columns: {ex.Message}"); + } + } + + /// + /// Table控件 + /// + /// + /// + /// + private void UpdateTableColumns(AntdUI.Table table, string formName, string controlName) + { + if (table.Columns != null) + { + foreach (var column in table.Columns) + { + + ///格式 MainForm_myTable_ColumnName_Title = "姓名" + + string resourceKey = $"{formName}_{controlName}_{column.Key}_Title"; + string translatedTitle = LanguageManager.GetString(resourceKey); + if (translatedTitle != resourceKey) + { + column.Title = translatedTitle; + } + } + // 强制表格重新加载布局以应用新的标题 + table.LoadLayout(); + } + } + + + /// + /// 遍历Tabs中所有TabPage的所有控件 + /// + /// 要遍历的Tabs控件 + /// 对每个控件执行的操作 + public static void ForEachControl(AntdUI.Tabs tabs, Action action) + { + if (tabs?.Pages == null) return; + + foreach (AntdUI.TabPage page in tabs.Pages) + { + // 遍历当前页面的所有控件 + ForEachControlRecursive(page, action); + } + } + + /// + /// 遍历指定TabPage中的所有控件(包括子控件) + /// + /// 要遍历的TabPage + /// 对每个控件执行的操作 + public static void ForEachControl(AntdUI.TabPage page, Action action) + { + ForEachControlRecursive(page, action); + } + + /// + /// 递归遍历控件树 + /// + private static void ForEachControlRecursive(Control control, Action action) + { + // 执行操作 + action(control); + + // 递归遍历子控件 + foreach (Control child in control.Controls) + { + ForEachControlRecursive(child, action); + } + } + + + + #region tabs + /// + /// 为Tabs控件及其所有子控件更新语言 + /// + /// 要更新的Tabs控件 + /// 窗体名称 + public static void UpdateLanguage(Tabs tabs, string formName) + { + if (tabs?.Pages == null) return; + + foreach (AntdUI.TabPage page in tabs.Pages) + { + // 更新TabPage标题 + UpdateControlLanguage(page, formName, tabs.Name, page.Name, "_Text"); + + // 递归更新所有子控件 + UpdateControlsLanguageRecursive(page.Controls, formName, tabs.Name, page.Name); + } + } + + /// + /// 递归更新控件树中所有控件的语言 + /// + private static void UpdateControlsLanguageRecursive(Control.ControlCollection controls, string formName, string tabsName, string pageName) + { + foreach (Control control in controls) + { + // 更新当前控件的文本 + UpdateControlLanguage(control, formName, tabsName, pageName, "_Text"); + + // 针对特定类型控件的特殊处理 + if (control is DataGridView grid) + { + UpdateDataGridViewLanguage(grid, formName, tabsName, pageName); + } + else if (control is AntdUI.Input input) + { + UpdateInPutLanguage(input, formName, tabsName, pageName); + } + else if (control is CustomComboBox combo) + { + UpdateComboBoxLanguage(combo, formName, tabsName, pageName); + } + else if (control is AntdUI.Table antdTable) + { + UpdateTableLanguage(antdTable, formName, tabsName, pageName); + } + // 可以添加其他特殊控件的处理... + + // 递归处理子控件 + if (control.Controls.Count > 0) + { + UpdateControlsLanguageRecursive(control.Controls, formName, tabsName, pageName); + } + } + } + + /// + /// 更新单个控件的语言 + /// + private static void UpdateControlLanguage(Control control, string formName, string tabsName, string pageName, string suffix) + { + // 格式: FormName_TabsName_PageName_ControlName_Suffix {pageName}_ {tabsName}_ + string resourceKey = $"{formName}_{tabsName}_{control.Name}{suffix}"; + string translatedText = LanguageManager.GetString(resourceKey); + + // 只在资源存在时更新 + if (translatedText != resourceKey) + { + control.Text = translatedText; + } + } + + private static void UpdateInPutLanguage(AntdUI.Input input, string formName, string tabsName, string pageName) + { + // 格式: FormName_TabsName_PageName_GridName_ColumnName_Title {pageName} + string resourceKey = $"{formName}_{tabsName}_{input.Name}_Placeholder"; + string translatedTitle = LanguageManager.GetString(resourceKey); + + if (translatedTitle != resourceKey) + { + input.PlaceholderText = translatedTitle; + } + } + + /// + /// 更新DataGridView的列标题语言 + /// + private static void UpdateDataGridViewLanguage(DataGridView grid, string formName, string tabsName, string pageName) + { + + foreach (DataGridViewColumn column in grid.Columns) + { + // 格式: FormName_TabsName_PageName_GridName_ColumnName_Title {pageName} + string resourceKey = $"{formName}_{tabsName}_{grid.Name}_{column.Name}_Title"; + string translatedTitle = LanguageManager.GetString(resourceKey); + + if (translatedTitle != resourceKey) + { + column.HeaderText = translatedTitle; + } + } + } + + private static void UpdateTableLanguage(AntdUI.Table table, string formName, string tabsName, string pageName) + { + foreach (var column in table.Columns) + { + // 格式: FormName_TabsName_PageName_GridName_ColumnName_Title {pageName} + //SettingControl_tabsSystemSet_configTable_PlcNum_Title + string resourceKey = $"{formName}_{tabsName}_{table.Name}_{column.Key}_Title"; + string translatedTitle = LanguageManager.GetString(resourceKey); + + if (translatedTitle != resourceKey) + { + column.Title = translatedTitle; + } + } + } + + /// + /// 更新ComboBox的项目语言 + /// + private static void UpdateComboBoxLanguage(CustomComboBox combo, string formName, string tabsName, string pageName) + { + // 如果ComboBox是数据绑定的,可能需要特殊处理 + for (int i = 0; i < combo.Items.Count; i++) + { + //{pageName}_ + string resourceKey = $"{formName}_{tabsName}_{combo.Name}_WatermarkText"; + string translatedItem = LanguageManager.GetString(resourceKey); + + if (translatedItem != resourceKey) + { + combo.WatermarkText = translatedItem; + } + } + } + + /// + /// 获取控件的完整资源键 + /// + public static string GetResourceKey(Control control, string formName, string tabsName, string pageName, string suffix) + { + return $"{formName}_{tabsName}_{pageName}_{control.Name}{suffix}"; + } + + + /// + /// 更新Tabs及其所有子控件的语言 + /// + /// Tabs控件 + /// 窗体名称 + public static void UpdateTabsLanguage(Tabs tabs, string formName) + { + if (tabs?.Pages == null) return; + + string tabsName = tabs.Name; + foreach (Control control in GetAllControls(tabs)) + { + // 构建资源键基础部分 + string baseKey = $"{formName}_{tabsName}_{control.Name}"; + string text; + + // 根据控件类型更新对应的文本属性 + switch (control) + { + case AntdUI.Input input: + text = LanguageManager.GetString($"{baseKey}_Placeholder"); + if (text != null) input.PlaceholderText = text; + break; + + case CustomComboBox combo: + text = LanguageManager.GetString($"{baseKey}_WatermarkText"); + if (text != null) combo.WatermarkText = text; + break; + + case DataGridView grid: + foreach (DataGridViewColumn column in grid.Columns) + { + text = LanguageManager.GetString($"{baseKey}_{column.Name}_Title"); + if (text != null) column.HeaderText = text; + } + break; + + case AntdUI.Table table: + foreach (var column in table.Columns) + { + text = LanguageManager.GetString($"{baseKey}_{column.Key}_Title"); + if (text != null) column.Title = text; + } + break; + + default: + // 普通控件处理Text属性 + text = LanguageManager.GetString($"{baseKey}_Text"); + if (text != null) control.Text = text; + break; + } + } + } + + /// + /// 获取控件及其所有子控件 + /// + private static IEnumerable GetAllControls(Tabs tabs) + { + var controls = new List(); + foreach (AntdUI.TabPage page in tabs.Pages) + { + controls.Add(page); // 添加TabPage本身 + controls.AddRange(GetChildControls(page)); + } + return controls; + } + + /// + /// 递归获取子控件 + /// + private static IEnumerable GetChildControls(Control control) + { + var controls = new List(); + foreach (Control child in control.Controls) + { + controls.Add(child); + controls.AddRange(GetChildControls(child)); + } + return controls; + } + #endregion + + + + private void UpdateProperty(object control, string propertyName, string userControlName, string controlName, string suffix) + { + string resourceKey = $"{userControlName}_{controlName}{suffix}"; + string translatedValue = LanguageManager.GetString(resourceKey); + if (translatedValue != resourceKey) + { + var property = control.GetType().GetProperty(propertyName); + if (property != null && property.CanWrite) + { + property.SetValue(control, translatedValue); + } + } + } + + + protected override void Dispose(bool disposing) + { + if (disposing) + { + LanguageManager.LanguageChanged -= OnLanguageChanged; + } + base.Dispose(disposing); + } + } + + public static class StringExtensions + { + /// + /// + /// + /// + /// + public static string Translated(this string key) + { + return LanguageManager.GetString(key); + } + + public static string Translated(this string key, params object[] args) + { + string translatedString = LanguageManager.GetString(key); + return args.Length > 0 ? string.Format(translatedString, args) : translatedString; + } + } +} \ No newline at end of file diff --git a/Language/Languages.Designer.cs b/Language/Languages.Designer.cs new file mode 100644 index 0000000..3e0a460 --- /dev/null +++ b/Language/Languages.Designer.cs @@ -0,0 +1,5438 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Language { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Languages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Languages() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Language.Languages", typeof(Languages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 添加通信组 的本地化字符串。 + /// + internal static string CommunicationEditForm_BtnAdd_Text { + get { + return ResourceManager.GetString("CommunicationEditForm_BtnAdd_Text", resourceCulture); + } + } + + /// + /// 查找类似 操作 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_EditHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_EditHeader", resourceCulture); + } + } + + /// + /// 查找类似 组名 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_GroupNameHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_GroupNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 是否启用 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_IsActiveHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_IsActiveHeader", resourceCulture); + } + } + + /// + /// 查找类似 反馈PLC 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_IsFeedbackPlcHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_IsFeedbackPlcHeader", resourceCulture); + } + } + + /// + /// 查找类似 触发读取 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_IsTiggerReadHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_IsTiggerReadHeader", resourceCulture); + } + } + + /// + /// 查找类似 长度 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_LengthHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_LengthHeader", resourceCulture); + } + } + + /// + /// 查找类似 PLC编号 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_PlcNumHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_PlcNumHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_RemarkHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_RemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 起始地址 的本地化字符串。 + /// + internal static string CommunicationEditForm_groupTable_StartHeader { + get { + return ResourceManager.GetString("CommunicationEditForm_groupTable_StartHeader", resourceCulture); + } + } + + /// + /// 查找类似 通信组配置 的本地化字符串。 + /// + internal static string CommunicationEditForm_lblTitle_Text { + get { + return ResourceManager.GetString("CommunicationEditForm_lblTitle_Text", resourceCulture); + } + } + + /// + /// 查找类似 D40已复位0 的本地化字符串。 + /// + internal static string D40已复位0 { + get { + return ResourceManager.GetString("D40已复位0", resourceCulture); + } + } + + /// + /// 查找类似 报警信息 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_Alarm_AlarmLogALARMHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_Alarm_AlarmLogALARMHeader", resourceCulture); + } + } + + /// + /// 查找类似 报警类型 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_Alarm_AlarmLogAlarmTypeHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_Alarm_AlarmLogAlarmTypeHeader", resourceCulture); + } + } + + /// + /// 查找类似 日期时间 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_Alarm_AlarmLogDateTimeHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_Alarm_AlarmLogDateTimeHeader", resourceCulture); + } + } + + /// + /// 查找类似 日志信息 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_Log_LogDateInformationHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_Log_LogDateInformationHeader", resourceCulture); + } + } + + /// + /// 查找类似 日期时间 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_Log_LogDateTimeHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_Log_LogDateTimeHeader", resourceCulture); + } + } + + /// + /// 查找类似 日志类型 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_Log_LogDateTypeHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_Log_LogDateTypeHeader", resourceCulture); + } + } + + /// + /// 查找类似 日期时间 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_OPLog_OPLogDateTimeHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_OPLog_OPLogDateTimeHeader", resourceCulture); + } + } + + /// + /// 查找类似 操作信息 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_OPLog_OPLogOperationalMessageHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_OPLog_OPLogOperationalMessageHeader", resourceCulture); + } + } + + /// + /// 查找类似 操作类型 的本地化字符串。 + /// + internal static string FrmAlarmLog_dgv_OPLog_OPLogOperationTypeHeader { + get { + return ResourceManager.GetString("FrmAlarmLog_dgv_OPLog_OPLogOperationTypeHeader", resourceCulture); + } + } + + /// + /// 查找类似 操作日志 的本地化字符串。 + /// + internal static string FrmAlarmLog_lblOperationLog_Text { + get { + return ResourceManager.GetString("FrmAlarmLog_lblOperationLog_Text", resourceCulture); + } + } + + /// + /// 查找类似 系统报警 的本地化字符串。 + /// + internal static string FrmAlarmLog_lblSystemAlarm_Text { + get { + return ResourceManager.GetString("FrmAlarmLog_lblSystemAlarm_Text", resourceCulture); + } + } + + /// + /// 查找类似 系统日志 的本地化字符串。 + /// + internal static string FrmAlarmLog_lblSystemLog_Text { + get { + return ResourceManager.GetString("FrmAlarmLog_lblSystemLog_Text", resourceCulture); + } + } + + /// + /// 查找类似 Pp 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe27_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe27_Text", resourceCulture); + } + } + + /// + /// 查找类似 Cp 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe28_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe28_Text", resourceCulture); + } + } + + /// + /// 查找类似 Ca 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe29_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe29_Text", resourceCulture); + } + } + + /// + /// 查找类似 PPK 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe30_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe30_Text", resourceCulture); + } + } + + /// + /// 查找类似 CPK 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe32_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe32_Text", resourceCulture); + } + } + + /// + /// 查找类似 Dev 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe33_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe33_Text", resourceCulture); + } + } + + /// + /// 查找类似 Mean 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe34_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe34_Text", resourceCulture); + } + } + + /// + /// 查找类似 SampleSize 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe35_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe35_Text", resourceCulture); + } + } + + /// + /// 查找类似 Groups 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe36_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe36_Text", resourceCulture); + } + } + + /// + /// 查找类似 Max 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe37_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe37_Text", resourceCulture); + } + } + + /// + /// 查找类似 Min 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe38_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe38_Text", resourceCulture); + } + } + + /// + /// 查找类似 Total 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe39_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe39_Text", resourceCulture); + } + } + + /// + /// 查找类似 平均值 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe40_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe40_Text", resourceCulture); + } + } + + /// + /// 查找类似 最大值 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe41_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe41_Text", resourceCulture); + } + } + + /// + /// 查找类似 最小值 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe42_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe42_Text", resourceCulture); + } + } + + /// + /// 查找类似 规格下限 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe49_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe49_Text", resourceCulture); + } + } + + /// + /// 查找类似 规格上限 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe50_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe50_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据组数 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe51_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe51_Text", resourceCulture); + } + } + + /// + /// 查找类似 样本子组大小 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe53_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe53_Text", resourceCulture); + } + } + + /// + /// 查找类似 目标值 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe54_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe54_Text", resourceCulture); + } + } + + /// + /// 查找类似 负3倍标准差 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe57_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe57_Text", resourceCulture); + } + } + + /// + /// 查找类似 标准差(组内) 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe58_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe58_Text", resourceCulture); + } + } + + /// + /// 查找类似 标准差(整体) 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe59_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe59_Text", resourceCulture); + } + } + + /// + /// 查找类似 正3倍标准差 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe63_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe63_Text", resourceCulture); + } + } + + /// + /// 查找类似 CPL 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe64_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe64_Text", resourceCulture); + } + } + + /// + /// 查找类似 CPU 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe65_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe65_Text", resourceCulture); + } + } + + /// + /// 查找类似 Cp 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe70_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe70_Text", resourceCulture); + } + } + + /// + /// 查找类似 Cpk 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe71_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe71_Text", resourceCulture); + } + } + + /// + /// 查找类似 Ca 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe74_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe74_Text", resourceCulture); + } + } + + /// + /// 查找类似 PPL 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe76_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe76_Text", resourceCulture); + } + } + + /// + /// 查找类似 Ppk 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe77_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe77_Text", resourceCulture); + } + } + + /// + /// 查找类似 PPU 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe78_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe78_Text", resourceCulture); + } + } + + /// + /// 查找类似 Pp 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabe79_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabe79_Text", resourceCulture); + } + } + + /// + /// 查找类似 CpkGrade 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabel1_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabel1_Text", resourceCulture); + } + } + + /// + /// 查找类似 样本总数 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabel2_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabel2_Text", resourceCulture); + } + } + + /// + /// 查找类似 PPM < LSL 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabel3_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabel3_Text", resourceCulture); + } + } + + /// + /// 查找类似 PPM Toatl 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabel4_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabel4_Text", resourceCulture); + } + } + + /// + /// 查找类似 PPM < USL 的本地化字符串。 + /// + internal static string FrmCpkCount_angleLabel5_Text { + get { + return ResourceManager.GetString("FrmCpkCount_angleLabel5_Text", resourceCulture); + } + } + + /// + /// 查找类似 清空数据 的本地化字符串。 + /// + internal static string FrmCpkCount_btClear_Text { + get { + return ResourceManager.GetString("FrmCpkCount_btClear_Text", resourceCulture); + } + } + + /// + /// 查找类似 计算CPK 的本地化字符串。 + /// + internal static string FrmCpkCount_btCPK_Text { + get { + return ResourceManager.GetString("FrmCpkCount_btCPK_Text", resourceCulture); + } + } + + /// + /// 查找类似 分析选项 的本地化字符串。 + /// + internal static string FrmCpkCount_btn_AnalysisOptions_Text { + get { + return ResourceManager.GetString("FrmCpkCount_btn_AnalysisOptions_Text", resourceCulture); + } + } + + /// + /// 查找类似 查 询 的本地化字符串。 + /// + internal static string FrmCpkCount_btSelect_Text { + get { + return ResourceManager.GetString("FrmCpkCount_btSelect_Text", resourceCulture); + } + } + + /// + /// 查找类似 生成虚拟数据 的本地化字符串。 + /// + internal static string FrmCpkCount_btTestData_Text { + get { + return ResourceManager.GetString("FrmCpkCount_btTestData_Text", resourceCulture); + } + } + + /// + /// 查找类似 常 量 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX1_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX1_Text", resourceCulture); + } + } + + /// + /// 查找类似 统 计 值 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX2_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX2_Text", resourceCulture); + } + } + + /// + /// 查找类似 工序能力(组内) 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX3_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX3_Text", resourceCulture); + } + } + + /// + /// 查找类似 其他值 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX4_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX4_Text", resourceCulture); + } + } + + /// + /// 查找类似 计 算 值 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX5_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX5_Text", resourceCulture); + } + } + + /// + /// 查找类似 实测性能 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX6_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX6_Text", resourceCulture); + } + } + + /// + /// 查找类似 工序能力(整体) 的本地化字符串。 + /// + internal static string FrmCpkCount_groupBoxEX7_Text { + get { + return ResourceManager.GetString("FrmCpkCount_groupBoxEX7_Text", resourceCulture); + } + } + + /// + /// 查找类似 查询选项 的本地化字符串。 + /// + internal static string FrmCpkCount_label1_Text { + get { + return ResourceManager.GetString("FrmCpkCount_label1_Text", resourceCulture); + } + } + + /// + /// 查找类似 查询时间区间 的本地化字符串。 + /// + internal static string FrmCpkCount_label2_Text { + get { + return ResourceManager.GetString("FrmCpkCount_label2_Text", resourceCulture); + } + } + + /// + /// 查找类似 XR控制图 的本地化字符串。 + /// + internal static string FrmCpkCount_tabPagePlus1_Text { + get { + return ResourceManager.GetString("FrmCpkCount_tabPagePlus1_Text", resourceCulture); + } + } + + /// + /// 查找类似 CPK分析图 的本地化字符串。 + /// + internal static string FrmCpkCount_tabPagePlus2_Text { + get { + return ResourceManager.GetString("FrmCpkCount_tabPagePlus2_Text", resourceCulture); + } + } + + /// + /// 查找类似 样本运行图 的本地化字符串。 + /// + internal static string FrmCpkCount_tabPagePlus3_Text { + get { + return ResourceManager.GetString("FrmCpkCount_tabPagePlus3_Text", resourceCulture); + } + } + + /// + /// 查找类似 均值运行图 的本地化字符串。 + /// + internal static string FrmCpkCount_tabPagePlus4_Text { + get { + return ResourceManager.GetString("FrmCpkCount_tabPagePlus4_Text", resourceCulture); + } + } + + /// + /// 查找类似 生产型号 的本地化字符串。 + /// + internal static string FrmDataMonitor_angleLabel1_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_angleLabel1_Text", resourceCulture); + } + } + + /// + /// 查找类似 物料编码 的本地化字符串。 + /// + internal static string FrmDataMonitor_angleLabel2_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_angleLabel2_Text", resourceCulture); + } + } + + /// + /// 查找类似 开始监控 的本地化字符串。 + /// + internal static string FrmDataMonitor_btSatrt_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_btSatrt_Text", resourceCulture); + } + } + + /// + /// 查找类似 停止监控 的本地化字符串。 + /// + internal static string FrmDataMonitor_btStop_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_btStop_Text", resourceCulture); + } + } + + /// + /// 查找类似 chart1 的本地化字符串。 + /// + internal static string FrmDataMonitor_chartPowerData1_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_chartPowerData1_Text", resourceCulture); + } + } + + /// + /// 查找类似 chart1 的本地化字符串。 + /// + internal static string FrmDataMonitor_chartPowerData2_Text + { + get + { + return ResourceManager.GetString("FrmDataMonitor_chartPowerData2_Text", resourceCulture); + } + } + + + + /// 查找类似 电芯等级 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutQtyHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutQtyHeader", resourceCulture); + } + } + + + + /// + /// 查找类似 电芯成功绑定数量 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutSuccTotalHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutSuccTotalHeader", resourceCulture); + } + } + + /// + /// 查找类似 电芯数量 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutTotalHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutTotalHeader", resourceCulture); + } + } + + /// + /// 查找类似 叠盘层数 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutStackingLayerHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutStackingLayerHeader", resourceCulture); + } + } + + /// + /// 查找类似 机架号 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutGongWeiHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutGongWeiHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutRemarkHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutRemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 综合结果 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutResultHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutResultHeader", resourceCulture); + } + } + + /// + /// 查找类似 时间 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutTestTimeHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutTestTimeHeader", resourceCulture); + } + } + + /// + /// 查找类似 托盘码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvBlankingData_OutVassoioIDHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutVassoioIDHeader", resourceCulture); + } + } + + ///// + ///// 查找类似 离子清洁设备号 的本地化字符串。 + ///// + //internal static string FrmDataMonitor_dgvBlankingData_OutWindDeviceNumHeader { + // get { + // return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutWindDeviceNumHeader", resourceCulture); + // } + //} + + ///// + ///// 查找类似 除尘风速 的本地化字符串。 + ///// + //internal static string FrmDataMonitor_dgvBlankingData_OutWindSpeedHeader { + // get { + // return ResourceManager.GetString("FrmDataMonitor_dgvBlankingData_OutWindSpeedHeader", resourceCulture); + // } + //} + + /// + /// 查找类似 电芯码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InBarCodeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InBarCodeHeader", resourceCulture); + } + } + + /// + /// 查找类似 通道 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InChannelNoHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InChannelNoHeader", resourceCulture); + } + } + + /// + /// 查找类似 进站是否上传MES 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InFlagHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InFlagHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InRemarkHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InRemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 电池在料盘中的位置 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_LocationHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_LocationHeader", resourceCulture); + } + } + + /// + /// 查找类似 电池二级档位 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InMoreGradeHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InMoreGradeHeader", resourceCulture); + } + } + + /// + /// 查找类似 结果 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InResultHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InResultHeader", resourceCulture); + } + } + + ///// + ///// 查找类似 托杯码 的本地化字符串。 + ///// + //internal static string FrmDataMonitor_dgvFeedingData_InRFIDHeader { + // get { + // return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InRFIDHeader", resourceCulture); + // } + //} + + /// + /// 查找类似 时间 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InTestTimeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InTestTimeHeader", resourceCulture); + } + } + /// + /// 查找类似 托盘位置号 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InLocationNumHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InLocationNumHeader", resourceCulture); + } + } + /// + /// 查找类似 托盘行号 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InRowNumHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InLocationNumHeader", resourceCulture); + } + } + /// + /// 查找类似 托盘码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InVassoioIDHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InVassoioIDHeader", resourceCulture); + } + } + /// + /// 查找类似 托盘工位号 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_GongWeiHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_GongWeiHeader", resourceCulture); + } + } + /// + /// 查找类似 电芯档位 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InGradeHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InGradeHeader", resourceCulture); + } + } + + /// + /// 查找类似 生产型号 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvFeedingData_InModelNameHeader + { + get + { + return ResourceManager.GetString("FrmDataMonitor_dgvFeedingData_InModelNameHeader", resourceCulture); + } + } + /// + /// 查找类似 通道 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCChannelHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCChannelHeader", resourceCulture); + } + } + + /// + /// 查找类似 料框码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCCMaterialTrayCodeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCCMaterialTrayCodeHeader", resourceCulture); + } + } + + /// + /// 查找类似 设备编码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCEquipNumHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCEquipNumHeader", resourceCulture); + } + } + + /// + /// 查找类似 物料编码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCMaterialCodeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCMaterialCodeHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCRemarkHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCRemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 结果 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCResultHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCResultHeader", resourceCulture); + } + } + + /// + /// 查找类似 时间 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvMaterialData_CCTestTimeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvMaterialData_CCTestTimeHeader", resourceCulture); + } + } + + /// + /// 查找类似 电芯码 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvSteelShellData_GKBarCodeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvSteelShellData_GKBarCodeHeader", resourceCulture); + } + } + + /// + /// 查找类似 通道 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvSteelShellData_GKChannelHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvSteelShellData_GKChannelHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvSteelShellData_GKRemarkHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvSteelShellData_GKRemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 结果 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvSteelShellData_GKResultHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvSteelShellData_GKResultHeader", resourceCulture); + } + } + + /// + /// 查找类似 时间 的本地化字符串。 + /// + internal static string FrmDataMonitor_dgvSteelShellData_GKTestTimeHeader { + get { + return ResourceManager.GetString("FrmDataMonitor_dgvSteelShellData_GKTestTimeHeader", resourceCulture); + } + } + + /// + /// 查找类似 日志记录 的本地化字符串。 + /// + internal static string FrmDataMonitor_groupBoxEX1_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_groupBoxEX1_Text", resourceCulture); + } + } + + /// + /// 查找类似 参数 的本地化字符串。 + /// + internal static string FrmDataMonitor_groupBoxEX2_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_groupBoxEX2_Text", resourceCulture); + } + } + + /// + /// 查找类似 结构件料盘 的本地化字符串。 + /// + internal static string FrmDataMonitor_groupBoxEX3_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_groupBoxEX3_Text", resourceCulture); + } + } + + /// + /// 查找类似 电芯进站 的本地化字符串。 + /// + internal static string FrmDataMonitor_groupBoxEX4_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_groupBoxEX4_Text", resourceCulture); + } + } + + /// + /// 查找类似 电芯出站 的本地化字符串。 + /// + internal static string FrmDataMonitor_groupBoxEX5_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_groupBoxEX5_Text", resourceCulture); + } + } + + /// + /// 查找类似 参数项 的本地化字符串。 + /// + internal static string FrmDataMonitor_lVConfigRange_Column0_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_lVConfigRange_Column0_Text", resourceCulture); + } + } + + /// + /// 查找类似 最小值 的本地化字符串。 + /// + internal static string FrmDataMonitor_lVConfigRange_Column1_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_lVConfigRange_Column1_Text", resourceCulture); + } + } + + /// + /// 查找类似 最大值 的本地化字符串。 + /// + internal static string FrmDataMonitor_lVConfigRange_Column2_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_lVConfigRange_Column2_Text", resourceCulture); + } + } + + /// + /// 查找类似 单位 的本地化字符串。 + /// + internal static string FrmDataMonitor_lVConfigRange_Column3_Text { + get { + return ResourceManager.GetString("FrmDataMonitor_lVConfigRange_Column3_Text", resourceCulture); + } + } + + /// + /// 查找类似 新增通信组 的本地化字符串。 + /// + internal static string FrmGroupConfig_btn_Add_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_btn_Add_Text", resourceCulture); + } + } + + /// + /// 查找类似 删除通信组 的本地化字符串。 + /// + internal static string FrmGroupConfig_btn_Delete_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_btn_Delete_Text", resourceCulture); + } + } + + /// + /// 查找类似 修改通信组 的本地化字符串。 + /// + internal static string FrmGroupConfig_btn_Modify_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_btn_Modify_Text", resourceCulture); + } + } + + /// + /// 查找类似 是否需要反馈结果 的本地化字符串。 + /// + internal static string FrmGroupConfig_chk_IsFeedbackPlc_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_chk_IsFeedbackPlc_Text", resourceCulture); + } + } + + /// + /// 查找类似 是否启用 的本地化字符串。 + /// + internal static string FrmGroupConfig_ckb_IsEnable_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_ckb_IsEnable_Text", resourceCulture); + } + } + + /// + /// 查找类似 是否为触发读取 的本地化字符串。 + /// + internal static string FrmGroupConfig_ckb_IsTiggerRead_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_ckb_IsTiggerRead_Text", resourceCulture); + } + } + + /// + /// 查找类似 通信组名称 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_GroupNameHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_GroupNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 启用 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_IsActiveHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_IsActiveHeader", resourceCulture); + } + } + + /// + /// 查找类似 是否需要反馈结果 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_IsFeedbackPlcHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_IsFeedbackPlcHeader", resourceCulture); + } + } + + /// + /// 查找类似 是否为触发读取 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_IsTiggerReadHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_IsTiggerReadHeader", resourceCulture); + } + } + + /// + /// 查找类似 长度 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_LengthHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_LengthHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注说明 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_RemarkHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_RemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 起始地址 的本地化字符串。 + /// + internal static string FrmGroupConfig_dgv_Main_StartHeader { + get { + return ResourceManager.GetString("FrmGroupConfig_dgv_Main_StartHeader", resourceCulture); + } + } + + /// + /// 查找类似 通信组配置 的本地化字符串。 + /// + internal static string FrmGroupConfig_label1_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_label1_Text", resourceCulture); + } + } + + /// + /// 查找类似 通信组名称 的本地化字符串。 + /// + internal static string FrmGroupConfig_label2_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_label2_Text", resourceCulture); + } + } + + /// + /// 查找类似 起始地址 的本地化字符串。 + /// + internal static string FrmGroupConfig_label3_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_label3_Text", resourceCulture); + } + } + + /// + /// 查找类似 长度 的本地化字符串。 + /// + internal static string FrmGroupConfig_label4_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_label4_Text", resourceCulture); + } + } + + /// + /// 查找类似 备注说明 的本地化字符串。 + /// + internal static string FrmGroupConfig_label6_Text { + get { + return ResourceManager.GetString("FrmGroupConfig_label6_Text", resourceCulture); + } + } + + /// + /// 查找类似 导 出 Excel 的本地化字符串。 + /// + internal static string FrmHistory_btn_AlarmExport_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_AlarmExport_Text", resourceCulture); + } + } + + /// + /// 查找类似 时 间 查 询 的本地化字符串。 + /// + internal static string FrmHistory_btn_AlarmQuery_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_AlarmQuery_Text", resourceCulture); + } + } + + /// + /// 查找类似 导 出 的本地化字符串。 + /// + internal static string FrmHistory_btn_ClassExPort_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_ClassExPort_Text", resourceCulture); + } + } + + /// + /// 查找类似 查 询 的本地化字符串。 + /// + internal static string FrmHistory_btn_ClassQuery_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_ClassQuery_Text", resourceCulture); + } + } + + /// + /// 查找类似 导 出 的本地化字符串。 + /// + internal static string FrmHistory_btn_DaysExPort_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_DaysExPort_Text", resourceCulture); + } + } + + /// + /// 查找类似 查 询 的本地化字符串。 + /// + internal static string FrmHistory_btn_DaysQuery_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_DaysQuery_Text", resourceCulture); + } + } + + /// + /// 查找类似 导 出 Excel 的本地化字符串。 + /// + internal static string FrmHistory_btn_ExPort_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_ExPort_Text", resourceCulture); + } + } + + /// + /// 查找类似 导 出 的本地化字符串。 + /// + internal static string FrmHistory_btn_MonthExPort_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_MonthExPort_Text", resourceCulture); + } + } + + /// + /// 查找类似 查 询 的本地化字符串。 + /// + internal static string FrmHistory_btn_MonthQuery_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_MonthQuery_Text", resourceCulture); + } + } + + /// + /// 查找类似 查 询 的本地化字符串。 + /// + internal static string FrmHistory_btn_Query_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_Query_Text", resourceCulture); + } + } + + /// + /// 查找类似 补 传 的本地化字符串。 + /// + internal static string FrmHistory_btn_ReUpMes_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_ReUpMes_Text", resourceCulture); + } + } + + /// + /// 查找类似 导 出 的本地化字符串。 + /// + internal static string FrmHistory_btn_WeekExPort_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_WeekExPort_Text", resourceCulture); + } + } + + /// + /// 查找类似 查 询 的本地化字符串。 + /// + internal static string FrmHistory_btn_WeekQuery_Text { + get { + return ResourceManager.GetString("FrmHistory_btn_WeekQuery_Text", resourceCulture); + } + } + + /// + /// 查找类似 报警内容 的本地化字符串。 + /// + internal static string FrmHistory_dgv_AlarmData_AlarmContent { + get { + return ResourceManager.GetString("FrmHistory_dgv_AlarmData_AlarmContent", resourceCulture); + } + } + + /// + /// 查找类似 报警次数 的本地化字符串。 + /// + internal static string FrmHistory_dgv_AlarmData_AlarmCount { + get { + return ResourceManager.GetString("FrmHistory_dgv_AlarmData_AlarmCount", resourceCulture); + } + } + + /// + /// 查找类似 报警时间 的本地化字符串。 + /// + internal static string FrmHistory_dgv_AlarmData_AlarmTime { + get { + return ResourceManager.GetString("FrmHistory_dgv_AlarmData_AlarmTime", resourceCulture); + } + } + + /// + /// 查找类似 类别 的本地化字符串。 + /// + internal static string FrmHistory_dgv_AlarmData_Class { + get { + return ResourceManager.GetString("FrmHistory_dgv_AlarmData_Class", resourceCulture); + } + } + + /// + /// 查找类似 PLC地址 的本地化字符串。 + /// + internal static string FrmHistory_dgv_AlarmData_PLCAdress { + get { + return ResourceManager.GetString("FrmHistory_dgv_AlarmData_PLCAdress", resourceCulture); + } + } + + /// + /// 查找类似 条码 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_BarCode { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_BarCode", resourceCulture); + } + } + + /// + /// 查找类似 电池型号 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_Model + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_Model", resourceCulture); + } + } + + /// + /// 查找类似 通道编号 的本地化字符串。 + /// + //internal static string FrmHistory_dgv_Main_ChannelNo { + // get { + // return ResourceManager.GetString("FrmHistory_dgv_Main_ChannelNo", resourceCulture); + // } + //} + + /// + /// 查找类似 标志 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_Flag { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_Flag", resourceCulture); + } + } + + /// + /// 查找类似 信息 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_Info { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_Info", resourceCulture); + } + } + + /// + /// 查找类似 物料编码 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_MaterialCode { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_MaterialCode", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_Remark { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_Remark", resourceCulture); + } + } + + /// + /// 查找类似 结果 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_Result { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_Result", resourceCulture); + } + } + + /// + /// 查找类似 RFID托杯码 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_RFID { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_RFID", resourceCulture); + } + } + + /// + /// 查找类似 测试时间 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_TestTime { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_TestTime", resourceCulture); + } + } + + /// + /// 查找类似 风设备编号 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_WindDeviceNum { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_WindDeviceNum", resourceCulture); + } + } + + /// + /// 查找类似 风速 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_WindSpeed { + get { + return ResourceManager.GetString("FrmHistory_dgv_Main_WindSpeed", resourceCulture); + } + } + + /// + /// 查找类似 电池等级 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_CellGrade + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_CellGrade", resourceCulture); + } + } + + /// + /// 查找类似 机架号 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_Gongwei + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_Gongwei", resourceCulture); + } + } + + /// + /// 查找类似 箱唛码 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_ContainerCode + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_ContainerCode", resourceCulture); + } + } + + /// + /// 查找类似 电池位置 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_CellPosition + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_CellPosition", resourceCulture); + } + } + + /// + /// 查找类似 绑定结果 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_PackResult + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_PackResult", resourceCulture); + } + } + + /// + /// 查找类似 绑定失败原因 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_PackFailReason + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_PackFailReason", resourceCulture); + } + } + + /// + /// 查找类似 出站类型 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_OutStationType + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_OutStationType", resourceCulture); + } + } + + /// + /// 查找类似 替换前电池条码 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_OldBarCode + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_OldBarCode", resourceCulture); + } + } + + /// + /// 查找类似 替换后电池条码 的本地化字符串。 + /// + internal static string FrmHistory_dgv_Main_NewBarCode + { + get + { + return ResourceManager.GetString("FrmHistory_dgv_Main_NewBarCode", resourceCulture); + } + } + + /// + /// 查找类似 稼动率均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvClass_JiaDL { + get { + return ResourceManager.GetString("FrmHistory_dgvClass_JiaDL", resourceCulture); + } + } + + /// + /// 查找类似 PPM均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvClass_Ppm { + get { + return ResourceManager.GetString("FrmHistory_dgvClass_Ppm", resourceCulture); + } + } + + /// + /// 查找类似 良品率 的本地化字符串。 + /// + internal static string FrmHistory_dgvClass_Prod { + get { + return ResourceManager.GetString("FrmHistory_dgvClass_Prod", resourceCulture); + } + } + + /// + /// 查找类似 产品投入 的本地化字符串。 + /// + internal static string FrmHistory_dgvClass_ProdIn { + get { + return ResourceManager.GetString("FrmHistory_dgvClass_ProdIn", resourceCulture); + } + } + + /// + /// 查找类似 产品产出 的本地化字符串。 + /// + internal static string FrmHistory_dgvClass_ProdOut { + get { + return ResourceManager.GetString("FrmHistory_dgvClass_ProdOut", resourceCulture); + } + } + + /// + /// 查找类似 测试时间 的本地化字符串。 + /// + internal static string FrmHistory_dgvClass_TestTime { + get { + return ResourceManager.GetString("FrmHistory_dgvClass_TestTime", resourceCulture); + } + } + + /// + /// 查找类似 日期 的本地化字符串。 + /// + internal static string FrmHistory_dgvDays_Day { + get { + return ResourceManager.GetString("FrmHistory_dgvDays_Day", resourceCulture); + } + } + + /// + /// 查找类似 稼动率均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvDays_JiaDL { + get { + return ResourceManager.GetString("FrmHistory_dgvDays_JiaDL", resourceCulture); + } + } + + /// + /// 查找类似 PPM均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvDays_Ppm { + get { + return ResourceManager.GetString("FrmHistory_dgvDays_Ppm", resourceCulture); + } + } + + /// + /// 查找类似 良品率 的本地化字符串。 + /// + internal static string FrmHistory_dgvDays_Prod { + get { + return ResourceManager.GetString("FrmHistory_dgvDays_Prod", resourceCulture); + } + } + + /// + /// 查找类似 产品投入 的本地化字符串。 + /// + internal static string FrmHistory_dgvDays_ProdIn { + get { + return ResourceManager.GetString("FrmHistory_dgvDays_ProdIn", resourceCulture); + } + } + + /// + /// 查找类似 产品产出 的本地化字符串。 + /// + internal static string FrmHistory_dgvDays_ProdOut { + get { + return ResourceManager.GetString("FrmHistory_dgvDays_ProdOut", resourceCulture); + } + } + + /// + /// 查找类似 稼动率均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvMonth_JiaDL { + get { + return ResourceManager.GetString("FrmHistory_dgvMonth_JiaDL", resourceCulture); + } + } + + /// + /// 查找类似 月份 的本地化字符串。 + /// + internal static string FrmHistory_dgvMonth_Month { + get { + return ResourceManager.GetString("FrmHistory_dgvMonth_Month", resourceCulture); + } + } + + /// + /// 查找类似 PPM均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvMonth_Ppm { + get { + return ResourceManager.GetString("FrmHistory_dgvMonth_Ppm", resourceCulture); + } + } + + /// + /// 查找类似 良品率 的本地化字符串。 + /// + internal static string FrmHistory_dgvMonth_Prod { + get { + return ResourceManager.GetString("FrmHistory_dgvMonth_Prod", resourceCulture); + } + } + + /// + /// 查找类似 产品投入 的本地化字符串。 + /// + internal static string FrmHistory_dgvMonth_ProdIn { + get { + return ResourceManager.GetString("FrmHistory_dgvMonth_ProdIn", resourceCulture); + } + } + + /// + /// 查找类似 产品产出 的本地化字符串。 + /// + internal static string FrmHistory_dgvMonth_ProdOut { + get { + return ResourceManager.GetString("FrmHistory_dgvMonth_ProdOut", resourceCulture); + } + } + + /// + /// 查找类似 稼动率均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvWeek_JiaDL { + get { + return ResourceManager.GetString("FrmHistory_dgvWeek_JiaDL", resourceCulture); + } + } + + /// + /// 查找类似 PPM均值 的本地化字符串。 + /// + internal static string FrmHistory_dgvWeek_Ppm { + get { + return ResourceManager.GetString("FrmHistory_dgvWeek_Ppm", resourceCulture); + } + } + + /// + /// 查找类似 良品率 的本地化字符串。 + /// + internal static string FrmHistory_dgvWeek_Prod { + get { + return ResourceManager.GetString("FrmHistory_dgvWeek_Prod", resourceCulture); + } + } + + /// + /// 查找类似 累计投入 的本地化字符串。 + /// + internal static string FrmHistory_dgvWeek_ProdIn { + get { + return ResourceManager.GetString("FrmHistory_dgvWeek_ProdIn", resourceCulture); + } + } + + /// + /// 查找类似 累计产出 的本地化字符串。 + /// + internal static string FrmHistory_dgvWeek_ProdOut { + get { + return ResourceManager.GetString("FrmHistory_dgvWeek_ProdOut", resourceCulture); + } + } + + /// + /// 查找类似 周别 的本地化字符串。 + /// + internal static string FrmHistory_dgvWeek_Week { + get { + return ResourceManager.GetString("FrmHistory_dgvWeek_Week", resourceCulture); + } + } + + /// + /// 查找类似 班次 的本地化字符串。 + /// + internal static string FrmHistory_label11_Text { + get { + return ResourceManager.GetString("FrmHistory_label11_Text", resourceCulture); + } + } + + /// + /// 查找类似 电芯码 的本地化字符串。 + /// + internal static string FrmHistory_label13_Text { + get { + return ResourceManager.GetString("FrmHistory_label13_Text", resourceCulture); + } + } + + /// + /// 查找类似 RFID 的本地化字符串。 + /// + internal static string FrmHistory_label4_Text { + get { + return ResourceManager.GetString("FrmHistory_label4_Text", resourceCulture); + } + } + + /// + /// 查找类似 统计日期 的本地化字符串。 + /// + internal static string FrmHistory_label5_Text { + get { + return ResourceManager.GetString("FrmHistory_label5_Text", resourceCulture); + } + } + + /// + /// 查找类似 统计日期 的本地化字符串。 + /// + internal static string FrmHistory_label6_Text { + get { + return ResourceManager.GetString("FrmHistory_label6_Text", resourceCulture); + } + } + + /// + /// 查找类似 统计时间 的本地化字符串。 + /// + internal static string FrmHistory_label7_Text { + get { + return ResourceManager.GetString("FrmHistory_label7_Text", resourceCulture); + } + } + + /// + /// 查找类似 统计时间 的本地化字符串。 + /// + internal static string FrmHistory_label8_Text { + get { + return ResourceManager.GetString("FrmHistory_label8_Text", resourceCulture); + } + } + + /// + /// 查找类似 结束时间 的本地化字符串。 + /// + internal static string FrmHistory_lblAlarmEndTime_Text { + get { + return ResourceManager.GetString("FrmHistory_lblAlarmEndTime_Text", resourceCulture); + } + } + + /// + /// 查找类似 开始时间 的本地化字符串。 + /// + internal static string FrmHistory_lblAlarmStartTime_Text { + get { + return ResourceManager.GetString("FrmHistory_lblAlarmStartTime_Text", resourceCulture); + } + } + + /// + /// 查找类似 条码 的本地化字符串。 + /// + internal static string FrmHistory_lblBarcode_Text { + get { + return ResourceManager.GetString("FrmHistory_lblBarcode_Text", resourceCulture); + } + } + + /// + /// 查找类似 结束时间 的本地化字符串。 + /// + internal static string FrmHistory_lblEndtime_Text { + get { + return ResourceManager.GetString("FrmHistory_lblEndtime_Text", resourceCulture); + } + } + + /// + /// 查找类似 开始时间 的本地化字符串。 + /// + internal static string FrmHistory_lblStartTime_Text { + get { + return ResourceManager.GetString("FrmHistory_lblStartTime_Text", resourceCulture); + } + } + + /// + /// 查找类似 查询类型 的本地化字符串。 + /// + internal static string FrmHistory_lblType_Text { + get { + return ResourceManager.GetString("FrmHistory_lblType_Text", resourceCulture); + } + } + + /// + /// 查找类似 历史生产数据查询 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus1_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus1_Text", resourceCulture); + } + } + + /// + /// 查找类似 产能统计查询 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus2_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus2_Text", resourceCulture); + } + } + + /// + /// 查找类似 日志报警数据查询 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus3_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus3_Text", resourceCulture); + } + } + + /// + /// 查找类似 按班次统计 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus4_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus4_Text", resourceCulture); + } + } + + /// + /// 查找类似 按日统计 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus5_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus5_Text", resourceCulture); + } + } + + /// + /// 查找类似 按周统计 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus6_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus6_Text", resourceCulture); + } + } + + /// + /// 查找类似 按月统计 的本地化字符串。 + /// + internal static string FrmHistory_tabPagePlus7_Text { + get { + return ResourceManager.GetString("FrmHistory_tabPagePlus7_Text", resourceCulture); + } + } + + /// + /// 查找类似 登录 的本地化字符串。 + /// + internal static string FrmLogin_btn_Login_Text { + get { + return ResourceManager.GetString("FrmLogin_btn_Login_Text", resourceCulture); + } + } + + /// + /// 查找类似 亿纬动力 的本地化字符串。 + /// + internal static string FrmLogin_lblCompany_Text { + get { + return ResourceManager.GetString("FrmLogin_lblCompany_Text", resourceCulture); + } + } + + /// + /// 查找类似 亿纬动力 的本地化字符串。 + /// + internal static string FrmLoginMes_lblMesCompany_Text { + get { + return ResourceManager.GetString("FrmLoginMes_lblMesCompany_Text", resourceCulture); + } + } + + /// + /// 查找类似 启动 的本地化字符串。 + /// + internal static string FrmMain_btSatrt_Text { + get { + return ResourceManager.GetString("FrmMain_btSatrt_Text", resourceCulture); + } + } + + /// + /// 查找类似 49工厂 的本地化字符串。 + /// + internal static string FrmMain_lblHeading_Text { + get { + return ResourceManager.GetString("FrmMain_lblHeading_Text", resourceCulture); + } + } + + /// + /// 查找类似 亿纬动力 的本地化字符串。 + /// + internal static string FrmMain_lblLogTitle_Text { + get { + return ResourceManager.GetString("FrmMain_lblLogTitle_Text", resourceCulture); + } + } + + /// + /// 查找类似 一次外观检测数据采集系统 的本地化字符串。 + /// + internal static string FrmMain_lblSubtitle_Text { + get { + return ResourceManager.GetString("FrmMain_lblSubtitle_Text", resourceCulture); + } + } + + /// + /// 查找类似 日志报警 的本地化字符串。 + /// + internal static string FrmMain_nav_AlarmLog_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_AlarmLog_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 数据分析 的本地化字符串。 + /// + internal static string FrmMain_nav_CPK_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_CPK_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 数据监控 的本地化字符串。 + /// + internal static string FrmMain_nav_DataMonitor_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_DataMonitor_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 电池状况 的本地化字符串。 + /// + internal static string FrmMain_nav_BatteryStatus_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_BatteryStatus_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 数据追溯 的本地化字符串。 + /// + internal static string FrmMain_nav_HistotryData_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_HistotryData_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 集中监控 的本地化字符串。 + /// + internal static string FrmMain_nav_Monitor_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_Monitor_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 参数设置 的本地化字符串。 + /// + internal static string FrmMain_nav_SetSystem_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_SetSystem_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 系统设置 的本地化字符串。 + /// + internal static string FrmMain_nav_System_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_System_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 用户管理 的本地化字符串。 + /// + internal static string FrmMain_nav_UserInfo_TitleName { + get { + return ResourceManager.GetString("FrmMain_nav_UserInfo_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 关于 的本地化字符串。 + /// + internal static string FrmMain_关于_Text { + get { + return ResourceManager.GetString("FrmMain_关于_Text", resourceCulture); + } + } + + /// + /// 查找类似 显示主界面 的本地化字符串。 + /// + internal static string FrmMain_显示主界面_Text { + get { + return ResourceManager.GetString("FrmMain_显示主界面_Text", resourceCulture); + } + } + + /// + /// 查找类似 退出 的本地化字符串。 + /// + internal static string FrmMain_退出_Text { + get { + return ResourceManager.GetString("FrmMain_退出_Text", resourceCulture); + } + } + + /// + /// 查找类似 隐藏主界面 的本地化字符串。 + /// + internal static string FrmMain_隐藏主界面_Text { + get { + return ResourceManager.GetString("FrmMain_隐藏主界面_Text", resourceCulture); + } + } + + /// + /// 查找类似 非刷卡模式 的本地化字符串。 + /// + internal static string FrmMain_非刷卡模式ToolStripMenuItem_Text { + get { + return ResourceManager.GetString("FrmMain_非刷卡模式ToolStripMenuItem_Text", resourceCulture); + } + } + + /// + /// 查找类似 智能电表 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text", resourceCulture); + } + } + + /// + /// 查找类似 A相电压 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text1 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text1", resourceCulture); + } + } + + /// + /// 查找类似 总有功功率 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text10 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text10", resourceCulture); + } + } + + /// + /// 查找类似 总功率因素 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text11 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text11", resourceCulture); + } + } + + /// + /// 查找类似 电压变比 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text12 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text12", resourceCulture); + } + } + + /// + /// 查找类似 电流变比 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text13 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text13", resourceCulture); + } + } + + /// + /// 查找类似 累计电能 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text14 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text14", resourceCulture); + } + } + + /// + /// 查找类似 B相电压 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text2 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text2", resourceCulture); + } + } + + /// + /// 查找类似 C相电压 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text3 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text3", resourceCulture); + } + } + + /// + /// 查找类似 A相电流 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text4 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text4", resourceCulture); + } + } + + /// + /// 查找类似 B相电流 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text5 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text5", resourceCulture); + } + } + + /// + /// 查找类似 C相电流 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text6 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text6", resourceCulture); + } + } + + /// + /// 查找类似 A相功率 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text7 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text7", resourceCulture); + } + } + + /// + /// 查找类似 B相功率 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text8 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text8", resourceCulture); + } + } + + /// + /// 查找类似 C相功率 的本地化字符串。 + /// + internal static string FrmMonitor_EyMaterH1_Text9 { + get { + return ResourceManager.GetString("FrmMonitor_EyMaterH1_Text9", resourceCulture); + } + } + + /// + /// 查找类似 告警TOP10统计 的本地化字符串。 + /// + internal static string FrmMonitor_gpAlarmBox_Text { + get { + return ResourceManager.GetString("FrmMonitor_gpAlarmBox_Text", resourceCulture); + } + } + + /// + /// 查找类似 产能统计 的本地化字符串。 + /// + internal static string FrmMonitor_gpCapacityBox_Text { + get { + return ResourceManager.GetString("FrmMonitor_gpCapacityBox_Text", resourceCulture); + } + } + + /// + /// 查找类似 不良项统计 的本地化字符串。 + /// + internal static string FrmMonitor_gpNgBox_Text { + get { + return ResourceManager.GetString("FrmMonitor_gpNgBox_Text", resourceCulture); + } + } + + /// + /// 查找类似 OK数 的本地化字符串。 + /// + internal static string FrmMonitor_lblOkTotal_Text { + get { + return ResourceManager.GetString("FrmMonitor_lblOkTotal_Text", resourceCulture); + } + } + + /// + /// 查找类似 优率 的本地化字符串。 + /// + internal static string FrmMonitor_lblRate_Text { + get { + return ResourceManager.GetString("FrmMonitor_lblRate_Text", resourceCulture); + } + } + + /// + /// 查找类似 生产总数 的本地化字符串。 + /// + internal static string FrmMonitor_lblTotalQty_Text { + get { + return ResourceManager.GetString("FrmMonitor_lblTotalQty_Text", resourceCulture); + } + } + + /// + /// 查找类似 稼动率 的本地化字符串。 + /// + internal static string FrmMonitor_lblUtilizationRate_Text { + get { + return ResourceManager.GetString("FrmMonitor_lblUtilizationRate_Text", resourceCulture); + } + } + + /// + /// 查找类似 设备编号 的本地化字符串。 + /// + internal static string FrmMonitor_titleEqp_code_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_titleEqp_code_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 工厂代号 的本地化字符串。 + /// + internal static string FrmMonitor_titleFactory_code_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_titleFactory_code_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 线体编号 的本地化字符串。 + /// + internal static string FrmMonitor_titleLine_No_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_titleLine_No_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 生产型号 的本地化字符串。 + /// + internal static string FrmMonitor_titleModeName_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_titleModeName_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 开机时间 的本地化字符串。 + /// + internal static string FrmMonitor_titleRunTime_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_titleRunTime_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 运行时间 的本地化字符串。 + /// + internal static string FrmMonitor_titleStartTime_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_titleStartTime_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 智能电表(设备) 的本地化字符串。 + /// + internal static string FrmMonitor_ucElectricityMeterV1_TitleName { + get { + return ResourceManager.GetString("FrmMonitor_ucElectricityMeterV1_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 取消 的本地化字符串。 + /// + internal static string FrmMsgBoxOutWithAck_btn_Cancel_Text { + get { + return ResourceManager.GetString("FrmMsgBoxOutWithAck_btn_Cancel_Text", resourceCulture); + } + } + + /// + /// 查找类似 确定 的本地化字符串。 + /// + internal static string FrmMsgBoxOutWithAckbtn_Sure_Text { + get { + return ResourceManager.GetString("FrmMsgBoxOutWithAckbtn_Sure_Text", resourceCulture); + } + } + + /// + /// 查找类似 是否确认要退出系统? 的本地化字符串。 + /// + internal static string FrmMsgBoxOutWithAcklbl_Content_Text { + get { + return ResourceManager.GetString("FrmMsgBoxOutWithAcklbl_Content_Text", resourceCulture); + } + } + + /// + /// 查找类似 退出系统 的本地化字符串。 + /// + internal static string FrmMsgBoxOutWithAcklbl_Title_Text { + get { + return ResourceManager.GetString("FrmMsgBoxOutWithAcklbl_Title_Text", resourceCulture); + } + } + + /// + /// 查找类似 取消 的本地化字符串。 + /// + internal static string FrmMsgBoxWithAck_btn_Cancel_Text { + get { + return ResourceManager.GetString("FrmMsgBoxWithAck_btn_Cancel_Text", resourceCulture); + } + } + + /// + /// 查找类似 确定 的本地化字符串。 + /// + internal static string FrmMsgBoxWithAck_btn_Sure_Text { + get { + return ResourceManager.GetString("FrmMsgBoxWithAck_btn_Sure_Text", resourceCulture); + } + } + + /// + /// 查找类似 是否确认要退出系统? 的本地化字符串。 + /// + internal static string FrmMsgBoxWithAck_lbl_Content_Text { + get { + return ResourceManager.GetString("FrmMsgBoxWithAck_lbl_Content_Text", resourceCulture); + } + } + + /// + /// 查找类似 退出系统 的本地化字符串。 + /// + internal static string FrmMsgBoxWithAck_lbl_Title_Text { + get { + return ResourceManager.GetString("FrmMsgBoxWithAck_lbl_Title_Text", resourceCulture); + } + } + + /// + /// 查找类似 添加型号 的本地化字符串。 + /// + internal static string FrmRecipe_btn_Add_Text { + get { + return ResourceManager.GetString("FrmRecipe_btn_Add_Text", resourceCulture); + } + } + + /// + /// 查找类似 保存参数 的本地化字符串。 + /// + internal static string FrmRecipe_btn_Save_Text { + get { + return ResourceManager.GetString("FrmRecipe_btn_Save_Text", resourceCulture); + } + } + + /// + /// 查找类似 删除型号 的本地化字符串。 + /// + internal static string FrmRecipe_btnDelProductModel_Text { + get { + return ResourceManager.GetString("FrmRecipe_btnDelProductModel_Text", resourceCulture); + } + } + + /// + /// 查找类似 参数项名称 的本地化字符串。 + /// + internal static string FrmRecipe_dgvPara_CGNameHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvPara_CGNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 最大值 的本地化字符串。 + /// + internal static string FrmRecipe_dgvPara_ParaValueMaxHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvPara_ParaValueMaxHeader", resourceCulture); + } + } + + /// + /// 查找类似 最小值 的本地化字符串。 + /// + internal static string FrmRecipe_dgvPara_ParaValueMinHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvPara_ParaValueMinHeader", resourceCulture); + } + } + + /// + /// 查找类似 单位 的本地化字符串。 + /// + internal static string FrmRecipe_dgvPara_UintHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvPara_UintHeader", resourceCulture); + } + } + + /// + /// 查找类似 物料编码 的本地化字符串。 + /// + internal static string FrmRecipe_dgvProdModel_MaterialCodeHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvProdModel_MaterialCodeHeader", resourceCulture); + } + } + + /// + /// 查找类似 生产型号 的本地化字符串。 + /// + internal static string FrmRecipe_dgvProdModel_ModelNameHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvProdModel_ModelNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmRecipe_dgvProdModel_RemarkHeader { + get { + return ResourceManager.GetString("FrmRecipe_dgvProdModel_RemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 当前型号 的本地化字符串。 + /// + internal static string FrmRecipe_label1_Text { + get { + return ResourceManager.GetString("FrmRecipe_label1_Text", resourceCulture); + } + } + + /// + /// 查找类似 生产型号 的本地化字符串。 + /// + internal static string FrmRecipe_label2_Text { + get { + return ResourceManager.GetString("FrmRecipe_label2_Text", resourceCulture); + } + } + + /// + /// 查找类似 物料编码 的本地化字符串。 + /// + internal static string FrmRecipe_label4_Text { + get { + return ResourceManager.GetString("FrmRecipe_label4_Text", resourceCulture); + } + } + + /// + /// 查找类似 THPR 的本地化字符串。 + /// + internal static string FrmRecipe_lb_Model_Text { + get { + return ResourceManager.GetString("FrmRecipe_lb_Model_Text", resourceCulture); + } + } + + /// + /// 查找类似 添加PLC 的本地化字符串。 + /// + internal static string FrmSystemSet_btAddPLC_Text { + get { + return ResourceManager.GetString("FrmSystemSet_btAddPLC_Text", resourceCulture); + } + } + + /// + /// 查找类似 取消设置 的本地化字符串。 + /// + internal static string FrmSystemSet_btn_Cancel_Text { + get { + return ResourceManager.GetString("FrmSystemSet_btn_Cancel_Text", resourceCulture); + } + } + + /// + /// 查找类似 通信组配置 的本地化字符串。 + /// + internal static string FrmSystemSet_btn_GroupConfig_Text { + get { + return ResourceManager.GetString("FrmSystemSet_btn_GroupConfig_Text", resourceCulture); + } + } + + /// + /// 查找类似 确定设置 的本地化字符串。 + /// + internal static string FrmSystemSet_btn_Sure_Text { + get { + return ResourceManager.GetString("FrmSystemSet_btn_Sure_Text", resourceCulture); + } + } + + /// + /// 查找类似 变量配置 的本地化字符串。 + /// + internal static string FrmSystemSet_btn_VarConfig_Text { + get { + return ResourceManager.GetString("FrmSystemSet_btn_VarConfig_Text", resourceCulture); + } + } + + + /// + /// 查找类似 PLC配置 的本地化字符串。 + /// + internal static string FrmSystemSet_btnPlcConfig_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_btnPlcConfig_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 设置 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_CommConfigHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_CommConfigHeader", resourceCulture); + } + } + + /// + /// 查找类似 操作 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_EditHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_EditHeader", resourceCulture); + } + } + + /// + /// 查找类似 心跳地址 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_HeartBeatHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_HeartBeatHeader", resourceCulture); + } + } + + /// + /// 查找类似 IP地址 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_IPAddressHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_IPAddressHeader", resourceCulture); + } + } + + /// + /// 查找类似 激活状态 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_IsActiveHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_IsActiveHeader", resourceCulture); + } + } + + /// + /// 查找类似 心跳状态 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_IsHeartBeatHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_IsHeartBeatHeader", resourceCulture); + } + } + + /// + /// 查找类似 PLC编号 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_PlcNumHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_PlcNumHeader", resourceCulture); + } + } + + /// + /// 查找类似 PLC类型 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_PLCTypeHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_PLCTypeHeader", resourceCulture); + } + } + + /// + /// 查找类似 端口号 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_PortHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_PortHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string FrmSystemSet_dgvPlcConfigs_RemarkHeader { + get { + return ResourceManager.GetString("FrmSystemSet_dgvPlcConfigs_RemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 物料编码 的本地化字符串。 + /// + internal static string FrmSystemSet_lbl_materialCode_Text + { + get { + return ResourceManager.GetString("FrmSystemSet_lbl_materialCode_Text", resourceCulture); + } + } + + /// + /// 查找类似 获取MES参数 的本地化字符串。 + /// + internal static string FrmSystemSet_label10_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label10_Text", resourceCulture); + } + } + + /// + /// 查找类似 开启刷卡模式 的本地化字符串。 + /// + internal static string FrmSystemSet_label11_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label11_Text", resourceCulture); + } + } + + /// + /// 查找类似 PLC类型配置 的本地化字符串。 + /// + internal static string FrmSystemSet_label12_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label12_Text", resourceCulture); + } + } + + /// + /// 查找类似 设备编号 的本地化字符串。 + /// + internal static string FrmSystemSet_label13_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label13_Text", resourceCulture); + } + } + + /// + /// 查找类似 产线编号 的本地化字符串。 + /// + internal static string FrmSystemSet_label14_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label14_Text", resourceCulture); + } + } + + /// + /// 查找类似 工厂代码 的本地化字符串。 + /// + internal static string FrmSystemSet_label15_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label15_Text", resourceCulture); + } + } + + /// + /// 查找类似 自动切换监控界面时间 的本地化字符串。 + /// + internal static string FrmSystemSet_label16_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label16_Text", resourceCulture); + } + } + + /// + /// 查找类似 无操作自动切换监控界面 的本地化字符串。 + /// + internal static string FrmSystemSet_label17_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label17_Text", resourceCulture); + } + } + + /// + /// 查找类似 端口号配置 的本地化字符串。 + /// + internal static string FrmSystemSet_label2_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label2_Text", resourceCulture); + } + } + + /// + /// 查找类似 无操作自动锁屏 的本地化字符串。 + /// + internal static string FrmSystemSet_label3_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label3_Text", resourceCulture); + } + } + + /// + /// 查找类似 自动锁屏时间 的本地化字符串。 + /// + internal static string FrmSystemSet_label4_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label4_Text", resourceCulture); + } + } + + /// + /// 查找类似 焊机功率曲线显示数量 的本地化字符串。 + /// + internal static string FrmSystemSet_label5_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label5_Text", resourceCulture); + } + } + + /// + /// 查找类似 软件自动登录 的本地化字符串。 + /// + internal static string FrmSystemSet_label6_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label6_Text", resourceCulture); + } + } + + /// + /// 查找类似 开机自动启动 的本地化字符串。 + /// + internal static string FrmSystemSet_label7_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label7_Text", resourceCulture); + } + } + + /// + /// 查找类似 线程耗时日志保存 的本地化字符串。 + /// + internal static string FrmSystemSet_label8_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label8_Text", resourceCulture); + } + } + + /// + /// 查找类似 MES/非MES模式切换 的本地化字符串。 + /// + internal static string FrmSystemSet_label9_Text { + get { + return ResourceManager.GetString("FrmSystemSet_label9_Text", resourceCulture); + } + } + + /// + /// 查找类似 风速仪 的本地化字符串。 + /// + internal static string FrmSystemSet_lblAnemometer_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblAnemometer_Text", resourceCulture); + } + } + + /// + /// 查找类似 调试模式 的本地化字符串。 + /// + internal static string FrmSystemSet_lblDebugMode_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblDebugMode_Text", resourceCulture); + } + } + + /// + /// 查找类似 设备报警 的本地化字符串。 + /// + internal static string FrmSystemSet_lblDeviceAlarm_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblDeviceAlarm_Text", resourceCulture); + } + } + + /// + /// 查找类似 设备参数设定值变更 的本地化字符串。 + /// + internal static string FrmSystemSet_lblDeviceParamChange_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblDeviceParamChange_Text", resourceCulture); + } + } + + /// + /// 查找类似 设备参数设定值请求 的本地化字符串。 + /// + internal static string FrmSystemSet_lblDeviceParamRequest_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblDeviceParamRequest_Text", resourceCulture); + } + } + + /// + /// 查找类似 设备状态 的本地化字符串。 + /// + internal static string FrmSystemSet_lblDeviceStatus_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblDeviceStatus_Text", resourceCulture); + } + } + + /// + /// 查找类似 员工权限校验 的本地化字符串。 + /// + internal static string FrmSystemSet_lblEmployeeAuthCheck_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblEmployeeAuthCheck_Text", resourceCulture); + } + } + + /// + /// 查找类似 电表能耗 的本地化字符串。 + /// + internal static string FrmSystemSet_lblEnergyConsumption_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblEnergyConsumption_Text", resourceCulture); + } + } + + /// + /// 查找类似 原材料投入信息 的本地化字符串。 + /// + internal static string FrmSystemSet_lblMaterialInputInfo_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblMaterialInputInfo_Text", resourceCulture); + } + } + + /// + /// 查找类似 产品进站 的本地化字符串。 + /// + internal static string FrmSystemSet_lblProductInStation_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblProductInStation_Text", resourceCulture); + } + } + + /// + /// 查找类似 产品出站 的本地化字符串。 + /// + internal static string FrmSystemSet_lblProductOutStation_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblProductOutStation_Text", resourceCulture); + } + } + + /// + /// 查找类似 产品加工过程数据 的本地化字符串。 + /// + internal static string FrmSystemSet_lblProductProcessParams_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblProductProcessParams_Text", resourceCulture); + } + } + + /// + /// 查找类似 产品加工结果数据 的本地化字符串。 + /// + internal static string FrmSystemSet_lblProductResultParams_Text { + get { + return ResourceManager.GetString("FrmSystemSet_lblProductResultParams_Text", resourceCulture); + } + } + + /// + /// 查找类似 PLC配置 的本地化字符串。 + /// + internal static string FrmSystemSet_title1_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_title1_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 MES设置 的本地化字符串。 + /// + internal static string FrmSystemSet_title3_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_title3_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 MES参数配置 的本地化字符串。 + /// + internal static string FrmSystemSet_title4_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_title4_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 MES配置 的本地化字符串。 + /// + internal static string FrmSystemSet_titleMesConfig_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_titleMesConfig_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 PLC配置 的本地化字符串。 + /// + internal static string FrmSystemSet_titlePlcConfig_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_titlePlcConfig_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 系统设置 的本地化字符串。 + /// + internal static string FrmSystemSet_titleSystemConfig_TitleName { + get { + return ResourceManager.GetString("FrmSystemSet_titleSystemConfig_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 127.0.0.1 的本地化字符串。 + /// + internal static string FrmSystemSet_txt_IP_Text { + get { + return ResourceManager.GetString("FrmSystemSet_txt_IP_Text", resourceCulture); + } + } + + /// + /// 查找类似 9600 的本地化字符串。 + /// + internal static string FrmSystemSet_txt_Prot_Text { + get { + return ResourceManager.GetString("FrmSystemSet_txt_Prot_Text", resourceCulture); + } + } + + /// + /// 查找类似 添加用户 的本地化字符串。 + /// + internal static string FrmUserManage_btn_Add_Text { + get { + return ResourceManager.GetString("FrmUserManage_btn_Add_Text", resourceCulture); + } + } + + /// + /// 查找类似 清空信息 的本地化字符串。 + /// + internal static string FrmUserManage_btn_Clear_Text { + get { + return ResourceManager.GetString("FrmUserManage_btn_Clear_Text", resourceCulture); + } + } + + /// + /// 查找类似 删除用户 的本地化字符串。 + /// + internal static string FrmUserManage_btn_Delete_Text { + get { + return ResourceManager.GetString("FrmUserManage_btn_Delete_Text", resourceCulture); + } + } + + /// + /// 查找类似 修改用户 的本地化字符串。 + /// + internal static string FrmUserManage_btn_Modify_Text { + get { + return ResourceManager.GetString("FrmUserManage_btn_Modify_Text", resourceCulture); + } + } + + /// + /// 查找类似 全选/不选 的本地化字符串。 + /// + internal static string FrmUserManage_btn_SelectAll_Text { + get { + return ResourceManager.GetString("FrmUserManage_btn_SelectAll_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据分析 的本地化字符串。 + /// + internal static string FrmUserManage_chk_CPKData_Text { + get { + return ResourceManager.GetString("FrmUserManage_chk_CPKData_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据追溯 的本地化字符串。 + /// + internal static string FrmUserManage_chk_HistorySelect_Text { + get { + return ResourceManager.GetString("FrmUserManage_chk_HistorySelect_Text", resourceCulture); + } + } + + /// + /// 查找类似 参数设置 的本地化字符串。 + /// + internal static string FrmUserManage_chk_Paramset_Text { + get { + return ResourceManager.GetString("FrmUserManage_chk_Paramset_Text", resourceCulture); + } + } + + /// + /// 查找类似 日志报警 的本地化字符串。 + /// + internal static string FrmUserManage_chk_SystemLog_Text { + get { + return ResourceManager.GetString("FrmUserManage_chk_SystemLog_Text", resourceCulture); + } + } + + /// + /// 查找类似 系统设置 的本地化字符串。 + /// + internal static string FrmUserManage_chk_SystemSet_Text { + get { + return ResourceManager.GetString("FrmUserManage_chk_SystemSet_Text", resourceCulture); + } + } + + /// + /// 查找类似 用户管理 的本地化字符串。 + /// + internal static string FrmUserManage_chk_UserManage_Text { + get { + return ResourceManager.GetString("FrmUserManage_chk_UserManage_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据分析 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_CpkDataHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_CpkDataHeader", resourceCulture); + } + } + + /// + /// 查找类似 数据追溯 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_HistoryDataHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_HistoryDataHeader", resourceCulture); + } + } + + /// + /// 查找类似 用户权限 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_LoginLevelHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_LoginLevelHeader", resourceCulture); + } + } + + /// + /// 查找类似 用户名 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_LoginNameHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_LoginNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 用户密码 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_LoginPwdHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_LoginPwdHeader", resourceCulture); + } + } + + /// + /// 查找类似 IC卡号 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_LoginUidHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_LoginUidHeader", resourceCulture); + } + } + + /// + /// 查找类似 参数设置 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_ParamSetHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_ParamSetHeader", resourceCulture); + } + } + + /// + /// 查找类似 日志报警 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_SystemLogHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_SystemLogHeader", resourceCulture); + } + } + + /// + /// 查找类似 系统设置 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_SystemSetHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_SystemSetHeader", resourceCulture); + } + } + + /// + /// 查找类似 用户管理 的本地化字符串。 + /// + internal static string FrmUserManage_dgv_Main_UserManageHeader { + get { + return ResourceManager.GetString("FrmUserManage_dgv_Main_UserManageHeader", resourceCulture); + } + } + + /// + /// 查找类似 IC卡号 的本地化字符串。 + /// + internal static string FrmUserManage_lblICCard_Text { + get { + return ResourceManager.GetString("FrmUserManage_lblICCard_Text", resourceCulture); + } + } + + /// + /// 查找类似 确认密码 的本地化字符串。 + /// + internal static string FrmUserManage_lblPwd_Text { + get { + return ResourceManager.GetString("FrmUserManage_lblPwd_Text", resourceCulture); + } + } + + /// + /// 查找类似 用户信息 的本地化字符串。 + /// + internal static string FrmUserManage_lblUserInfo_Text { + get { + return ResourceManager.GetString("FrmUserManage_lblUserInfo_Text", resourceCulture); + } + } + + /// + /// 查找类似 用户权限 的本地化字符串。 + /// + internal static string FrmUserManage_lblUserIssion_Text { + get { + return ResourceManager.GetString("FrmUserManage_lblUserIssion_Text", resourceCulture); + } + } + + /// + /// 查找类似 用户密码 的本地化字符串。 + /// + internal static string FrmUserManage_lblUserPwd_Text { + get { + return ResourceManager.GetString("FrmUserManage_lblUserPwd_Text", resourceCulture); + } + } + + /// + /// 查找类似 用户信息 的本地化字符串。 + /// + internal static string FrmUserManage_longTitleStyle21_TitleName { + get { + return ResourceManager.GetString("FrmUserManage_longTitleStyle21_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 权限配置 的本地化字符串。 + /// + internal static string FrmUserManage_longTitleStyle22_TitleName { + get { + return ResourceManager.GetString("FrmUserManage_longTitleStyle22_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 用户操作 的本地化字符串。 + /// + internal static string FrmUserManage_longTitleStyle23_TitleName { + get { + return ResourceManager.GetString("FrmUserManage_longTitleStyle23_TitleName", resourceCulture); + } + } + + /// + /// 查找类似 起始索引 的本地化字符串。 + /// + internal static string FrmVariableConfig_dgv_Main_StartHeader { + get { + return ResourceManager.GetString("FrmVariableConfig_dgv_Main_StartHeader", resourceCulture); + } + } + + /// + /// 查找类似 变量地址 的本地化字符串。 + /// + internal static string FrmVariableConfig_dgv_Main_VarAddressHeader { + get { + return ResourceManager.GetString("FrmVariableConfig_dgv_Main_VarAddressHeader", resourceCulture); + } + } + + /// + /// 查找类似 变量名称 的本地化字符串。 + /// + internal static string FrmVariableConfig_dgv_Main_VarNameHeader { + get { + return ResourceManager.GetString("FrmVariableConfig_dgv_Main_VarNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 变量配置 的本地化字符串。 + /// + internal static string FrmVariableConfig_label1_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label1_Text", resourceCulture); + } + } + + /// + /// 查找类似 变量地址 的本地化字符串。 + /// + internal static string FrmVariableConfig_label10_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label10_Text", resourceCulture); + } + } + + /// + /// 查找类似 通信组名称 的本地化字符串。 + /// + internal static string FrmVariableConfig_label2_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label2_Text", resourceCulture); + } + } + + /// + /// 查找类似 起始索引 的本地化字符串。 + /// + internal static string FrmVariableConfig_label3_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label3_Text", resourceCulture); + } + } + + /// + /// 查找类似 位偏移/长度 的本地化字符串。 + /// + internal static string FrmVariableConfig_label4_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label4_Text", resourceCulture); + } + } + + /// + /// 查找类似 变量名称 的本地化字符串。 + /// + internal static string FrmVariableConfig_label5_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label5_Text", resourceCulture); + } + } + + /// + /// 查找类似 备注说明 的本地化字符串。 + /// + internal static string FrmVariableConfig_label6_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label6_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据类型 的本地化字符串。 + /// + internal static string FrmVariableConfig_label7_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label7_Text", resourceCulture); + } + } + + /// + /// 查找类似 线性系数 的本地化字符串。 + /// + internal static string FrmVariableConfig_label8_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label8_Text", resourceCulture); + } + } + + /// + /// 查找类似 偏移量 的本地化字符串。 + /// + internal static string FrmVariableConfig_label9_Text { + get { + return ResourceManager.GetString("FrmVariableConfig_label9_Text", resourceCulture); + } + } + + /// + /// 查找类似 HMI手动弹窗状态已上传成功,代码 的本地化字符串。 + /// + internal static string HMI手动弹窗状态已上传成功_代码 { + get { + return ResourceManager.GetString("HMI手动弹窗状态已上传成功,代码", resourceCulture); + } + } + + /// + /// 查找类似 HMI手动弹窗结束状态已上传成功,代码 的本地化字符串。 + /// + internal static string HMI手动弹窗结束状态已上传成功_代码 { + get { + return ResourceManager.GetString("HMI手动弹窗结束状态已上传成功,代码", resourceCulture); + } + } + + /// + /// 查找类似 MES不良 的本地化字符串。 + /// + internal static string MES不良 { + get { + return ResourceManager.GetString("MES不良", resourceCulture); + } + } + + /// + /// 查找类似 MES停机 的本地化字符串。 + /// + internal static string MES停机 { + get { + return ResourceManager.GetString("MES停机", resourceCulture); + } + } + + /// + /// 查找类似 MES参数设置成功 的本地化字符串。 + /// + internal static string MES参数设置成功 { + get { + return ResourceManager.GetString("MES参数设置成功", resourceCulture); + } + } + + /// + /// 查找类似 MES未登录 的本地化字符串。 + /// + internal static string MES未登录 { + get { + return ResourceManager.GetString("MES未登录", resourceCulture); + } + } + + /// + /// 查找类似 MES用户已注销 的本地化字符串。 + /// + internal static string MES用户已注销 { + get { + return ResourceManager.GetString("MES用户已注销", resourceCulture); + } + } + + /// + /// 查找类似 MES登录成功,登录用户 的本地化字符串。 + /// + internal static string MES登录成功_登录用户 { + get { + return ResourceManager.GetString("MES登录成功,登录用户", resourceCulture); + } + } + + /// + /// 查找类似 PC写入PLC时间失败! 的本地化字符串。 + /// + internal static string PC写入PLC时间失败 { + get { + return ResourceManager.GetString("PC写入PLC时间失败", resourceCulture); + } + } + + /// + /// 查找类似 PC写入PLC时间异常 的本地化字符串。 + /// + internal static string PC写入PLC时间异常 { + get { + return ResourceManager.GetString("PC写入PLC时间异常", resourceCulture); + } + } + + /// + /// 查找类似 PC写入PLC时间成功 的本地化字符串。 + /// + internal static string PC写入PLC时间成功 { + get { + return ResourceManager.GetString("PC写入PLC时间成功", resourceCulture); + } + } + + /// + /// 查找类似 添加变量 的本地化字符串。 + /// + internal static string VariableEditForm_BtnAdd_Text { + get { + return ResourceManager.GetString("VariableEditForm_BtnAdd_Text", resourceCulture); + } + } + + /// + /// 查找类似 变量配置 的本地化字符串。 + /// + internal static string VariableEditForm_lblTitle_Text { + get { + return ResourceManager.GetString("VariableEditForm_lblTitle_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据类型 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_DataTypeHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_DataTypeHeader", resourceCulture); + } + } + + /// + /// 查找类似 操作 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_EditHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_EditHeader", resourceCulture); + } + } + + /// + /// 查找类似 组名 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_GroupNameHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_GroupNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 长度偏移 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_OffsetOrLengthHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_OffsetOrLengthHeader", resourceCulture); + } + } + + /// + /// 查找类似 PLC编号 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_PlcNumHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_PlcNumHeader", resourceCulture); + } + } + + /// + /// 查找类似 备注 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_RemarkHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_RemarkHeader", resourceCulture); + } + } + + /// + /// 查找类似 起始地址 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_StartHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_StartHeader", resourceCulture); + } + } + + /// + /// 查找类似 变量地址 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_VarAddressHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_VarAddressHeader", resourceCulture); + } + } + + /// + /// 查找类似 变量名称 的本地化字符串。 + /// + internal static string VariableEditForm_variableTable_VarNameHeader { + get { + return ResourceManager.GetString("VariableEditForm_variableTable_VarNameHeader", resourceCulture); + } + } + + /// + /// 查找类似 上限 的本地化字符串。 + /// + internal static string 上限 { + get { + return ResourceManager.GetString("上限", resourceCulture); + } + } + + /// + /// 查找类似 下限 的本地化字符串。 + /// + internal static string 下限 { + get { + return ResourceManager.GetString("下限", resourceCulture); + } + } + + /// + /// 查找类似 不支持的数据类型 的本地化字符串。 + /// + internal static string 不支持的数据类型 { + get { + return ResourceManager.GetString("不支持的数据类型", resourceCulture); + } + } + + /// + /// 查找类似 产出 的本地化字符串。 + /// + internal static string 产出 { + get { + return ResourceManager.GetString("产出", resourceCulture); + } + } + + /// + /// 查找类似 优率 的本地化字符串。 + /// + internal static string 优率 { + get { + return ResourceManager.GetString("优率", resourceCulture); + } + } + + /// + /// 查找类似 信息 的本地化字符串。 + /// + internal static string 信息 { + get { + return ResourceManager.GetString("信息", resourceCulture); + } + } + + /// + /// 查找类似 修改 的本地化字符串。 + /// + internal static string 修改 { + get { + return ResourceManager.GetString("修改", resourceCulture); + } + } + + /// + /// 查找类似 修改MES/非MES模式切换 的本地化字符串。 + /// + internal static string 修改MES_非MES模式切换 { + get { + return ResourceManager.GetString("修改MES/非MES模式切换", resourceCulture); + } + } + + /// + /// 查找类似 修改切换监控界面间隔时间 的本地化字符串。 + /// + internal static string 修改切换监控界面间隔时间 { + get { + return ResourceManager.GetString("修改切换监控界面间隔时间", resourceCulture); + } + } + + /// + /// 查找类似 修改刷卡模式 的本地化字符串。 + /// + internal static string 修改刷卡模式 { + get { + return ResourceManager.GetString("修改刷卡模式", resourceCulture); + } + } + + /// + /// 查找类似 修改无操作自动切换监控界面方式 的本地化字符串。 + /// + internal static string 修改无操作自动切换监控界面方式 { + get { + return ResourceManager.GetString("修改无操作自动切换监控界面方式", resourceCulture); + } + } + + /// + /// 查找类似 修改无操作自动锁屏方式 的本地化字符串。 + /// + internal static string 修改无操作自动锁屏方式 { + get { + return ResourceManager.GetString("修改无操作自动锁屏方式", resourceCulture); + } + } + + /// + /// 查找类似 修改曲线显示数量 的本地化字符串。 + /// + internal static string 修改曲线显示数量 { + get { + return ResourceManager.GetString("修改曲线显示数量", resourceCulture); + } + } + + /// + /// 查找类似 修改线程耗时日志保存 的本地化字符串。 + /// + internal static string 修改线程耗时日志保存 { + get { + return ResourceManager.GetString("修改线程耗时日志保存", resourceCulture); + } + } + + /// + /// 查找类似 修改获取MES参数 的本地化字符串。 + /// + internal static string 修改获取MES参数 { + get { + return ResourceManager.GetString("修改获取MES参数", resourceCulture); + } + } + + /// + /// 查找类似 修改调试模式 的本地化字符串。 + /// + internal static string 修改调试模式 { + get { + return ResourceManager.GetString("修改调试模式", resourceCulture); + } + } + + /// + /// 查找类似 修改软件自动启动方式 的本地化字符串。 + /// + internal static string 修改软件自动启动方式 { + get { + return ResourceManager.GetString("修改软件自动启动方式", resourceCulture); + } + } + + /// + /// 查找类似 修改软件自动登录方式 的本地化字符串。 + /// + internal static string 修改软件自动登录方式 { + get { + return ResourceManager.GetString("修改软件自动登录方式", resourceCulture); + } + } + + /// + /// 查找类似 修改锁屏间隔时间 的本地化字符串。 + /// + internal static string 修改锁屏间隔时间 { + get { + return ResourceManager.GetString("修改锁屏间隔时间", resourceCulture); + } + } + + /// + /// 查找类似 停止与PLC连接 的本地化字符串。 + /// + internal static string 停止与PLC连接 { + get { + return ResourceManager.GetString("停止与PLC连接", resourceCulture); + } + } + + /// + /// 查找类似 先停止运行再切换MES 的本地化字符串。 + /// + internal static string 先停止运行再切换MES { + get { + return ResourceManager.GetString("先停止运行再切换MES", resourceCulture); + } + } + + /// + /// 查找类似 全天 的本地化字符串。 + /// + internal static string 全天 { + get { + return ResourceManager.GetString("全天", resourceCulture); + } + } + + /// + /// 查找类似 关闭MES模式成功 的本地化字符串。 + /// + internal static string 关闭MES模式成功 { + get { + return ResourceManager.GetString("关闭MES模式成功", resourceCulture); + } + } + + /// + /// 查找类似 其他不良 的本地化字符串。 + /// + internal static string 其他不良 { + get { + return ResourceManager.GetString("其他不良", resourceCulture); + } + } + + /// + /// 查找类似 其它非计划停机 的本地化字符串。 + /// + internal static string 其它非计划停机 { + get { + return ResourceManager.GetString("其它非计划停机", resourceCulture); + } + } + + /// + /// 查找类似 出站 的本地化字符串。 + /// + internal static string 出站 { + get { + return ResourceManager.GetString("出站", resourceCulture); + } + } + + /// + /// 查找类似 出站A工位发送给PLC 的本地化字符串。 + /// + internal static string 出站A工位发送给PLC { + get { + return ResourceManager.GetString("出站A工位发送给PLC", resourceCulture); + } + } + + /// + /// 查找类似 出站B工位发送给PLC 的本地化字符串。 + /// + internal static string 出站B工位发送给PLC { + get { + return ResourceManager.GetString("出站B工位发送给PLC", resourceCulture); + } + } + + /// + /// 查找类似 出站C工位发送给PLC 的本地化字符串。 + /// + internal static string 出站C工位发送给PLC { + get { + return ResourceManager.GetString("出站C工位发送给PLC", resourceCulture); + } + } + + /// + /// 查找类似 出站下料工位A有料标志为0 的本地化字符串。 + /// + internal static string 出站下料工位A有料标志为0 { + get { + return ResourceManager.GetString("出站下料工位A有料标志为0", resourceCulture); + } + } + + /// + /// 查找类似 出站下料工位B有料标志为0 的本地化字符串。 + /// + internal static string 出站下料工位B有料标志为0 { + get { + return ResourceManager.GetString("出站下料工位B有料标志为0", resourceCulture); + } + } + + /// + /// 查找类似 出站失败 的本地化字符串。 + /// + internal static string 出站失败 { + get { + return ResourceManager.GetString("出站失败", resourceCulture); + } + } + + /// + /// 查找类似 切换刷卡模式成功 的本地化字符串。 + /// + internal static string 切换刷卡模式成功 { + get { + return ResourceManager.GetString("切换刷卡模式成功", resourceCulture); + } + } + + /// + /// 查找类似 创建临时文件失败 的本地化字符串。 + /// + internal static string 创建临时文件失败 { + get { + return ResourceManager.GetString("创建临时文件失败", resourceCulture); + } + } + + /// + /// 查找类似 删除 的本地化字符串。 + /// + internal static string 删除 { + get { + return ResourceManager.GetString("删除", resourceCulture); + } + } + + /// + /// 查找类似 删除成功 的本地化字符串。 + /// + internal static string 删除成功 { + get { + return ResourceManager.GetString("删除成功", resourceCulture); + } + } + + /// + /// 查找类似 功率值 的本地化字符串。 + /// + internal static string 功率值 { + get { + return ResourceManager.GetString("功率值", resourceCulture); + } + } + + /// + /// 查找类似 功能待开发中! 的本地化字符串。 + /// + internal static string 功能待开发中_ { + get { + return ResourceManager.GetString("功能待开发中!", resourceCulture); + } + } + + /// + /// 查找类似 加载系统配置失败 的本地化字符串。 + /// + internal static string 加载系统配置失败 { + get { + return ResourceManager.GetString("加载系统配置失败", resourceCulture); + } + } + + /// + /// 查找类似 加载系统配置成功 的本地化字符串。 + /// + internal static string 加载系统配置成功 { + get { + return ResourceManager.GetString("加载系统配置成功", resourceCulture); + } + } + + + /// + /// 查找类似 卷芯进站共耗时 的本地化字符串。 + /// + internal static string 卷芯进站共耗时 { + get { + return ResourceManager.GetString("卷芯进站共耗时", resourceCulture); + } + } + + /// + /// 查找类似 历史报警 的本地化字符串。 + /// + internal static string 历史报警 { + get { + return ResourceManager.GetString("历史报警", resourceCulture); + } + } + + /// + /// 查找类似 历史数据 的本地化字符串。 + /// + internal static string 历史数据 { + get { + return ResourceManager.GetString("历史数据", resourceCulture); + } + } + + /// + /// 查找类似 变量 的本地化字符串。 + /// + internal static string 变量 { + get { + return ResourceManager.GetString("变量", resourceCulture); + } + } + + /// + /// 查找类似 变量名不能为空 的本地化字符串。 + /// + internal static string 变量名不能为空 { + get { + return ResourceManager.GetString("变量名不能为空", resourceCulture); + } + } + + /// + /// 查找类似 变量名已存在 的本地化字符串。 + /// + internal static string 变量名已存在 { + get { + return ResourceManager.GetString("变量名已存在", resourceCulture); + } + } + + /// + /// 查找类似 变量地址格式不正确 的本地化字符串。 + /// + internal static string 变量地址格式不正确 { + get { + return ResourceManager.GetString("变量地址格式不正确", resourceCulture); + } + } + + /// + /// 查找类似 各不良项 的本地化字符串。 + /// + internal static string 各不良项 { + get { + return ResourceManager.GetString("各不良项", resourceCulture); + } + } + + /// + /// 查找类似 启动开始监控 的本地化字符串。 + /// + internal static string 启动开始监控 { + get { + return ResourceManager.GetString("启动开始监控", resourceCulture); + } + } + + /// + /// 查找类似 启动开始监控失败 的本地化字符串。 + /// + internal static string 启动开始监控失败 { + get { + return ResourceManager.GetString("启动开始监控失败", resourceCulture); + } + } + + /// + /// 查找类似 品质异常 的本地化字符串。 + /// + internal static string 品质异常 { + get { + return ResourceManager.GetString("品质异常", resourceCulture); + } + } + + /// + /// 查找类似 品质检查 的本地化字符串。 + /// + internal static string 品质检查 { + get { + return ResourceManager.GetString("品质检查", resourceCulture); + } + } + + /// + /// 查找类似 图表初始化异常 的本地化字符串。 + /// + internal static string 图表初始化异常 { + get { + return ResourceManager.GetString("图表初始化异常", resourceCulture); + } + } + + /// + /// 查找类似 地址范围超出限制,结束地址不能超过32767 的本地化字符串。 + /// + internal static string 地址范围超出限制_结束地址不能超过32767 { + get { + return ResourceManager.GetString("地址范围超出限制,结束地址不能超过32767", resourceCulture); + } + } + + /// + /// 查找类似 型号选择 的本地化字符串。 + /// + internal static string 型号选择 { + get { + return ResourceManager.GetString("型号选择", resourceCulture); + } + } + + /// + /// 查找类似 夜班 的本地化字符串。 + /// + internal static string 夜班 { + get { + return ResourceManager.GetString("夜班", resourceCulture); + } + } + + /// + /// 查找类似 定时刷新异常 的本地化字符串。 + /// + internal static string 定时刷新异常 { + get { + return ResourceManager.GetString("定时刷新异常", resourceCulture); + } + } + + /// + /// 查找类似 导出失败 的本地化字符串。 + /// + internal static string 导出失败 { + get { + return ResourceManager.GetString("导出失败", resourceCulture); + } + } + + /// + /// 查找类似 导出成功! 的本地化字符串。 + /// + internal static string 导出成功_ { + get { + return ResourceManager.GetString("导出成功!", resourceCulture); + } + } + + /// + /// 查找类似 导出报表失败 的本地化字符串。 + /// + internal static string 导出报表失败 { + get { + return ResourceManager.GetString("导出报表失败", resourceCulture); + } + } + + /// + /// 查找类似 工程变更 的本地化字符串。 + /// + internal static string 工程变更 { + get { + return ResourceManager.GetString("工程变更", resourceCulture); + } + } + + /// + /// 查找类似 已断开与PLC 的本地化字符串。 + /// + internal static string 已断开与PLC { + get { + return ResourceManager.GetString("已断开与PLC", resourceCulture); + } + } + + /// + /// 查找类似 开始时间不能大于结束时间 的本地化字符串。 + /// + internal static string 开始时间不能大于结束时间 { + get { + return ResourceManager.GetString("开始时间不能大于结束时间", resourceCulture); + } + } + + /// + /// 查找类似 当前已登录 的本地化字符串。 + /// + internal static string 当前已登录 { + get { + return ResourceManager.GetString("当前已登录", resourceCulture); + } + } + + /// + /// 查找类似 当前无报警 的本地化字符串。 + /// + internal static string 当前无报警 { + get { + return ResourceManager.GetString("当前无报警", resourceCulture); + } + } + + /// + /// 查找类似 当前用户已注销 的本地化字符串。 + /// + internal static string 当前用户已注销 { + get { + return ResourceManager.GetString("当前用户已注销", resourceCulture); + } + } + + /// + /// 查找类似 待料 的本地化字符串。 + /// + internal static string 待料 { + get { + return ResourceManager.GetString("待料", resourceCulture); + } + } + + /// + /// 查找类似 成功 的本地化字符串。 + /// + internal static string 成功 { + get { + return ResourceManager.GetString("成功", resourceCulture); + } + } + + /// + /// 查找类似 成功连接PLC 的本地化字符串。 + /// + internal static string 成功连接PLC { + get { + return ResourceManager.GetString("成功连接PLC", resourceCulture); + } + } + + /// + /// 查找类似 打开报表记录 的本地化字符串。 + /// + internal static string 打开报表记录 { + get { + return ResourceManager.GetString("打开报表记录", resourceCulture); + } + } + + /// + /// 查找类似 打开报警记录 的本地化字符串。 + /// + internal static string 打开报警记录 { + get { + return ResourceManager.GetString("打开报警记录", resourceCulture); + } + } + + /// + /// 查找类似 扫码不良 的本地化字符串。 + /// + internal static string 扫码不良 { + get { + return ResourceManager.GetString("扫码不良", resourceCulture); + } + } + + /// + /// 查找类似 投入 的本地化字符串。 + /// + internal static string 投入 { + get { + return ResourceManager.GetString("投入", resourceCulture); + } + } + + /// + /// 查找类似 告警TOP10 的本地化字符串。 + /// + internal static string 告警TOP10 { + get { + return ResourceManager.GetString("告警TOP10", resourceCulture); + } + } + + /// + /// 查找类似 告警查询 的本地化字符串。 + /// + internal static string 告警查询 { + get { + return ResourceManager.GetString("告警查询", resourceCulture); + } + } + + /// + /// 查找类似 报警项 的本地化字符串。 + /// + internal static string 报警项 { + get { + return ResourceManager.GetString("报警项", resourceCulture); + } + } + + /// + /// 查找类似 提示 的本地化字符串。 + /// + internal static string 提示 { + get { + return ResourceManager.GetString("提示", resourceCulture); + } + } + + /// + /// 查找类似 操作日志 的本地化字符串。 + /// + internal static string 操作日志 { + get { + return ResourceManager.GetString("操作日志", resourceCulture); + } + } + + /// + /// 查找类似 数值 的本地化字符串。 + /// + internal static string 数值 { + get { + return ResourceManager.GetString("数值", resourceCulture); + } + } + + /// + /// 查找类似 数据分析 的本地化字符串。 + /// + internal static string 数据分析 { + get { + return ResourceManager.GetString("数据分析", resourceCulture); + } + } + + /// + /// 查找类似 数据报表导出 的本地化字符串。 + /// + internal static string 数据报表导出 { + get { + return ResourceManager.GetString("数据报表导出", resourceCulture); + } + } + + /// + /// 查找类似 新变量 的本地化字符串。 + /// + internal static string 新变量 { + get { + return ResourceManager.GetString("新变量", resourceCulture); + } + } + + /// + /// 查找类似 新建变量成功 的本地化字符串。 + /// + internal static string 新建变量成功 { + get { + return ResourceManager.GetString("新建变量成功", resourceCulture); + } + } + + /// + /// 查找类似 无PLC配置信息 的本地化字符串。 + /// + internal static string 无PLC配置信息 { + get { + return ResourceManager.GetString("无PLC配置信息", resourceCulture); + } + } + + /// + /// 查找类似 无效的组名 的本地化字符串。 + /// + internal static string 无效的组名 { + get { + return ResourceManager.GetString("无效的组名", resourceCulture); + } + } + + /// + /// 查找类似 无效的起始地址 的本地化字符串。 + /// + internal static string 无效的起始地址 { + get { + return ResourceManager.GetString("无效的起始地址", resourceCulture); + } + } + + /// + /// 查找类似 时间 的本地化字符串。 + /// + internal static string 时间 { + get { + return ResourceManager.GetString("时间", resourceCulture); + } + } + + /// + /// 查找类似 星期一 的本地化字符串。 + /// + internal static string 星期一 { + get { + return ResourceManager.GetString("星期一", resourceCulture); + } + } + + /// + /// 查找类似 星期三 的本地化字符串。 + /// + internal static string 星期三 { + get { + return ResourceManager.GetString("星期三", resourceCulture); + } + } + + /// + /// 查找类似 星期二 的本地化字符串。 + /// + internal static string 星期二 { + get { + return ResourceManager.GetString("星期二", resourceCulture); + } + } + + /// + /// 查找类似 星期五 的本地化字符串。 + /// + internal static string 星期五 { + get { + return ResourceManager.GetString("星期五", resourceCulture); + } + } + + /// + /// 查找类似 星期六 的本地化字符串。 + /// + internal static string 星期六 { + get { + return ResourceManager.GetString("星期六", resourceCulture); + } + } + + /// + /// 查找类似 星期四 的本地化字符串。 + /// + internal static string 星期四 { + get { + return ResourceManager.GetString("星期四", resourceCulture); + } + } + + /// + /// 查找类似 星期日 的本地化字符串。 + /// + internal static string 星期日 { + get { + return ResourceManager.GetString("星期日", resourceCulture); + } + } + + /// + /// 查找类似 是否切换刷卡模式 的本地化字符串。 + /// + internal static string 是否切换刷卡模式 { + get { + return ResourceManager.GetString("是否切换刷卡模式", resourceCulture); + } + } + + /// + /// 查找类似 是否确定要退出系统 的本地化字符串。 + /// + internal static string 是否确定要退出系统 { + get { + return ResourceManager.GetString("是否确定要退出系统", resourceCulture); + } + } + + /// + /// 查找类似 更新12小时数据异常 的本地化字符串。 + /// + internal static string 更新12小时数据异常 { + get { + return ResourceManager.GetString("更新12小时数据异常", resourceCulture); + } + } + + /// + /// 查找类似 更新不良图表异常 的本地化字符串。 + /// + internal static string 更新不良图表异常 { + get { + return ResourceManager.GetString("更新不良图表异常", resourceCulture); + } + } + + /// + /// 查找类似 更新报警图表异常 的本地化字符串。 + /// + internal static string 更新报警图表异常 { + get { + return ResourceManager.GetString("更新报警图表异常", resourceCulture); + } + } + + /// + /// 查找类似 更新效率控件异常 的本地化字符串。 + /// + internal static string 更新效率控件异常 { + get { + return ResourceManager.GetString("更新效率控件异常", resourceCulture); + } + } + + /// + /// 查找类似 更新时间显示异常 的本地化字符串。 + /// + internal static string 更新时间显示异常 { + get { + return ResourceManager.GetString("更新时间显示异常", resourceCulture); + } + } + + /// + /// 查找类似 更新能源显示异常 的本地化字符串。 + /// + internal static string 更新能源显示异常 { + get { + return ResourceManager.GetString("更新能源显示异常", resourceCulture); + } + } + + /// + /// 查找类似 未登录 的本地化字符串。 + /// + internal static string 未登录 { + get { + return ResourceManager.GetString("未登录", resourceCulture); + } + } + + /// + /// 查找类似 权限 的本地化字符串。 + /// + internal static string 权限 { + get { + return ResourceManager.GetString("权限", resourceCulture); + } + } + + /// + /// 查找类似 权限不足 的本地化字符串。 + /// + internal static string 权限不足 { + get { + return ResourceManager.GetString("权限不足", resourceCulture); + } + } + + /// + /// 查找类似 来料不良 的本地化字符串。 + /// + internal static string 来料不良 { + get { + return ResourceManager.GetString("来料不良", resourceCulture); + } + } + + /// + /// 查找类似 查询时间不能超过7天 的本地化字符串。 + /// + internal static string 查询时间不能超过7天 { + get { + return ResourceManager.GetString("查询时间不能超过7天", resourceCulture); + } + } + + /// + /// 查找类似 查询范围不能超过1天 的本地化字符串。 + /// + internal static string 查询范围不能超过1天 { + get { + return ResourceManager.GetString("查询范围不能超过1天", resourceCulture); + } + } + + /// + /// 查找类似 栈板信息 的本地化字符串。 + /// + internal static string 栈板信息 { + get { + return ResourceManager.GetString("栈板信息", resourceCulture); + } + } + + /// + /// 查找类似 次数 的本地化字符串。 + /// + internal static string 次数 { + get { + return ResourceManager.GetString("次数", resourceCulture); + } + } + + /// + /// 查找类似 没有可用的地址空间 的本地化字符串。 + /// + internal static string 没有可用的地址空间 { + get { + return ResourceManager.GetString("没有可用的地址空间", resourceCulture); + } + } + + /// + /// 查找类似 没有找到足够大的地址空间 的本地化字符串。 + /// + internal static string 没有找到足够大的地址空间 { + get { + return ResourceManager.GetString("没有找到足够大的地址空间", resourceCulture); + } + } + + /// + /// 查找类似 清洁点检 的本地化字符串。 + /// + internal static string 清洁点检 { + get { + return ResourceManager.GetString("清洁点检", resourceCulture); + } + } + + /// + /// 查找类似 物料编码不能为空! 的本地化字符串。 + /// + internal static string 物料编码不能为空 { + get { + return ResourceManager.GetString("物料编码不能为空", resourceCulture); + } + } + + /// + /// 查找类似 环境不满足 的本地化字符串。 + /// + internal static string 环境不满足 { + get { + return ResourceManager.GetString("环境不满足", resourceCulture); + } + } + + /// + /// 查找类似 用户查询失败 的本地化字符串。 + /// + internal static string 用户查询失败 { + get { + return ResourceManager.GetString("用户查询失败", resourceCulture); + } + } + + /// + /// 查找类似 电芯出站A共耗时 的本地化字符串。 + /// + internal static string 电芯出站A共耗时 { + get { + return ResourceManager.GetString("电芯出站A共耗时", resourceCulture); + } + } + + /// + /// 查找类似 电芯出站B共耗时 的本地化字符串。 + /// + internal static string 电芯出站B共耗时 { + get { + return ResourceManager.GetString("电芯出站B共耗时", resourceCulture); + } + } + + /// + /// 查找类似 电芯出站C共耗时 的本地化字符串。 + /// + internal static string 电芯出站C共耗时 { + get { + return ResourceManager.GetString("电芯出站C共耗时", resourceCulture); + } + } + + /// + /// 查找类似 电芯码不良 的本地化字符串。 + /// + internal static string 电芯码不良 { + get { + return ResourceManager.GetString("电芯码不良", resourceCulture); + } + } + + /// + /// 查找类似 登录成功,登录用户 的本地化字符串。 + /// + internal static string 登录成功_登录用户 { + get { + return ResourceManager.GetString("登录成功,登录用户", resourceCulture); + } + } + + /// + /// 查找类似 登录提示 的本地化字符串。 + /// + internal static string 登录提示 { + get { + return ResourceManager.GetString("登录提示", resourceCulture); + } + } + + /// + /// 查找类似 登录用户或密码错误!!! 的本地化字符串。 + /// + internal static string 登录用户或密码错误 { + get { + return ResourceManager.GetString("登录用户或密码错误", resourceCulture); + } + } + + /// + /// 查找类似 登录系统 的本地化字符串。 + /// + internal static string 登录系统 { + get { + return ResourceManager.GetString("登录系统", resourceCulture); + } + } + + /// + /// 查找类似 白班 的本地化字符串。 + /// + internal static string 白班 { + get { + return ResourceManager.GetString("白班", resourceCulture); + } + } + + /// + /// 查找类似 确认保存 的本地化字符串。 + /// + internal static string 确认保存 { + get { + return ResourceManager.GetString("确认保存", resourceCulture); + } + } + + /// + /// 查找类似 禁用 的本地化字符串。 + /// + internal static string 禁用 { + get { + return ResourceManager.GetString("禁用", resourceCulture); + } + } + + /// + /// 查找类似 窗体加载异常 的本地化字符串。 + /// + internal static string 窗体加载异常 { + get { + return ResourceManager.GetString("窗体加载异常", resourceCulture); + } + } + + /// + /// 查找类似 系统日志 的本地化字符串。 + /// + internal static string 系统日志 { + get { + return ResourceManager.GetString("系统日志", resourceCulture); + } + } + + /// + /// 查找类似 组名不能为空 的本地化字符串。 + /// + internal static string 组名不能为空 { + get { + return ResourceManager.GetString("组名不能为空", resourceCulture); + } + } + + /// + /// 查找类似 结果数据上传失败 的本地化字符串。 + /// + internal static string 结果数据上传失败 { + get { + return ResourceManager.GetString("结果数据上传失败", resourceCulture); + } + } + + /// + /// 查找类似 良品 的本地化字符串。 + /// + internal static string 良品 { + get { + return ResourceManager.GetString("良品", resourceCulture); + } + } + + /// + /// 查找类似 获取参数失败 的本地化字符串。 + /// + internal static string 获取参数失败 { + get { + return ResourceManager.GetString("获取参数失败", resourceCulture); + } + } + + /// + /// 查找类似 触发了手动HMI弹窗功能 的本地化字符串。 + /// + internal static string 触发了手动HMI弹窗功能 { + get { + return ResourceManager.GetString("触发了手动HMI弹窗功能", resourceCulture); + } + } + + /// + /// 查找类似 设备故障 的本地化字符串。 + /// + internal static string 设备故障 { + get { + return ResourceManager.GetString("设备故障", resourceCulture); + } + } + + /// + /// 查找类似 设备转型 的本地化字符串。 + /// + internal static string 设备转型 { + get { + return ResourceManager.GetString("设备转型", resourceCulture); + } + } + + /// + /// 查找类似 请填写登录密码 的本地化字符串。 + /// + internal static string 请填写登录密码 { + get { + return ResourceManager.GetString("请填写登录密码", resourceCulture); + } + } + + /// + /// 查找类似 请填写登录用户名 的本地化字符串。 + /// + internal static string 请填写登录用户名 { + get { + return ResourceManager.GetString("请填写登录用户名", resourceCulture); + } + } + + /// + /// 查找类似 请检查配置文件 的本地化字符串。 + /// + internal static string 请检查配置文件 { + get { + return ResourceManager.GetString("请检查配置文件", resourceCulture); + } + } + + /// + /// 查找类似 起始地址格式不正确 的本地化字符串。 + /// + internal static string 起始地址格式不正确 { + get { + return ResourceManager.GetString("起始地址格式不正确", resourceCulture); + } + } + + /// + /// 查找类似 进站 的本地化字符串。 + /// + internal static string 进站 { + get { + return ResourceManager.GetString("进站", resourceCulture); + } + } + + /// + /// 查找类似 进站A工位发送给PLC 的本地化字符串。 + /// + internal static string 进站A工位发送给PLC { + get { + return ResourceManager.GetString("进站A工位发送给PLC", resourceCulture); + } + } + + /// + /// 查找类似 进站B工位发送给PLC 的本地化字符串。 + /// + internal static string 进站B工位发送给PLC { + get { + return ResourceManager.GetString("进站B工位发送给PLC", resourceCulture); + } + } + + /// + /// 查找类似 进站C工位发送给PLC 的本地化字符串。 + /// + internal static string 进站C工位发送给PLC { + get { + return ResourceManager.GetString("进站C工位发送给PLC", resourceCulture); + } + } + + /// + /// 查找类似 进站上料工位A有料标志为0 的本地化字符串。 + /// + internal static string 进站上料工位A有料标志为0 { + get { + return ResourceManager.GetString("进站上料工位A有料标志为0", resourceCulture); + } + } + + /// + /// 查找类似 进站上料工位B有料标志为0 的本地化字符串。 + /// + internal static string 进站上料工位B有料标志为0 { + get { + return ResourceManager.GetString("进站上料工位B有料标志为0", resourceCulture); + } + } + + /// + /// 查找类似 进站失败 的本地化字符串。 + /// + internal static string 进站失败 { + get { + return ResourceManager.GetString("进站失败", resourceCulture); + } + } + + /// + /// 查找类似 连接PLC 的本地化字符串。 + /// + internal static string 连接PLC { + get { + return ResourceManager.GetString("连接PLC", resourceCulture); + } + } + + /// + /// 查找类似 连接PLC中 的本地化字符串。 + /// + internal static string 连接PLC中 { + get { + return ResourceManager.GetString("连接PLC中", resourceCulture); + } + } + + /// + /// 查找类似 连接PLC失败 的本地化字符串。 + /// + internal static string 连接PLC失败 { + get { + return ResourceManager.GetString("连接PLC失败", resourceCulture); + } + } + + /// + /// 查找类似 连接PLC时发生异常 的本地化字符串。 + /// + internal static string 连接PLC时发生异常 { + get { + return ResourceManager.GetString("连接PLC时发生异常", resourceCulture); + } + } + + /// + /// 查找类似 退出成功 的本地化字符串。 + /// + internal static string 退出成功 { + get { + return ResourceManager.GetString("退出成功", resourceCulture); + } + } + + /// + /// 查找类似 退出用户 的本地化字符串。 + /// + internal static string 退出用户 { + get { + return ResourceManager.GetString("退出用户", resourceCulture); + } + } + + /// + /// 查找类似 退出系统 的本地化字符串。 + /// + internal static string 退出系统 { + get { + return ResourceManager.GetString("退出系统", resourceCulture); + } + } + + /// + /// 查找类似 通信组 的本地化字符串。 + /// + internal static string 通信组 { + get { + return ResourceManager.GetString("通信组", resourceCulture); + } + } + + /// + /// 查找类似 通道号 的本地化字符串。 + /// + internal static string 通道号 { + get { + return ResourceManager.GetString("通道号", resourceCulture); + } + } + + /// + /// 查找类似 配件,物料更换 的本地化字符串。 + /// + internal static string 配件_物料更换 { + get { + return ResourceManager.GetString("配件,物料更换", resourceCulture); + } + } + + /// + /// 查找类似 配置保存成功 的本地化字符串。 + /// + internal static string 配置保存成功 { + get { + return ResourceManager.GetString("配置保存成功", resourceCulture); + } + } + + /// + /// 查找类似 配置文件加载完成 的本地化字符串。 + /// + internal static string 配置文件加载完成 { + get { + return ResourceManager.GetString("配置文件加载完成", resourceCulture); + } + } + + /// + /// 查找类似 错误 的本地化字符串。 + /// + internal static string 错误 { + get { + return ResourceManager.GetString("错误", resourceCulture); + } + } + + /// + /// 查找类似 错误提示 的本地化字符串。 + /// + internal static string 错误提示 { + get { + return ResourceManager.GetString("错误提示", resourceCulture); + } + } + + /// + /// 查找类似 长度必须大于0 的本地化字符串。 + /// + internal static string 长度必须大于0 { + get { + return ResourceManager.GetString("长度必须大于0", resourceCulture); + } + } + + /// + /// 查找类似 长度必须是大于0的数字 的本地化字符串。 + /// + internal static string 长度必须是大于0的数字 { + get { + return ResourceManager.GetString("长度必须是大于0的数字", resourceCulture); + } + } + + /// + /// 查找类似 项名 的本地化字符串。 + /// + internal static string 项名 { + get { + return ResourceManager.GetString("项名", resourceCulture); + } + } + + /// + /// 查找类似 验证配置时发生错误,请检查输入是否正确 的本地化字符串。 + /// + internal static string 验证配置时发生错误_请检查输入是否正确 { + get { + return ResourceManager.GetString("验证配置时发生错误,请检查输入是否正确", resourceCulture); + } + } + + /// + /// 查找类似 验证错误 的本地化字符串。 + /// + internal static string 验证错误 { + get { + return ResourceManager.GetString("验证错误", resourceCulture); + } + } + + /// + /// 查找类似 默认组 的本地化字符串。 + /// + internal static string 默认组 { + get { + return ResourceManager.GetString("默认组", resourceCulture); + } + } + } +} diff --git a/Language/Languages.en.resx b/Language/Languages.en.resx new file mode 100644 index 0000000..f01c8c6 --- /dev/null +++ b/Language/Languages.en.resx @@ -0,0 +1,2520 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Tip + + + Failed to connect to PLC, please check PLC connection configuration, network + + + Delete variable + + + rising vote + + + Falling Edge Alarm + + + Offset Number + + + Falling Edge + + + Communication Group + + + Data Type + + + Modify a variable + + + Bit Offset/Length + + + Rising Edge Alarm + + + New Variation + + + D40 has been reset 0 + + + Alarm information Normal + + + Media type + + + Date and Time + + + Log information + + + Date and Time + + + Log Types + + + Date and Time + + + Operation information + + + Operation Type + + + The operation log + + + System Alarm + + + system log + + + PP + + + CP + + + Ca + + + PPK + + + CPK + + + Dev + + + Mean + + + SampleSize + + + Groups + + + Max + + + Min + + + Total + + + Average Value + + + Max + + + Min + + + Lower limit of specification + + + Upper limit of specification + + + Number of data groups + + + Sample Subgroup Size + + + target value + + + Negative 3x standard deviation + + + Standard deviation (within group) + + + Standard deviation (overall) + + + Positive 3x SD + + + CPL + + + CPU + + + CP + + + CPK + + + Ca + + + PPL + + + Ppk + + + PPU + + + PP + + + CpkGrade + + + Total number of samples + + + Ppm < LSL + + + Ppm Toatl + + + Ppm < USL + + + Clear data + + + Calculate CPK + + + Analytics options + + + Query + + + Generate dummy data + + + Magnitude + + + Stats + + + Process capability (within the group) + + + Other values + + + Calculated value + + + Measured performance + + + Process capability (overall) + + + Query options + + + Query time interval + + + XR Control Chart + + + CPK Analysis Chart + + + Sample run diagram + + + Mean Run Chart + + + Model + + + Material code + + + Start monitoring + + + Stop monitoring + + + chart1 + + + chart1 + + + Remark + + + Comprehensive result + + + Number of stack layers + + + Machine No. + + + Time + + + Pallet barcode + + + Cell grade + + + Quantity of successfully bound cells + + + Quantity of cells + + + Steel Shell Code + + + Model + + + Passage + + + Pallet position number + + + Location + + + More Grade + + + Pallet row number + + + Remarks + + + Results + + + Time + + + Container barcode + + + Machine No. + + + Cell grade + + + Passage + + + Tray code + + + Device Encoding + + + Material code + + + Remarks + + + Results + + + Time + + + Steel Shell Code + + + Passage + + + Remarks + + + Results + + + Time + + + Logging + + + Parameters + + + Structural parts tray + + + Battery incoming + + + Battery binding + + + Parameter + + + Min + + + Max + + + Units + + + New Distribution Group + + + Delete Distribution Group + + + Modify Distribution Group + + + Whether feedback is required or not + + + whether to enable + + + Is it a triggered read + + + Distribution group name + + + ON + + + Whether feedback is required or not + + + Is it a triggered read + + + Length + + + Remarks + + + Start Address + + + Distribution Group Configuration + + + Distribution group name + + + Start Address + + + Length + + + Remarks + + + Export Excel + + + Time query + + + Export + + + Query + + + Export + + + Query + + + Export Excel + + + guide + + + Query + + + Query + + + Re-upload + + + guide + + + Query + + + Average Operating Rate + + + Average Ppm + + + Production Yield Rate + + + ProdIn + + + ProdOut + + + TestTime + + + Day + + + Average Operating Rate + + + Average Ppm + + + Optimum Rate + + + ProdIn + + + ProdOut + + + Average Operating Rate + + + Month + + + Average Ppm + + + Production Yield Rate + + + Total ProdIn + + + Total ProdOut + + + Average Operating Rate + + + Average Ppm + + + Production Yield Rate + + + Total ProdIn + + + Total ProdOut + + + Week + + + AlarmContent + + + AlarmCount + + + AlarmTime + + + Class + + + PLCAdress + + + Battery barcode + + + Bottom support plate code + + + Number of plies + + + Pallet position number + + + Remark + + + Result + + + Number of stack layers + + + TestTime + + + Battery Grade + + + Machine No. + + + Battery Position + + + Container Code + + + Binding Result + + + Binding Failure Reason + + + Outbound Type + + + Original Cell Barcode + + + New Cell Barcode + + + Pallet barcode + + + shifts + + + Steel Shell Code + + + RFID + + + Statistics date + + + Statistics date + + + Statistics Time + + + Statistics Time + + + End time + + + Start Time + + + Barcode + + + End time + + + Start Time + + + Type + + + Historical production data query + + + Capacity statistics query + + + Log alarm data query + + + Statistics by Shift + + + Daily statistics + + + Statistics by week + + + Monthly statistics + + + Yiwei Power + + + Login + + + Yiwei Power + + + Start + + + Factory 57 + + + Yiwei Power + + + Battery packaging data A collection system + + + Log Alarm + + + Data analysis + + + Data Monitoring + + + Data traceability + + + Battery Status + + + Centralized monitoring + + + Easy parameter setting + + + System Configuration + + + Managing Users + + + about + + + Show home screen + + + Exit + + + Hide Main Menu + + + Non-Swipe Mode + + + Smart Meter + + + UA + + + Total Power + + + Total Factor + + + Pt + + + Ct + + + Accumulated Power + + + UB + + + UC + + + IA + + + IB + + + IC + + + PowerA + + + PowerB + + + PowerC + + + Alarm Top10 Statistics + + + Capacity statistics + + + Bad item statistics + + + OK number + + + Superior Rate + + + Total Production + + + Utilization rate + + + Equipment No + + + Plant code + + + Line number + + + Model + + + Up time + + + Run time + + + Smart meter (device) + + + OK + + + Are you sure you want to exit the system? + + + Log out system + + + Cancel + + + Cancel + + + OK + + + Are you sure you want to exit the system? + + + Log out system + + + Delete model + + + Add model + + + Save the parameters + + + Parameter item name + + + Max + + + Min + + + Unit + + + Material code + + + Model + + + Remark + + + Current model + + + Model + + + Material code + + + Current model + + + Add PLC + + + Cancellation settings + + + Distribution Group Configuration + + + OK settings + + + Variable Configuration + + + Settings + + + rising vote + + + Heartbeat Address + + + IP Address + + + Active status + + + Heartbeat status + + + Modify a variable + + + PLC type + + + The port number + + + Remarks + + + Get MES parameters + + + Turn on swipe mode + + + PLC type configuration + + + Equipment No + + + Line number + + + Factory Code + + + Automatically switch the monitoring interface time + + + No operation automatically switches the monitoring interface + + + Customer Material Number + + + Port number configuration + + + No operating automatic lock screen + + + Auto lock screen time + + + Number of welder power curve displays + + + Software automatically logs in + + + Automatically run KICOME when restarting my computer + + + Thread time-consuming log saving + + + MES/non-MES mode switching + + + Anemometer + + + debugging mode + + + Equipment alarm + + + Device parameter setpoint changed + + + Device parameter setpoint request + + + Equipment State + + + Employee Permissions Verification + + + Meter energy consumption + + + Raw material input information + + + Product inbound + + + Product outbound + + + Product Process Data + + + Product processing result data + + + MES Configuration + + + PLC Configuration + + + System Configuration + + + Machine ID + + + 127.0.0.1 + + + 9600 + + + Add User + + + Empty message + + + Deleting a User + + + Modification User + + + Check/Uncheck all + + + Data analysis + + + Data traceability + + + Easy parameter setting + + + Log Alarm + + + System Configuration + + + Managing Users + + + Data analysis + + + Data traceability + + + user rights + + + Username + + + user password + + + IC Card No + + + Easy parameter setting + + + Log Alarm + + + System Configuration + + + Managing Users + + + IC Card No + + + Enter Password again + + + User Information + + + user rights + + + user password + + + User Information + + + Set Permission + + + User operation + + + Start Index + + + Variable address + + + Variable Name + + + Variable address + + + Variable Configuration + + + Distribution group name + + + Start Index + + + Bit Offset/Length + + + Variable Name + + + Remarks + + + Data Type + + + Linearity coefficient + + + Offset Number + + + IC Card No + + + HMI manual pop-up status has been uploaded successfully, code + + + The end state of the HMI manual pop-up window has been uploaded successfully, and the code + + + MES downtime + + + MES parameter setting successfully + + + MES is not logged in + + + MES login is successful, login user + + + MES user logged out + + + PC write PLC time failed! + + + PC write PLC time successed! + + + PC writes PLC time exception + + + Add variable + + + Variable Configuration + + + Data Type + + + rising vote + + + Falling Edge Alarm + + + Length offset + + + Modify a variable + + + Remarks + + + Start Address + + + Variable address + + + Variable Name + + + Upper limit + + + Lower limit + + + Unsupported data type + + + Creates + + + Product model cannot be empty + + + Product model cannot be empty! + + + Product model and parameter list cannot be empty + + + Superior Rate + + + Save the parameters + + + Failed to save task + + + Save successfully + + + Info + + + Modify + + + Modify MES/non-MES mode switching + + + Modify the interval between switch monitoring interfaces + + + Modify Swipe Mode + + + Modify a variable + + + Failed to modify variable + + + Modification User + + + Failed to modify user + + + Modify Distribution Group + + + Failed to modify distribution group: + + + Modify the mode of automatic switching monitoring interface without operation + + + Modify the unoperational automatic screen locking method + + + Modify the number of curve displays + + + Modify thread time-consuming log saving + + + Modify to get MES parameters + + + Modify the debugging mode + + + Modify the automatic startup method of the software + + + Modify the automatic login method of the software + + + Modify the lock screen interval + + + Stop connecting to PLC + + + Stop running before switching MES + + + Full Day + + + Successfully turning off mes mode + + + Other unplanned downtime + + + Outbound + + + OutBound failed + + + Switching swiping mode successfully + + + Failed creating temporary file + + + Delete it + + + Delete the current re-investment barcode + + + Delete succeeded + + + Failed creating temporary file + + + Delete it + + + Delete variable + + + Failed to delete variable + + + Delete model + + + Failed to delete + + + Delete succeeded + + + Remove Tip + + + Failed to delete user + + + Delete Distribution Group + + + Failed to delete the distribution group + + + Power value + + + Features to be developed! + + + The total time taken to enter the station + + + Failed to load system configuration + + + Successed to load system configuration + + + Figure 19 Historical alarm + + + Historical data + + + Parameter modified successfully + + + Easy parameter setting + + + Variables + + + Variable name cannot be empty + + + The variable name already exists + + + Variable name does not exist + + + Incorrectly formatted variable address + + + Each defective item + + + Start monitoring + + + Start to start monitoring failed + + + Unusual quality + + + Quality inspection + + + Chart initialization exception + + + Incorrect address format, should start with 'D' followed by a number + + + The address format is incorrect, it should be a pure number + + + The address range exceeds the limit, and the end address cannot exceed 32767 + + + The material code corresponding to the model cannot be empty + + + 型号选择 + + + OPS Night Shift + + + Timed refresh exception + + + Export report failed + + + Export report succeeded, whether to open it now + + + Export report succeeded, do you want to open it now? + + + Export alarm succeeded, do you want to open it now? + + + Engineering changes + + + Disconnected from PLC + + + Start loading configuration parameters... + + + The start time can not be greater than the end time + + + Currently in MES mode, please log in + + + Currently in MES mode, please log in! + + + Currently logged in + + + Currently logged in, do you want to switch the swipe mode + + + Currently logged in, do you want to switch the swipe mode!! + + + There are currently no alarms + + + You are not currently logged in, please log in first! + + + You are not currently logged in, please log in + + + You are not currently logged in, please log in! + + + Current user logged out + + + Insufficient privileges for current logged in user! + + + The current device is running. For inquiries, please press the stop button first! + + + To be expected + + + Success + + + Successfully connect PLC + + + Open report record + + + Open alarm log + + + Inputs + + + Alarm TOP10 + + + Alarm query + + + Alarm item + + + Prompt + + + The operation log + + + Value + + + Data analysis + + + Data Report Export + + + New Variable + + + New variable created successfully + + + No PLC configuration information + + + Invalid group name + + + Invalid start address + + + Time + + + Monday + + + Wednesday + + + Tuesday + + + Friday + + + Saturday + + + Thursday + + + Sunday + + + Do you want to save the modified configuration? + + + Whether to turn off MES mode + + + Whether to turn off MES mode! + + + whether delete + + + Are you sure you want to exit the system + + + Do you want to delete the model + + + Toggle Swipe Mode + + + Are you sure you want to exit the system + + + Updated 12-hour data anomalies + + + Update Bad Chart Anomalies + + + Update Alarm Chart Anomalies + + + Update Efficiency Control Exception + + + Update Time Display Unexpected + + + Update energy display anomalies + + + please sign in here + + + No data found, please test + + + Jurisdiction + + + Permission Denied + + + Poor incoming materials + + + Query failed: + + + Query failed + + + Query action + + + Query time cannot exceed 7 days + + + Query range cannot exceed 1 day + + + Times + + + No address space available + + + No group names available, please add groups in Group.xlsx first + + + Not enough address space found + + + Cleaning point inspection + + + Material code cannot be empty! + + + The environment is not satisfied + + + User query failed + + + Code error + + + Add variable + + + Failed to add variable + + + Add model + + + Add Failure: Modification already exists, add again + + + add failed + + + add success + + + Add User + + + Failed to add users + + + Delete variable + + + Failed to add distribution group: + + + Communication group added successfully + + + Material code cannot be empty + + + Material code cannot be empty! + + + User! + + + User name cannot be empty + + + msg.user_password_not_be_empty + + + User query failed + + + Users + + + Successful login, login user + + + Login Tips + + + Incorrect login user or password + + + log in system + + + Day Shift + + + Confirmation + + + Form loading exception + + + Confirmation password can not be empty + + + Manual input is prohibited, please use the brand scan to enter + + + system log + + + Remarks + + + Good products + + + Failed to get parameters + + + Please sign in with your card first! + + + Please fill in the login password. + + + Please fill in the login username. + + + Start address format is incorrect + + + InBound + + + InBound failed + + + OutBound failed + + + Connect PLC + + + Connect PLC + + + Failed to connect to PLC, please check PLC connection configuration, network + + + Log out system + + + Communication Group + + + <strong>%s</strong> config saved successfully + + + Error + + + Length must be greater than 0 + + + Length must be a number greater than 0 + + + Verification Error + + + Default Group + + + MaterialCode + + + RFID + + + WindSpeed + + + WindDeviceNum + + + Info + + + Flag + + + Battery Grade + + + Machine No. + + + Battery Position + + + Container Code + + + Binding Result + + + Binding Failure Reason + + + Outbound Type + + + Original Cell Barcode + + + New Cell Barcode + + + Alarm query + + + User query failed + + + Error prompt + + + Query failed: + + + PC writes PLC time exception + + + Form loading exception + + + Updated 12-hour data anomalies + + + Update Efficiency Control Exception + + + Update Time Display Unexpected + + + Update energy display anomalies + + + Update Alarm Chart Anomalies + + + Update Bad Chart Anomalies + + + Quit Successfully + + + Quit the user + + + Stop connecting to PLC + + + Modify the automatic login method of the software + + + Modify the automatic startup method of the software + + + Modify the unoperational automatic screen locking method + + + Modify the lock screen interval + + + Modify the mode of automatic switching monitoring interface without operation + + + Modify the debugging mode + + + Modify the interval between switch monitoring interfaces + + + Modify the number of curve displays + + + Modify Swipe Mode + + + Toggle Swipe Mode + + + Switching swiping mode successfully + + + Current user logged out + + + Prompt + + + Stop running before switching MES + + + Modify MES/non-MES mode switching + + + Successfully turning off mes mode + + + MES user logged out + + + Modify to get MES parameters + + + Modify thread time-consuming log saving + + + The configuration file is loaded + + + No PLC configuration information + + + Please check the profile + + + Failed to connect PLC + + + Successfully connect PLC + + + Anomalies occurred when connecting to PLC + + + Result data upload failed + + + Good products + + + Triggered the manual HMI pop-up window function + + + Failure of equipment + + + Equipment transformation + + + MES downtime + + + Accessories, material replacement + + + Poor incoming materials + + + To be expected + + + Cleaning point inspection + + + Material code cannot be empty! + + + The environment is not satisfied + + + Other unplanned downtime + + + HMI manual pop-up status has been uploaded successfully, code + + + The end state of the HMI manual pop-up window has been uploaded successfully, and the code + + + Please sign in with your card first! + + + Please check the profile + + + Start address format is incorrect + + + InBound + + + Inbound A station is sent to PLC + + + Inbound B station is sent to PLC + + + Inbound C station is sent to PLC + + + The total time taken to enter the station + + + Outbound A station is sent to PLC + + + Outbound B station is sent to PLC + + + Outbound C station is sent to PLC + + + Cell outbound A consumes a total time + + + Cell outbound B consumes a total time + + + Cell outbound C consumes a total time + + + Result data upload failed + + + MES parameter setting successfully + + + Inbound workstation A paid mark is 0 + + + Inbound workstation B paid mark is 0 + + + Outbound workstation A paid mark is 0 + + + Outbound workstation B paid mark is 0 + + + Channel number + + + PLC settings + + + Scan code item + + + MES item + + + Other item + + + Item + + + OutStationResult + + + ProcessName + + + schedule + + + InstationTime + + + OutStationTime + + + OutStation2Mes + + + Result + + + Info + + + Anemometer equipment number + + + Dust removal wind speed + + + Flag + + + Material code cannot be empty! + + + An error occurred while validating the configuration, please check if the input is correct + + + PLC Configuration + + + MES Settings + + + MES parameter configuration + + + Enable + + + Disable + + + Export succeeded! + + + Export failed + + + IC Card No + + + Product model cannot be empty + + + Product model and parameter list cannot be empty + + + Save the parameters + + + Failed to save task + + + Save successfully + + + Modify a variable + + + Failed to modify variable + + + Modification User + + + Failed to modify user + + + Modify Distribution Group + + + Failed to modify distribution group: + + + Delete variable + + + Failed to delete variable + + + Delete model + + + Failed to delete + + + Remove Tip + + + Failed to delete user + + + Delete Distribution Group + + + Failed to delete the distribution group + + + The material code corresponding to the model cannot be empty + + + The current device is running. For inquiries, please press the stop button first! + + + Alarm TOP10 + + + Whether to turn off MES mode + + + Whether to turn off MES mode! + + + whether delete + + + Do you want to delete the model + + + Tip + + + Failed to connect to PLC, please check PLC connection configuration, network + + + Parameter modified successfully + + + Easy parameter setting + + + Variable name does not exist + + + Export report succeeded, whether to open it now + + + Currently in MES mode, please log in + + + Currently logged in, do you want to switch the swipe mode + + + Currently logged in, do you want to switch the swipe mode!! + + + You are not currently logged in, please log in first! + + + You are not currently logged in, please log in + + + Query action + + + Add variable + + + Failed to add variable + + + Add model + + + Add Failure: Modification already exists, add again + + + add failed + + + add success + + + Add User + + + Failed to add users + + + Delete variable + + + Failed to add distribution group: + + + Communication group added successfully + + + Material code cannot be empty + + + User! + + + User name cannot be empty + + + msg.user_password_not_be_empty + + + Users + + + Confirmation password can not be empty + + + Manual input is prohibited, please use the brand scan to enter + + + Model + + \ No newline at end of file diff --git a/Language/Languages.hu.resx b/Language/Languages.hu.resx new file mode 100644 index 0000000..74af9db --- /dev/null +++ b/Language/Languages.hu.resx @@ -0,0 +1,2175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Változó törlése + + + Rising Edge + + + Leeső él riasztás + + + Eltolás + + + Falling Edge + + + Kommunikációs csoport + + + Adattípus + + + Változó módosítása + + + Biteltolás/hossz + + + Rising Edge Alarm + + + Változó hozzáadva + + + A D40 visszaállították 0 + + + Riasztási információk + + + Riasztás típusa + + + Dátum Idő + + + Naplózza az üzeneteket + + + Dátum Idő + + + Napló típusa + + + Dátum Idő + + + Működési információk + + + Művelet típusa + + + Műveleti napló + + + Rendszerriasztás + + + Rendszernapló + + + PP (egyértelműsítő lap) + + + CP + + + Ca + + + PPK + + + CPK + + + Dev + + + Mean + + + SampleSize + + + Csoportok + + + Max + + + Minimum + + + Összesen + + + Átlagos + + + Max + + + Min + + + Specifikáció Alsó határérték + + + Max Specs + + + Adatcsoportok száma + + + Minta alcsoport mérete + + + Célérték + + + Negatív 3x szórás + + + Szórás (csoporton belül) + + + Szórás (teljes) + + + Pozitív 3x SD + + + CPL + + + CPU + + + CP + + + CPK + + + Ca + + + PPL + + + Ppk + + + PPU + + + PP (egyértelműsítő lap) + + + CpkGrade + + + Minták száma összesen + + + Ppm < Lsl + + + Ppm Toatl + + + Ppm < USL + + + Üres adatok + + + Számítsa ki a CPK-t + + + Elemzési lehetőségek + + + Lekérdezés + + + Hozzon létre áladatokat + + + Állandó + + + Statisztikák + + + Folyamatképesség (a csoporton belül) + + + Egyéb érték + + + Kiszámított érték + + + Mért teljesítmény + + + Folyamatképesség (általános) + + + Lekérdezési lehetőségek + + + Lekérdezési időintervallum + + + XR vezérlési táblázat + + + CPK elemzési táblázat + + + Minta futtatási diagram + + + Átlagos futási diagram + + + Termelési modell + + + Anyagkód + + + Kezdje el a megfigyelést + + + Monitorozás leállítása + + + chart1 + + + chart1 + + + Megjegyzések + + + Összesített eredmények + + + A rétegek száma a veremben + + + Gépszám + + + Idő + + + Raklap vonalkód + + + Cella osztály + + + Sikeresen kapcsolt cellák mennyisége + + + Cellák Összes mennyisége + + + Acélhéj kód + + + Termelési modell + + + Csatorna + + + Raklap pozíció száma + + + Raklap pozíció száma + + + + + + Raklapsorszám + + + Megjegyzés + + + Eredmény + + + Idő + + + Raklap vonalkód + + + Gépszám + + + Cella osztály + + + Csatorna + + + Tálcakód + + + Eszközkód + + + Anyagkód + + + Megjegyzés + + + Eredmény + + + Idő + + + Acélhéj kód + + + Csatorna + + + Megjegyzés + + + Eredmény + + + Idő + + + Naplózás + + + Argumentumok + + + Szerkezeti alkatrészek tálcája + + + Akkumulátor Be + + + Akkumulátor Párosítva + + + Paraméterelem + + + Min + + + Max + + + Egység + + + Új terjesztési csoport + + + Terjesztési csoport törlése + + + Terjesztési csoport módosítása + + + Visszajelzés szükséges-e vagy sem + + + Engedélyezve vagy sem + + + Ez egy kiváltott olvasás + + + Terjesztési csoport neve + + + Engedélyezve + + + Visszajelzés szükséges-e vagy sem + + + Ez egy kiváltott olvasás + + + Hossz + + + Hozzászólás leírása + + + Kezdő cím + + + Terjesztési csoport konfiguráció + + + Terjesztési csoport neve + + + Kezdő cím + + + Hossz + + + Hozzászólás leírása + + + Excel exportálása + + + Idő lekérdezés + + + Exportálás + + + Lekérdezés + + + Exportálás + + + Lekérdezés + + + Excel exportálása + + + Exportálás + + + Lekérdezés + + + Lekérdezés + + + Újra feltöltés + + + Exportálás + + + Lekérdezés + + + Átlagos Működési Arány + + + Átlagos Ppm + + + Termelési Hibaarány + + + Termelés Bevitel + + + Termelés Kibocsátás + + + Tesztidő + + + Nap + + + Átlagos Működési Arány + + + Átlagos Ppm + + + Optimális Arány + + + Termelés Bevitel + + + Termelés Kibocsátás + + + Átlagos Működési Arány + + + Hónap + + + Átlagos Ppm + + + Termelési Hibaarány + + + Termelés Bevitel Összesen + + + Termelés Kibocsátás Összesen + + + Átlagos Működési Arány + + + Átlagos Ppm + + + Termelési Értékelési Arány + + + Termelés Bevitel Összesen + + + Termelés Kibocsátás Összesen + + + Hét + + + Részegtartalom + + + Részegszám + + + Részegidő + + + Osztály + + + PLC-cím + + + Sávkód + + + Alsó kártya kódja + + + Kanal sorszáma + + + Raklap pozíció száma + + + Megjegyzés + + + Eredmény + + + A rétegek száma a veremben + + + Próbaidő + + + Akkumulátor minősége + + + Gépszám + + + Akkumulátor helyzete + + + Dobozcímkákód + + + Kötési eredmény + + + Kötési sikertelenség okát + + + Kilépési típus + + + Eredeti elem vonalkódja + + + Új elem vonalkódja + + + Raklap vonalkód + + + Shift + + + Acélhéj kód + + + RFID + + + Statisztikák dátuma + + + Statisztikák dátuma + + + Statisztikai idő + + + Statisztikai idő + + + Befejezés időpontja + + + Kezdés időpontja + + + Vonalkód + + + Befejezés időpontja + + + Kezdés időpontja + + + Lekérdezés típusa + + + Történelmi termelési adatok lekérdezése + + + Kapacitásstatisztikai lekérdezés + + + Riasztási adatok lekérdezésének naplózása + + + Statisztika műszakonként + + + Statisztika napról napra + + + Heti statisztika + + + Havi statisztikák + + + Yiwei Power + + + Bejelentkezés + + + Yiwei Power + + + A program indulása + + + Factory 57 + + + Yiwei Power + + + szerelő rendszere Rendszer + + + Riasztás naplózása + + + Adatok + + + Adatfigyelés + + + Adatok nyomonkövethetősége + + + Akkumulátor állapota + + + Központosított monitorozás + + + Paraméterbeállítások + + + Rendszerbeállítások + + + Felhasználókezelés + + + A program névjegye + + + Kezdőképernyő megjelenítése + + + Exit + + + Kezdőképernyő elrejtése + + + Non-Swipe Mode + + + Intelligens mérő + + + A fázis Feszültség + + + Teljes aktív teljesítmény + + + Teljes teljesítménytényező + + + Feszültségarány + + + Jelenlegi arány + + + Felhalmozott teljesítmény + + + B fázis feszültség + + + C fázisú feszültség + + + A fázis áram + + + B fázisú áram + + + C fázisú áram + + + Phase A Power + + + B fázisú tápellátás + + + C fázisú tápellátás + + + Riasztás Top10 Statisztika + + + Kapacitásstatisztikák + + + Hibás tételstatisztika + + + OK szám + + + Kiemelkedő ár + + + Teljes termelés + + + Elérhetőség + + + Eszköz száma + + + Gyári kód + + + Sor száma + + + Termelési modell + + + Bekapcsolási idő + + + Futásidő + + + Intelligens mérő (eszköz) + + + OK + + + Biztosan kilép a rendszerből? + + + Jelentkezzen ki a rendszerből + + + Mégsem + + + Mégsem + + + OK + + + Biztosan kilép a rendszerből? + + + Jelentkezzen ki a rendszerből + + + Modell törlése + + + Modell hozzáadása + + + Paraméterek mentve + + + Paraméterelem neve + + + Max + + + Min + + + Egység + + + Anyagkód + + + Termelési modell + + + Megjegyzés + + + Jelenlegi modell + + + Termelési modell + + + Anyagkód + + + Jelenlegi modell + + + Add hozzá a PLC-t + + + Nincs beállítva + + + Terjesztési csoport konfiguráció + + + Határozza meg a beállításokat + + + Változó konfiguráció + + + A lefoglalások megjelenítése + + + Rising Edge + + + Heartbeat Address + + + IP-cím + + + Aktív + + + Szívverés állapota + + + Változó módosítása + + + PLC típus + + + Kiszolgálóportok + + + Megjegyzés + + + Szerezze be a MES-paraméter + + + Pöccintési mód bekapcsolása + + + PLC típus konfiguráció + + + Eszköz száma + + + Sor száma + + + Gyári kód + + + Automatikusan kapcsolja át a felügyeleti interfész idejét + + + Nincs olyan művelet, amely automatikusan átkapcsolja a felügyeleti felületet + + + Ügyfél cikkszáma + + + Portszám konfiguráció + + + Nincs működő automatikus zárolási képernyő + + + Automatikus zárolási képernyőidő + + + Hegesztő teljesítménygörbe kijelzések száma + + + A szoftver automatikusan bejelentkezik + + + Automatikus indítás + + + Szál időigényes napló mentése + + + MES/nem MES üzemmód váltás + + + Anemométer + + + Hibakeresési mód + + + Berendezés riasztó + + + Eszközparaméter alapértéke módosítva + + + Eszközparaméter alapérték kérése + + + Eszköz állapota + + + Alkalmazotti engedélyek ellenőrzése + + + Mérőóra energiafogyasztása + + + Nyersanyag bemeneti információ + + + Termék bejövő + + + Termék kimenő + + + Termékfolyamatadatok + + + A termék feldolgozási eredményadatai + + + MES konfiguráció + + + PLC konfiguráció + + + Rendszerbeállítások + + + Gép AZ + + + 127.0.0.1 + + + 9600 + + + Felhasználó hozzáadása + + + Üres üzenet + + + Felhasználó törlése + + + Felhasználó módosítása + + + Válassza ki/szüntesse meg az összes kiválasztását + + + Adatok + + + Adatok nyomonkövethetősége + + + Paraméterbeállítások + + + Riasztás naplózása + + + Rendszerbeállítások + + + Felhasználókezelés + + + Adatok + + + Adatok nyomonkövethetősége + + + Felhasználói jogosultságok + + + Felhasználónév + + + Felhasználói jelszó + + + IC-kártya száma + + + Paraméterbeállítások + + + Riasztás naplózása + + + Rendszerbeállítások + + + Felhasználókezelés + + + IC-kártya száma + + + Jelszó megerősítése + + + Felhasználói adatok + + + Felhasználói jogosultságok + + + Felhasználói jelszó + + + Felhasználói adatok + + + Engedélyek konfigurálása + + + Felhasználói művelet + + + Index indítása + + + Változó cím + + + Változó neve + + + Változó cím + + + Változó konfiguráció + + + Terjesztési csoport neve + + + Index indítása + + + Biteltolás/hossz + + + Változó neve + + + Hozzászólás leírása + + + Adattípus + + + Linearitási együttható + + + Eltolás + + + A HMI kézi előugró ablak állapotát sikeresen feltöltötték, kódot + + + A HMI kézi előugró ablak befejezési állapotát sikeresen feltöltötték, kód + + + MES leállás + + + Sikeresen beállították a MES paramétereket + + + A MES nincs bejelentkezve + + + A MES felhasználó kijelentkezett + + + A MES bejelentkezés sikeres, bejelentkezett felhasználó + + + PC írási PLC idő sikertelen! + + + A PC sikeresen írta a PLC időt + + + Adjon hozzá változókat + + + Változó konfiguráció + + + Adattípus + + + Rising Edge + + + Leeső él riasztás + + + Hosszeltolás + + + Változó módosítása + + + Megjegyzés + + + Kezdő cím + + + Változó cím + + + Változó neve + + + Sapka + + + Alsó határ + + + Nem támogatott adattípus + + + Kimenet + + + A termékmodell nem lehet üres! + + + Kiemelkedő ár + + + Információ + + + Módosítás + + + Módosítsa a MES/nem MES módkapcsolást + + + Módosítsa a kapcsolási felügyeleti felület intervallumát + + + Módosítsa a kártyahúzási módot + + + Módosítsa a felügyeleti felület automatikus váltási módját művelet nélkül + + + Módosítsa az automatikus képernyőzárás módját művelet nélkül + + + Módosítsa a görbe megjelenítésének számát + + + Módosítsa a szál időigényes naplómentését + + + Módosítsa a MES paraméterek megszerzését + + + Módosítsa a hibakeresési módot + + + Módosítsa a szoftver automatikus indítási módját + + + A szoftver automatikus bejelentkezési módjának módosítása + + + Módosítsa a zárolási képernyő intervallumát + + + Hagyja le a PLC-hez való csatlakozást + + + Először állítsa le a futást, majd váltson MES-re + + + Egész nap + + + Sikeresen kikapcsolta a MES módot + + + Egyéb nem tervezett leállások + + + Indulás + + + Sikeresen váltott a kártya lehúzási módra + + + Ideiglenes fájl létrehozása sikertelen + + + Törlés + + + Törölje az aktuális átdolgozott vonalkódot + + + Sikeresen törölve + + + Teljesítményérték + + + Fejlesztendő funkciók! + + + A megbízás a megbízás + + + A megszüntetések megszüntetése a megszüntetése + + + Történelmi riasztás + + + Korábbi adatok + + + Változó + + + A változó neve nem lehet üres + + + A változó neve már létezik + + + Helytelenül formázott változócím + + + Minden egyes hibás tétel + + + Indítsd el a megfigyelést + + + Az indítási megfigyelés meghibásodott + + + Rendellenes minőség + + + Minőségellenőrzés + + + Diagraminicializációs kivétel + + + Helytelen címformátum, „D” betűvel kell kezdődnie, amelyet egy számnak kell követnie + + + A cím formátuma helytelen, tiszta számnak kell lennie + + + A címtartomány meghaladja a határértéket, a végcím pedig nem haladhatja meg a 32767-et + + + Modellválasztás + + + Éjszakai műszak + + + Ütemezett frissítési kivétel + + + Jelentés exportálása sikertelen + + + A jelentés exportálása sikeres volt, megnyitja most? + + + A riasztás exportálása sikeres volt, megnyitja most? + + + Mérnöki változások + + + A PLC-től lekapcsolva + + + Kezdjük a konfigurációs paraméterek betöltését... + + + A kezdési idő nem lehet hosszabb a befejezési időnél + + + Jelenleg MES módban van, kérjük, jelentkezzen be! + + + Jelenleg bejelentkezett + + + Jelenleg nincsenek riasztások + + + Jelenleg nincs bejelentkezve, kérjük, jelentkezzen be! + + + Az aktuális felhasználó kijelentkezett + + + Nincs elegendő jogosultság az aktuálisan bejelentkezett felhasználó számára! + + + Az anyagokra várva + + + Autocfg - sikeres művelet + + + Sikeres csatlakozás a PLC-hez + + + Jelentésrekord megnyitása + + + Riasztási napló megnyitása + + + Befektetés + + + Riasztási TOP10 + + + Riasztási lekérdezés + + + Riasztási elem + + + Tippek + + + Műveleti napló + + + Érték + + + Adatok + + + Adatjelentés exportálása + + + Új változó + + + Új változó sikeresen létrehozva + + + Nincs PLC konfigurációs információ + + + Érvénytelen csoportnév + + + Érvénytelen kezdő cím + + + Idő + + + H + + + Sze + + + Kedd + + + P + + + Szo + + + Cs + + + Szudán + + + Menti a módosított konfigurációt? + + + Akár válts-e a kártya lehúzási módra + + + Biztosan kilép a rendszerből + + + 12 órás adatkivételek frissítése + + + Frissítse rossz diagram kivételt + + + Frissítse a riasztási diagram kivételét + + + Frissítse a hatékonysági vezérlő kivétel + + + A frissítési idő megjelenítése abnormális + + + A frissített energia kijelző abnormális + + + Nincs bejelentkezve + + + Nem található adat, kérjük, tesztelje + + + Engedélyek + + + Nincs elegendő engedély + + + Rossz bejövő anyagok + + + A lekérdezés sikertelen volt: + + + A lekérdezési idő nem haladhatja meg a 7 napot + + + A lekérdezési tartomány nem haladhatja meg az 1 napot + + + Times + + + Nincs elérhető címterület + + + Nincs elérhető csoportnév, kérjük, először adjon hozzá csoportokat az Group.xlsx fájlban + + + Nem található elég hely a címben + + + Rossz cellakód + + + A bejelentkezés sikeres, bejelentkezett felhasználó + + + Bejelentkezési tippek + + + Rossz bejelentkező felhasználó vagy jelszó!!! + + + Jelentkezzen be a rendszerbe + + + Nappali műszak + + + Mentés megerősítése + + + Rendszernapló + + + Hozzászólás leírása + + + Jó termék + + + Nem sikerült megszerezni a paramétereket + + + Kérjük, először jelentkezzen be a kártyájával! + + + Kérjük, töltse ki a bejelentkezési jelszót + + + Kérjük, töltse ki a bejelentkezési felhasználónevét + + + A kezdő cím formátuma helytelen + + + Akna leállítása + + + A belépés sikerült + + + Kibulás sikerült + + + Csatlakoztassa a PLC-t + + + Connect PLC + + + Nem sikerült csatlakozni a PLC-hez, kérjük, ellenőrizze a PLC-kapcsolat konfigurációját, hálózatát + + + Jelentkezzen ki a rendszerből + + + Kommunikációs csoport + + + Konfiguráció mentése sikeres + + + Error + + + A hossznak 0-nál nagyobbnak kell lennie + + + A hossznak 0-nál nagyobb számnak kell lennie + + + Ellenőrzési hiba + + + Alapértelmezett csoport + + + Anyag kódja + + + RFID doboz kódja + + + Szélsebesség + + + Szélkészülék sorszáma + + + Információ + + + Visszajelzés + + + Akkumulátor minősége + + + Gépszám + + + Akkumulátor helyzete + + + Dobozcímkákód + + + Kötési eredmény + + + Kötési sikertelenség okát + + + Kilépési típus + + + Eredeti elem vonalkódja + + + Új elem vonalkódja + + + Riasztási lekérdezés + + + A felhasználói lekérdezés sikertelen volt + + + Hibaüzenet + + + A lekérdezés sikertelen volt: + + + A PC PLC-be írási ideje abnormális + + + Az űrlap betöltési kivétel + + + 12 órás adatkivételek frissítése + + + Frissítse a hatékonysági vezérlő kivétel + + + A frissítési idő megjelenítése abnormális + + + A frissített energia kijelző abnormális + + + Frissítse a riasztási diagram kivételét + + + Frissítse rossz diagram kivételt + + + A kilépés sikeres + + + Felhasználó kilépése + + + Hagyja le a PLC-hez való csatlakozást + + + A szoftver automatikus bejelentkezési módjának módosítása + + + Módosítsa a szoftver automatikus indítási módját + + + Módosítsa az automatikus képernyőzárás módját művelet nélkül + + + Módosítsa a zárolási képernyő intervallumát + + + Módosítsa a felügyeleti felület automatikus váltási módját művelet nélkül + + + Módosítsa a hibakeresési módot + + + Módosítsa a kapcsolási felügyeleti felület intervallumát + + + Módosítsa a görbe megjelenítésének számát + + + Módosítsa a kártyahúzási módot + + + Akár válts-e a kártya lehúzási módra + + + Sikeresen váltott a kártya lehúzási módra + + + Az aktuális felhasználó kijelentkezett + + + Tippek + + + Először állítsa le a futást, majd váltson MES-re + + + Módosítsa a MES/nem MES módkapcsolást + + + Sikeresen kikapcsolta a MES módot + + + A MES felhasználó kijelentkezett + + + Módosítsa a MES paraméterek megszerzését + + + Módosítsa a szál időigényes naplómentését + + + A konfigurációs fájl betöltése befejeződött + + + Nincs PLC konfigurációs információ + + + Kérjük ellenőrizze a konfigurációs fájlt + + + Nem sikerült csatlakoztatni a PLC-hez + + + Sikeres csatlakozás a PLC-hez + + + A PLC csatlakoztatásakor kivétel történt + + + A manuális HMI előugró funkció elindult + + + Berendezés hibája + + + Berendezések átalakítása + + + MES leállás + + + Tartozékok, anyagcsere + + + Rossz bejövő anyagok + + + Az anyagokra várva + + + Tisztító ellenőrzés + + + Az anyagkód nem lehet üres! + + + A környezet nem elégedett + + + A felhasználói lekérdezés sikertelen volt + + + Egyéb nem tervezett leállások + + + A HMI kézi előugró ablak állapotát sikeresen feltöltötték, kódot + + + A HMI kézi előugró ablak befejezési állapotát sikeresen feltöltötték, kód + + + A bejövő állomás és a PLC-nek küldeni + + + A B állomás bejövő állomása és a PLC-nek küldött + + + A bejövő C állomás elküldte a PLC-nek + + + Összes időt vesz igénybe a mag bejutása + + + Az A állomásból való kimenő elküldés a PLC-nek + + + A kimenő B állomás elküldje a PLC-nek + + + A kimenő C állomás elküldi a PLC-nek + + + Az akkumulátorcellák kilépésének összes ideje Az A állomásból + + + A B állomásból kilépő akkumulátorcellák összes időbe telik + + + Az akkumulátorcellák C kilépésének összes időbe telt ideje + + + Rossz cellakód + + + Jelentkezzen be a rendszerbe + + + Nappali műszak + + + Mentés megerősítése + + + Az űrlap betöltési kivétel + + + Rendszernapló + + + Hozzászólás leírása + + + Az eredmény adatfeltöltése sikertelen volt + + + Jó termék + + + A manuális HMI előugró funkció elindult + + + Berendezés hibája + + + Berendezések átalakítása + + + Kérjük, először jelentkezzen be a kártyájával! + + + Kérjük ellenőrizze a konfigurációs fájlt + + + A kezdő cím formátuma helytelen + + + Akna leállítása + + + Sikeresen beállították a MES paramétereket + + + Az A bejövő állomás anyagjelzője 0 + + + Az B bejövő állomás anyagjelzője 0 + + + Az A kimenő állomás anyagjelzője 0 + + + Az B kimenő állomás anyagjelzője 0 + + + A csatornaszám + + + PLC konfiguráció + + + rossz QR-kód olvasás + + + MES rossz + + + egyéb rossz + + + item + + + OutStationResult + + + ProcessName + + + schedule + + + InstationTime + + + OutStationTime + + + OutStation2Mes + + + Result + + + Info + + + Anemométer berendezésszáma + + + Poreltávolító szélsebesség + + + Címkék + + + Az anyagkód nem lehet üres! + + + A hossznak 0-nál nagyobbnak kell lennie + + + A hossznak 0-nál nagyobb számnak kell lennie + + + Hiba történt a konfiguráció érvényesítése során, kérjük, ellenőrizze, hogy a bemenet helyes-e + + + PLC konfiguráció + + + MES-beállítások + + + MES paraméter konfiguráció + + + Ellenőrzési hiba + + + Alapértelmezett csoport + + + Engedélyezés + + + Letiltás + + + Export sikeres! + + + Export sikertelen + + \ No newline at end of file diff --git a/Language/Languages.ms.resx b/Language/Languages.ms.resx new file mode 100644 index 0000000..344a68d --- /dev/null +++ b/Language/Languages.ms.resx @@ -0,0 +1,2694 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tercuit cuit + + + Gagal menyambung ke PLC, sila semak konfigurasi sambungan PLC, rangkaian + + + Hapuskan Pemboleh Ubah + + + Rising Edge + + + Penggera Tepi Jatuh + + + Ofset + + + Pinggir Jatuh + + + Kumpulan Komunikasi + + + Jenis data + + + Ubahsuai Pembolehubah + + + Panjang + + + Penggera Rising Edge + + + Pemboleh ubah ditambah + + + D40 telah ditetapkan semula 0 + + + Maklumat penggera + + + Jenis penggera + + + Masa Tarikh + + + Log Mesej + + + Masa Tarikh + + + Jenis log + + + Masa Tarikh + + + Maklumat operasi + + + Jenis operasi + + + Log Operasi + + + Penggera Sistem + + + Log Sistem + + + Pp + + + CP + + + Ca + + + PPK + + + Bpk + + + Dev + + + Min + + + SampleSize + + + Kumpulan + + + Maks + + + Min + + + Jumlah + + + kepercayaan kepada tuhan + + + Maks + + + Min + + + Spesifikasi Had Bawah + + + Spesifikasi Maksimum + + + Bilangan kumpulan data + + + Saiz Subkumpulan Sampel + + + Nilai sasaran + + + Sisihan piawai 3x negatif + + + Sisihan piawai (dalam kumpulan) + + + keselurujan + + + Positif 3x SD + + + CPL + + + CPU + + + CP + + + Bpk + + + Ca + + + PPL + + + Ppk + + + PPU + + + Pp + + + CpkGrade + + + Jumlah sampel + + + Ppm < LSL + + + Ppm Toatl + + + Ppm < USL + + + Data kosong + + + Kira cpk + + + Pilihan Analisis + + + Pertanyaan + + + Jana data tiruan + + + Jumlah + + + Statistik + + + Keupayaan proses (dalam kumpulan) + + + Nilai lain + + + Nilai yang dikira + + + Prestasi diukur + + + keselurujan + + + Pilihan pertanyaan + + + Selang masa pertanyaan + + + Carta Kawalan XR + + + Carta Analisis CPK + + + Contoh rajah larian + + + Mean Run Chart + + + Model Pengeluaran + + + Kod Bahan + + + Mula memantau + + + Hentikan pemantauan + + + carta1 + + + carta1 + + + Catatan + + + Keputusan yang komprehensif + + + Bilangan lapisan pada tindanan + + + No. Mesin + + + Masa + + + Kod bar palet + + + Gred sel + + + Kuantiti sel yang berjaya dihubungkan + + + Jumlah keseluruhan sel + + + Kod Cangkerang Keluli + + + Model Pengeluaran + + + Nombor Saluran + + + Nombor lokasi palet + + + Nombor lokasi palet + + + + + + Nombor talian palet + + + Perhatian + + + hasil mahsul + + + zaman + + + Kod bar palet + + + No. Mesin + + + Gred sel + + + Saluran + + + Kod dulang + + + Kod Peranti + + + Kod Bahan + + + Perhatian + + + hasil mahsul + + + zaman + + + Kod Cangkerang Keluli + + + Nombor Saluran + + + Perhatian + + + hasil mahsul + + + zaman + + + Pembalakan + + + hujah-hujah + + + Dulang bahagian struktur + + + Bateri Masuk + + + Bateri Dipadankan + + + Item parameter + + + Min + + + Maks + + + Unit + + + Kumpulan Pengedaran Baharu + + + Hapuskan Kumpulan Pengedaran + + + Ubah suai Kumpulan Pengedaran + + + Sama ada maklum balas diperlukan atau tidak + + + Didayakan atau tidak + + + Adakah ia bacaan yang dicetuskan + + + Nama kumpulan pengedaran + + + Dibenarkan + + + Sama ada maklum balas diperlukan atau tidak + + + Adakah ia bacaan yang dicetuskan + + + Panjang + + + Keterangan komen + + + Alamat permulaan + + + Konfigurasi Kumpulan Pengedaran + + + Nama kumpulan pengedaran + + + Alamat permulaan + + + Panjang + + + Keterangan komen + + + Eksport Excel + + + Pertanyaan masa + + + Eksport + + + Pertanyaan + + + Eksport + + + Pertanyaan + + + Eksport Excel + + + Eksport + + + Pertanyaan + + + Pertanyaan + + + Muat naik semula + + + Eksport + + + Pertanyaan + + + Purata Kadar Operasi + + + Purata Ppm + + + Kadar Hasil Baik + + + Produksi Masuk + + + Produksi Keluar + + + Masa Ujian + + + Hari + + + Purata Kadar Operasi + + + Purata Ppm + + + Kadar Optimum + + + Produksi Masuk + + + Produksi Keluar + + + Purata Kadar Operasi + + + Bulan + + + Purata Ppm + + + Kadar Hasil Baik + + + Jumlah Produksi Masuk + + + Jumlah Produksi Keluar + + + Purata Kadar Operasi + + + Purata Ppm + + + Kadar Hasil Produksi + + + Jumlah Produksi Masuk + + + Jumlah Produksi Keluar + + + Minggu + + + Kandungan Penggera + + + Jumlah Penggera + + + Masa Penggera + + + Kelas + + + Alamat PLC + + + Kod Bar + + + Kod palet asas + + + Nombor Saluran + + + Nombor lokasi palet + + + Catatan + + + Keputusan + + + Bilangan lapisan pada tindanan + + + Masa Ujian + + + Gred Bateri + + + No. Mesin + + + Posisi Bateri + + + Kod Kotak + + + Hasil Pengikatan + + + Sebab Kegagalan Pengikatan + + + Jenis Keluar + + + Barcode Sel Sebelum Diganti + + + Barcode Sel Selepas Diganti + + + Kod palet + + + Shift + + + Kod Cangkerang Keluli + + + RFID + + + Tarikh statistik + + + Tarikh statistik + + + Masa statistik + + + Masa statistik + + + Masa tamat + + + Waktu Total + + + Kod bar + + + Masa tamat + + + Waktu Total + + + Jenis Pertanyaan + + + Pertanyaan data pengeluaran sejarah + + + Pertanyaan statistik kapasiti + + + Log pertanyaan data penggera + + + Statistik mengikut Shift + + + Statistik mengikut hari + + + Statistik mengikut minggu + + + Statistik Bulanan + + + Yiwei Power + + + Log masuk + + + Yiwei Power + + + Mula + + + Kilang 57 + + + Yiwei Power + + + Sistem Pengurusan Perakitan + + + Penggera Log + + + Wawasan + + + Pemantauan data + + + Kebolehkesanan data + + + Keadaan bateri + + + Pemantauan berpusat + + + Tetapan Parameter + + + Tetapan Sistem + + + Pengurusan Pengguna + + + Penyampai + + + Tunjukkan skrin utama + + + Keluar + + + Sembunyikan Skrin Utama + + + Mod Bukan Leret + + + Meter pintar + + + Voltan Fasa A + + + Jumlah Kuasa Aktif + + + Jumlah faktor kuasa + + + Nisbah voltan + + + Nisbah Semasa + + + Kuasa Terkumpul + + + Voltan Fasa B + + + Voltan Fasa C + + + Arus Fasa A + + + Arus fasa B + + + Arus fasa C + + + Fasa A kuasa + + + Kuasa fasa B + + + Kuasa fasa C + + + Statistik Top10 Penggera + + + Statistik kapasiti + + + Statistik item buruk + + + Nombor OK + + + Kadar Unggul + + + Jumlah Pengeluaran + + + Ketersediaan + + + Nombor peranti + + + Kod Kilang + + + Nombor baris + + + Model Pengeluaran + + + Kuasa tepat pada masanya + + + Masa lampau + + + Meter pintar (peranti) + + + berkenan (bahasa istana) + + + Adakah anda pasti mahu keluar dari sistem? + + + Log keluar dari sistem + + + Dibatalkan + + + Dibatalkan + + + berkenan (bahasa istana) + + + Adakah anda pasti mahu keluar dari sistem? + + + Log keluar dari sistem + + + Hapuskan model + + + Tambah model + + + Parameter disimpan + + + Nama item parameter + + + Maks + + + Min + + + Unit + + + Kod Bahan + + + Model Pengeluaran + + + Perhatian + + + Model semasa + + + Model Pengeluaran + + + Kod Bahan + + + Model semasa + + + Tambah PLC + + + Nyahtetap + + + Konfigurasi Kumpulan Pengedaran + + + Tentukan tetapan + + + Konfigurasi Pemboleh Ubah + + + setubuh + + + Rising Edge + + + Alamat Denyutan Jantung + + + Alamat IP + + + Aktif + + + Status degupan jantung + + + Ubahsuai Pembolehubah + + + Jenis PLC + + + Nombor port + + + Perhatian + + + Dapatkan parameter mes + + + Hidupkan mod leret + + + Konfigurasi jenis PLC + + + Nombor peranti + + + Nombor baris + + + Kod Kilang + + + Tukar masa antara muka pemantauan secara automatik + + + Tiada operasi yang menukar antara muka pemantauan secara automatik + + + Konfigurasi alamat IP + + + Konfigurasi nombor port + + + Tiada skrin kunci automatik yang beroperasi + + + Masa skrin kunci automatik + + + Bilangan paparan lengkung kuasa pengimpal + + + Perisian log masuk secara automatik + + + Mulakan secara automatik + + + Penjimatan log yang memakan masa benang + + + Mod mes/bukan mes bertukar + + + Anemometer + + + Mod Nyahpepijat + + + Penggera peralatan + + + Titik tetapan parameter peranti berubah + + + Permintaan setpoint parameter peranti + + + Status peranti + + + Pengesahan Kebenaran Pekerja + + + Penggunaan tenaga meter + + + Maklumat input bahan mentah + + + Produk masuk + + + Produk keluar + + + Data Proses Produk + + + Data hasil pemprosesan produk + + + Konfigurasi mes + + + Konfigurasi PLC + + + Tetapan Sistem + + + ID Mesin + + + 127.0.0.1 + + + 9600 + + + Tambah pengguna + + + Mesej kosong + + + Hapuskan pengguna + + + Ubah suai pengguna + + + Pilih/nyahpilih semua + + + Wawasan + + + Kebolehkesanan data + + + Tetapan Parameter + + + Penggera Log + + + Tetapan Sistem + + + Pengurusan Pengguna + + + Wawasan + + + Kebolehkesanan data + + + Kebenaran Pengguna + + + & Simpan Imej Sebagai + + + Kata laluan pengguna + + + Nombor kad IC + + + Tetapan Parameter + + + Penggera Log + + + Tetapan Sistem + + + Pengurusan Pengguna + + + Nombor kad IC + + + Sahkan Kata Laluan + + + Maklumat Pengguna + + + Kebenaran Pengguna + + + Kata laluan pengguna + + + Maklumat Pengguna + + + Konfigurasi Kebenaran + + + Tindakan pengguna + + + Indeks Mula + + + Alamat boleh ubah + + + Nama pemboleh ubah + + + Alamat boleh ubah + + + Konfigurasi Pemboleh Ubah + + + Nama kumpulan pengedaran + + + Indeks Mula + + + Panjang + + + Nama pemboleh ubah + + + Keterangan komen + + + Jenis data + + + Pekali linear + + + Ofset + + + Nombor kad IC + + + Mes tidak log masuk + + + Log masuk MES berjaya, log masuk pengguna + + + Status pop timbul manual HMI telah berjaya dimuat naik, kod + + + Status akhir tetingkap pop timbul manual HMI telah berjaya dimuat naik, kod + + + MES Downtime + + + Tetapan parameter MES berjaya + + + Mes tidak log masuk + + + Pengguna MES telah log keluar + + + Masa PC tulis PLC gagal! + + + PC menulis masa PLC berjaya + + + PC menulis masa PLC yang tidak normal + + + Tambah pemboleh ubah + + + Konfigurasi Pemboleh Ubah + + + Jenis data + + + Rising Edge + + + Penggera Tepi Jatuh + + + Ofset panjang + + + Ubahsuai Pembolehubah + + + Perhatian + + + Alamat permulaan + + + Alamat boleh ubah + + + Nama pemboleh ubah + + + Cap + + + Had bawah + + + Jenis data tidak disokong + + + Kedua-dua kata laluan tidak sepadan + + + Output + + + Model produk tidak boleh kosong + + + Model produk tidak boleh kosong! + + + Model produk dan senarai parameter tidak boleh kosong + + + Kadar Unggul + + + Parameter disimpan + + + Gagal menyimpan + + + Berjaya disimpan + + + Maklumat + + + ubah suai + + + Ubah suai pensuisan mod MES/bukan MES + + + Ubah suai selang antara muka pemantauan suis + + + Ubah suai mod leret kad + + + Ubah suai mod antara muka pemantauan penukaran automatik tanpa operasi + + + Ubah suai kaedah kunci skrin automatik tanpa operasi + + + Ubah suai kuantiti paparan lengkung + + + Ubah suai penyimpanan log memakan masa benang + + + Ubah suai dan dapatkan parameter MES + + + Ubah suai mod penyahpepijatan + + + Ubah suai mod permulaan automatik perisian + + + Ubah suai kaedah log masuk automatik perisian + + + Ubah suai selang skrin kunci + + + Hentikan sambungan dengan PLC + + + Hentikan berjalan dahulu dan kemudian tukar kepada MES + + + Sepanjang hari + + + Matikan mod MES berjaya + + + Lain-lain downtime yang tidak dirancang + + + Keluar + + + Stesen keluar A dihantar ke PLC + + + Stesen keluar B dihantar ke PLC + + + Stesen keluar C dihantar ke PLC + + + Keluar gagal + + + Berjaya menukar mod leret kad + + + Gagal mencipta fail sementara + + + tadahkan + + + Padamkan kod bar yang diubah suai semasa + + + Berjaya dihapuskan + + + Nilai kuasa + + + Ubah Suai Variabel + + + Gagal mengubahsuai pemboleh ubah + + + Ubah suai pengguna + + + Gagal mengubah suai pengguna + + + Ubah suai Kumpulan Pengedaran + + + Gagal mengubah suai kumpulan pengedaran: + + + Berhenti berlari sebelum bertukar mes + + + Sepanjang hari + + + Keluar + + + Gagal mencipta fail sementara + + + tadahkan + + + Hapuskan Pemboleh Ubah + + + Gagal menghapuskan pemboleh ubah + + + Hapuskan model + + + Gagal dihapuskan: + + + Berjaya dihapuskan + + + Nilai kuasa + + + Hapuskan petunjuk + + + Gagal menghapuskan pengguna + + + Hapuskan Kumpulan Pengedaran + + + Gagal menghapuskan kumpulan pengedaran + + + Ciri-ciri yang akan dibangunkan! + + + Jumlah masa untuk menggulung teras memasuki stesen + + + Gagal memuatkan konfigurasi sistem + + + Konfigurasi sistem berjaya dimuatkan + + + Penggera sejarah + + + Data sejarah + + + Parameter berjaya diubah suai + + + Tetapan Parameter + + + ubah + + + Nama pemboleh ubah tidak boleh kosong + + + Nama pemboleh ubah sudah wujud + + + Nama pemboleh ubah tidak wujud + + + Nama pemboleh ubah tidak boleh kosong + + + Nama pemboleh ubah sudah wujud + + + Alamat pemboleh ubah yang diformat dengan salah + + + Setiap item yang rosak + + + Mulakan mulakan pemantauan + + + Gagal memulakan pemantauan permulaan + + + Kualiti yang tidak normal + + + Pemeriksaan kualiti + + + Pengecualian permulaan carta + + + Format alamat yang salah, harus bermula dengan 'D' diikuti dengan nombor + + + Format alamat tidak betul, ia sepatutnya nombor tulen + + + Julat alamat melebihi had, dan alamat akhir tidak boleh melebihi 32767 + + + Kod bahan yang sepadan dengan model tidak boleh kosong + + + Pemilihan model + + + syif malam + + + Pengecualian penyegaran berjadual + + + Eksport laporan gagal + + + Eksport laporan berjaya, sama ada untuk membukanya sekarang + + + Eksport laporan berjaya, adakah anda mahu membukanya sekarang? + + + Penggera eksport berjaya, adakah anda mahu membukanya sekarang? + + + Perubahan kejuruteraan + + + Terputus dari PLC + + + Mula memuatkan parameter konfigurasi… + + + Masa mula tidak boleh lebih besar daripada masa tamat + + + Pada masa ini dalam mod mes, sila log masuk + + + Buat masa ini dalam mod mes, sila log masuk! + + + Kini log masuk + + + Sedang log masuk, adakah anda ingin menukar mod leret + + + Sedang log masuk, adakah anda ingin menukar mod leret!! + + + Tiada penggera pada masa ini + + + Anda belum log masuk. Sila log masuk sebelum meneruskan + + + Anda belum log masuk buat masa ini, sila log masuk terlebih dahulu! + + + Anda belum log masuk, sila log masuk + + + Anda belum log masuk, sila log masuk! + + + Pengguna semasa telah log keluar + + + Kebenaran pengguna log masuk semasa tidak mencukupi + + + Keistimewaan tidak mencukupi untuk pengguna log masuk semasa! + + + Peranti semasa sedang berjalan. Untuk pertanyaan, sila tekan butang berhenti terlebih dahulu! + + + Menunggu bahan + + + berjaya + + + Berjaya menyambung ke PLC + + + Buka rekod laporan + + + Buka log penggera + + + Melabur + + + Hubungi polis TOP10 + + + Pertanyaan penggera + + + Item penggera + + + Petunjuk + + + Log Operasi + + + Nilai + + + Wawasan + + + Eksport Laporan Data + + + Pemboleh Ubah Baharu + + + Pemboleh ubah baharu berjaya dicipta + + + Tiada maklumat konfigurasi PLC + + + Nama kumpulan tidak sah + + + Alamat mula tidak sah + + + zaman + + + Sakit perut + + + Ke tandas + + + Selasa + + + Friday + + + Sabtu + + + Khamis + + + Ahad + + + Adakah anda ingin menyimpan konfigurasi yang diubah suai? + + + Sama ada untuk mematikan mod mes + + + Sama ada untuk mematikan mod mes! + + + Hapus atau tidak + + + Adakah anda pasti mahu keluar dari sistem + + + Adakah anda mahu menghapuskan model + + + Sama ada untuk menukar mod leret kad + + + Adakah anda pasti mahu keluar dari sistem + + + Kemas kini pengecualian data selama 12 jam + + + Kemas kini pengecualian carta yang buruk + + + Kemas kini pengecualian carta penggera + + + Kemas kini pengecualian kawalan kecekapan + + + Paparan masa kemas kini tidak normal + + + Kemas kini paparan tenaga tidak normal + + + Tidak log masuk + + + Tiada data ditemui, sila uji + + + Kebenaran + + + Kebenaran tidak mencukupi + + + Bahan masuk yang lemah + + + Pertanyaan gagal: + + + Tindakan pertanyaan + + + Masa pertanyaan tidak boleh melebihi 7 hari + + + Julat pertanyaan tidak boleh melebihi 1 hari + + + Pengeksponenan + + + Ruang alamat tidak tersedia + + + Tiada nama kumpulan yang tersedia, sila tambah kumpulan dalam Group.xlsx terlebih dahulu + + + Ruang alamat tidak mencukupi ditemui + + + Tambah pemboleh ubah + + + Gagal menambah pemboleh ubah + + + Tambah model + + + Tambah Kegagalan: Pengubahsuaian sudah wujud, tambah lagi + + + Gagal ditambah + + + Berjaya ditambah + + + Tambah pengguna + + + Gagal menambah pengguna: + + + Hapuskan Pemboleh Ubah + + + Gagal menambah kumpulan pengedaran: + + + Kumpulan komunikasi berjaya ditambah + + + Kod bahan tidak boleh kosong + + + Pemeriksaan pembersihan + + + Kod bahan tidak boleh kosong! + + + pengguna + + + Nama pengguna tidak boleh kosong + + + Kata laluan pengguna tidak boleh kosong + + + Persekitaran tidak memuaskan + + + Pertanyaan pengguna gagal + + + Kod sel bateri yang rosak + + + Log masuk berjaya, log masuk pengguna + + + Petua Log Masuk + + + Pengguna log masuk atau kata laluan salah!!! + + + Log masuk ke sistem + + + Shif hari + + + Sahkan Simpan + + + Pengecualian pemuatan borang + + + Sahkan kata laluan tidak boleh kosong + + + Input manual dilarang, sila gunakan imbasan jenama untuk masuk + + + Log Sistem + + + Keterangan komen + + + Nama pengguna sudah wujud + + + Sila leret kad anda untuk log masuk terlebih dahulu + + + Sila log masuk dengan kad anda terlebih dahulu! + + + Produk yang baik + + + Gagal mendapatkan parameter + + + Sila log masuk dengan kad anda terlebih dahulu! + + + Sila isikan kata laluan log masuk + + + Sila isikan nama pengguna log masuk + + + Format alamat mula tidak betul + + + Pit stop + + + Masuk gagal + + + Keluar gagal + + + Sambungkan PLC + + + Connect PLC + + + Gagal menyambung ke PLC, sila semak konfigurasi sambungan PLC, rangkaian + + + Log keluar dari sistem + + + Kumpulan Komunikasi + + + Sila pilih model produk + + + Sila pilih pemboleh ubah untuk diubah suai + + + Konfigurasi berjaya disimpan + + + kekasaran + + + Panjang mesti lebih besar daripada 0 + + + Panjang mesti nombor yang lebih besar daripada sifar + + + Ralat pengesahan + + + Kumpulan lalai + + + Kod Bahan + + + Kod RFID Cawan + + + Kelajuan Angin + + + Nombor Alat Angin + + + Maklumat + + + Tanda + + + Gred Bateri + + + No. Mesin + + + Posisi Bateri + + + Kod Kotak + + + Hasil Pengikatan + + + Sebab Kegagalan Pengikatan + + + Jenis Keluar + + + Barcode Sel Sebelum Diganti + + + Barcode Sel Selepas Diganti + + + Pertanyaan penggera + + + Pertanyaan pengguna gagal + + + Peringatan ralat + + + Pertanyaan gagal: + + + PC menulis masa PLC yang tidak normal + + + Pengecualian pemuatan borang + + + Kemas kini pengecualian data selama 12 jam + + + Kemas kini pengecualian kawalan kecekapan + + + Paparan masa kemas kini tidak normal + + + Kemas kini paparan tenaga tidak normal + + + Kemas kini pengecualian carta penggera + + + Kemas kini pengecualian carta yang buruk + + + Keluar berjaya + + + Keluar daripada pengguna + + + Hentikan sambungan dengan PLC + + + Ubah suai kaedah log masuk automatik perisian + + + Ubah suai mod permulaan automatik perisian + + + Ubah suai kaedah kunci skrin automatik tanpa operasi + + + Ubah suai selang skrin kunci + + + Ubah suai mod antara muka pemantauan penukaran automatik tanpa operasi + + + Ubah suai mod penyahpepijatan + + + Ubah suai selang antara muka pemantauan suis + + + Ubah suai kuantiti paparan lengkung + + + Ubah suai mod leret kad + + + Sama ada untuk menukar mod leret kad + + + Berjaya menukar mod leret kad + + + Pengguna semasa telah log keluar + + + Petunjuk + + + Hentikan berjalan dahulu dan kemudian tukar kepada MES + + + Ubah suai pensuisan mod MES/bukan MES + + + Matikan mod MES berjaya + + + Pengguna MES telah log keluar + + + Ubah suai dan dapatkan parameter MES + + + Ubah suai penyimpanan log memakan masa benang + + + Pemuatan fail konfigurasi selesai + + + Tiada maklumat konfigurasi PLC + + + Sila semak profil + + + Gagal menyambung ke PLC + + + Berjaya menyambung ke PLC + + + Pengecualian berlaku semasa menyambung ke PLC + + + Sila pilih pemboleh ubah untuk dihapuskan + + + Akibatnya, muat naik data gagal + + + Produk yang baik + + + Fungsi pop timbul HMI manual dicetuskan + + + Kegagalan peralatan + + + Transformasi peralatan + + + Sila log masuk dengan kad anda terlebih dahulu! + + + Sila semak profil + + + Format alamat mula tidak betul + + + Pit stop + + + MES Downtime + + + Aksesori, penggantian bahan + + + Bahan masuk yang lemah + + + Menunggu bahan + + + Pemeriksaan pembersihan + + + Kod bahan tidak boleh kosong! + + + Persekitaran tidak memuaskan + + + Lain-lain downtime yang tidak dirancang + + + Status pop timbul manual HMI telah berjaya dimuat naik, kod + + + Status akhir tetingkap pop timbul manual HMI telah berjaya dimuat naik, kod + + + Sila log masuk dengan kad anda terlebih dahulu! + + + Sila semak profil + + + Format alamat mula tidak betul + + + Pit stop + + + Masuk ke stesen A dan hantar ke PLC + + + Masuk ke stesen B dan hantar ke PLC + + + Masuk ke stesen C dan hantar ke PLC + + + Jumlah masa untuk menggulung teras memasuki stesen + + + Stesen keluar A dihantar ke PLC + + + Stesen keluar B dihantar ke PLC + + + Stesen keluar C dihantar ke PLC + + + Jumlah masa untuk sel bateri keluar A + + + Jumlah masa untuk sel bateri keluar B + + + Jumlah masa untuk sel bateri keluar C + + + Akibatnya, muat naik data gagal + + + Tetapan parameter MES berjaya + + + Stesen masuk A mempunyai tanda bahan 0 + + + Stesen masuk B mempunyai tanda bahan 0 + + + Stesen keluar A mempunyai tanda bahan 0 + + + Stesen keluar B mempunyai tanda bahan 0 + + + Nombor saluran + + + Konfigurasi PLC + + + skan kod tidak berjaya + + + MES tidak berjaya + + + lainnya tidak berjaya + + + Nama item + + + OutStationResult + + + ProcessName + + + schedule + + + InstationTime + + + OutStationTime + + + OutStation2Mes + + + Result + + + Info + + + Nombor peralatan anemometer + + + Kelajuan kelajuan penyingkiran habuk + + + Label + + + Kod bahan tidak boleh kosong! + + + Ralat berlaku semasa mengesahkan konfigurasi, sila semak sama ada input adalah betul + + + Konfigurasi PLC + + + Tetapan mes + + + Konfigurasi parameter mes + + + Masuk gagal + + + Sambungkan PLC + + + Connect PLC + + + Gagal menyambung ke PLC + + + Gagal menyambung ke PLC, sila semak konfigurasi sambungan PLC, rangkaian + + + Pengecualian berlaku semasa menyambung ke PLC + + + Keluar berjaya + + + Keluar daripada pengguna + + + Log keluar dari sistem + + + Pilih model pengeluaran yang anda ingin hapuskan + + + Kumpulan Komunikasi + + + Nama kumpulan pengedaran tidak wujud! + + + Nama kumpulan pengedaran tidak boleh kosong! + + + Nama kumpulan pengedaran sudah wujud + + + Nombor saluran + + + Aksesori, penggantian bahan + + + Konfigurasi berjaya disimpan + + + Pemuatan fail konfigurasi selesai + + + kekasaran + + + Peringatan ralat + + + Panjang mesti lebih besar daripada 0 + + + Panjang mesti nombor yang lebih besar daripada sifar + + + Nama item + + + Ralat berlaku semasa mengesahkan konfigurasi, sila semak sama ada input adalah betul + + + Ralat pengesahan + + + Kumpulan lalai + + + Mengaktifkan + + + Melumpuhkan + + + Pengeksportan berjaya! + + + Pengeksportan gagal + + + Nombor kad IC + + + Model produk tidak boleh kosong + + + Model produk dan senarai parameter tidak boleh kosong + + + Parameter disimpan + + + Gagal menyimpan + + + Berjaya disimpan + + + Ubah Suai Variabel + + + Gagal mengubahsuai pemboleh ubah + + + Ubah suai pengguna + + + Gagal mengubah suai pengguna + + + Ubah suai Kumpulan Pengedaran + + + Gagal mengubah suai kumpulan pengedaran: + + + Hapuskan Pemboleh Ubah + + + Gagal menghapuskan pemboleh ubah + + + Hapuskan model + + + Gagal dihapuskan: + + + Hapuskan petunjuk + + + Gagal menghapuskan pengguna + + + Hapuskan Kumpulan Pengedaran + + + Gagal menghapuskan kumpulan pengedaran + + + Kod bahan yang sepadan dengan model tidak boleh kosong + + + Peranti semasa sedang berjalan. Untuk pertanyaan, sila tekan butang berhenti terlebih dahulu! + + + Hubungi polis TOP10 + + + Sama ada untuk mematikan mod mes + + + Sama ada untuk mematikan mod mes! + + + Hapus atau tidak + + + Adakah anda mahu menghapuskan model + + + Kedua-dua kata laluan tidak sepadan + + + Kebenaran pengguna log masuk semasa tidak mencukupi + + + tercuit cuit + + + Gagal menyambung ke PLC, sila semak konfigurasi sambungan PLC, rangkaian + + + Parameter berjaya diubah suai + + + Tetapan Parameter + + + Nama pemboleh ubah tidak wujud + + + Eksport laporan berjaya, sama ada untuk membukanya sekarang + + + Pada masa ini dalam mod mes, sila log masuk + + + Sedang log masuk, adakah anda ingin menukar mod leret + + + Sedang log masuk, adakah anda ingin menukar mod leret!! + + + Anda belum log masuk buat masa ini, sila log masuk terlebih dahulu! + + + Anda belum log masuk, sila log masuk + + + Tindakan pertanyaan + + + Tambah pemboleh ubah + + + Gagal menambah pemboleh ubah + + + Tambah model + + + Tambah Kegagalan: Pengubahsuaian sudah wujud, tambah lagi + + + Gagal ditambah + + + Berjaya ditambah + + + Tambah pengguna + + + Gagal menambah pengguna: + + + Hapuskan Pemboleh Ubah + + + Gagal menambah kumpulan pengedaran: + + + Kumpulan komunikasi berjaya ditambah + + + Kod bahan tidak boleh kosong + + + pengguna + + + Nama pengguna tidak boleh kosong + + + Kata laluan pengguna tidak boleh kosong + + + Sahkan kata laluan tidak boleh kosong + + + Input manual dilarang, sila gunakan imbasan jenama untuk masuk + + + Nama pemboleh ubah tidak boleh kosong + + + Nama pemboleh ubah sudah wujud + + + Anda belum log masuk. Sila log masuk sebelum meneruskan + + + Nama pengguna sudah wujud + + + Sila leret kad anda untuk log masuk terlebih dahulu + + + Sila pilih model produk + + + Sila pilih pemboleh ubah untuk diubah suai + + + Sila pilih pemboleh ubah untuk dihapuskan + + + Pilih model pengeluaran yang anda ingin hapuskan + + + Nama kumpulan pengedaran tidak wujud! + + + Nama kumpulan pengedaran tidak boleh kosong! + + + Nama kumpulan pengedaran sudah wujud + + + Model Pengeluaran + + \ No newline at end of file diff --git a/Language/Languages.resx b/Language/Languages.resx new file mode 100644 index 0000000..343e8a6 --- /dev/null +++ b/Language/Languages.resx @@ -0,0 +1,2278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 添加通信组 + + + 操作 + + + 组名 + + + 是否启用 + + + 反馈PLC + + + 触发读取 + + + 长度 + + + PLC编号 + + + 备注 + + + 起始地址 + + + 通信组配置 + + + D40已复位0 + + + 报警信息 + + + 报警类型 + + + 日期时间 + + + 日志信息 + + + 日期时间 + + + 日志类型 + + + 日期时间 + + + 操作信息 + + + 操作类型 + + + 操作日志 + + + 系统报警 + + + 系统日志 + + + Pp + + + Cp + + + Ca + + + PPK + + + CPK + + + Dev + + + Mean + + + SampleSize + + + Groups + + + Max + + + Min + + + Total + + + 平均值 + + + 最大值 + + + 最小值 + + + 规格下限 + + + 规格上限 + + + 数据组数 + + + 样本子组大小 + + + 目标值 + + + 负3倍标准差 + + + 标准差(组内) + + + 标准差(整体) + + + 正3倍标准差 + + + CPL + + + CPU + + + Cp + + + Cpk + + + Ca + + + PPL + + + Ppk + + + PPU + + + Pp + + + CpkGrade + + + 样本总数 + + + PPM < LSL + + + PPM Toatl + + + PPM < USL + + + 清空数据 + + + 计算CPK + + + 分析选项 + + + 查 询 + + + 生成虚拟数据 + + + 常 量 + + + 统 计 值 + + + 工序能力(组内) + + + 其他值 + + + 计 算 值 + + + 实测性能 + + + 工序能力(整体) + + + 查询选项 + + + 查询时间区间 + + + XR控制图 + + + CPK分析图 + + + 样本运行图 + + + 均值运行图 + + + 生产型号 + + + 物料编码 + + + 开始监控 + + + 停止监控 + + + chart1 + + + chart1 + + + 备注 + + + 综合结果 + + + 叠盘层数 + + + 机架号 + + + 测试时间 + + + 箱唛码 + + + 电芯档位 + + + 电芯成功绑定数量 + + + 电芯数量 + + + 电池条码 + + + 生产型号 + + + 通道 + + + 托盘位置号 + + + 电池位置 + + + 电池二级档位 + + + 托盘行号 + + + 备注 + + + 结果 + + + 时间 + + + 料框码 + + + 机架号 + + + 电芯档位 + + + 通道 + + + 料框码 + + + 设备编码 + + + 物料编码 + + + 备注 + + + 结果 + + + 时间 + + + 电芯码 + + + 通道 + + + 备注 + + + 结果 + + + 时间 + + + 日志记录 + + + 参数 + + + 结构件料盘 + + + 电池进站 + + + 电池与箱唛绑定 + + + 参数项 + + + 最小值 + + + 最大值 + + + 单位 + + + 新增通信组 + + + 删除通信组 + + + 修改通信组 + + + 是否需要反馈结果 + + + 是否启用 + + + 是否为触发读取 + + + 通信组名称 + + + 启用 + + + 是否需要反馈结果 + + + 是否为触发读取 + + + 长度 + + + 备注说明 + + + 起始地址 + + + 通信组配置 + + + 通信组名称 + + + 起始地址 + + + 长度 + + + 备注说明 + + + 导 出 Excel + + + 时 间 查 询 + + + 导 出 + + + 查 询 + + + 导 出 + + + 查 询 + + + 导 出 Excel + + + 导 出 + + + 查 询 + + + 查 询 + + + 补 传 + + + 导 出 + + + 查 询 + + + 稼动率均值 + + + PPM均值 + + + 良品率 + + + 产品投入 + + + 产品产出 + + + 测试时间 + + + 日期 + + + 稼动率均值 + + + PPM均值 + + + 良品率 + + + 产品投入 + + + 产品产出 + + + 稼动率均值 + + + 月份 + + + PPM均值 + + + 良品率 + + + 产品投入 + + + 产品产出 + + + 稼动率均值 + + + PPM均值 + + + 良品率 + + + 累计投入 + + + 累计产出 + + + 周别 + + + 报警内容 + + + 报警次数 + + + 报警时间 + + + 类别 + + + PLC地址 + + + 条码 + + + 电池型号 + + + 底托卡板码 + + + 通道编号 + + + 托盘位置号 + + + 备注 + + + 结果 + + + 叠盘层数 + + + 测试时间 + + + 电池等级 + + + 机架号 + + + 电池位置 + + + 箱唛码 + + + 绑定结果 + + + 绑定失败原因 + + + 出站类型 + + + 替换前电池条码 + + + 替换后电池条码 + + + 托盘码 + + + 班次 + + + 电芯码 + + + RFID + + + 统计日期 + + + 统计日期 + + + 统计时间 + + + 统计时间 + + + 结束时间 + + + 开始时间 + + + 条码 + + + 结束时间 + + + 开始时间 + + + 查询类型 + + + 历史生产数据查询 + + + 产能统计查询 + + + 日志报警数据查询 + + + 按班次统计 + + + 按日统计 + + + 按周统计 + + + 按月统计 + + + 亿纬动力 + + + 登录 + + + 亿纬动力 + + + 启动 + + + 60 工厂 + + + 亿纬动力 + + + 组装管理系统 + + + 日志报警 + + + 数据分析 + + + 数据监控 + + + 数据追溯 + + + 电池状况 + + + 集中监控 + + + 参数设置 + + + 系统设置 + + + 用户管理 + + + 关于 + + + 显示主界面 + + + 退出 + + + 隐藏主界面 + + + 非刷卡模式 + + + 智能电表 + + + A相电压 + + + 总有功功率 + + + 总功率因素 + + + 电压变比 + + + 电流变比 + + + 累计电能 + + + B相电压 + + + C相电压 + + + A相电流 + + + B相电流 + + + C相电流 + + + A相功率 + + + B相功率 + + + C相功率 + + + 告警TOP10统计 + + + 产能统计 + + + 不良项统计 + + + OK数 + + + 优率 + + + 生产总数 + + + 稼动率 + + + 设备编号 + + + 工厂代号 + + + 线体编号 + + + 生产型号 + + + 开机时间 + + + 运行时间 + + + 智能电表(设备) + + + 确定 + + + 是否确认要退出系统? + + + 退出系统 + + + 取消 + + + 取消 + + + 确定 + + + 是否确认要退出系统? + + + 退出系统 + + + 删除型号 + + + 添加型号 + + + 保存参数 + + + 参数项名称 + + + 最大值 + + + 最小值 + + + 单位 + + + 物料编码 + + + 生产型号 + + + 备注 + + + 当前型号 + + + 生产型号 + + + 物料编码 + + + 当前型号 + + + 添加PLC + + + 取消设置 + + + 通信组配置 + + + 确定设置 + + + 变量配置 + + + 设置 + + + 操作 + + + 心跳地址 + + + IP地址 + + + 激活状态 + + + 心跳状态 + + + PLC编号 + + + PLC类型 + + + 端口号 + + + 备注 + + + 获取MES参数 + + + 开启刷卡模式 + + + PLC类型配置 + + + 设备编号 + + + 产线编号 + + + 工厂代码 + + + 自动切换监控界面时间 + + + 无操作自动切换监控界面 + + + 物料编号 + + + 端口号配置 + + + 无操作自动锁屏 + + + 自动锁屏时间 + + + 焊机功率曲线显示数量 + + + 软件自动登录 + + + 开机自动启动 + + + 线程耗时日志保存 + + + MES/非MES模式切换 + + + 风速仪 + + + 调试模式 + + + 设备报警 + + + 设备参数设定值变更 + + + 设备参数设定值请求 + + + 设备状态 + + + 员工权限校验 + + + 电表能耗 + + + 原材料投入信息 + + + 产品进站 + + + 产品出站 + + + 产品加工过程数据 + + + 产品加工结果数据 + + + MES配置 + + + PLC配置 + + + 系统设置 + + + 机架号 + + + 127.0.0.1 + + + 9600 + + + 添加用户 + + + 清空信息 + + + 删除用户 + + + 修改用户 + + + 全选/不选 + + + 数据分析 + + + 数据追溯 + + + 参数设置 + + + 日志报警 + + + 系统设置 + + + 用户管理 + + + 数据分析 + + + 数据追溯 + + + 用户权限 + + + 用户名 + + + 用户密码 + + + IC卡号 + + + 参数设置 + + + 日志报警 + + + 系统设置 + + + 用户管理 + + + IC卡号 + + + 确认密码 + + + 用户信息 + + + 用户权限 + + + 用户密码 + + + 用户信息 + + + 权限配置 + + + 用户操作 + + + 起始索引 + + + 变量地址 + + + 变量名称 + + + 变量地址 + + + 变量配置 + + + 通信组名称 + + + 起始索引 + + + 位偏移/长度 + + + 变量名称 + + + 备注说明 + + + 数据类型 + + + 线性系数 + + + 偏移量 + + + MES未登录 + + + MES登录成功,登录用户 + + + PC写入PLC时间失败! + + + PC写入PLC时间成功 + + + 添加变量 + + + 变量配置 + + + 数据类型 + + + 操作 + + + 组名 + + + 长度偏移 + + + PLC编号 + + + 备注 + + + 起始地址 + + + 变量地址 + + + 变量名称 + + + 上限 + + + 下限 + + + 不支持的数据类型 + + + 产出 + + + 产品型号不能为空! + + + 优率 + + + 信息 + + + 修改 + + + 修改MES/非MES模式切换 + + + 修改切换监控界面间隔时间 + + + 修改刷卡模式 + + + 修改无操作自动切换监控界面方式 + + + 修改无操作自动锁屏方式 + + + 修改曲线显示数量 + + + 修改线程耗时日志保存 + + + 修改获取MES参数 + + + 修改调试模式 + + + 修改软件自动启动方式 + + + 修改软件自动登录方式 + + + 修改锁屏间隔时间 + + + 停止与PLC连接 + + + 先停止运行再切换MES + + + 全天 + + + 关闭MES模式成功 + + + 其它非计划停机 + + + 出站 + + + 创建临时文件失败 + + + 删除 + + + 删除当前复投条码 + + + 删除成功 + + + 功率值 + + + 功能待开发中! + + + 加载系统配置失败 + + + 加载系统配置成功 + + + 历史报警 + + + 历史数据 + + + 变量 + + + 变量名不能为空 + + + 变量名已存在 + + + 变量地址格式不正确 + + + 各不良项 + + + 启动开始监控 + + + 启动开始监控失败 + + + 品质异常 + + + 品质检查 + + + 图表初始化异常 + + + 地址格式不正确,应以'D'开头后跟数字 + + + 地址格式不正确,应是纯数字 + + + 地址范围超出限制,结束地址不能超过32767 + + + 型号选择 + + + 夜班 + + + 定时刷新异常 + + + 导出报表失败 + + + 导出报表成功,是否立即打开? + + + 导出报警成功,是否立即打开? + + + 工程变更 + + + 已断开与PLC + + + 开始加载配置参数…… + + + 开始时间不能大于结束时间 + + + 当前为MES模式,请登录! + + + 当前已登录 + + + 当前无报警 + + + 当前未登录,请登录! + + + 当前用户已注销 + + + 当前登录用户权限不足! + + + 待料 + + + 成功 + + + 成功连接PLC + + + 打开报表记录 + + + 打开报警记录 + + + 投入 + + + 告警TOP10 + + + 报警查询 + + + 报警项 + + + 提示 + + + 操作日志 + + + 数值 + + + 数据分析 + + + 数据报表导出 + + + 新变量 + + + 新建变量成功 + + + 无PLC配置信息 + + + 无效的组名 + + + 无效的起始地址 + + + 时间 + + + 星期一 + + + 星期三 + + + 星期二 + + + 星期五 + + + 星期六 + + + 星期四 + + + 星期日 + + + 是否保存修改的配置? + + + 是否切换刷卡模式 + + + 是否确定要退出系统 + + + 更新12小时数据异常 + + + 更新不良图表异常 + + + 更新报警图表异常 + + + 更新效率控件异常 + + + 更新时间显示异常 + + + 更新能源显示异常 + + + 未登录 + + + 未能查到数据,请检测 + + + 权限 + + + 权限不足 + + + 来料不良 + + + 查询失败: + + + 查询时间不能超过7天 + + + 查询范围不能超过1天 + + + 次数 + + + 没有可用的地址空间 + + + 没有可用的组名,请先在Group.xlsx中添加组 + + + 没有找到足够大的地址空间 + + + 电芯码不良 + + + 登录成功,登录用户 + + + 登录提示 + + + 登录用户或密码错误!!! + + + 登录系统 + + + 白班 + + + 确认保存 + + + 系统日志 + + + 组名不能为空 + + + 良品 + + + 获取参数失败 + + + 请先刷卡登录! + + + 请填写登录密码 + + + 请填写登录用户名 + + + 起始地址格式不正确 + + + 进站 + + + 进站失败 + + + 出站失败 + + + 连接PLC + + + 连接PLC中 + + + 连接PLC失败,请检查PLC连接配置,网络 + + + 退出系统 + + + 通信组 + + + 配置保存成功 + + + 错误 + + + 长度必须大于0 + + + 长度必须是大于0的数字 + + + 验证错误 + + + 默认组 + + + 物料编码 + + + RFID托杯码 + + + 风速 + + + 风设备编号 + + + 信息 + + + 标志 + + + 告警查询 + + + 用户查询失败 + + + 错误提示 + + + 查询失败: + + + PC写入PLC时间异常 + + + 窗体加载异常 + + + 更新12小时数据异常 + + + 更新效率控件异常 + + + 更新时间显示异常 + + + 更新能源显示异常 + + + 更新报警图表异常 + + + 更新不良图表异常 + + + 退出成功 + + + 退出用户 + + + 停止与PLC连接 + + + 修改软件自动登录方式 + + + 修改软件自动启动方式 + + + 修改无操作自动锁屏方式 + + + 修改锁屏间隔时间 + + + 修改无操作自动切换监控界面方式 + + + 修改调试模式 + + + 修改切换监控界面间隔时间 + + + 修改曲线显示数量 + + + 修改刷卡模式 + + + 是否切换刷卡模式 + + + 切换刷卡模式成功 + + + 当前用户已注销 + + + 提示 + + + 先停止运行再切换MES + + + 修改MES/非MES模式切换 + + + 关闭MES模式成功 + + + MES用户已注销 + + + 修改获取MES参数 + + + 修改线程耗时日志保存 + + + 配置文件加载完成 + + + 无PLC配置信息 + + + 请检查配置文件 + + + 连接PLC失败 + + + 成功连接PLC + + + 连接PLC时发生异常 + + + 触发了手动HMI弹窗功能 + + + 设备故障 + + + 设备转型 + + + MES停机 + + + 配件,物料更换 + + + 来料不良 + + + 待料 + + + 清洁点检 + + + 物料编码不能为空! + + + 环境不满足 + + + 其它非计划停机 + + + HMI手动弹窗状态已上传成功,代码 + + + HMI手动弹窗结束状态已上传成功,代码 + + + 进站A工位发送给PLC + + + 进站B工位发送给PLC + + + 进站C工位发送给PLC + + + 卷芯进站共耗时 + + + 出站A工位发送给PLC + + + 出站B工位发送给PLC + + + 出站C工位发送给PLC + + + 用户查询失败 + + + 电芯出站A共耗时 + + + 电芯出站B共耗时 + + + 电芯出站C共耗时 + + + 电芯码不良 + + + 登录系统 + + + 白班 + + + 确认保存 + + + 窗体加载异常 + + + 系统日志 + + + 组名不能为空 + + + 结果数据上传失败 + + + MES参数设置成功 + + + 良品 + + + 触发了手动HMI弹窗功能 + + + 设备故障 + + + 设备转型 + + + 请先刷卡登录! + + + 请检查配置文件 + + + 起始地址格式不正确 + + + 进站 + + + 进站A工位发送给PLC + + + 进站B工位发送给PLC + + + 进站C工位发送给PLC + + + 进站上料工位A有料标志为0 + + + 进站上料工位B有料标志为0 + + + 出站下料工位A有料标志为0 + + + 出站下料工位B有料标志为0 + + + 通道号 + + + PLC配置 + + + 扫码不良 + + + MES不良 + + + 其他不良 + + + 项名 + + + 出站判定 + + + 工序 + + + 班次 + + + 进站时间 + + + 出站时间 + + + 出站上传 + + + 结果 + + + 提示 + + + 风速仪个数 + + + 除尘风速 + + + 标记 + + + 物料编码不能为空! + + + 验证配置时发生错误,请检查输入是否正确 + + + PLC配置 + + + MES配置 + + + MES参数配置 + + + + 连接PLC + + + 连接PLC中 + + + 连接PLC失败 + + + 连接PLC失败,请检查PLC连接配置,网络 + + + 连接PLC时发生异常 + + + 退出成功 + + + 退出用户 + + + 退出系统 + + + 通信组 + + + 通道号 + + + 配件,物料更换 + + + 配置保存成功 + + + 配置文件加载完成 + + + 错误 + + + 错误提示 + + + 长度必须大于0 + + + 长度必须是大于0的数字 + + + 验证配置时发生错误,请检查输入是否正确 + + + 验证错误 + + + 默认组 + + + 启用 + + + 禁用 + + + 导出成功! + + + 导出失败 + + + IC卡号 + + + 产品型号不能为空 + + + 产品型号和参数列表不能为空! + + + 保存参数 + + + 保存失败! + + + 保存成功! + + + 修改变量 + + + 修改变量失败: + + + 修改用户 + + + 修改用户失败 + + + 修改通信组 + + + 修改通信组失败: + + + 删除变量 + + + 删除变量失败: + + + 删除型号 + + + 删除失败: + + + 删除提示 + + + 删除用户失败 + + + 删除通信组 + + + 删除通信组失败: + + + 型号对应的物料编码不能为空! + + + 当前设备正在运行中,如需查询,请先按停止按钮! + + + 报警TOP10 + + + 是否关闭MES模式 + + + 是否关闭MES模式! + + + 是否删除 + + + 是否要删除型号 + + + 两次输入密码不一致 + + + 当前登录用户权限不足 + + \ No newline at end of file diff --git a/Language/LocalLanguage.cs b/Language/LocalLanguage.cs new file mode 100644 index 0000000..8e95d1a --- /dev/null +++ b/Language/LocalLanguage.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Language +{ + public class LocalLanguage + { + private static Dictionary> _languageData; + + static LocalLanguage() + { + InitializeLanguageData(); + } + + private static void InitializeLanguageData() + { + _languageData = new Dictionary> + { + // 中文语言包 + ["zh"] = new Dictionary + { + ["MessageTips1"] = "软件已经启动,请在后台确认。", + ["MessageTips2"] = "正在初始化日志系统...", + ["MessageTips3"] = "正在设置异常处理...", + ["MessageTips4"] = "正在读取配置...", + ["MessageTips5"] = "初始化完成", + ["MessageTips6"] = "致命错误", + ["MessageTips7"] = "程序出现大异常,请联系 【金源自动化软件设计部】。\r\n异常信息: {0}\r\n异常堆栈:{1}", + ["MessageTips8"] = "加载语言设置时出错: {0}", + ["MessageTips9"] = "语言加载错误", + + + + // ... 可以继续添加更多中文键值对 + }, + + // 英文语言包 + ["en"] = new Dictionary + { + ["MessageTips1"] = "The software has been started, please confirm in the background.", + ["MessageTips2"] = "Initializing the logging system", + ["MessageTips3"] = "Setting up exception handling", + ["MessageTips4"] = "Reading configuration", + ["MessageTips5"] = "Initialization completed", + ["MessageTips6"] = "fatal error", + ["MessageTips7"] = "The program has encountered a major exception. Please contact the Jinyuan Automation Software Design Department.\r\nAbnormal information: {0}\r\nException Stack:{1}", + ["MessageTips8"] = "Error loading language settings: {0}", + ["MessageTips9"] = "Language loading error", + // ... 可以继续添加更多英文键值对 + }, + + // 日文语言包 + ["ja"] = new Dictionary + { + ["MessageTips1"] = "ソフトウェアが起動しました。バックグラウンドで確認してください。", + ["MessageTips2"] = "ログシステムを初期化しています...", + ["MessageTips3"] = "例外処理を設定しています...", + ["MessageTips4"] = "構成を読み込み中...", + ["MessageTips5"] = "初期化完了", + ["MessageTips6"] = "致命的なエラー", + ["MessageTips7"] = "プログラムに大きな異常が発生した場合は、【金源自動化ソフトウェア設計部】に連絡してください。日本語の\r\n例外情報: {0}\r\n例外スタック:{1}", + ["MessageTips8"] = "言語設定のロードエラー: {0}", + ["MessageTips9"] = "言語ロードエラー", + + // ... 可以继续添加更多日文键值对 + }, + + // 马来语言包 + ["ms"] = new Dictionary + { + ["MessageTips1"] = "Perisian telah dimulakan, sila sahkan di latar belakang.", + ["MessageTips2"] = "Memulakan sistem log", + ["MessageTips3"] = "Menetapkan pengendalian pengecualian", + ["MessageTips4"] = "Membaca konfigurasi", + ["MessageTips5"] = "Pemulaan selesai", + ["MessageTips6"] = "Ralat Fatal", + ["MessageTips7"] = "Program telah menghadapi pengecualian utama. Sila hubungi Jabatan Ralat Perisian Automatisasi Jinyuan.\r\nMaklumat tidak normal: {0}\r\nStack Kecualian:{1}", + ["MessageTips8"] = "Ralat memuatkan tetapan bahasa: {0}", + ["MessageTips9"] = "Ralat memuatkan bahasa", + + + }, + + // 匈牙利语言包 + ["hu"] = new Dictionary + { + ["MessageTips1"] = "A szoftver elindult, kérjük, erősítse meg a háttérben.", + ["MessageTips2"] = "A naplózási rendszer indítása", + ["MessageTips3"] = "Kivételek kezelésének beállítása", + ["MessageTips4"] = "Olvasási beállítások", + ["MessageTips5"] = "Inicializálás befejezve", + ["MessageTips6"] = "Halálos hiba", + ["MessageTips7"] = "A program jelentős kivétellel szembesült. Kérjük, lépjen kapcsolatba a Jinyuan Automation Software Design Osztállyal. \r\nKóros információk: {0}\r\nKivételek stack:{1}", + ["MessageTips8"] = "Hiba történt a nyelvbeállítások betöltésével: {0}", + ["MessageTips9"] = "Nyelvbetöltési hiba", + + + }, + + // 越南语言包 + ["vi"] = new Dictionary + { + ["MessageTips1"] = "Phần mềm đã được khởi chạy, hãy xác nhận trong nền.", + ["MessageTips2"] = "Đang khởi chạy hệ thống nhật ký...", + ["MessageTips3"] = "Thiết lập xử lý ngoại lệ...", + ["MessageTips4"] = "Đang đọc cấu hình...", + ["MessageTips5"] = "Khởi tạo xong", + ["MessageTips6"] = "Lỗi nghiêm trọng", + ["MessageTips7"] = "Chương trình xuất hiện đại dị thường, xin liên hệ 【 Kim Nguyên tự động hóa phần mềm thiết kế bộ 】.\r\nThông tin ngoại lệ: {0}\r\nNgăn xếp ngoại lệ:{1}", + ["MessageTips8"] = "Gặp lỗi khi tải cài đặt ngôn ngữ: {0}", + ["MessageTips9"] = "Lỗi tải ngôn ngữ", + + + } + // 可以继续添加更多语言... + }; + } + + /// + /// 获取当前语言的文本 + /// + /// 文本键值 + /// 对应语言的文本,如果未找到则返回键值本身 + public static string GetText(string key, string _currentLanguage) + { + if (_languageData.ContainsKey(_currentLanguage) && + _languageData[_currentLanguage].ContainsKey(key)) + { + return _languageData[_currentLanguage][key]; + } + return key; // 如果找不到对应的文本,返回键值本身 + } + + /// + /// 获取带变量的文本 + /// + /// 文本键值 + /// 要替换的变量值 + /// 替换变量后的文本 + public static string GetText(string key, string _currentLanguage, params object[] args) + { + try + { + if (_languageData.ContainsKey(_currentLanguage) && + _languageData[_currentLanguage].ContainsKey(key)) + { + string format = _languageData[_currentLanguage][key]; + if (args != null && args.Length > 0) + { + return string.Format(format, args); + } + return format; + } + return key; + } + catch (FormatException ex) + { + // 记录错误:格式字符串与参数不匹配 + Debug.WriteLine($"Language format error - Key: {key}, Error: {ex.Message}"); + return key; + } + } + } +} diff --git a/Language/MsgResources.Designer.cs b/Language/MsgResources.Designer.cs new file mode 100644 index 0000000..dcd6ea6 --- /dev/null +++ b/Language/MsgResources.Designer.cs @@ -0,0 +1,675 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace UpperComputerSystem.Language { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class MsgResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal MsgResources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UpperComputerSystem.Language.MsgResources", typeof(MsgResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 条码 的本地化字符串。 + /// + internal static string Barcode { + get { + return ResourceManager.GetString("Barcode", resourceCulture); + } + } + + /// + /// 查找类似 通道 {0} 的本地化字符串。 + /// + internal static string Channel { + get { + return ResourceManager.GetString("Channel", resourceCulture); + } + } + + /// + /// 查找类似 开始联机 的本地化字符串。 + /// + internal static string FrmMain_btnToggle_Text { + get { + return ResourceManager.GetString("FrmMain_btnToggle_Text", resourceCulture); + } + } + + /// + /// 查找类似 主页 的本地化字符串。 + /// + internal static string FrmMain_SidebarItem_Home_Text { + get { + return ResourceManager.GetString("FrmMain_SidebarItem_Home_Text", resourceCulture); + } + } + + /// + /// 查找类似 配方 的本地化字符串。 + /// + internal static string FrmMain_SidebarItem_Recipe_Text { + get { + return ResourceManager.GetString("FrmMain_SidebarItem_Recipe_Text", resourceCulture); + } + } + + /// + /// 查找类似 查询 的本地化字符串。 + /// + internal static string FrmMain_SidebarItem_Search_Text { + get { + return ResourceManager.GetString("FrmMain_SidebarItem_Search_Text", resourceCulture); + } + } + + /// + /// 查找类似 设置 的本地化字符串。 + /// + internal static string FrmMain_SidebarItem_Settings_Text { + get { + return ResourceManager.GetString("FrmMain_SidebarItem_Settings_Text", resourceCulture); + } + } + + /// + /// 查找类似 统计 的本地化字符串。 + /// + internal static string FrmMain_SidebarItem_Statistics_Text { + get { + return ResourceManager.GetString("FrmMain_SidebarItem_Statistics_Text", resourceCulture); + } + } + + /// + /// 查找类似 用户 的本地化字符串。 + /// + internal static string FrmMain_SidebarItem_User_Text { + get { + return ResourceManager.GetString("FrmMain_SidebarItem_User_Text", resourceCulture); + } + } + + /// + /// 查找类似 亿纬锂能 | 锂电池翻包设备 的本地化字符串。 + /// + internal static string FrmMain_windowBar_Text { + get { + return ResourceManager.GetString("FrmMain_windowBar_Text", resourceCulture); + } + } + + /// + /// 查找类似 停止流程 的本地化字符串。 + /// + internal static string HomeControl_bt_EndProcess_Text { + get { + return ResourceManager.GetString("HomeControl_bt_EndProcess_Text", resourceCulture); + } + } + + /// + /// 查找类似 日志记录 的本地化字符串。 + /// + internal static string HomeControl_gbLog_Text { + get { + return ResourceManager.GetString("HomeControl_gbLog_Text", resourceCulture); + } + } + + /// + /// 查找类似 工艺参数 的本地化字符串。 + /// + internal static string HomeControl_gpGongYiParam_Text { + get { + return ResourceManager.GetString("HomeControl_gpGongYiParam_Text", resourceCulture); + } + } + + /// + /// 查找类似 数据列表 的本地化字符串。 + /// + internal static string HomeControl_gpHistoryData_Text { + get { + return ResourceManager.GetString("HomeControl_gpHistoryData_Text", resourceCulture); + } + } + + /// + /// 查找类似 绝缘测试实时数据 的本地化字符串。 + /// + internal static string HomeControl_gpInsulationData_Text { + get { + return ResourceManager.GetString("HomeControl_gpInsulationData_Text", resourceCulture); + } + } + + /// + /// 查找类似 上料实时条码 的本地化字符串。 + /// + internal static string HomeControl_gpIntBarcode_Text { + get { + return ResourceManager.GetString("HomeControl_gpIntBarcode_Text", resourceCulture); + } + } + + /// + /// 查找类似 OCV实时检测数据 的本地化字符串。 + /// + internal static string HomeControl_gpOcvData_Text { + get { + return ResourceManager.GetString("HomeControl_gpOcvData_Text", resourceCulture); + } + } + + /// + /// 查找类似 下料实时条码 的本地化字符串。 + /// + internal static string HomeControl_gpOutBarcode_Text { + get { + return ResourceManager.GetString("HomeControl_gpOutBarcode_Text", resourceCulture); + } + } + + /// + /// 查找类似 不满足8个电芯使用 的本地化字符串。 + /// + internal static string HomeControl_lblInTip_Text { + get { + return ResourceManager.GetString("HomeControl_lblInTip_Text", resourceCulture); + } + } + + /// + /// 查找类似 目检1结果 的本地化字符串。 + /// + internal static string HomeControl_lblMuJian1_Text { + get { + return ResourceManager.GetString("HomeControl_lblMuJian1_Text", resourceCulture); + } + } + + /// + /// 查找类似 目检2结果 的本地化字符串。 + /// + internal static string HomeControl_lblMuJian2_Text { + get { + return ResourceManager.GetString("HomeControl_lblMuJian2_Text", resourceCulture); + } + } + + /// + /// 查找类似 下料绝缘测试结果 的本地化字符串。 + /// + internal static string HomeControl_lbOutJueyuanRes_Text { + get { + return ResourceManager.GetString("HomeControl_lbOutJueyuanRes_Text", resourceCulture); + } + } + + /// + /// 查找类似 最大值 的本地化字符串。 + /// + internal static string HomeControl_tableConfigRange_ParaValueMax_Title { + get { + return ResourceManager.GetString("HomeControl_tableConfigRange_ParaValueMax_Title", resourceCulture); + } + } + + /// + /// 查找类似 最大值 的本地化字符串。 + /// + internal static string HomeControl_tableConfigRange_ParaValueMin_Title { + get { + return ResourceManager.GetString("HomeControl_tableConfigRange_ParaValueMin_Title", resourceCulture); + } + } + + /// + /// 查找类似 参数项 的本地化字符串。 + /// + internal static string HomeControl_tableConfigRange_Remark_Title { + get { + return ResourceManager.GetString("HomeControl_tableConfigRange_Remark_Title", resourceCulture); + } + } + + /// + /// 查找类似 单位 的本地化字符串。 + /// + internal static string HomeControl_tableConfigRange_Uint_Title { + get { + return ResourceManager.GetString("HomeControl_tableConfigRange_Uint_Title", resourceCulture); + } + } + + /// + /// 查找类似 进站条码1 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode1_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode1_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码2 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode2_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode2_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码3 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode3_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode3_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码4 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode4_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode4_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码5 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode5_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode5_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码6 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode6_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode6_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码7 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode7_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode7_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 进站条码8 的本地化字符串。 + /// + internal static string HomeControl_txtInBarcode8_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtInBarcode8_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码1 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode1_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode1_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码2 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode2_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode2_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码3 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode3_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode3_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码4 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode4_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode4_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码5 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode5_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode5_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码6 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode6_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode6_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码7 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode7_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode7_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 出站条码8 的本地化字符串。 + /// + internal static string HomeControl_txtOutBarcode8_Placeholder { + get { + return ResourceManager.GetString("HomeControl_txtOutBarcode8_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 登录 的本地化字符串。 + /// + internal static string LoginForm_BtnLogin_Text { + get { + return ResourceManager.GetString("LoginForm_BtnLogin_Text", resourceCulture); + } + } + + /// + /// 查找类似 电芯测试系统 的本地化字符串。 + /// + internal static string LoginForm_lbWelcome_Text { + get { + return ResourceManager.GetString("LoginForm_lbWelcome_Text", resourceCulture); + } + } + + /// + /// 查找类似 请输入密码 的本地化字符串。 + /// + internal static string LoginForm_txtPassword_Placeholder { + get { + return ResourceManager.GetString("LoginForm_txtPassword_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 请输入用户名 的本地化字符串。 + /// + internal static string LoginForm_txtUsername_Placeholder { + get { + return ResourceManager.GetString("LoginForm_txtUsername_Placeholder", resourceCulture); + } + } + + /// + /// 查找类似 登录系统 的本地化字符串。 + /// + internal static string LoginForm_windowBar1_Text { + get { + return ResourceManager.GetString("LoginForm_windowBar1_Text", resourceCulture); + } + } + + /// + /// 查找类似 内阻 的本地化字符串。 + /// + internal static string Resistance { + get { + return ResourceManager.GetString("Resistance", resourceCulture); + } + } + + /// + /// 查找类似 电压 的本地化字符串。 + /// + internal static string Voltage { + get { + return ResourceManager.GetString("Voltage", resourceCulture); + } + } + + /// + /// 查找类似 主页 的本地化字符串。 + /// + internal static string 主页 { + get { + return ResourceManager.GetString("主页", resourceCulture); + } + } + + /// + /// 查找类似 内阻 的本地化字符串。 + /// + internal static string 内阻 { + get { + return ResourceManager.GetString("内阻", resourceCulture); + } + } + + /// + /// 查找类似 出站条码 的本地化字符串。 + /// + internal static string 出站条码 { + get { + return ResourceManager.GetString("出站条码", resourceCulture); + } + } + + /// + /// 查找类似 单位 的本地化字符串。 + /// + internal static string 单位 { + get { + return ResourceManager.GetString("单位", resourceCulture); + } + } + + /// + /// 查找类似 参数项 的本地化字符串。 + /// + internal static string 参数项 { + get { + return ResourceManager.GetString("参数项", resourceCulture); + } + } + + /// + /// 查找类似 已注销登录 的本地化字符串。 + /// + internal static string 已注销登录 { + get { + return ResourceManager.GetString("已注销登录", resourceCulture); + } + } + + /// + /// 查找类似 最大值 的本地化字符串。 + /// + internal static string 最大值 { + get { + return ResourceManager.GetString("最大值", resourceCulture); + } + } + + /// + /// 查找类似 最小值 的本地化字符串。 + /// + internal static string 最小值 { + get { + return ResourceManager.GetString("最小值", resourceCulture); + } + } + + /// + /// 查找类似 查询 的本地化字符串。 + /// + internal static string 查询 { + get { + return ResourceManager.GetString("查询", resourceCulture); + } + } + + /// + /// 查找类似 用户 的本地化字符串。 + /// + internal static string 用户 { + get { + return ResourceManager.GetString("用户", resourceCulture); + } + } + + /// + /// 查找类似 电压 的本地化字符串。 + /// + internal static string 电压 { + get { + return ResourceManager.GetString("电压", resourceCulture); + } + } + + /// + /// 查找类似 目检结果 的本地化字符串。 + /// + internal static string 目检结果 { + get { + return ResourceManager.GetString("目检结果", resourceCulture); + } + } + + /// + /// 查找类似 绝缘电阻 的本地化字符串。 + /// + internal static string 绝缘电阻 { + get { + return ResourceManager.GetString("绝缘电阻", resourceCulture); + } + } + + /// + /// 查找类似 统计 的本地化字符串。 + /// + internal static string 统计 { + get { + return ResourceManager.GetString("统计", resourceCulture); + } + } + + /// + /// 查找类似 综合结果 的本地化字符串。 + /// + internal static string 综合结果 { + get { + return ResourceManager.GetString("综合结果", resourceCulture); + } + } + + /// + /// 查找类似 设置 的本地化字符串。 + /// + internal static string 设置 { + get { + return ResourceManager.GetString("设置", resourceCulture); + } + } + + /// + /// 查找类似 进站条码 的本地化字符串。 + /// + internal static string 进站条码 { + get { + return ResourceManager.GetString("进站条码", resourceCulture); + } + } + + /// + /// 查找类似 通道 的本地化字符串。 + /// + internal static string 通道 { + get { + return ResourceManager.GetString("通道", resourceCulture); + } + } + + /// + /// 查找类似 配方 的本地化字符串。 + /// + internal static string 配方 { + get { + return ResourceManager.GetString("配方", resourceCulture); + } + } + } +} diff --git a/Language/Properties/AssemblyInfo.cs b/Language/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..922ede0 --- /dev/null +++ b/Language/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Language")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Language")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("292a5c9c-7a82-4d25-a885-ddcedc93f03c")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Language/Resources/DataGridColumnAttribute.cs b/Language/Resources/DataGridColumnAttribute.cs new file mode 100644 index 0000000..dd9ce09 --- /dev/null +++ b/Language/Resources/DataGridColumnAttribute.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JinYuan.Models.HelperAttribute +{ + /// + /// 数据表格列映射特性(支持字段/属性) + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] + public sealed class DataGridColumnAttribute : Attribute + { + /// + /// 目标列名(默认使用成员名) + /// + public string ColumnName { get; set; } + + /// + /// 列数据类型(默认使用成员类型) + /// + public Type ColumnType { get; set; } + + public DataGridColumnAttribute() { } + public DataGridColumnAttribute(string columnName) => ColumnName = columnName; + } +} diff --git a/Language/app.config b/Language/app.config new file mode 100644 index 0000000..957095e --- /dev/null +++ b/Language/app.config @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Language/packages.config b/Language/packages.config new file mode 100644 index 0000000..f0422d8 --- /dev/null +++ b/Language/packages.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LargeSquareOne/App.config b/LargeSquareOne/App.config new file mode 100644 index 0000000..c7377ba --- /dev/null +++ b/LargeSquareOne/App.config @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LargeSquareOne/Assts/Fonts/75049.png b/LargeSquareOne/Assts/Fonts/75049.png new file mode 100644 index 0000000..c076caa Binary files /dev/null and b/LargeSquareOne/Assts/Fonts/75049.png differ diff --git a/LargeSquareOne/Assts/Fonts/FZY4JW.ttf b/LargeSquareOne/Assts/Fonts/FZY4JW.ttf new file mode 100644 index 0000000..eb485a8 Binary files /dev/null and b/LargeSquareOne/Assts/Fonts/FZY4JW.ttf differ diff --git a/LargeSquareOne/Assts/Fonts/Zen圓体-Regular.ttf b/LargeSquareOne/Assts/Fonts/Zen圓体-Regular.ttf new file mode 100644 index 0000000..27860e7 Binary files /dev/null and b/LargeSquareOne/Assts/Fonts/Zen圓体-Regular.ttf differ diff --git a/LargeSquareOne/Assts/Fonts/taolichunfeng.ttf b/LargeSquareOne/Assts/Fonts/taolichunfeng.ttf new file mode 100644 index 0000000..73e6014 Binary files /dev/null and b/LargeSquareOne/Assts/Fonts/taolichunfeng.ttf differ diff --git a/LargeSquareOne/Assts/Fonts/zaozigongfangjinzhuti.ttf b/LargeSquareOne/Assts/Fonts/zaozigongfangjinzhuti.ttf new file mode 100644 index 0000000..4c5fbc1 Binary files /dev/null and b/LargeSquareOne/Assts/Fonts/zaozigongfangjinzhuti.ttf differ diff --git a/LargeSquareOne/Assts/Image/BackGround.png b/LargeSquareOne/Assts/Image/BackGround.png new file mode 100644 index 0000000..04d2375 Binary files /dev/null and b/LargeSquareOne/Assts/Image/BackGround.png differ diff --git a/LargeSquareOne/Assts/Image/Main.jpg b/LargeSquareOne/Assts/Image/Main.jpg new file mode 100644 index 0000000..bc2f65e Binary files /dev/null and b/LargeSquareOne/Assts/Image/Main.jpg differ diff --git a/LargeSquareOne/Assts/Image/电池.ico b/LargeSquareOne/Assts/Image/电池.ico new file mode 100644 index 0000000..2750edc Binary files /dev/null and b/LargeSquareOne/Assts/Image/电池.ico differ diff --git a/LargeSquareOne/CommunicationEditForm.Designer.cs b/LargeSquareOne/CommunicationEditForm.Designer.cs new file mode 100644 index 0000000..8a00d3f --- /dev/null +++ b/LargeSquareOne/CommunicationEditForm.Designer.cs @@ -0,0 +1,195 @@ +namespace LargeSquareOne +{ + partial class CommunicationEditForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + this.panelExt1 = new JinYuan.ControlLib.PanelExt(); + this.groupTable = new System.Windows.Forms.DataGridView(); + this.topPanel = new System.Windows.Forms.Panel(); + this.BtnAdd = new System.Windows.Forms.Button(); + this.btn_Close = new System.Windows.Forms.Button(); + this.lblTitle = new System.Windows.Forms.Label(); + this.panelExt1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.groupTable)).BeginInit(); + this.topPanel.SuspendLayout(); + this.SuspendLayout(); + // + // panelExt1 + // + this.panelExt1.BackColor = System.Drawing.Color.Transparent; + this.panelExt1.BordeColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(79)))), ((int)(((byte)(150))))); + this.panelExt1.BordeWidth = 2; + this.panelExt1.BottomGap = 0; + this.panelExt1.Controls.Add(this.groupTable); + this.panelExt1.Controls.Add(this.topPanel); + this.panelExt1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelExt1.LeftGap = 0; + this.panelExt1.Location = new System.Drawing.Point(0, 0); + this.panelExt1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.panelExt1.Name = "panelExt1"; + this.panelExt1.RightGap = 0; + //this.panelExt1.Size = new System.Drawing.Size(600, 480); + this.panelExt1.TabIndex = 0; + this.panelExt1.TopGap = 0; + // + // groupTable + // + this.groupTable.AllowUserToAddRows = false; + this.groupTable.AllowUserToDeleteRows = false; + this.groupTable.AllowUserToResizeRows = false; + this.groupTable.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.groupTable.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.groupTable.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + dataGridViewCellStyle1.Font = new System.Drawing.Font("微软雅黑", 12F); + dataGridViewCellStyle1.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.groupTable.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1; + this.groupTable.ColumnHeadersHeight = 45; + this.groupTable.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle2.Font = new System.Drawing.Font("微软雅黑", 12F); + dataGridViewCellStyle2.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle2.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.groupTable.DefaultCellStyle = dataGridViewCellStyle2; + this.groupTable.EnableHeadersVisualStyles = false; + this.groupTable.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.groupTable.Location = new System.Drawing.Point(19, 55); + this.groupTable.Name = "groupTable"; + this.groupTable.ReadOnly = true; + this.groupTable.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle3.Font = new System.Drawing.Font("微软雅黑", 12F); + dataGridViewCellStyle3.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle3.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle3.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.groupTable.RowHeadersDefaultCellStyle = dataGridViewCellStyle3; + this.groupTable.RowHeadersVisible = false; + this.groupTable.RowHeadersWidth = 55; + this.groupTable.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; + this.groupTable.RowTemplate.Height = 40; + this.groupTable.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.groupTable.Size = new System.Drawing.Size(800, 580); + this.groupTable.TabIndex = 15; + // + // topPanel + // + this.topPanel.Controls.Add(this.BtnAdd); + this.topPanel.Controls.Add(this.btn_Close); + this.topPanel.Controls.Add(this.lblTitle); + this.topPanel.Dock = System.Windows.Forms.DockStyle.Top; + this.topPanel.Location = new System.Drawing.Point(0, 0); + this.topPanel.Name = "topPanel"; + this.topPanel.Size = new System.Drawing.Size(1237, 49); + this.topPanel.TabIndex = 0; + this.topPanel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Panel_MouseDown); + this.topPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Panel_MouseMove); + // + // BtnAdd + // + this.BtnAdd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(27)))), ((int)(((byte)(78))))); + this.BtnAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.BtnAdd.Font = new System.Drawing.Font("微软雅黑", 11.5F); + this.BtnAdd.ForeColor = System.Drawing.Color.White; + this.BtnAdd.Location = new System.Drawing.Point(996, 7); + this.BtnAdd.Name = "BtnAdd"; + this.BtnAdd.Size = new System.Drawing.Size(105, 36); + this.BtnAdd.TabIndex = 49; + this.BtnAdd.Text = "添加通信组"; + this.BtnAdd.UseVisualStyleBackColor = false; + this.BtnAdd.Click += new System.EventHandler(this.BtnAdd_Click); + // + // btn_Close + // + this.btn_Close.FlatAppearance.BorderSize = 0; + this.btn_Close.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(29)))), ((int)(((byte)(84))))); + this.btn_Close.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent; + this.btn_Close.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Close.Font = new System.Drawing.Font("微软雅黑", 15.5F); + this.btn_Close.ForeColor = System.Drawing.Color.White; + this.btn_Close.Location = new System.Drawing.Point(1189, 7); + this.btn_Close.Name = "btn_Close"; + this.btn_Close.Size = new System.Drawing.Size(32, 32); + this.btn_Close.TabIndex = 1; + this.btn_Close.Text = "X"; + this.btn_Close.UseVisualStyleBackColor = true; + this.btn_Close.Click += new System.EventHandler(this.btn_Close_Click); + // + // lblTitle + // + this.lblTitle.AutoSize = true; + this.lblTitle.ForeColor = System.Drawing.Color.White; + this.lblTitle.Location = new System.Drawing.Point(15, 18); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(112, 27); + this.lblTitle.TabIndex = 0; + this.lblTitle.Text = "通信组配置"; + // + // CommunicationEditForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.ClientSize = new System.Drawing.Size(1237, 636); + this.Controls.Add(this.panelExt1); + this.Font = new System.Drawing.Font("微软雅黑", 12F); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.Name = "CommunicationEditForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "FrmGroupConfig"; + this.panelExt1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.groupTable)).EndInit(); + this.topPanel.ResumeLayout(false); + this.topPanel.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private JinYuan.ControlLib.PanelExt panelExt1; + private System.Windows.Forms.Panel topPanel; + private System.Windows.Forms.Button btn_Close; + private System.Windows.Forms.Label lblTitle; + private System.Windows.Forms.DataGridView groupTable; + private System.Windows.Forms.Button BtnAdd; + } +} \ No newline at end of file diff --git a/LargeSquareOne/CommunicationEditForm.cs b/LargeSquareOne/CommunicationEditForm.cs new file mode 100644 index 0000000..71e4503 --- /dev/null +++ b/LargeSquareOne/CommunicationEditForm.cs @@ -0,0 +1,717 @@ +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using Language; +using MiniExcelLibs; +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +namespace LargeSquareOne +{ + public partial class CommunicationEditForm : MultiLanguageForm + { + + private string groupPath = CommonMethods.groupConfigPath; //Application.StartupPath + $"\\Config\\Group_{CommonMethods.sysConfig.StationNo}.xlsx"; + private List TotalGroups = new List(); + private PlcGroupConfig editingConfig; + private int PlcNum; + + public CommunicationEditForm(int plcNum) + { + PlcNum = plcNum; + InitializeComponent(); + this.groupTable.AutoGenerateColumns = false; + + InitializeDataGridView(); + + TotalGroups = GetALLGroups(); + LoadGroups(); + + } + + + /// + /// 初始化DataGridView + /// + private void InitializeDataGridView() + { + groupTable.AutoGenerateColumns = false; + groupTable.AllowUserToAddRows = false; + groupTable.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + groupTable.MultiSelect = false; + groupTable.ReadOnly = false; + + // 添加列 + groupTable.Columns.AddRange(new DataGridViewColumn[] + { + new DataGridViewTextBoxColumn + { + Name = "PlcNum", + HeaderText = "PLC编号", + Width = 120, + ReadOnly = true, + DataPropertyName = "PlcNum", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewTextBoxColumn + { + Name = "GroupName", + HeaderText = "组名", + Width = 120, + DataPropertyName = "GroupName", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewTextBoxColumn + { + Name = "Start", + HeaderText = "起始地址", + Width = 150, + DataPropertyName = "Start", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewTextBoxColumn + { + Name = "Length", + HeaderText = "长度", + Width = 120, + DataPropertyName = "Length", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewCheckBoxColumn + { + Name = "IsTiggerRead", + HeaderText = "触发读取", + Width = 150, + DataPropertyName = "IsTiggerRead", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewCheckBoxColumn + { + Name = "IsFeedbackPlc", + HeaderText = "反馈PLC", + Width = 150, + DataPropertyName = "IsFeedbackPlc", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewCheckBoxColumn + { + Name = "IsActive", + HeaderText = "是否启用", + Width = 150, + DataPropertyName = "IsActive", + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewTextBoxColumn + { + Name = "Remark", + HeaderText = "备注", + Width = 150, + DataPropertyName = "Remark", + Visible=false, + DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, + }, + new DataGridViewButtonColumn + { + Name = "Edit", + HeaderText = "操作", + Width = 100, + Text = "修改".Translated(), + UseColumnTextForButtonValue = true + }, + new DataGridViewButtonColumn + { + Name = "Delete", + HeaderText = "", + Width = 100, + Text = "删除".Translated(), + UseColumnTextForButtonValue = true + } + }); + + // 添加事件处理 + groupTable.CellBeginEdit += DataGridView_CellBeginEdit; + groupTable.CellEndEdit += DataGridView_CellEndEdit; + groupTable.CellContentClick += DataGridView_CellContentClick; + } + + /// + /// 加载数据到表格 + /// + private void LoadGroups() + { + var plcGroups = TotalGroups.Where(g => g.PlcNum == PlcNum).ToList(); + groupTable.DataSource = null; + groupTable.DataSource = plcGroups; + } + + + /// + /// 获取所有通信组 + /// + /// + private List GetALLGroups() + { + try + { + return MiniExcel.Query(groupPath).ToList(); + } + catch (Exception) + { + + return new List(); + } + + } + + /// + /// 单元格开始编辑 + /// + private void DataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) + { + if (e.RowIndex < 0) return; + + editingConfig = TotalGroups[e.RowIndex]; + + // 禁止编辑PLC编号和组名列 + if (groupTable.Columns[e.ColumnIndex].Name == "PlcNum") + { + e.Cancel = true; + } + } + + /// + /// 单元格结束编辑 + /// + private void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0 || e.RowIndex >= TotalGroups.Count) return; + + var config = TotalGroups[e.RowIndex]; + var value = groupTable[e.ColumnIndex, e.RowIndex].Value; + + try + { + UpdateConfigValue(config, e.ColumnIndex, value); + } + catch (Exception ex) + { + ShowError($"更新数据失败: {ex.Message}"); + } + } + + /// + /// 更新配置值 + /// + private void UpdateConfigValue(PlcGroupConfig config, int columnIndex, object value) + { + switch (groupTable.Columns[columnIndex].Name) + { + case "GroupName": + if (string.IsNullOrWhiteSpace(value?.ToString())) + { + throw new Exception("组名不能为空".Translated()); + } + config.GroupName = value.ToString(); + break; + + case "Start": + if (!ValidateAddressFormat(value?.ToString())) + { + throw new Exception("起始地址格式不正确".Translated()); + } + config.Start = value.ToString(); + break; + + case "Length": + if (!int.TryParse(value?.ToString(), out int length) || length <= 0) + { + throw new Exception("长度必须是大于0的数字".Translated()); + } + config.Length = length; + break; + + case "IsTiggerRead": + config.IsTiggerRead = value != null && (bool)value; + break; + + case "IsFeedbackPlc": + config.IsFeedbackPlc = value != null && (bool)value; + break; + + case "IsActive": + config.IsActive = value != null && (bool)value; + break; + + case "Remark": + config.Remark = value?.ToString() ?? string.Empty; + break; + } + } + + /// + /// 单元格点击事件 + /// + private void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0) return; + + // 获取当前行显示的数据 + var currentRow = groupTable.Rows[e.RowIndex]; + var config = (PlcGroupConfig)currentRow.DataBoundItem; + + // 找到在 TotalGroups 中的真实索引 + var realIndex = TotalGroups.FindIndex(g => + g.PlcNum == config.PlcNum && + g.GroupName == config.GroupName && + g.Start == config.Start); + + // 编辑按钮 + if (groupTable.Columns[e.ColumnIndex] is DataGridViewButtonColumn && + groupTable.Columns[e.ColumnIndex].Name == "Edit") + { + // 传递真实的索引,而不是显示的行索引 + HandleEdit(config, realIndex); + } + // 删除按钮 + else if (groupTable.Columns[e.ColumnIndex] is DataGridViewButtonColumn && + groupTable.Columns[e.ColumnIndex].Name == "Delete") + { + HandleDelete(config); + } + } + + /// + /// 处理编辑操作 + /// + private void HandleEdit(PlcGroupConfig config, int rowIndex) + { + try + { + var result = MessageBox.Show("是否保存修改的配置?".Translated(), "确认保存".Translated(), MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (result != DialogResult.Yes) return; + + if (!ValidateConfigAll(config)) return; + + // 更新TotalGroups中的配置 + TotalGroups[rowIndex] = config; + + // 保存到Excel + SaveToExcel(TotalGroups); + + // 重新加载显示 + LoadGroups(); + + ShowSuccess("配置保存成功".Translated()); + } + catch (Exception ex) + { + ShowError($"保存失败: {ex.Message}"); + } + } + + /// + /// 处理删除操作 + /// + private void HandleDelete(PlcGroupConfig config) + { + var result = MessageBox.Show($"确定要删除该通信组吗?\n PLC编号[{config.PlcNum}] 组名: [{config.GroupName}]", "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + + if (result == DialogResult.Yes) + { + try + { + TotalGroups.Remove(config); + SaveToExcel(TotalGroups); + LoadGroups(); + ShowSuccess("删除成功".Translated()); + } + catch (Exception ex) + { + ShowError($"删除失败: {ex.Message}"); + } + } + } + + + /// + /// 保存配置到Excel文件 + /// + private void SaveToExcel(List configs) + { + try + { + // 创建临时文件路径 + string tempFilePath = Path.Combine( + Path.GetDirectoryName(groupPath), + $"temp_{Path.GetFileName(groupPath)}"); + + // 先保存到临时文件 + MiniExcel.SaveAs(tempFilePath, configs); + + // 检查临时文件是否创建成功 + if (!File.Exists(tempFilePath)) + { + throw new Exception("创建临时文件失败".Translated()); + } + + try + { + // 如果原文件存在,先删除 + if (File.Exists(groupPath)) + { + File.Delete(groupPath); + } + + // 将临时文件重命名为目标文件 + File.Move(tempFilePath, groupPath); + } + finally + { + // 确保临时文件被删除 + if (File.Exists(tempFilePath)) + { + File.Delete(tempFilePath); + } + } + } + catch (Exception ex) + { + throw new Exception($"保存Excel文件时发生错误: {ex.Message}", ex); + } + } + + + + /// + /// 验证单行配置 + /// + private bool ValidateConfigAll(PlcGroupConfig config) + { + try + { + // 基本字段验证 + if (string.IsNullOrWhiteSpace(config.GroupName)) + { + ShowError("组名不能为空".Translated()); + return false; + } + + if (string.IsNullOrWhiteSpace(config.Start)) + { + ShowError("起始地址不能为空".Translated()); + return false; + } + + if (config.Length <= 0) + { + ShowError("长度必须大于0".Translated()); + return false; + } + + // 地址格式验证 + if (!ValidateAddressFormat(config.Start)) + { + ShowError("起始地址格式不正确,应以'D'开头后跟数字".Translated()); + return false; + } + // 打印调试信息 + Console.WriteLine($"当前要添加的配置 - PLC号: {config.PlcNum}, 组名: {config.GroupName}"); + + //// 打印所有的配置 + //Console.WriteLine("\n所有配置信息:"); + //foreach (var g in TotalGroups) + //{ + // Console.WriteLine($"PLC号: {g.PlcNum}, 组名: {g.GroupName}"); + //} + + // 筛选同PLC的配置(不包括当前正在添加的配置) + var groupsInSamePLC = TotalGroups.Where(g => + g.PlcNum == config.PlcNum && // 筛选 PLC1 的配置 + g != config // 这个条件是需要的,因为可能当前配置已经在集合中 + ).ToList(); + + + // 3. 只在同一个PLC内检查地址是否冲突 + if (groupsInSamePLC.Any(g => g.GroupName.Equals(config.GroupName, StringComparison.OrdinalIgnoreCase))) + { + ShowError($"在PLC {config.PlcNum} 中,组名 {config.GroupName} 已被使用"); + return false; + } + //Console.WriteLine("\n筛选后的配置:"); + //foreach (var g in groupsInSamePLC) + //{ + // Console.WriteLine($"PLC号: {g.PlcNum}, 组名: {g.GroupName}"); + //} + + // 3. 只在同一个PLC内检查地址是否冲突 + if (groupsInSamePLC.Any(g => g.Start.Equals(config.Start, StringComparison.OrdinalIgnoreCase))) + { + ShowError($"在PLC {config.PlcNum} 中,起始地址 {config.Start} 已被使用"); + return false; + } + + // 地址范围验证 + int startAddress = int.Parse(config.Start.Substring(1)); + int endAddress = startAddress + config.Length - 1; + + if (endAddress > 32675) + { + ShowError($"地址范围超出限制,结束地址不能超过D32675".Translated()); + return false; + } + + // 检查地址范围冲突 + foreach (var other in groupsInSamePLC) + { + int otherStart = int.Parse(other.Start.Substring(1)); + int otherEnd = otherStart + other.Length - 1; + + if (!(endAddress < otherStart || startAddress > otherEnd)) + { + ShowError($"地址范围与组 \"{other.GroupName}\" 冲突"); + return false; + } + } + + return true; + } + catch (Exception ex) + { + ShowError($"验证配置时发生错误: {ex.Message}"); + return false; + } + } + + // 地址格式验证 + private bool ValidateAddressFormat(string address) + { + if (string.IsNullOrWhiteSpace(address)) return false; + + // 检查是否以D开头(不区分大小写) + if (!address.StartsWith("D", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // 检查后面是否为有效数字 + string numberPart = address.Substring(1); + if (!int.TryParse(numberPart, out int addressNum)) + { + return false; + } + + // 检查地址范围(根据实际需求调整范围) + if (addressNum < 0 || addressNum > 9999) + { + return false; + } + + return true; + } + + #region 添加新通信组 + /// + /// 添加新通信组 + /// + /// + /// + private void BtnAdd_Click(object sender, EventArgs e) + { + try + { + // 创建新组配置 + var newGroup = new PlcGroupConfig + { + PlcNum = PlcNum, // 使用当前PlcNum而不是CurrentPLCConfig.PlcNum + GroupName = GenerateNewGroupName(), + Start = FindNextAvailableAddress(), + Length = 100, + IsTiggerRead = true, + IsFeedbackPlc = true, + IsActive = true, + Remark = "" + }; + + // 验证新配置 + if (!ValidateConfigAll(newGroup)) + { + return; + } + + // 添加到总配置列表 + TotalGroups.Add(newGroup); + + // 保存到Excel文件 + SaveToExcel(TotalGroups); + + // 重新加载显示 + LoadGroups(); + + ShowSuccess("新建通信组成功".Translated()); + } + catch (Exception ex) + { + ShowError($"添加通信组失败: {ex.Message}"); + } + } + + /// + /// 生成新的组名 + /// + private string GenerateNewGroupName() + { + int index = 1; + string baseName = "新建组".Translated(); + string newName = baseName; + + // 查找可用的组名 + while (TotalGroups.Any(g => g.PlcNum == PlcNum && g.GroupName.Equals(newName, StringComparison.OrdinalIgnoreCase))) + { + index++; + newName = $"{baseName}{index}"; + } + + return newName; + } + + /// + /// 查找下一个可用的地址 + /// + private string FindNextAvailableAddress() + { + // 获取当前PLC的所有组 + var plcGroups = TotalGroups.Where(g => g.PlcNum == PlcNum && g.IsActive).ToList(); + + if (!plcGroups.Any()) + { + return "D0"; // 如果没有现有组,从D0开始 + } + + // 找到最大的结束地址 + int maxEndAddress = plcGroups.Max(g => + { + int startAddr = int.Parse(g.Start.Substring(1)); + return startAddr + g.Length; + }); + + // 确保地址不超过最大限制(32675) + if (maxEndAddress >= 32675) + { + throw new Exception("没有可用的地址空间".Translated()); + } + + // 返回下一个可用地址 + return $"D{maxEndAddress}"; + } + + /// + /// 查找地址间隔 + /// + private string FindAddressGap(int requiredLength = 100) + { + // 获取当前PLC的所有组,并按起始地址排序 + var plcGroups = TotalGroups + .Where(g => g.PlcNum == PlcNum) + .Select(g => new + { + Start = int.Parse(g.Start.Substring(1)), + End = int.Parse(g.Start.Substring(1)) + g.Length - 1 + }) + .OrderBy(g => g.Start) + .ToList(); + + // 如果没有组,返回起始地址 + if (!plcGroups.Any()) + { + return "D0"; + } + + // 检查第一个组之前是否有足够空间 + if (plcGroups.First().Start >= requiredLength) + { + return "D0"; + } + + // 检查组之间的间隔 + for (int i = 0; i < plcGroups.Count - 1; i++) + { + int gapStart = plcGroups[i].End + 1; + int gapEnd = plcGroups[i + 1].Start - 1; + + if (gapEnd - gapStart + 1 >= requiredLength) + { + return $"D{gapStart}"; + } + } + + // 检查最后一个组之后是否有足够空间 + int lastEnd = plcGroups.Last().End; + if (lastEnd + requiredLength <= 32675) + { + return $"D{lastEnd + 1}"; + } + + throw new Exception("没有找到足够大的地址空间".Translated()); + } + + private void btn_Close_Click(object sender, EventArgs e) + { + this.Close(); + } + + #endregion + + + + // 错误提示 + private void ShowError(string message) + { + MessageBox.Show(message, "验证错误".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + // 成功提示 + private void ShowSuccess(string message) + { + MessageBox.Show(message, "成功".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + + + + + + #region 无边框拖动 + private Point mPoint; + private void Panel_MouseDown(object sender, MouseEventArgs e) + { + mPoint = new Point(e.X, e.Y); + } + + private void Panel_MouseMove(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + this.Location = new Point(this.Location.X + e.X - mPoint.X, this.Location.Y + e.Y - mPoint.Y); + } + } + #endregion + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + + + } +} diff --git a/LargeSquareOne/CommunicationEditForm.resx b/LargeSquareOne/CommunicationEditForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/LargeSquareOne/CommunicationEditForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/LargeSquareOne/Config/Configure.xml b/LargeSquareOne/Config/Configure.xml new file mode 100644 index 0000000..781faa1 --- /dev/null +++ b/LargeSquareOne/Config/Configure.xml @@ -0,0 +1,166 @@ + + + + + False + + False + + 3 + + True + + 1 + + 1 + + False + + False + + False + + False + + False + + False + + False + + 0 + + 2-1 + + 2025-09-01 16:10:57 + + True + + False + + + + 60J + + PW-571 + + 60PLR04 + 81044802 + + 8889205-04 + + 1,2 + + 20:30:00 + + D:\APILog + + 127.0.0.1 + + 10.22.160.9 + + 80 + + 4 + + 3 + + 9 + + http://10.54.50.1:8082/core/api/public/equipment/base/user/login/verify + + http://10.54.50.1:8082/core/api/public/param/setting/request + + http://10.54.50.1:8082/core/api/public/param/setting/change + http://10.22.160.9/prod-api/produce/trayQuery/trayComposeInfo + http://10.22.160.2/core/api/public/equip/auto/gradequery + http://10.22.160.2/core/api/public/semi/packaging/data/bind + http://10.22.160.2/core/api/public/packaging/machine/data/bind + http://10.22.160.9/prod-api/api/fms/mp/unbindWholeTray + http://10.22.160.3/core/api/public/process/param/new/result + + http://10.54.50.1:8082/core/api/public/equipment/alarm/currency + + http://10.54.50.1:8082/core/api/public/eve/pm/eqm/run/status/operation + + http://10.54.50.1:8082/core/api/public/eve/pm/energy/consumption/collection/submit + + https://iot.eveportal.com:9470/eve_api/ems/iot/upload_device_collect_data + + + + 1030 + + 0 + + 360 + + 358 + + 0 + + 0 + + 0 + + 0 + + 0 + + 0 + + + + 25 + + FSY-2A-001 + + FSY-2A-002 + + FSY-2A-003 + + FSY-2A-004 + + FSY-2A-005 + + FSY-2A-006 + + FSY-2A-007 + + FSY-2A-008 + + FSY-2A-009 + + FSY-2A-010 + + FSY-2A-011 + + FSY-2A-012 + + FSY-2A-013 + + FSY-2A-014 + + FSY-2A-015 + + FSY-2A-016 + + FSY-2A-017 + + FSY-2A-018 + + FSY-2A-019 + + FSY-2A-020 + + FSY-2A-021 + + FSY-2A-022 + + FSY-2A-023 + + FSY-2A-024 + + FSY-2A-025 + + \ No newline at end of file diff --git a/LargeSquareOne/Config/Device.xlsx b/LargeSquareOne/Config/Device.xlsx new file mode 100644 index 0000000..ba9276e Binary files /dev/null and b/LargeSquareOne/Config/Device.xlsx differ diff --git a/LargeSquareOne/Config/FdConfig.xlsx b/LargeSquareOne/Config/FdConfig.xlsx new file mode 100644 index 0000000..b341c73 Binary files /dev/null and b/LargeSquareOne/Config/FdConfig.xlsx differ diff --git a/LargeSquareOne/Config/FdConfigMapping.xlsx b/LargeSquareOne/Config/FdConfigMapping.xlsx new file mode 100644 index 0000000..f4ee69f Binary files /dev/null and b/LargeSquareOne/Config/FdConfigMapping.xlsx differ diff --git a/LargeSquareOne/Config/Group.xlsx b/LargeSquareOne/Config/Group.xlsx new file mode 100644 index 0000000..2b4b82b Binary files /dev/null and b/LargeSquareOne/Config/Group.xlsx differ diff --git a/LargeSquareOne/Config/Variable.xlsx b/LargeSquareOne/Config/Variable.xlsx new file mode 100644 index 0000000..d15734d Binary files /dev/null and b/LargeSquareOne/Config/Variable.xlsx differ diff --git a/LargeSquareOne/CustomMessageBox.Designer.cs b/LargeSquareOne/CustomMessageBox.Designer.cs new file mode 100644 index 0000000..5d29f4f --- /dev/null +++ b/LargeSquareOne/CustomMessageBox.Designer.cs @@ -0,0 +1,208 @@ + +namespace LargeSquareOne +{ + partial class CustomMessageBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + this.panel1 = new System.Windows.Forms.Panel(); + this.panel4 = new System.Windows.Forms.Panel(); + this.dataGridView1 = new System.Windows.Forms.DataGridView(); + this.panel3 = new System.Windows.Forms.Panel(); + this.btStop = new HML.ButtonPlus(); + this.btSatrt = new HML.ButtonPlus(); + this.panel2 = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.lblMessage = new System.Windows.Forms.Label(); + this.panel1.SuspendLayout(); + this.panel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); + this.panel3.SuspendLayout(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Controls.Add(this.panel4); + this.panel1.Controls.Add(this.panel3); + this.panel1.Controls.Add(this.panel2); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(652, 428); + this.panel1.TabIndex = 0; + // + // panel4 + // + this.panel4.Controls.Add(this.dataGridView1); + this.panel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel4.Location = new System.Drawing.Point(0, 53); + this.panel4.Name = "panel4"; + this.panel4.Size = new System.Drawing.Size(652, 319); + this.panel4.TabIndex = 4; + // + // dataGridView1 + // + this.dataGridView1.AllowUserToAddRows = false; + this.dataGridView1.AllowUserToDeleteRows = false; + this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.AllCells; + this.dataGridView1.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.DisplayedCells; + this.dataGridView1.BackgroundColor = System.Drawing.Color.White; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control; + dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F); + dataGridViewCellStyle1.ForeColor = System.Drawing.Color.Black; + dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1; + this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle2.BackColor = System.Drawing.Color.White; + dataGridViewCellStyle2.Font = new System.Drawing.Font("Microsoft Sans Serif", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + dataGridViewCellStyle2.ForeColor = System.Drawing.Color.Black; + dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.ControlLightLight; + dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dataGridView1.DefaultCellStyle = dataGridViewCellStyle2; + this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.dataGridView1.Location = new System.Drawing.Point(0, 0); + this.dataGridView1.Name = "dataGridView1"; + this.dataGridView1.ReadOnly = true; + this.dataGridView1.RowTemplate.DefaultCellStyle.BackColor = System.Drawing.Color.White; + this.dataGridView1.RowTemplate.DefaultCellStyle.Font = new System.Drawing.Font("Microsoft Sans Serif", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.dataGridView1.RowTemplate.DefaultCellStyle.ForeColor = System.Drawing.Color.Black; + this.dataGridView1.RowTemplate.Height = 23; + this.dataGridView1.Size = new System.Drawing.Size(652, 319); + this.dataGridView1.TabIndex = 0; + this.dataGridView1.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dataGridView1_RowPostPaint); + // + // panel3 + // + this.panel3.BackColor = System.Drawing.Color.Silver; + this.panel3.Controls.Add(this.btStop); + this.panel3.Controls.Add(this.btSatrt); + this.panel3.Dock = System.Windows.Forms.DockStyle.Bottom; + this.panel3.Location = new System.Drawing.Point(0, 372); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(652, 56); + this.panel3.TabIndex = 3; + // + // btStop + // + this.btStop.BackNormalColor = System.Drawing.Color.Red; + this.btStop.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold); + this.btStop.Location = new System.Drawing.Point(390, 4); + this.btStop.Name = "btStop"; + this.btStop.Size = new System.Drawing.Size(101, 49); + this.btStop.TabIndex = 15; + this.btStop.Text = "取 消"; + this.btStop.Click += new System.EventHandler(this.btnNo_Click); + // + // btSatrt + // + this.btSatrt.BackNormalColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(192)))), ((int)(((byte)(0))))); + this.btSatrt.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btSatrt.Location = new System.Drawing.Point(134, 4); + this.btSatrt.Name = "btSatrt"; + this.btSatrt.Size = new System.Drawing.Size(101, 49); + this.btSatrt.TabIndex = 14; + this.btSatrt.Text = "确 定"; + this.btSatrt.Click += new System.EventHandler(this.btnOK_Click); + // + // panel2 + // + this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(34)))), ((int)(((byte)(40)))), ((int)(((byte)(49))))); + this.panel2.Controls.Add(this.pictureBox1); + this.panel2.Controls.Add(this.lblMessage); + this.panel2.Dock = System.Windows.Forms.DockStyle.Top; + this.panel2.Location = new System.Drawing.Point(0, 0); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(652, 53); + this.panel2.TabIndex = 0; + // + // pictureBox1 + // + this.pictureBox1.Image = global::LargeSquareOne.Properties.Resources.黄色_警告; + this.pictureBox1.Location = new System.Drawing.Point(7, 6); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(45, 37); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBox1.TabIndex = 1; + this.pictureBox1.TabStop = false; + // + // lblMessage + // + this.lblMessage.AutoSize = true; + this.lblMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblMessage.ForeColor = System.Drawing.Color.Red; + this.lblMessage.Location = new System.Drawing.Point(58, 14); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(43, 20); + this.lblMessage.TabIndex = 0; + this.lblMessage.Text = "提示"; + // + // CustomMessageBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(652, 428); + this.Controls.Add(this.panel1); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CustomMessageBox"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.TopMost = true; + this.Load += new System.EventHandler(this.CustomMessageBox_Load); + this.panel1.ResumeLayout(false); + this.panel4.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); + this.panel3.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.DataGridView dataGridView1; + private System.Windows.Forms.Panel panel4; + private System.Windows.Forms.Panel panel3; + private System.Windows.Forms.Label lblMessage; + + private System.Windows.Forms.PictureBox pictureBox1; + private HML.ButtonPlus btStop; + private HML.ButtonPlus btSatrt; + } +} \ No newline at end of file diff --git a/LargeSquareOne/CustomMessageBox.cs b/LargeSquareOne/CustomMessageBox.cs new file mode 100644 index 0000000..c4752db --- /dev/null +++ b/LargeSquareOne/CustomMessageBox.cs @@ -0,0 +1,71 @@ +using Language; +using System; +using System.Data; +using System.Drawing; +using System.Windows.Forms; + +namespace LargeSquareOne +{ + public partial class CustomMessageBox : MultiLanguageForm + { + DataTable dataTable = new DataTable(); + string strLblMessage = ""; + + public CustomMessageBox(DataTable _dataTable, string _strLblMessage) + { + InitializeComponent(); + + + dataTable = _dataTable; + strLblMessage = _strLblMessage; + } + + private void CustomMessageBox_Load(object sender, EventArgs e) + { + dataGridView1.DataSource = dataTable; + lblMessage.Text = strLblMessage; + } + + //public void SetMessage(DataTable dataTable,string strLblMessage) + //{ + // dataGridView1.DataSource = dataTable; + // lblMessage.Text = strLblMessage; + //} + + private void btnOK_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.OK; + + } + private void btnNo_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.No; + this.Close(); + } + + private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) + { + //自动编号,与数据无关 + Rectangle rectangle = new Rectangle(e.RowBounds.Location.X, + e.RowBounds.Location.Y, + dataGridView1.RowHeadersWidth - 4, + e.RowBounds.Height); + TextRenderer.DrawText(e.Graphics, + (e.RowIndex + 1).ToString(), + dataGridView1.RowHeadersDefaultCellStyle.Font, + rectangle, + dataGridView1.RowHeadersDefaultCellStyle.ForeColor, + TextFormatFlags.VerticalCenter | TextFormatFlags.Right); + } + + //public static void Show(DataTable dataTable, string message, string title) + //{ + // CustomMessageBox messageBox = new CustomMessageBox(dataTable, message); + // messageBox.SetMessage(dataTable,message); + // messageBox.Text = title; + // messageBox.ShowDialog(); + //} + + + } +} diff --git a/LargeSquareOne/CustomMessageBox.resx b/LargeSquareOne/CustomMessageBox.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/LargeSquareOne/CustomMessageBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/LargeSquareOne/FDConfigForm.Designer.cs b/LargeSquareOne/FDConfigForm.Designer.cs new file mode 100644 index 0000000..473ea35 --- /dev/null +++ b/LargeSquareOne/FDConfigForm.Designer.cs @@ -0,0 +1,200 @@ +namespace LargeSquareOne +{ + partial class FDConfigForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + this.panelExt1 = new JinYuan.ControlLib.PanelExt(); + this.groupTable = new System.Windows.Forms.DataGridView(); + this.topPanel = new System.Windows.Forms.Panel(); + this.BtnAdd = new System.Windows.Forms.Button(); + this.btn_Close = new System.Windows.Forms.Button(); + this.lblTitle = new System.Windows.Forms.Label(); + this.panelExt1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.groupTable)).BeginInit(); + this.topPanel.SuspendLayout(); + this.SuspendLayout(); + // + // panelExt1 + // + this.panelExt1.BackColor = System.Drawing.Color.Transparent; + this.panelExt1.BordeColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(79)))), ((int)(((byte)(150))))); + this.panelExt1.BordeWidth = 2; + this.panelExt1.BottomGap = 0; + this.panelExt1.Controls.Add(this.groupTable); + this.panelExt1.Controls.Add(this.topPanel); + this.panelExt1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelExt1.LeftGap = 0; + this.panelExt1.Location = new System.Drawing.Point(0, 0); + this.panelExt1.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.panelExt1.Name = "panelExt1"; + this.panelExt1.RightGap = 0; + this.panelExt1.Size = new System.Drawing.Size(990, 509); + this.panelExt1.TabIndex = 0; + this.panelExt1.TopGap = 0; + // + // groupTable + // + this.groupTable.AllowUserToAddRows = false; + this.groupTable.AllowUserToDeleteRows = false; + this.groupTable.AllowUserToResizeRows = false; + this.groupTable.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.groupTable.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.groupTable.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + dataGridViewCellStyle4.Font = new System.Drawing.Font("微软雅黑", 12F); + dataGridViewCellStyle4.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle4.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.groupTable.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle4; + this.groupTable.ColumnHeadersHeight = 45; + this.groupTable.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle5.Font = new System.Drawing.Font("微软雅黑", 12F); + dataGridViewCellStyle5.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle5.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle5.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.groupTable.DefaultCellStyle = dataGridViewCellStyle5; + this.groupTable.EnableHeadersVisualStyles = false; + this.groupTable.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.groupTable.Location = new System.Drawing.Point(15, 44); + this.groupTable.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.groupTable.Name = "groupTable"; + this.groupTable.ReadOnly = true; + this.groupTable.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle6.Font = new System.Drawing.Font("微软雅黑", 12F); + dataGridViewCellStyle6.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle6.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle6.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle6.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.groupTable.RowHeadersDefaultCellStyle = dataGridViewCellStyle6; + this.groupTable.RowHeadersVisible = false; + this.groupTable.RowHeadersWidth = 55; + this.groupTable.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; + this.groupTable.RowTemplate.Height = 40; + this.groupTable.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.groupTable.Size = new System.Drawing.Size(933, 439); + this.groupTable.TabIndex = 15; + // + // topPanel + // + this.topPanel.Controls.Add(this.BtnAdd); + this.topPanel.Controls.Add(this.btn_Close); + this.topPanel.Controls.Add(this.lblTitle); + this.topPanel.Dock = System.Windows.Forms.DockStyle.Top; + this.topPanel.Location = new System.Drawing.Point(0, 0); + this.topPanel.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.topPanel.Name = "topPanel"; + this.topPanel.Size = new System.Drawing.Size(990, 39); + this.topPanel.TabIndex = 0; + this.topPanel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Panel_MouseDown); + this.topPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Panel_MouseMove); + // + // BtnAdd + // + this.BtnAdd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(27)))), ((int)(((byte)(78))))); + this.BtnAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.BtnAdd.Font = new System.Drawing.Font("微软雅黑", 11.5F); + this.BtnAdd.ForeColor = System.Drawing.Color.White; + this.BtnAdd.Location = new System.Drawing.Point(565, 7); + this.BtnAdd.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.BtnAdd.Name = "BtnAdd"; + this.BtnAdd.Size = new System.Drawing.Size(130, 29); + this.BtnAdd.TabIndex = 49; + this.BtnAdd.Text = "添加分档类型"; + this.BtnAdd.UseVisualStyleBackColor = false; + this.BtnAdd.Click += new System.EventHandler(this.BtnAdd_Click); + // + // btn_Close + // + this.btn_Close.FlatAppearance.BorderSize = 0; + this.btn_Close.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(29)))), ((int)(((byte)(84))))); + this.btn_Close.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent; + this.btn_Close.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Close.Font = new System.Drawing.Font("微软雅黑", 15.5F); + this.btn_Close.ForeColor = System.Drawing.Color.White; + this.btn_Close.Location = new System.Drawing.Point(951, 6); + this.btn_Close.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.btn_Close.Name = "btn_Close"; + this.btn_Close.Size = new System.Drawing.Size(26, 26); + this.btn_Close.TabIndex = 1; + this.btn_Close.Text = "X"; + this.btn_Close.UseVisualStyleBackColor = true; + this.btn_Close.Click += new System.EventHandler(this.btn_Close_Click); + // + // lblTitle + // + this.lblTitle.AutoSize = true; + this.lblTitle.ForeColor = System.Drawing.Color.White; + this.lblTitle.Location = new System.Drawing.Point(12, 14); + this.lblTitle.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(106, 21); + this.lblTitle.TabIndex = 0; + this.lblTitle.Text = "分档类型配置"; + // + // FDConfigForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.ClientSize = new System.Drawing.Size(990, 509); + this.Controls.Add(this.panelExt1); + this.Font = new System.Drawing.Font("微软雅黑", 12F); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.Name = "FDConfigForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "FrmGroupConfig"; + this.panelExt1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.groupTable)).EndInit(); + this.topPanel.ResumeLayout(false); + this.topPanel.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private JinYuan.ControlLib.PanelExt panelExt1; + private System.Windows.Forms.Panel topPanel; + private System.Windows.Forms.Button btn_Close; + private System.Windows.Forms.Label lblTitle; + private System.Windows.Forms.DataGridView groupTable; + private System.Windows.Forms.Button BtnAdd; + } +} \ No newline at end of file diff --git a/LargeSquareOne/FDConfigForm.cs b/LargeSquareOne/FDConfigForm.cs new file mode 100644 index 0000000..90d56a3 --- /dev/null +++ b/LargeSquareOne/FDConfigForm.cs @@ -0,0 +1,464 @@ +using Google.Protobuf.WellKnownTypes; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using Language; +using MiniExcelLibs; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +namespace LargeSquareOne +{ + public partial class FDConfigForm : MultiLanguageForm + { + // 定义事件 + public static event EventHandler OnFDConfigChanged; + private readonly string fdConfigMappingPath = CommonMethods.FdConfigMappingPath; + private List configMappings = new List(); + private BindingList bindList = new BindingList(); + private bool _isLoading = false; + + private readonly DataGridViewCellStyle _centerCellStyle = new DataGridViewCellStyle() + { + Alignment = DataGridViewContentAlignment.MiddleCenter + }; + + public FDConfigForm() + { + InitializeComponent(); + groupTable.AutoGenerateColumns = false; + + InitializeDataGridView(); + EnsureConfigDirectoryExists(); + configMappings = GetALLConfigs(); + bindList = new BindingList(configMappings); + + _isLoading = true; + LoadConfigs(); + _isLoading = false; + } + + private void EnsureConfigDirectoryExists() + { + string dir = Path.GetDirectoryName(fdConfigMappingPath); + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + } + + private void InitializeDataGridView() + { + // 禁用自动添加新行 + groupTable.AllowUserToAddRows = false; + groupTable.AllowUserToDeleteRows = false; + groupTable.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + groupTable.MultiSelect = false; + groupTable.ReadOnly = false; + groupTable.DoubleBuffered(true); + + // 设置默认单元格样式 + groupTable.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; + groupTable.RowHeadersVisible = false; + + groupTable.Columns.AddRange(new DataGridViewColumn[] + { + new DataGridViewTextBoxColumn + { + Name = "FDNum", + HeaderText = "分档编号".Translated(), + Width = 120, + ReadOnly = true, + DataPropertyName = "FDNum", + DefaultCellStyle = _centerCellStyle + }, + new DataGridViewTextBoxColumn + { + Name = "FDName", + HeaderText = "分档类型".Translated(), + Width = 120, + DataPropertyName = "FDName", + DefaultCellStyle = _centerCellStyle + }, + new DataGridViewTextBoxColumn + { + Name = "ModelType", + HeaderText = "电池型号".Translated(), + Width = 120, + DataPropertyName = "ModelType", + DefaultCellStyle = _centerCellStyle + }, + new DataGridViewButtonColumn + { + Name = "SaveBtn", + HeaderText = "操作".Translated(), + Width = 100, + Text = "保存该行".Translated(), + UseColumnTextForButtonValue = true + }, + new DataGridViewButtonColumn + { + Name = "DeleteBtn", + HeaderText = "操作".Translated(), + Width = 100, + Text = "删除".Translated(), + UseColumnTextForButtonValue = true + } + }); + + // 事件绑定 + groupTable.CellContentClick += GroupTable_CellContentClick; + groupTable.DataError += GroupTable_DataError; + groupTable.CellBeginEdit += GroupTable_CellBeginEdit; + groupTable.CellValidating += GroupTable_CellValidating; // 添加验证事件 + } + + #region 数据错误处理 + private void GroupTable_DataError(object sender, DataGridViewDataErrorEventArgs e) + { + e.Cancel = true; + } + #endregion + + #region 单元格编辑前事件 - 阻止编辑FDNum + private void GroupTable_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) + { + if (groupTable.Columns[e.ColumnIndex].Name == "FDNum") + { + e.Cancel = true; + } + } + #endregion + + #region 单元格验证 - 实时更新绑定数据 + private void GroupTable_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) + { + // 当单元格编辑完成时,确保数据更新到绑定列表 + if (e.RowIndex < 0 || e.RowIndex >= bindList.Count) + return; + + var row = groupTable.Rows[e.RowIndex]; + var item = bindList[e.RowIndex]; + string colName = groupTable.Columns[e.ColumnIndex].Name; + + if (colName == "FDName") + { + string newValue = e.FormattedValue?.ToString()?.Trim() ?? string.Empty; + // 如果值为空,设置为空字符串 + if (string.IsNullOrEmpty(newValue)) + { + item.FDName = string.Empty; + } + else + { + item.FDName = newValue; + } + } + else if (colName == "ModelType") + { + string newValue = e.FormattedValue?.ToString()?.Trim() ?? string.Empty; + item.ModelType = newValue; + } + } + #endregion + + private void LoadConfigs() + { + try + { + groupTable.DataSource = null; + groupTable.DataSource = bindList; + } + catch (Exception ex) + { + ShowError($"加载数据失败:{ex.Message}"); + } + } + + private List GetALLConfigs() + { + try + { + if (!File.Exists(fdConfigMappingPath)) + return new List(); + return MiniExcel.Query(fdConfigMappingPath).ToList(); + } + catch (Exception ex) + { + ShowError($"读取配置文件失败:{ex.Message}"); + return new List(); + } + } + + private void GroupTable_CellContentClick(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0) return; + if (e.ColumnIndex < 0) return; + + int rowIdx = e.RowIndex; + string colName = groupTable.Columns[e.ColumnIndex].Name; + + // 检查行索引是否有效 + if (rowIdx >= bindList.Count) + { + ShowError("数据行索引无效".Translated()); + return; + } + + if (colName == "SaveBtn") + { + var item = bindList[rowIdx]; + + // 验证数据 + if (!ValidateSingleConfig(item, rowIdx)) + return; + + try + { + // 提交当前编辑 + groupTable.CommitEdit(DataGridViewDataErrorContexts.Commit); + + configMappings = new List(bindList); + SaveToExcel(configMappings); + ShowSuccess("保存成功".Translated()); + } + catch (Exception ex) + { + ShowError($"保存失败:{ex.Message}"); + } + } + else if (colName == "DeleteBtn") + { + var delItem = bindList[rowIdx]; + string msg = $"{"确定删除该分档配置?".Translated()}\n{"分档编号:".Translated()}{delItem.FDNum}\n{"分档类型:".Translated()}{delItem.FDName}"; + var res = MessageBox.Show(msg, "确认删除".Translated(), MessageBoxButtons.YesNo, MessageBoxIcon.Warning); + if (res != DialogResult.Yes) return; + + try + { + bindList.RemoveAt(rowIdx); + configMappings = new List(bindList); + SaveToExcel(configMappings); + ShowSuccess("删除成功".Translated()); + } + catch (Exception ex) + { + ShowError($"删除失败:{ex.Message}"); + } + } + } + + + // 保存成功后更新全局配置 + private void SaveToExcel(List configs) + { + EnsureConfigDirectoryExists(); + string dir = Path.GetDirectoryName(fdConfigMappingPath); + string tempFile = Path.Combine(dir, $"_tmp_{Path.GetFileName(fdConfigMappingPath)}"); + + try + { + MiniExcel.SaveAs(tempFile, configs); + if (!File.Exists(tempFile)) + throw new Exception("临时文件生成失败".Translated()); + + // 备份原文件 + string backupFile = Path.Combine(dir, $"{Path.GetFileNameWithoutExtension(fdConfigMappingPath)}_backup_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); + if (File.Exists(fdConfigMappingPath)) + { + File.Copy(fdConfigMappingPath, backupFile, true); + } + + if (File.Exists(fdConfigMappingPath)) + File.Delete(fdConfigMappingPath); + File.Move(tempFile, fdConfigMappingPath); + + // 删除旧备份 + CleanOldBackups(dir, 5); + + // 更新全局分档配置 + CommonMethods.FDConfigMappings = configs; + + // 更新分档类型列表到全局 + var gradeTypes = configs.Select(x => x.FDName).Distinct().ToList(); + if (!gradeTypes.Contains("不设置")) + gradeTypes.Insert(0, "不设置"); + if (!gradeTypes.Contains("NG")) + gradeTypes.Add("NG"); + CommonMethods.FDGradeTypes = gradeTypes; + + // 保存成功后,触发刷新事件 + CommonMethods.LoadFDGradeTypes(); + + // 如果需要通知主窗体刷新,可以触发事件 + OnFDConfigChanged?.Invoke(this, EventArgs.Empty); + } + catch (Exception ex) + { + throw new Exception($"保存Excel失败:{ex.Message}", ex); + } + finally + { + if (File.Exists(tempFile)) + { + try { File.Delete(tempFile); } catch { } + } + } + } + + private void CleanOldBackups(string directory, int keepCount) + { + try + { + var backupFiles = Directory.GetFiles(directory, "*_backup_*.xlsx") + .OrderByDescending(f => f) + .Skip(keepCount) + .ToList(); + + foreach (var file in backupFiles) + { + try { File.Delete(file); } catch { } + } + } + catch { } + } + + private bool ValidateSingleConfig(FDConfigMapping config, int rowIndex = -1) + { + if (string.IsNullOrWhiteSpace(config.FDName)) + { + ShowError("分档类型不能为空".Translated()); + return false; + } + if (config.FDNum <= 0) + { + ShowError("分档编号必须大于0".Translated()); + return false; + } + + bool duplicate; + if (rowIndex == -1) + { + duplicate = bindList.Any(x => x.FDNum == config.FDNum); + } + else + { + duplicate = bindList.Take(rowIndex).Any(x => x.FDNum == config.FDNum) + || bindList.Skip(rowIndex + 1).Any(x => x.FDNum == config.FDNum); + } + + if (duplicate) + { + ShowError($"分档编号 {config.FDNum} 已存在,不可重复".Translated()); + return false; + } + return true; + } + + #region 按钮事件 + private void BtnAdd_Click(object sender, EventArgs e) + { + try + { + // 先提交当前编辑,防止数据丢失 + groupTable.CommitEdit(DataGridViewDataErrorContexts.Commit); + + // 计算新的编号 + int maxNum = bindList.Count > 0 ? bindList.Max(x => x.FDNum) : 0; + int autoNum = maxNum + 1; + + // 添加到绑定列表 + var newItem = new FDConfigMapping + { + FDNum = autoNum, + FDName = string.Empty, + ModelType = string.Empty + }; + + bindList.Add(newItem); + + // 刷新显示,不重新加载整个数据源,只刷新视图 + int newIndex = bindList.Count - 1; + groupTable.Refresh(); + + // 选中新行并开始编辑 + if (newIndex >= 0 && newIndex < groupTable.Rows.Count) + { + groupTable.ClearSelection(); + groupTable.Rows[newIndex].Selected = true; + groupTable.CurrentCell = groupTable.Rows[newIndex].Cells["FDName"]; + groupTable.BeginEdit(true); + } + } + catch (Exception ex) + { + ShowError($"添加行失败:{ex.Message}"); + } + } + + private void btn_Close_Click(object sender, EventArgs e) + { + // 关闭前提交所有编辑 + try + { + groupTable.CommitEdit(DataGridViewDataErrorContexts.Commit); + } + catch { } + this.Close(); + } + #endregion + + #region 提示弹窗 + private void ShowError(string message) + { + MessageBox.Show(message, "错误".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private void ShowSuccess(string message) + { + MessageBox.Show(message, "提示".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Information); + } + #endregion + + #region 无边框拖动 + private Point mPoint; + private void Panel_MouseDown(object sender, MouseEventArgs e) + { + mPoint = e.Location; + } + + private void Panel_MouseMove(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + this.Left += e.X - mPoint.X; + this.Top += e.Y - mPoint.Y; + } + } + #endregion + + #region 窗口防闪烁 + protected override CreateParams CreateParams + { + get + { + var cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + #endregion + } + + public static class DgvExt + { + public static void DoubleBuffered(this DataGridView dgv, bool enable) + { + var prop = dgv.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + prop?.SetValue(dgv, enable, null); + } + } +} \ No newline at end of file diff --git a/LargeSquareOne/FDConfigForm.resx b/LargeSquareOne/FDConfigForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/LargeSquareOne/FDConfigForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/LargeSquareOne/FrmAlarmLog.Designer.cs b/LargeSquareOne/FrmAlarmLog.Designer.cs new file mode 100644 index 0000000..b380bfe --- /dev/null +++ b/LargeSquareOne/FrmAlarmLog.Designer.cs @@ -0,0 +1,378 @@ +namespace LargeSquareOne +{ + partial class FrmAlarmLog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle7 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle8 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle9 = new System.Windows.Forms.DataGridViewCellStyle(); + this.dgv_OPLog = new System.Windows.Forms.DataGridView(); + this.OPLogDateTime = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.OPLogOperationType = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.OPLogOperationalMessage = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dgv_Log = new System.Windows.Forms.DataGridView(); + this.LogDateTime = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.LogDateType = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.LogDateInformation = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.lblSystemLog = new System.Windows.Forms.Label(); + this.lblOperationLog = new System.Windows.Forms.Label(); + this.dgv_Alarm = new System.Windows.Forms.DataGridView(); + this.AlarmLogDateTime = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.AlarmLogAlarmType = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.AlarmLogALARM = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.lblSystemAlarm = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.dgv_OPLog)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.dgv_Log)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.dgv_Alarm)).BeginInit(); + this.SuspendLayout(); + // + // dgv_OPLog + // + this.dgv_OPLog.AllowUserToAddRows = false; + this.dgv_OPLog.AllowUserToDeleteRows = false; + this.dgv_OPLog.AllowUserToResizeColumns = false; + this.dgv_OPLog.AllowUserToResizeRows = false; + this.dgv_OPLog.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.dgv_OPLog.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.dgv_OPLog.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle1.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle1.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle1.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgv_OPLog.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1; + this.dgv_OPLog.ColumnHeadersHeight = 30; + this.dgv_OPLog.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.dgv_OPLog.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.OPLogDateTime, + this.OPLogOperationType, + this.OPLogOperationalMessage}); + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle2.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle2.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle2.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle2.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgv_OPLog.DefaultCellStyle = dataGridViewCellStyle2; + this.dgv_OPLog.EnableHeadersVisualStyles = false; + this.dgv_OPLog.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.dgv_OPLog.Location = new System.Drawing.Point(22, 282); + this.dgv_OPLog.MultiSelect = false; + this.dgv_OPLog.Name = "dgv_OPLog"; + this.dgv_OPLog.ReadOnly = true; + this.dgv_OPLog.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle3.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle3.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle3.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle3.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgv_OPLog.RowHeadersDefaultCellStyle = dataGridViewCellStyle3; + this.dgv_OPLog.RowHeadersWidth = 120; + this.dgv_OPLog.RowTemplate.Height = 23; + this.dgv_OPLog.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgv_OPLog.Size = new System.Drawing.Size(1827, 266); + this.dgv_OPLog.TabIndex = 6; + this.dgv_OPLog.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dgv_Log_RowPostPaint); + // + // OPLogDateTime + // + this.OPLogDateTime.HeaderText = "日期时间"; + this.OPLogDateTime.MinimumWidth = 6; + this.OPLogDateTime.Name = "OPLogDateTime"; + this.OPLogDateTime.ReadOnly = true; + this.OPLogDateTime.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.OPLogDateTime.Width = 200; + // + // OPLogOperationType + // + this.OPLogOperationType.HeaderText = "操作类型"; + this.OPLogOperationType.MinimumWidth = 6; + this.OPLogOperationType.Name = "OPLogOperationType"; + this.OPLogOperationType.ReadOnly = true; + this.OPLogOperationType.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.OPLogOperationType.Width = 200; + // + // OPLogOperationalMessage + // + this.OPLogOperationalMessage.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.OPLogOperationalMessage.HeaderText = "操作信息"; + this.OPLogOperationalMessage.MinimumWidth = 6; + this.OPLogOperationalMessage.Name = "OPLogOperationalMessage"; + this.OPLogOperationalMessage.ReadOnly = true; + this.OPLogOperationalMessage.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // dgv_Log + // + this.dgv_Log.AllowUserToAddRows = false; + this.dgv_Log.AllowUserToDeleteRows = false; + this.dgv_Log.AllowUserToResizeColumns = false; + this.dgv_Log.AllowUserToResizeRows = false; + this.dgv_Log.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.dgv_Log.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.dgv_Log.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle4.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle4.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle4.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgv_Log.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle4; + this.dgv_Log.ColumnHeadersHeight = 30; + this.dgv_Log.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.dgv_Log.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.LogDateTime, + this.LogDateType, + this.LogDateInformation}); + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle5.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle5.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle5.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle5.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgv_Log.DefaultCellStyle = dataGridViewCellStyle5; + this.dgv_Log.EnableHeadersVisualStyles = false; + this.dgv_Log.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.dgv_Log.Location = new System.Drawing.Point(22, 14); + this.dgv_Log.MultiSelect = false; + this.dgv_Log.Name = "dgv_Log"; + this.dgv_Log.ReadOnly = true; + this.dgv_Log.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle6.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle6.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle6.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle6.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle6.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgv_Log.RowHeadersDefaultCellStyle = dataGridViewCellStyle6; + this.dgv_Log.RowHeadersWidth = 120; + this.dgv_Log.RowTemplate.Height = 23; + this.dgv_Log.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgv_Log.Size = new System.Drawing.Size(1827, 266); + this.dgv_Log.TabIndex = 7; + this.dgv_Log.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dgv_Log_RowPostPaint); + // + // LogDateTime + // + this.LogDateTime.HeaderText = "日期时间"; + this.LogDateTime.MinimumWidth = 6; + this.LogDateTime.Name = "LogDateTime"; + this.LogDateTime.ReadOnly = true; + this.LogDateTime.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.LogDateTime.Width = 200; + // + // LogDateType + // + this.LogDateType.HeaderText = "日志类型"; + this.LogDateType.MinimumWidth = 6; + this.LogDateType.Name = "LogDateType"; + this.LogDateType.ReadOnly = true; + this.LogDateType.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.LogDateType.Width = 200; + // + // LogDateInformation + // + this.LogDateInformation.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.LogDateInformation.HeaderText = "日志信息"; + this.LogDateInformation.MinimumWidth = 6; + this.LogDateInformation.Name = "LogDateInformation"; + this.LogDateInformation.ReadOnly = true; + this.LogDateInformation.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // lblSystemLog + // + this.lblSystemLog.BackColor = System.Drawing.Color.Transparent; + this.lblSystemLog.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblSystemLog.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(246)))), ((int)(((byte)(255))))); + this.lblSystemLog.Location = new System.Drawing.Point(43, 19); + this.lblSystemLog.Name = "lblSystemLog"; + this.lblSystemLog.Size = new System.Drawing.Size(75, 23); + this.lblSystemLog.TabIndex = 11; + this.lblSystemLog.Text = "系统日志"; + // + // lblOperationLog + // + this.lblOperationLog.BackColor = System.Drawing.Color.Transparent; + this.lblOperationLog.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblOperationLog.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(246)))), ((int)(((byte)(255))))); + this.lblOperationLog.Location = new System.Drawing.Point(42, 287); + this.lblOperationLog.Name = "lblOperationLog"; + this.lblOperationLog.Size = new System.Drawing.Size(89, 19); + this.lblOperationLog.TabIndex = 10; + this.lblOperationLog.Text = "操作日志"; + // + // dgv_Alarm + // + this.dgv_Alarm.AllowUserToAddRows = false; + this.dgv_Alarm.AllowUserToDeleteRows = false; + this.dgv_Alarm.AllowUserToResizeColumns = false; + this.dgv_Alarm.AllowUserToResizeRows = false; + this.dgv_Alarm.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.dgv_Alarm.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.dgv_Alarm.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle7.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle7.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle7.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle7.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle7.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle7.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgv_Alarm.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle7; + this.dgv_Alarm.ColumnHeadersHeight = 30; + this.dgv_Alarm.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.dgv_Alarm.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.AlarmLogDateTime, + this.AlarmLogAlarmType, + this.AlarmLogALARM}); + dataGridViewCellStyle8.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle8.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle8.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle8.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle8.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle8.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle8.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgv_Alarm.DefaultCellStyle = dataGridViewCellStyle8; + this.dgv_Alarm.EnableHeadersVisualStyles = false; + this.dgv_Alarm.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.dgv_Alarm.Location = new System.Drawing.Point(22, 550); + this.dgv_Alarm.MultiSelect = false; + this.dgv_Alarm.Name = "dgv_Alarm"; + this.dgv_Alarm.ReadOnly = true; + this.dgv_Alarm.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle9.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle9.Font = new System.Drawing.Font("微软雅黑", 10.5F); + dataGridViewCellStyle9.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle9.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle9.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle9.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgv_Alarm.RowHeadersDefaultCellStyle = dataGridViewCellStyle9; + this.dgv_Alarm.RowHeadersWidth = 120; + this.dgv_Alarm.RowTemplate.Height = 23; + this.dgv_Alarm.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgv_Alarm.Size = new System.Drawing.Size(1827, 266); + this.dgv_Alarm.TabIndex = 5; + this.dgv_Alarm.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dgv_Log_RowPostPaint); + // + // AlarmLogDateTime + // + this.AlarmLogDateTime.HeaderText = "日期时间"; + this.AlarmLogDateTime.MinimumWidth = 6; + this.AlarmLogDateTime.Name = "AlarmLogDateTime"; + this.AlarmLogDateTime.ReadOnly = true; + this.AlarmLogDateTime.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.AlarmLogDateTime.Width = 200; + // + // AlarmLogAlarmType + // + this.AlarmLogAlarmType.HeaderText = "报警类型"; + this.AlarmLogAlarmType.MinimumWidth = 6; + this.AlarmLogAlarmType.Name = "AlarmLogAlarmType"; + this.AlarmLogAlarmType.ReadOnly = true; + this.AlarmLogAlarmType.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.AlarmLogAlarmType.Width = 200; + // + // AlarmLogALARM + // + this.AlarmLogALARM.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.AlarmLogALARM.HeaderText = "报警信息"; + this.AlarmLogALARM.MinimumWidth = 6; + this.AlarmLogALARM.Name = "AlarmLogALARM"; + this.AlarmLogALARM.ReadOnly = true; + this.AlarmLogALARM.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // lblSystemAlarm + // + this.lblSystemAlarm.BackColor = System.Drawing.Color.Transparent; + this.lblSystemAlarm.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblSystemAlarm.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(246)))), ((int)(((byte)(255))))); + this.lblSystemAlarm.Location = new System.Drawing.Point(43, 555); + this.lblSystemAlarm.Name = "lblSystemAlarm"; + this.lblSystemAlarm.Size = new System.Drawing.Size(89, 19); + this.lblSystemAlarm.TabIndex = 9; + this.lblSystemAlarm.Text = "系统报警"; + // + // FrmAlarmLog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 23F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.ClientSize = new System.Drawing.Size(1874, 816); + this.Controls.Add(this.lblOperationLog); + this.Controls.Add(this.lblSystemAlarm); + this.Controls.Add(this.dgv_Alarm); + this.Controls.Add(this.dgv_OPLog); + this.Controls.Add(this.lblSystemLog); + this.Controls.Add(this.dgv_Log); + this.Font = new System.Drawing.Font("微软雅黑", 10.5F); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "FrmAlarmLog"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "日志报警"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + ((System.ComponentModel.ISupportInitialize)(this.dgv_OPLog)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.dgv_Log)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.dgv_Alarm)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.DataGridView dgv_OPLog; + private System.Windows.Forms.DataGridView dgv_Log; + private System.Windows.Forms.Label lblSystemLog; + private System.Windows.Forms.Label lblOperationLog; + private System.Windows.Forms.DataGridView dgv_Alarm; + private System.Windows.Forms.Label lblSystemAlarm; + private System.Windows.Forms.DataGridViewTextBoxColumn OPLogDateTime; + private System.Windows.Forms.DataGridViewTextBoxColumn OPLogOperationType; + private System.Windows.Forms.DataGridViewTextBoxColumn OPLogOperationalMessage; + private System.Windows.Forms.DataGridViewTextBoxColumn LogDateTime; + private System.Windows.Forms.DataGridViewTextBoxColumn LogDateType; + private System.Windows.Forms.DataGridViewTextBoxColumn LogDateInformation; + private System.Windows.Forms.DataGridViewTextBoxColumn AlarmLogDateTime; + private System.Windows.Forms.DataGridViewTextBoxColumn AlarmLogAlarmType; + private System.Windows.Forms.DataGridViewTextBoxColumn AlarmLogALARM; + } +} \ No newline at end of file diff --git a/LargeSquareOne/FrmAlarmLog.cs b/LargeSquareOne/FrmAlarmLog.cs new file mode 100644 index 0000000..06ba51c --- /dev/null +++ b/LargeSquareOne/FrmAlarmLog.cs @@ -0,0 +1,191 @@ +using JinYuan.Helper; +using JinYuan.Models; +using JinYuan.VirtualDataLibrary; +using Language; +using System; +using System.Windows.Forms; + +namespace LargeSquareOne +{ + public partial class FrmAlarmLog : MultiLanguageForm + { + public FrmAlarmLog() + { + InitializeComponent(); + } + + private string CurrentTime + { + get { return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } + } + + /// + /// 通用的添加系统日志 + /// + /// + /// + public async void AddLog(bool isError, string info) + { + if (dgv_Log.InvokeRequired) + { + this.dgv_Log.Invoke(new Action(AddLog), isError, info); + } + else + { + + int rowCount = this.dgv_Log.Rows.Add(); + this.dgv_Log.Rows[rowCount].Cells[0].Value = CurrentTime; + this.dgv_Log.Rows[rowCount].Cells[1].Value = isError ? "错误".Translated() : "信息".Translated(); + this.dgv_Log.Rows[rowCount].Cells[2].Value = info; + // 设置最新行为活动行 (当前行) + this.dgv_Log.CurrentCell = this.dgv_Log.Rows[this.dgv_Log.Rows.Count - 1].Cells[0]; + + //dgv清理 + if (this.dgv_Log.RowCount > 300) + { + //this.dgv_Log.Rows.RemoveAt(0); + this.dgv_Log.Rows.Clear(); + GC.Collect(); + } + } + + //存储到数据库 + + //await CommonMethods.db.AddReturnBoolAsync(new SysLog() + //{ + // InsertTime = CurrentTime, + // LogType = "系统日志".Translated(), + // Note = info, + // AlarmType = isError ? "错误".Translated() : "信息".Translated(), + // Operater = CommonMethods.currentAdmin.LoginName + //}); + + } + + /// + /// 通用的添加操作日志 + /// + /// + /// + public async void AddOPLog(bool isError, string info) + { + if (this.dgv_OPLog.InvokeRequired) + { + this.dgv_OPLog.Invoke(new Action(AddOPLog), isError, info); + } + else + { + int rowCount = this.dgv_OPLog.Rows.Add(); + this.dgv_OPLog.Rows[rowCount].Cells[0].Value = CurrentTime; + this.dgv_OPLog.Rows[rowCount].Cells[1].Value = isError ? "错误".Translated() : "信息".Translated(); + this.dgv_OPLog.Rows[rowCount].Cells[2].Value = info; + // 设置最新行为活动行 (当前行) + this.dgv_OPLog.CurrentCell = this.dgv_OPLog.Rows[this.dgv_OPLog.Rows.Count - 1].Cells[0]; + + //dgv清理 + if (this.dgv_OPLog.RowCount > 300) + { + //this.dgv_OPLog.Rows.RemoveAt(0); + this.dgv_OPLog.Rows.Clear(); + GC.Collect(); + } + } + + //存储到数据库 + + //await CommonMethods.db.AddReturnBoolAsync(new SysLog() + //{ + // InsertTime = CurrentTime, + // LogType = "操作日志".Translated(), + // Note = info, + // AlarmType = isError ? "错误".Translated() : "信息".Translated(), + // Operater = CommonMethods.currentAdmin.LoginName + //}); + + + } + + /// + /// 通用的添加报警信息 + /// + /// sh + /// + public async void AddAlarm(SysLog sysLog) + { + if (this.dgv_Alarm.InvokeRequired) + { + this.dgv_Alarm.Invoke(new Action(AddAlarm), sysLog); + } + else + { + int rowCount = this.dgv_Alarm.Rows.Add(); + this.dgv_Alarm.Rows[rowCount].Cells[0].Value = sysLog.InsertTime; + this.dgv_Alarm.Rows[rowCount].Cells[1].Value = sysLog.AlarmType; + this.dgv_Alarm.Rows[rowCount].Cells[2].Value = sysLog.Note; + // 设置最新行为活动行 (当前行) + this.dgv_Alarm.CurrentCell = this.dgv_Alarm.Rows[this.dgv_Alarm.Rows.Count - 1].Cells[0]; + } + + //dgv清理 + if (this.dgv_Alarm.RowCount > 300) + { + //this.dgv_Alarm.Rows.RemoveAt(0); + this.dgv_Alarm.Rows.Clear(); + GC.Collect(); + } + + //存储到数据库 + await CommonMethods.db.AddReturnBoolAsync(sysLog).ConfigureAwait(false); + + } + + /// + /// 通用的添加并显示报警信息 + /// + /// sh + /// + public void ShowAlarm(string info) + { + if (this.dgv_Alarm.InvokeRequired) + { + this.dgv_Alarm.Invoke(new Action(ShowAlarm), info); + } + else + { + int rowCount = this.dgv_Alarm.Rows.Add(); + this.dgv_Alarm.Rows[rowCount].Cells[0].Value = CurrentTime; + this.dgv_Alarm.Rows[rowCount].Cells[1].Value = "停机报警"; + this.dgv_Alarm.Rows[rowCount].Cells[2].Value = info; + // 设置最新行为活动行 (当前行) + this.dgv_Alarm.CurrentCell = this.dgv_Alarm.Rows[this.dgv_Alarm.Rows.Count - 1].Cells[0]; + + + //dgv清理 + if (this.dgv_Alarm.RowCount > 300) + { + //this.dgv_Alarm.Rows.RemoveAt(0); + this.dgv_Alarm.Rows.Clear(); + GC.Collect(); + } + } + } + + private void dgv_Log_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) + { + DataGridViewHelper.DgvRowPostPaint((DataGridView)sender, e); + } + + #region 减少闪烁 + protected override CreateParams CreateParams + { + get + { + CreateParams parss = base.CreateParams; + parss.ExStyle |= 0x02000000; + return parss; + } + } + #endregion + + } +} diff --git a/LargeSquareOne/FrmAlarmLog.resx b/LargeSquareOne/FrmAlarmLog.resx new file mode 100644 index 0000000..0203ec6 --- /dev/null +++ b/LargeSquareOne/FrmAlarmLog.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/LargeSquareOne/FrmBatteryStatus.Designer.cs b/LargeSquareOne/FrmBatteryStatus.Designer.cs new file mode 100644 index 0000000..2a3f8cb --- /dev/null +++ b/LargeSquareOne/FrmBatteryStatus.Designer.cs @@ -0,0 +1,1000 @@ +using System.Windows.Forms; + +namespace LargeSquareOne +{ + partial class FrmBatteryStatus + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panelSample = new System.Windows.Forms.Panel(); + this.lbl_Init = new System.Windows.Forms.Label(); + this.lbl_Replace = new System.Windows.Forms.Label(); + this.lbl_PackNG = new System.Windows.Forms.Label(); + this.lbl_statusNomal = new System.Windows.Forms.Label(); + this.BatteryControl_Normal = new JinYuan.ControlLib.BatteryControl(JinYuan.ControlLib.BatteryStatus.Normal); + this.BatteryControl_PackNG = new JinYuan.ControlLib.BatteryControl(JinYuan.ControlLib.BatteryStatus.PackNG); + this.BatteryControl_Replacing = new JinYuan.ControlLib.BatteryControl(JinYuan.ControlLib.BatteryStatus.Replacing); + this.BatteryControl_init = new JinYuan.ControlLib.BatteryControl(JinYuan.ControlLib.BatteryStatus.Init); + this.panelExt1 = new System.Windows.Forms.Panel(); + this.button1 = new System.Windows.Forms.Button(); + this.btn_repacking = new System.Windows.Forms.Button(); + this.btn_clear = new System.Windows.Forms.Button(); + this.btn_ForceOut = new System.Windows.Forms.Button(); + this.btn_SubBarcode = new System.Windows.Forms.Button(); + this.txtBox_SubBarcode = new System.Windows.Forms.TextBox(); + this.lbl_SubBarcode = new System.Windows.Forms.Label(); + this.txtBox_Carton = new System.Windows.Forms.TextBox(); + this.lbl_Carton = new System.Windows.Forms.Label(); + this.txtBox_Row = new System.Windows.Forms.TextBox(); + this.lbl_row = new System.Windows.Forms.Label(); + this.btn_Search = new System.Windows.Forms.Button(); + this.txtBox_Barcode = new System.Windows.Forms.TextBox(); + this.lbl_barcode = new System.Windows.Forms.Label(); + this.tabBattery = new HML.TabControlPlus(); + this.tabPagePlus1 = new HML.TabPagePlus(); + this.panelExt_Grade1 = new JinYuan.ControlLib.PanelExt(); + this.tabPagePlus2 = new HML.TabPagePlus(); + this.panelExt_Grade2 = new JinYuan.ControlLib.PanelExt(); + this.tabPagePlus3 = new HML.TabPagePlus(); + this.panelExt_Grade3 = new JinYuan.ControlLib.PanelExt(); + this.groupBoxEX9 = new JinYuan.ControlLib.GroupBoxEX(); + this.dgv_ngRsn = new System.Windows.Forms.DataGridView(); + this.identification = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.location = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.grade = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.containerCode = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.packResult = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.packFalseReason = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.packTime = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.groupBoxEX8 = new JinYuan.ControlLib.GroupBoxEX(); + this.dgvReplaceBattery = new System.Windows.Forms.DataGridView(); + this.NewBarCode = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.OldBarCode = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.VassoioID = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.GongWei = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dataGridViewTextBoxColumn12 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dataGridViewTextBoxColumn15 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.tableLayoutPanel1.SuspendLayout(); + this.panelSample.SuspendLayout(); + this.panelExt1.SuspendLayout(); + this.tabBattery.SuspendLayout(); + this.tabPagePlus1.SuspendLayout(); + this.tabPagePlus2.SuspendLayout(); + this.tabPagePlus3.SuspendLayout(); + this.groupBoxEX9.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dgv_ngRsn)).BeginInit(); + this.groupBoxEX8.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dgvReplaceBattery)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tableLayoutPanel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 405F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.panelSample, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.panelExt1, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.tabBattery, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.groupBoxEX9, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.groupBoxEX8, 1, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 60F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 60F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 40F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(1406, 653); + this.tableLayoutPanel1.TabIndex = 0; + // + // panelSample + // + this.panelSample.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelSample.Controls.Add(this.lbl_Init); + this.panelSample.Controls.Add(this.lbl_Replace); + this.panelSample.Controls.Add(this.lbl_PackNG); + this.panelSample.Controls.Add(this.lbl_statusNomal); + this.panelSample.Controls.Add(this.BatteryControl_Normal); + this.panelSample.Controls.Add(this.BatteryControl_PackNG); + this.panelSample.Controls.Add(this.BatteryControl_Replacing); + this.panelSample.Controls.Add(this.BatteryControl_init); + this.panelSample.Location = new System.Drawing.Point(8, 8); + this.panelSample.Margin = new System.Windows.Forms.Padding(8, 8, 8, 8); + this.panelSample.Name = "panelSample"; + this.panelSample.Size = new System.Drawing.Size(389, 44); + this.panelSample.TabIndex = 0; + // + // lbl_Init + // + this.lbl_Init.AutoSize = true; + this.lbl_Init.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.lbl_Init.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Init.ForeColor = System.Drawing.Color.White; + this.lbl_Init.Location = new System.Drawing.Point(38, 17); + this.lbl_Init.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_Init.Name = "lbl_Init"; + this.lbl_Init.Size = new System.Drawing.Size(44, 17); + this.lbl_Init.TabIndex = 7; + this.lbl_Init.Text = "未绑定"; + // + // lbl_Replace + // + this.lbl_Replace.AutoSize = true; + this.lbl_Replace.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.lbl_Replace.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Replace.ForeColor = System.Drawing.Color.White; + this.lbl_Replace.Location = new System.Drawing.Point(316, 17); + this.lbl_Replace.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_Replace.Name = "lbl_Replace"; + this.lbl_Replace.Size = new System.Drawing.Size(44, 17); + this.lbl_Replace.TabIndex = 6; + this.lbl_Replace.Text = "替换中"; + // + // lbl_PackNG + // + this.lbl_PackNG.AutoSize = true; + this.lbl_PackNG.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.lbl_PackNG.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_PackNG.ForeColor = System.Drawing.Color.White; + this.lbl_PackNG.Location = new System.Drawing.Point(125, 17); + this.lbl_PackNG.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_PackNG.Name = "lbl_PackNG"; + this.lbl_PackNG.Size = new System.Drawing.Size(51, 17); + this.lbl_PackNG.TabIndex = 5; + this.lbl_PackNG.Text = "绑定NG"; + // + // lbl_statusNomal + // + this.lbl_statusNomal.AutoSize = true; + this.lbl_statusNomal.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.lbl_statusNomal.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_statusNomal.ForeColor = System.Drawing.Color.White; + this.lbl_statusNomal.Location = new System.Drawing.Point(220, 17); + this.lbl_statusNomal.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_statusNomal.Name = "lbl_statusNomal"; + this.lbl_statusNomal.Size = new System.Drawing.Size(50, 17); + this.lbl_statusNomal.TabIndex = 4; + this.lbl_statusNomal.Text = "绑定OK"; + // + // BatteryControl_Normal + // + this.BatteryControl_Normal.Anchor = System.Windows.Forms.AnchorStyles.None; + this.BatteryControl_Normal.AutoSize = true; + this.BatteryControl_Normal.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BatteryControl_Normal.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24))))); + this.BatteryControl_Normal.Barcode = null; + this.BatteryControl_Normal.BlinkColor = System.Drawing.Color.Lime; + this.BatteryControl_Normal.BlinkInterval = 1000; + this.BatteryControl_Normal.BlinkOn = false; + this.BatteryControl_Normal.Col = 0; + this.BatteryControl_Normal.Container = ""; + this.BatteryControl_Normal.Cursor = System.Windows.Forms.Cursors.Arrow; + this.BatteryControl_Normal.ForeColor = System.Drawing.Color.LimeGreen; + this.BatteryControl_Normal.Grade = ""; + this.BatteryControl_Normal.Interacton = SeeSharpTools.JY.GUI.LED.InteractionStyle.Indicator; + this.BatteryControl_Normal.Layer = 0; + this.BatteryControl_Normal.Location = new System.Drawing.Point(189, 7); + this.BatteryControl_Normal.Margin = new System.Windows.Forms.Padding(2); + this.BatteryControl_Normal.MaximumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_Normal.MinimumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_Normal.Name = "BatteryControl_Normal"; + this.BatteryControl_Normal.OffColor = System.Drawing.Color.Gray; + this.BatteryControl_Normal.OnColor = System.Drawing.Color.Lime; + this.BatteryControl_Normal.Row = 0; + this.BatteryControl_Normal.Size = new System.Drawing.Size(26, 28); + this.BatteryControl_Normal.Status = JinYuan.ControlLib.BatteryStatus.Normal; + this.BatteryControl_Normal.Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular; + this.BatteryControl_Normal.TabIndex = 8; + this.BatteryControl_Normal.Value = true; + // + // BatteryControl_PackNG + // + this.BatteryControl_PackNG.Anchor = System.Windows.Forms.AnchorStyles.None; + this.BatteryControl_PackNG.AutoScroll = true; + this.BatteryControl_PackNG.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BatteryControl_PackNG.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24))))); + this.BatteryControl_PackNG.Barcode = null; + this.BatteryControl_PackNG.BlinkColor = System.Drawing.Color.Lime; + this.BatteryControl_PackNG.BlinkInterval = 1000; + this.BatteryControl_PackNG.BlinkOn = false; + this.BatteryControl_PackNG.Col = 0; + this.BatteryControl_PackNG.Container = ""; + this.BatteryControl_PackNG.Cursor = System.Windows.Forms.Cursors.Arrow; + this.BatteryControl_PackNG.ForeColor = System.Drawing.Color.Red; + this.BatteryControl_PackNG.Grade = ""; + this.BatteryControl_PackNG.Interacton = SeeSharpTools.JY.GUI.LED.InteractionStyle.Indicator; + this.BatteryControl_PackNG.Layer = 0; + this.BatteryControl_PackNG.Location = new System.Drawing.Point(94, 7); + this.BatteryControl_PackNG.Margin = new System.Windows.Forms.Padding(2); + this.BatteryControl_PackNG.MaximumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_PackNG.MinimumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_PackNG.Name = "BatteryControl_PackNG"; + this.BatteryControl_PackNG.OffColor = System.Drawing.Color.Gray; + this.BatteryControl_PackNG.OnColor = System.Drawing.Color.Red; + this.BatteryControl_PackNG.Row = 0; + this.BatteryControl_PackNG.Size = new System.Drawing.Size(26, 28); + this.BatteryControl_PackNG.Status = JinYuan.ControlLib.BatteryStatus.PackNG; + this.BatteryControl_PackNG.Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular; + this.BatteryControl_PackNG.TabIndex = 9; + this.BatteryControl_PackNG.Value = true; + // + // BatteryControl_Replacing + // + this.BatteryControl_Replacing.Anchor = System.Windows.Forms.AnchorStyles.None; + this.BatteryControl_Replacing.AutoSize = true; + this.BatteryControl_Replacing.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BatteryControl_Replacing.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24))))); + this.BatteryControl_Replacing.Barcode = null; + this.BatteryControl_Replacing.BlinkColor = System.Drawing.Color.Lime; + this.BatteryControl_Replacing.BlinkInterval = 1000; + this.BatteryControl_Replacing.BlinkOn = false; + this.BatteryControl_Replacing.Col = 0; + this.BatteryControl_Replacing.Container = ""; + this.BatteryControl_Replacing.Cursor = System.Windows.Forms.Cursors.Arrow; + this.BatteryControl_Replacing.ForeColor = System.Drawing.Color.SkyBlue; + this.BatteryControl_Replacing.Grade = ""; + this.BatteryControl_Replacing.Interacton = SeeSharpTools.JY.GUI.LED.InteractionStyle.Indicator; + this.BatteryControl_Replacing.Layer = 0; + this.BatteryControl_Replacing.Location = new System.Drawing.Point(285, 7); + this.BatteryControl_Replacing.Margin = new System.Windows.Forms.Padding(2); + this.BatteryControl_Replacing.MaximumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_Replacing.MinimumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_Replacing.Name = "BatteryControl_Replacing"; + this.BatteryControl_Replacing.OffColor = System.Drawing.Color.Gray; + this.BatteryControl_Replacing.OnColor = System.Drawing.Color.Cyan; + this.BatteryControl_Replacing.Row = 0; + this.BatteryControl_Replacing.Size = new System.Drawing.Size(26, 28); + this.BatteryControl_Replacing.Status = JinYuan.ControlLib.BatteryStatus.Replacing; + this.BatteryControl_Replacing.Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular; + this.BatteryControl_Replacing.TabIndex = 10; + this.BatteryControl_Replacing.Value = true; + // + // BatteryControl_init + // + this.BatteryControl_init.Anchor = System.Windows.Forms.AnchorStyles.None; + this.BatteryControl_init.AutoScroll = true; + this.BatteryControl_init.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BatteryControl_init.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24))))); + this.BatteryControl_init.Barcode = null; + this.BatteryControl_init.BlinkColor = System.Drawing.Color.Lime; + this.BatteryControl_init.BlinkInterval = 1000; + this.BatteryControl_init.BlinkOn = false; + this.BatteryControl_init.Col = 0; + this.BatteryControl_init.Container = ""; + this.BatteryControl_init.Cursor = System.Windows.Forms.Cursors.Arrow; + this.BatteryControl_init.Grade = ""; + this.BatteryControl_init.Interacton = SeeSharpTools.JY.GUI.LED.InteractionStyle.Indicator; + this.BatteryControl_init.Layer = 0; + this.BatteryControl_init.Location = new System.Drawing.Point(7, 7); + this.BatteryControl_init.Margin = new System.Windows.Forms.Padding(2); + this.BatteryControl_init.MaximumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_init.MinimumSize = new System.Drawing.Size(26, 28); + this.BatteryControl_init.Name = "BatteryControl_init"; + this.BatteryControl_init.OffColor = System.Drawing.Color.Gray; + this.BatteryControl_init.OnColor = System.Drawing.Color.Lime; + this.BatteryControl_init.Row = 0; + this.BatteryControl_init.Size = new System.Drawing.Size(26, 28); + this.BatteryControl_init.Status = JinYuan.ControlLib.BatteryStatus.Init; + this.BatteryControl_init.Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular; + this.BatteryControl_init.TabIndex = 11; + this.BatteryControl_init.Value = false; + // + // panelExt1 + // + this.panelExt1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt1.Controls.Add(this.button1); + this.panelExt1.Controls.Add(this.btn_repacking); + this.panelExt1.Controls.Add(this.btn_clear); + this.panelExt1.Controls.Add(this.btn_ForceOut); + this.panelExt1.Controls.Add(this.btn_SubBarcode); + this.panelExt1.Controls.Add(this.txtBox_SubBarcode); + this.panelExt1.Controls.Add(this.lbl_SubBarcode); + this.panelExt1.Controls.Add(this.txtBox_Carton); + this.panelExt1.Controls.Add(this.lbl_Carton); + this.panelExt1.Controls.Add(this.txtBox_Row); + this.panelExt1.Controls.Add(this.lbl_row); + this.panelExt1.Controls.Add(this.btn_Search); + this.panelExt1.Controls.Add(this.txtBox_Barcode); + this.panelExt1.Controls.Add(this.lbl_barcode); + this.panelExt1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelExt1.Location = new System.Drawing.Point(407, 2); + this.panelExt1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.panelExt1.Name = "panelExt1"; + this.panelExt1.Size = new System.Drawing.Size(995, 56); + this.panelExt1.TabIndex = 1; + // + // button1 + // + this.button1.BackColor = System.Drawing.Color.Transparent; + this.button1.Enabled = false; + this.button1.Visible = false; + this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.button1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.button1.ForeColor = System.Drawing.Color.White; + this.button1.Location = new System.Drawing.Point(844, 18); + this.button1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(51, 26); + this.button1.TabIndex = 13; + this.button1.Text = "测试"; + this.button1.UseVisualStyleBackColor = false; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // btn_repacking + // + this.btn_repacking.BackColor = System.Drawing.Color.Transparent; + this.btn_repacking.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_repacking.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_repacking.ForeColor = System.Drawing.Color.White; + this.btn_repacking.Location = new System.Drawing.Point(1208, 26); + this.btn_repacking.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.btn_repacking.Name = "btn_repacking"; + this.btn_repacking.Size = new System.Drawing.Size(118, 26); + this.btn_repacking.TabIndex = 12; + this.btn_repacking.Text = "重新请求绑定托盘"; + this.btn_repacking.UseVisualStyleBackColor = false; + this.btn_repacking.Visible = false; + // + // btn_clear + // + this.btn_clear.BackColor = System.Drawing.Color.Transparent; + this.btn_clear.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_clear.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_clear.ForeColor = System.Drawing.Color.White; + this.btn_clear.Location = new System.Drawing.Point(759, 22); + this.btn_clear.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.btn_clear.Name = "btn_clear"; + this.btn_clear.Size = new System.Drawing.Size(68, 26); + this.btn_clear.TabIndex = 11; + this.btn_clear.Text = "全部清除"; + this.btn_clear.UseVisualStyleBackColor = false; + this.btn_clear.Click += new System.EventHandler(this.btn_clear_Click); + // + // btn_ForceOut + // + this.btn_ForceOut.BackColor = System.Drawing.Color.Transparent; + this.btn_ForceOut.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_ForceOut.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_ForceOut.ForeColor = System.Drawing.Color.Red; + this.btn_ForceOut.Location = new System.Drawing.Point(899, 14); + this.btn_ForceOut.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.btn_ForceOut.Name = "btn_ForceOut"; + this.btn_ForceOut.Size = new System.Drawing.Size(94, 36); + this.btn_ForceOut.TabIndex = 10; + this.btn_ForceOut.Text = "强制放行"; + this.btn_ForceOut.UseVisualStyleBackColor = false; + this.btn_ForceOut.Visible = false; + // + // btn_SubBarcode + // + this.btn_SubBarcode.BackColor = System.Drawing.Color.Transparent; + this.btn_SubBarcode.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_SubBarcode.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_SubBarcode.ForeColor = System.Drawing.Color.White; + this.btn_SubBarcode.Location = new System.Drawing.Point(660, 22); + this.btn_SubBarcode.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.btn_SubBarcode.Name = "btn_SubBarcode"; + this.btn_SubBarcode.Size = new System.Drawing.Size(95, 26); + this.btn_SubBarcode.TabIndex = 9; + this.btn_SubBarcode.Text = "确认电芯替换"; + this.btn_SubBarcode.UseVisualStyleBackColor = false; + this.btn_SubBarcode.Click += new System.EventHandler(this.btn_SubBarcode_Click); + // + // txtBox_SubBarcode + // + this.txtBox_SubBarcode.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtBox_SubBarcode.ForeColor = System.Drawing.Color.Black; + this.txtBox_SubBarcode.Location = new System.Drawing.Point(502, 27); + this.txtBox_SubBarcode.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.txtBox_SubBarcode.Name = "txtBox_SubBarcode"; + this.txtBox_SubBarcode.Size = new System.Drawing.Size(148, 23); + this.txtBox_SubBarcode.TabIndex = 8; + // + // lbl_SubBarcode + // + this.lbl_SubBarcode.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_SubBarcode.ForeColor = System.Drawing.Color.White; + this.lbl_SubBarcode.Location = new System.Drawing.Point(499, 7); + this.lbl_SubBarcode.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_SubBarcode.Name = "lbl_SubBarcode"; + this.lbl_SubBarcode.Size = new System.Drawing.Size(137, 22); + this.lbl_SubBarcode.TabIndex = 7; + this.lbl_SubBarcode.Text = "新电芯条码(替换后)"; + // + // txtBox_Carton + // + this.txtBox_Carton.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtBox_Carton.ForeColor = System.Drawing.Color.Black; + this.txtBox_Carton.Location = new System.Drawing.Point(344, 27); + this.txtBox_Carton.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.txtBox_Carton.Name = "txtBox_Carton"; + this.txtBox_Carton.Size = new System.Drawing.Size(138, 23); + this.txtBox_Carton.TabIndex = 6; + // + // lbl_Carton + // + this.lbl_Carton.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_Carton.ForeColor = System.Drawing.Color.White; + this.lbl_Carton.Location = new System.Drawing.Point(341, 7); + this.lbl_Carton.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_Carton.Name = "lbl_Carton"; + this.lbl_Carton.Size = new System.Drawing.Size(54, 19); + this.lbl_Carton.TabIndex = 5; + this.lbl_Carton.Text = "箱唛码"; + // + // txtBox_Row + // + this.txtBox_Row.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtBox_Row.ForeColor = System.Drawing.Color.Black; + this.txtBox_Row.Location = new System.Drawing.Point(15, 27); + this.txtBox_Row.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.txtBox_Row.Name = "txtBox_Row"; + this.txtBox_Row.Size = new System.Drawing.Size(74, 23); + this.txtBox_Row.TabIndex = 4; + // + // lbl_row + // + this.lbl_row.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_row.ForeColor = System.Drawing.Color.White; + this.lbl_row.Location = new System.Drawing.Point(12, 7); + this.lbl_row.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_row.Name = "lbl_row"; + this.lbl_row.Size = new System.Drawing.Size(64, 18); + this.lbl_row.TabIndex = 3; + this.lbl_row.Text = "电芯位置"; + // + // btn_Search + // + this.btn_Search.BackColor = System.Drawing.Color.Transparent; + this.btn_Search.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Search.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btn_Search.ForeColor = System.Drawing.Color.White; + this.btn_Search.Location = new System.Drawing.Point(261, 22); + this.btn_Search.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.btn_Search.Name = "btn_Search"; + this.btn_Search.Size = new System.Drawing.Size(68, 26); + this.btn_Search.TabIndex = 2; + this.btn_Search.Text = "查询"; + this.btn_Search.UseVisualStyleBackColor = false; + this.btn_Search.Click += new System.EventHandler(this.btn_Search_Click); + // + // txtBox_Barcode + // + this.txtBox_Barcode.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtBox_Barcode.ForeColor = System.Drawing.Color.Black; + this.txtBox_Barcode.Location = new System.Drawing.Point(101, 27); + this.txtBox_Barcode.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.txtBox_Barcode.Name = "txtBox_Barcode"; + this.txtBox_Barcode.Size = new System.Drawing.Size(148, 23); + this.txtBox_Barcode.TabIndex = 1; + // + // lbl_barcode + // + this.lbl_barcode.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lbl_barcode.ForeColor = System.Drawing.Color.White; + this.lbl_barcode.Location = new System.Drawing.Point(98, 7); + this.lbl_barcode.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lbl_barcode.Name = "lbl_barcode"; + this.lbl_barcode.Size = new System.Drawing.Size(94, 18); + this.lbl_barcode.TabIndex = 0; + this.lbl_barcode.Text = "电芯条码(待替换)"; + // + // tabBattery + // + this.tabBattery.ContentBorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.tabBattery.Controls.Add(this.tabPagePlus1); + this.tabBattery.Controls.Add(this.tabPagePlus2); + this.tabBattery.Controls.Add(this.tabPagePlus3); + this.tabBattery.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabBattery.Location = new System.Drawing.Point(3, 63); + this.tabBattery.Name = "tabBattery"; + this.tabBattery.Picker.ItemFont = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.tableLayoutPanel1.SetRowSpan(this.tabBattery, 2); + this.tabBattery.Size = new System.Drawing.Size(399, 585); + this.tabBattery.TabBarBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tabBattery.TabIndex = 1; + this.tabBattery.TabItemAutoWidth = true; + this.tabBattery.TabItemBackEnterColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tabBattery.TabItemBackNormalColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tabBattery.TabItemBackSelectedColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.tabBattery.TabItemFont = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.tabBattery.TabItemIcoSize = new System.Drawing.Size(32, 32); + this.tabBattery.TabItemSize = new System.Drawing.Size(150, 30); + // + // tabPagePlus1 + // + this.tabPagePlus1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tabPagePlus1.Controls.Add(this.panelExt_Grade1); + this.tabPagePlus1.Location = new System.Drawing.Point(1, 31); + this.tabPagePlus1.Name = "tabPagePlus1"; + this.tabPagePlus1.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); + this.tabPagePlus1.Size = new System.Drawing.Size(397, 553); + this.tabPagePlus1.TabIndex = 0; + this.tabPagePlus1.Text = "Grade1"; + // + // panelExt_Grade1 + // + this.panelExt_Grade1.AutoScroll = true; + this.panelExt_Grade1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt_Grade1.BordeColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt_Grade1.BordeWidth = 0; + this.panelExt_Grade1.BottomGap = 0; + this.panelExt_Grade1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelExt_Grade1.LeftGap = 0; + this.panelExt_Grade1.Location = new System.Drawing.Point(3, 3); + this.panelExt_Grade1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.panelExt_Grade1.Name = "panelExt_Grade1"; + this.panelExt_Grade1.RightGap = 0; + this.panelExt_Grade1.Size = new System.Drawing.Size(391, 547); + this.panelExt_Grade1.TabIndex = 0; + this.panelExt_Grade1.TopGap = 0; + // + // tabPagePlus2 + // + this.tabPagePlus2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tabPagePlus2.Controls.Add(this.panelExt_Grade2); + this.tabPagePlus2.Location = new System.Drawing.Point(1, 31); + this.tabPagePlus2.Name = "tabPagePlus2"; + this.tabPagePlus2.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); + this.tabPagePlus2.Size = new System.Drawing.Size(397, 553); + this.tabPagePlus2.TabIndex = 0; + this.tabPagePlus2.Text = "Grade2"; + // + // panelExt_Grade2 + // + this.panelExt_Grade2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt_Grade2.BordeColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt_Grade2.BordeWidth = 2; + this.panelExt_Grade2.BottomGap = 0; + this.panelExt_Grade2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelExt_Grade2.LeftGap = 0; + this.panelExt_Grade2.Location = new System.Drawing.Point(3, 3); + this.panelExt_Grade2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.panelExt_Grade2.Name = "panelExt_Grade2"; + this.panelExt_Grade2.RightGap = 0; + this.panelExt_Grade2.Size = new System.Drawing.Size(391, 547); + this.panelExt_Grade2.TabIndex = 0; + this.panelExt_Grade2.TopGap = 0; + // + // tabPagePlus3 + // + this.tabPagePlus3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.tabPagePlus3.Controls.Add(this.panelExt_Grade3); + this.tabPagePlus3.Location = new System.Drawing.Point(1, 31); + this.tabPagePlus3.Name = "tabPagePlus3"; + this.tabPagePlus3.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); + this.tabPagePlus3.Size = new System.Drawing.Size(397, 553); + this.tabPagePlus3.TabIndex = 0; + this.tabPagePlus3.Text = "Grade3"; + // + // panelExt_Grade3 + // + this.panelExt_Grade3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt_Grade3.BordeColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.panelExt_Grade3.BordeWidth = 2; + this.panelExt_Grade3.BottomGap = 0; + this.panelExt_Grade3.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelExt_Grade3.LeftGap = 0; + this.panelExt_Grade3.Location = new System.Drawing.Point(3, 3); + this.panelExt_Grade3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.panelExt_Grade3.Name = "panelExt_Grade3"; + this.panelExt_Grade3.RightGap = 0; + this.panelExt_Grade3.Size = new System.Drawing.Size(391, 547); + this.panelExt_Grade3.TabIndex = 0; + this.panelExt_Grade3.TopGap = 0; + // + // groupBoxEX9 + // + this.groupBoxEX9.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.groupBoxEX9.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.groupBoxEX9.Controls.Add(this.dgv_ngRsn); + this.groupBoxEX9.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBoxEX9.ForeColor = System.Drawing.Color.White; + this.groupBoxEX9.Location = new System.Drawing.Point(413, 68); + this.groupBoxEX9.Margin = new System.Windows.Forms.Padding(8, 8, 8, 8); + this.groupBoxEX9.Name = "groupBoxEX9"; + this.groupBoxEX9.Padding = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.groupBoxEX9.Size = new System.Drawing.Size(983, 338); + this.groupBoxEX9.TabIndex = 2; + this.groupBoxEX9.TabStop = false; + this.groupBoxEX9.Text = "电池与托盘绑定NG原因"; + // + // dgv_ngRsn + // + this.dgv_ngRsn.AllowUserToAddRows = false; + this.dgv_ngRsn.AllowUserToDeleteRows = false; + this.dgv_ngRsn.AllowUserToResizeColumns = false; + this.dgv_ngRsn.AllowUserToResizeRows = false; + this.dgv_ngRsn.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.dgv_ngRsn.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.dgv_ngRsn.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + dataGridViewCellStyle1.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle1.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgv_ngRsn.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1; + this.dgv_ngRsn.ColumnHeadersHeight = 35; + this.dgv_ngRsn.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.dgv_ngRsn.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.identification, + this.location, + this.grade, + this.containerCode, + this.packResult, + this.packFalseReason, + this.packTime}); + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + dataGridViewCellStyle2.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle2.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgv_ngRsn.DefaultCellStyle = dataGridViewCellStyle2; + this.dgv_ngRsn.Dock = System.Windows.Forms.DockStyle.Fill; + this.dgv_ngRsn.EnableHeadersVisualStyles = false; + this.dgv_ngRsn.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(53)))), ((int)(((byte)(96))))); + this.dgv_ngRsn.Location = new System.Drawing.Point(2, 16); + this.dgv_ngRsn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.dgv_ngRsn.Name = "dgv_ngRsn"; + this.dgv_ngRsn.ReadOnly = true; + this.dgv_ngRsn.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(41)))), ((int)(((byte)(96))))); + dataGridViewCellStyle3.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + dataGridViewCellStyle3.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle3.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(41)))), ((int)(((byte)(96))))); + dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgv_ngRsn.RowHeadersDefaultCellStyle = dataGridViewCellStyle3; + this.dgv_ngRsn.RowHeadersWidth = 51; + this.dgv_ngRsn.RowTemplate.Height = 27; + this.dgv_ngRsn.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgv_ngRsn.Size = new System.Drawing.Size(979, 320); + this.dgv_ngRsn.TabIndex = 3; + this.dgv_ngRsn.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dgv_ngRsn_RowPostPaint); + // + // identification + // + this.identification.DataPropertyName = "identification"; + this.identification.HeaderText = "电芯条码"; + this.identification.MinimumWidth = 6; + this.identification.Name = "identification"; + this.identification.ReadOnly = true; + this.identification.Width = 125; + // + // location + // + this.location.DataPropertyName = "location"; + this.location.HeaderText = "电芯位置"; + this.location.MinimumWidth = 6; + this.location.Name = "location"; + this.location.ReadOnly = true; + this.location.Width = 125; + // + // grade + // + this.grade.DataPropertyName = "grade"; + this.grade.HeaderText = "电芯档位"; + this.grade.MinimumWidth = 6; + this.grade.Name = "grade"; + this.grade.ReadOnly = true; + this.grade.Width = 125; + // + // containerCode + // + this.containerCode.DataPropertyName = "containerCode"; + this.containerCode.HeaderText = "箱唛码"; + this.containerCode.MinimumWidth = 6; + this.containerCode.Name = "containerCode"; + this.containerCode.ReadOnly = true; + this.containerCode.Width = 125; + // + // packResult + // + this.packResult.DataPropertyName = "packResult"; + this.packResult.HeaderText = "是否绑定卡板"; + this.packResult.MinimumWidth = 6; + this.packResult.Name = "packResult"; + this.packResult.ReadOnly = true; + this.packResult.Width = 125; + // + // packFalseReason + // + this.packFalseReason.DataPropertyName = "packFalseReason"; + this.packFalseReason.HeaderText = "绑定失败原因"; + this.packFalseReason.MinimumWidth = 6; + this.packFalseReason.Name = "packFalseReason"; + this.packFalseReason.ReadOnly = true; + this.packFalseReason.Width = 125; + // + // packTime + // + this.packTime.DataPropertyName = "packTime"; + this.packTime.HeaderText = "绑定时间"; + this.packTime.MinimumWidth = 6; + this.packTime.Name = "packTime"; + this.packTime.ReadOnly = true; + this.packTime.Width = 125; + // + // groupBoxEX8 + // + this.groupBoxEX8.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(14)))), ((int)(((byte)(23)))), ((int)(((byte)(38))))); + this.groupBoxEX8.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.groupBoxEX8.Controls.Add(this.dgvReplaceBattery); + this.groupBoxEX8.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBoxEX8.ForeColor = System.Drawing.Color.White; + this.groupBoxEX8.Location = new System.Drawing.Point(413, 422); + this.groupBoxEX8.Margin = new System.Windows.Forms.Padding(8, 8, 8, 8); + this.groupBoxEX8.Name = "groupBoxEX8"; + this.groupBoxEX8.Padding = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.groupBoxEX8.Size = new System.Drawing.Size(983, 221); + this.groupBoxEX8.TabIndex = 17; + this.groupBoxEX8.TabStop = false; + this.groupBoxEX8.Text = "电池替换"; + // + // dgvReplaceBattery + // + this.dgvReplaceBattery.AllowUserToAddRows = false; + this.dgvReplaceBattery.AllowUserToDeleteRows = false; + this.dgvReplaceBattery.AllowUserToResizeColumns = false; + this.dgvReplaceBattery.AllowUserToResizeRows = false; + this.dgvReplaceBattery.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.dgvReplaceBattery.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.dgvReplaceBattery.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle4.Font = new System.Drawing.Font("微软雅黑", 9F); + dataGridViewCellStyle4.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle4.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgvReplaceBattery.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle4; + this.dgvReplaceBattery.ColumnHeadersHeight = 35; + this.dgvReplaceBattery.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.dgvReplaceBattery.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.NewBarCode, + this.OldBarCode, + this.dataGridViewTextBoxColumn1, + this.dataGridViewTextBoxColumn2, + this.VassoioID, + this.GongWei, + this.dataGridViewTextBoxColumn12, + this.dataGridViewTextBoxColumn15}); + dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle5.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle5.Font = new System.Drawing.Font("微软雅黑", 9F); + dataGridViewCellStyle5.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle5.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle5.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.dgvReplaceBattery.DefaultCellStyle = dataGridViewCellStyle5; + this.dgvReplaceBattery.Dock = System.Windows.Forms.DockStyle.Fill; + this.dgvReplaceBattery.EnableHeadersVisualStyles = false; + this.dgvReplaceBattery.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(77)))), ((int)(((byte)(147))))); + this.dgvReplaceBattery.Location = new System.Drawing.Point(2, 16); + this.dgvReplaceBattery.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.dgvReplaceBattery.MultiSelect = false; + this.dgvReplaceBattery.Name = "dgvReplaceBattery"; + this.dgvReplaceBattery.ReadOnly = true; + this.dgvReplaceBattery.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(6)))), ((int)(((byte)(40)))), ((int)(((byte)(86))))); + dataGridViewCellStyle6.Font = new System.Drawing.Font("微软雅黑", 9F); + dataGridViewCellStyle6.ForeColor = System.Drawing.Color.White; + dataGridViewCellStyle6.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(20)))), ((int)(((byte)(80))))); + dataGridViewCellStyle6.SelectionForeColor = System.Drawing.Color.White; + dataGridViewCellStyle6.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.dgvReplaceBattery.RowHeadersDefaultCellStyle = dataGridViewCellStyle6; + this.dgvReplaceBattery.RowHeadersWidth = 50; + this.dgvReplaceBattery.RowTemplate.Height = 23; + this.dgvReplaceBattery.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgvReplaceBattery.Size = new System.Drawing.Size(979, 203); + this.dgvReplaceBattery.TabIndex = 13; + this.dgvReplaceBattery.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dgvReplaceBattery_RowPostPaint); + this.dgvReplaceBattery.RowPrePaint += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(this.dgv_ngRsn_RowPrePaint); + // + // NewBarCode + // + this.NewBarCode.DataPropertyName = "NewBarCode"; + this.NewBarCode.HeaderText = "替换后电池条码"; + this.NewBarCode.MinimumWidth = 6; + this.NewBarCode.Name = "NewBarCode"; + this.NewBarCode.ReadOnly = true; + this.NewBarCode.Width = 180; + // + // OldBarCode + // + this.OldBarCode.DataPropertyName = "OldBarCode"; + this.OldBarCode.HeaderText = "替换前电池条码"; + this.OldBarCode.MinimumWidth = 6; + this.OldBarCode.Name = "OldBarCode"; + this.OldBarCode.ReadOnly = true; + this.OldBarCode.Width = 180; + // + // dataGridViewTextBoxColumn1 + // + this.dataGridViewTextBoxColumn1.DataPropertyName = "Location"; + this.dataGridViewTextBoxColumn1.HeaderText = "电池位置"; + this.dataGridViewTextBoxColumn1.MinimumWidth = 6; + this.dataGridViewTextBoxColumn1.Name = "dataGridViewTextBoxColumn1"; + this.dataGridViewTextBoxColumn1.ReadOnly = true; + this.dataGridViewTextBoxColumn1.Width = 125; + // + // dataGridViewTextBoxColumn2 + // + this.dataGridViewTextBoxColumn2.DataPropertyName = "Grade"; + this.dataGridViewTextBoxColumn2.HeaderText = "电池档位"; + this.dataGridViewTextBoxColumn2.MinimumWidth = 6; + this.dataGridViewTextBoxColumn2.Name = "dataGridViewTextBoxColumn2"; + this.dataGridViewTextBoxColumn2.ReadOnly = true; + this.dataGridViewTextBoxColumn2.Width = 125; + // + // VassoioID + // + this.VassoioID.DataPropertyName = "VassoioID"; + this.VassoioID.HeaderText = "托盘码"; + this.VassoioID.MinimumWidth = 6; + this.VassoioID.Name = "VassoioID"; + this.VassoioID.ReadOnly = true; + this.VassoioID.Width = 125; + // + // GongWei + // + this.GongWei.DataPropertyName = "GongWei"; + this.GongWei.HeaderText = "机架号"; + this.GongWei.MinimumWidth = 6; + this.GongWei.Name = "GongWei"; + this.GongWei.ReadOnly = true; + this.GongWei.Width = 125; + // + // dataGridViewTextBoxColumn12 + // + this.dataGridViewTextBoxColumn12.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells; + this.dataGridViewTextBoxColumn12.DataPropertyName = "TestTime"; + this.dataGridViewTextBoxColumn12.HeaderText = "时间"; + this.dataGridViewTextBoxColumn12.MinimumWidth = 6; + this.dataGridViewTextBoxColumn12.Name = "dataGridViewTextBoxColumn12"; + this.dataGridViewTextBoxColumn12.ReadOnly = true; + this.dataGridViewTextBoxColumn12.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.dataGridViewTextBoxColumn12.Width = 37; + // + // dataGridViewTextBoxColumn15 + // + this.dataGridViewTextBoxColumn15.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells; + this.dataGridViewTextBoxColumn15.DataPropertyName = "Remark"; + this.dataGridViewTextBoxColumn15.HeaderText = "备注"; + this.dataGridViewTextBoxColumn15.MinimumWidth = 6; + this.dataGridViewTextBoxColumn15.Name = "dataGridViewTextBoxColumn15"; + this.dataGridViewTextBoxColumn15.ReadOnly = true; + this.dataGridViewTextBoxColumn15.Width = 56; + // + // FrmBatteryStatus + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(11)))), ((int)(((byte)(20)))), ((int)(((byte)(36))))); + this.ClientSize = new System.Drawing.Size(1406, 653); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.Name = "FrmBatteryStatus"; + this.ShowInTaskbar = false; + this.Text = "电池状况"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + this.Load += new System.EventHandler(this.FrmBatteryStatus_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.panelSample.ResumeLayout(false); + this.panelSample.PerformLayout(); + this.panelExt1.ResumeLayout(false); + this.panelExt1.PerformLayout(); + this.tabBattery.ResumeLayout(false); + this.tabPagePlus1.ResumeLayout(false); + this.tabPagePlus2.ResumeLayout(false); + this.tabPagePlus3.ResumeLayout(false); + this.groupBoxEX9.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dgv_ngRsn)).EndInit(); + this.groupBoxEX8.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dgvReplaceBattery)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panelExt1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Panel panelSample; + //private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + //private JinYuan.ControlLib.DynamicGradeStatusControl dynamicGradeStatusControl1; + //private JinYuan.ControlLib.BatteryGridControl batteryGridControl; + private System.Windows.Forms.TextBox txtBox_Row; + private System.Windows.Forms.Label lbl_row; + private System.Windows.Forms.Button btn_Search; + private System.Windows.Forms.TextBox txtBox_Barcode; + private System.Windows.Forms.Label lbl_barcode; + private System.Windows.Forms.TextBox txtBox_Carton; + private System.Windows.Forms.Label lbl_Carton; + private System.Windows.Forms.TextBox txtBox_SubBarcode; + private System.Windows.Forms.Label lbl_SubBarcode; + private System.Windows.Forms.Button btn_ForceOut; + private System.Windows.Forms.Button btn_SubBarcode; + private JinYuan.ControlLib.GroupBoxEX groupBoxEX9; + private System.Windows.Forms.DataGridView dgv_ngRsn; + private System.Windows.Forms.DataGridViewTextBoxColumn locationBat; + private System.Windows.Forms.Label lbl_statusNomal; + private HML.TabControlPlus tabBattery; + private HML.TabPagePlus tabPagePlus1; + private HML.TabPagePlus tabPagePlus2; + private HML.TabPagePlus tabPagePlus3; + private JinYuan.ControlLib.PanelExt panelExt_Grade1; + private JinYuan.ControlLib.PanelExt panelExt_Grade2; + private JinYuan.ControlLib.PanelExt panelExt_Grade3; + private JinYuan.ControlLib.BatteryControl BatteryControl_Normal; + private JinYuan.ControlLib.BatteryControl BatteryControl_PackNG; + private JinYuan.ControlLib.BatteryControl BatteryControl_Replacing; + private JinYuan.ControlLib.BatteryControl BatteryControl_init; + private System.Windows.Forms.Label lbl_Init; + private System.Windows.Forms.Label lbl_Replace; + private System.Windows.Forms.Label lbl_PackNG; + private System.Windows.Forms.Button btn_repacking; + private System.Windows.Forms.Button btn_clear; + private JinYuan.ControlLib.GroupBoxEX groupBoxEX8; + public System.Windows.Forms.DataGridView dgvReplaceBattery; + private Button button1; + private DataGridViewTextBoxColumn identification; + private DataGridViewTextBoxColumn location; + private DataGridViewTextBoxColumn grade; + private DataGridViewTextBoxColumn containerCode; + private DataGridViewTextBoxColumn packResult; + private DataGridViewTextBoxColumn packFalseReason; + private DataGridViewTextBoxColumn packTime; + private DataGridViewTextBoxColumn NewBarCode; + private DataGridViewTextBoxColumn OldBarCode; + private DataGridViewTextBoxColumn dataGridViewTextBoxColumn1; + private DataGridViewTextBoxColumn dataGridViewTextBoxColumn2; + private DataGridViewTextBoxColumn VassoioID; + private DataGridViewTextBoxColumn GongWei; + private DataGridViewTextBoxColumn dataGridViewTextBoxColumn12; + private DataGridViewTextBoxColumn dataGridViewTextBoxColumn15; + } +} diff --git a/LargeSquareOne/FrmBatteryStatus.cs b/LargeSquareOne/FrmBatteryStatus.cs new file mode 100644 index 0000000..8712cda --- /dev/null +++ b/LargeSquareOne/FrmBatteryStatus.cs @@ -0,0 +1,2763 @@ +using Google.Protobuf.WellKnownTypes; +using JinYuan.ControlLib; +using JinYuan.Helper; +using JinYuan.MES.Models; +using JinYuan.Models; +using JinYuan.Models.HelperAttribute; +using JinYuan.VirtualDataLibrary; +using Language; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Documents; +using System.Windows.Forms; + +namespace LargeSquareOne +{ + + public partial class FrmBatteryStatus : MultiLanguageForm + { + #region 字段定义 + // 电池控件字典:Key=stationNo(1/2/3),Value=控件字典(Key=layer-row-col) + private readonly Dictionary> _batteryControlsByStationNo = new Dictionary>(); + + // 条码到控件映射(加速查找) + private readonly Dictionary _barcodeToControlMap = new Dictionary(); + + // 数据绑定列表 + private readonly BindingList _replaceRecords = new BindingList(); + private readonly BindingList _ngBatteryRecords = new BindingList(); + private readonly BindingList _allBatteryRecords = new BindingList(); + + // 统计标签字典 + private readonly Dictionary> _statisticsLabelsByLoc = new Dictionary>(); + + // 并发控制 + private readonly SemaphoreSlim _operationSemaphore = new SemaphoreSlim(1, 1); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + // 防抖控制 + private DateTime _lastStatisticsUpdateTime = DateTime.MinValue; + private DateTime _lastBatteryClickTime = DateTime.MinValue; + + // 状态标记 + private bool _isControlsInitialized = false; + + // 统计项显示名称 + private readonly string[] _statusDisplayNames = new string[] + { + "电芯替换总数", // GradeNG + "电芯装箱NG总数", // PackNG + "电芯档位&装箱OK总数", // Normal + "满箱还缺总数" // Init + }; + + // 性能监控 + private PerformanceCounter _cpuUsageCounter; + #endregion + + #region 构造函数 + public FrmBatteryStatus() + { + InitializeComponent(); + // 基础窗体设置 + ConfigureFormProperties(); + + // 性能优化设置 + ApplyPerformanceOptimizations(); + + // 初始化控件 + InitializeDataGridViews(); + BindScannerEvents(); + InitializeDataBindings(); + + // 事件绑定 + Load += FrmBatteryStatus_Load; + + // 性能监控初始化 + InitializePerformanceMonitoring(); + } + #endregion + + #region 初始化方法 + /// + /// 配置窗体基础属性 + /// + private void ConfigureFormProperties() + { + Dock = DockStyle.Fill; + AutoSize = false; + FormBorderStyle = FormBorderStyle.None; + Padding = new Padding(0); + Margin = new Padding(0); + + // 双缓冲设置 + SetStyle( + ControlStyles.OptimizedDoubleBuffer | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.UserPaint | + ControlStyles.ResizeRedraw, true); + DoubleBuffered = true; + SetStyle(ControlStyles.SupportsTransparentBackColor, false); + } + + /// + /// 应用全局性能优化 + /// + private void ApplyPerformanceOptimizations() + { + // 禁用不必要的动画 + Application.EnableVisualStyles(); + //Application.SetCompatibleTextRenderingDefault(false); + + // 递归设置所有控件双缓冲 + SetDoubleBufferingRecursive(this, true); + + // 禁用自动滚动减少重绘 + AutoScroll = false; + AutoScrollMinSize = new Size(0, 0); + + // 优化TabControl + if (tabBattery != null) + { + SetDoubleBuffering(tabBattery, true); + } + + if (_cpuUsageCounter != null) + { + _cpuUsageCounter.Dispose(); + _cpuUsageCounter = null; + } + } + + /// + /// 初始化DataGridView控件 + /// + private void InitializeDataGridViews() + { + OptimizeDataGridView(dgv_ngRsn); + OptimizeDataGridView(dgvReplaceBattery); + } + + + + /// + /// 绑定扫描枪输入事件 + /// + private void BindScannerEvents() + { + // 回车切换焦点 + txtBox_Barcode.KeyDown += (s, e) => + { + if (e.KeyCode == Keys.Enter && !string.IsNullOrEmpty(txtBox_Barcode.Text.Trim())) + { + e.SuppressKeyPress = true; + txtBox_SubBarcode?.Focus(); + txtBox_SubBarcode?.SelectAll(); + } + }; + + // 焦点获取时全选文本 + txtBox_Barcode.Enter += (s, e) => ((TextBox)s)?.SelectAll(); + txtBox_SubBarcode.Enter += (s, e) => ((TextBox)s)?.SelectAll(); + } + + /// + /// 初始化数据绑定 + /// + private void InitializeDataBindings() + { + dgvReplaceBattery.DataSource = _replaceRecords; + dgv_ngRsn.DataSource = _ngBatteryRecords; + + // 验证绑定 + Debug.WriteLine($"dgv_ngRsn数据源类型:{dgv_ngRsn.DataSource?.GetType().Name}"); + Debug.WriteLine($"dgv_ngRsn列数:{dgv_ngRsn.Columns.Count}"); + + _ngBatteryRecords.ListChanged += (s, e) => + { + if (dgv_ngRsn.IsHandleCreated) + dgv_ngRsn.BeginInvoke(() => dgv_ngRsn.Invalidate()); + }; + + _replaceRecords.ListChanged += (s, e) => + { + if (dgvReplaceBattery.IsHandleCreated) + dgvReplaceBattery.BeginInvoke(() => dgvReplaceBattery.Invalidate()); + }; + + } + + /// + /// 初始化性能监控 + /// + private void InitializePerformanceMonitoring() + { + try + { + // 先释放旧的计数器 + if (_cpuUsageCounter != null) + { + _cpuUsageCounter.Dispose(); + _cpuUsageCounter = null; + } + + _cpuUsageCounter = new PerformanceCounter( + "Process", + "% Processor Time", + Process.GetCurrentProcess().ProcessName); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"性能监控初始化失败:{ex}", "BatteryStatusLog"); + _cpuUsageCounter = null; // 确保置空 + } + } + #endregion + + #region 性能优化相关方法 + /// + /// 优化DataGridView性能 + /// + private void OptimizeDataGridView(DataGridView dgv) + { + if (dgv == null) return; + + // 设置双缓冲 + var doubleBufferProp = dgv.GetType().GetProperty( + "DoubleBuffered", + BindingFlags.Instance | BindingFlags.NonPublic); + doubleBufferProp?.SetValue(dgv, true); + + dgv.EnableHeadersVisualStyles = false; + dgv.AutoGenerateColumns = false; + dgv.RowHeadersVisible = true; + dgv.AllowUserToAddRows = false; + dgv.AllowUserToDeleteRows = false; + dgv.AllowUserToOrderColumns = false; + dgv.AllowUserToResizeRows = false; + dgv.ReadOnly = true; + dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + dgv.MultiSelect = false; + + // 减少绘制开销 + dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + dgv.ColumnHeadersHeight = 25; + dgv.RowTemplate.Height = 22; + dgv.ScrollBars = ScrollBars.Vertical; + } + + /// + /// 设置控件双缓冲 + /// + /// 目标控件 + /// 是否启用 + private void SetDoubleBuffering(Control control, bool enable) + { + if (control == null) return; + + try + { + var prop = control.GetType().GetProperty( + "DoubleBuffered", + BindingFlags.Instance | BindingFlags.NonPublic); + prop?.SetValue(control, enable); + } + catch (Exception ex) + { + LogHelper.Instance.WriteLog($"设置双缓冲失败:{ex.Message}", "BatteryStatusLog"); + } + } + + /// + /// 递归设置控件双缓冲 + /// + private void SetDoubleBufferingRecursive(Control control, bool enable) + { + if (control == null) return; + + try + { + SetDoubleBuffering(control, enable); + + foreach (Control child in control.Controls) + { + SetDoubleBufferingRecursive(child, enable); + } + } + catch + { + // 忽略设置失败 + } + } + #endregion + + #region 窗体加载与控件初始化 + private async void FrmBatteryStatus_Load(object sender, EventArgs e) + { + try + { + if (_isControlsInitialized) return; + + SafeUI(() => + { + this.SuspendLayout(); + SetPanelsVisibility(false); + }); + + await Task.Delay(100); + + // 所有控件创建必须走 UI() + SafeUI(() => + { + InitializeBatteryControls(); + _isControlsInitialized = true; + + panelExt_Grade1?.Invalidate(); + panelExt_Grade2?.Invalidate(); + panelExt_Grade3?.Invalidate(); + tabBattery?.Invalidate(); + + this.ResumeLayout(false); + Invalidate(); + SetPanelsVisibility(true); + }); + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"加载电池界面异常:{ex}", "BatteryStatusLog"); + } + } + + /// + /// 异步初始化电池控件(避免UI阻塞) + /// + private async Task InitializeBatteryControlsAsync() + { + await Task.Run(() => + { + if (InvokeRequired) + { + Invoke(new Action(InitializeBatteryControls)); + } + else + { + InitializeBatteryControls(); + } + }).ConfigureAwait(false); + } + + + /// + /// 初始化电池控件 + /// + private void InitializeBatteryControls() + { + try + { + // 获取配置参数 + var config = CommonMethods.mesConfig; + int layers = config?.packLayers ?? 4; + int rows = config?.rowsPerLayer ?? 5; + int cols = config?.colsPerLayer ?? 12; + + Debug.WriteLine($"初始化电池控件:层={layers}, 行={rows}, 列={cols}"); + + // 暂停面板布局更新 + SuspendPanelsLayout(); + ClearPanelsControls(); + + // 获取FD配置 + var fdConfig = CommonMethods.curFdConfig; + if (fdConfig == null) return; + + // 初始化各档位控件 + InitializeGradeControls(1, fdConfig.Grade1, panelExt_Grade1, layers, rows, cols); + InitializeGradeControls(2, fdConfig.Grade2, panelExt_Grade2, layers, rows, cols); + InitializeGradeControls(3, fdConfig.Grade3, panelExt_Grade3, layers, rows, cols); + + // 恢复布局 + ResumePanelsLayout(); + + // 统计控件数量 + int totalControls = _batteryControlsByStationNo.Values.Sum(d => d.Count); + Debug.WriteLine($"电池控件初始化完成,总控件数:{totalControls}"); + } + catch (Exception ex) + { + Debug.WriteLine($"控件初始化异常:{ex.Message}"); + LogHelper.Instance.WriteError($"初始化电池控件异常:{ex}", "BatteryStatusLog"); + } + } + + // 窗体关闭时释放资源 + protected override void OnFormClosing(FormClosingEventArgs e) + { + base.OnFormClosing(e); + + //// 取消异步任务 + //_cancellationTokenSource.Cancel(); + + _cancellationTokenSource.Token.UnregisterAll(); // 新增:移除所有注册的回调 + + // 安全取消 + try + { + _cancellationTokenSource.Cancel(true); // true=允许回调抛异常但不终止程序 + } + catch (AggregateException ex) + { + // 记录回调中的具体异常(关键:定位哪个回调出问题) + foreach (var innerEx in ex.InnerExceptions) + { + LogHelper.Instance.WriteError($"取消任务时回调异常:{innerEx}", "BatteryStatusLog"); + } + } + catch (Exception ex) + { + LogHelper.Instance.WriteError($"取消CancellationTokenSource异常:{ex}", "BatteryStatusLog"); + } + + Task.Delay(100).Wait(); + + // 释放资源 + _operationSemaphore.Dispose(); + if (_cpuUsageCounter != null) + { + _cpuUsageCounter.Dispose(); + _cpuUsageCounter = null; + } + + lock (_batteryControlsByStationNo) + { + DisposeBatteryControls(); + ClearAllPanels(); + _batteryControlsByStationNo.Clear(); + _statisticsLabelsByLoc.Clear(); + _barcodeToControlMap.Clear(); + } + _cancellationTokenSource.Dispose(); + } + + + + // 重写窗体显示方法,优化渲染 + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + + + // 恢复布局 + foreach (Control control in this.Controls) + { + control.ResumeLayout(false); + } + } + + /// + /// 重写CreateParams减少闪烁 + /// + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED + return cp; + } + } + + + #endregion + + #region 电池控件管理 + /// + /// 初始化指定档位的电池控件 + /// + /// 机架号(1/2/3) + /// 档位名称 + /// 容器面板 + /// 层数 + /// 行数 + /// 列数 + private void InitializeGradeControls(int stationNo, string grade, PanelExt container, int layers, int rows, int cols) + { + if (stationNo < 1 || stationNo > 3 || container == null || container.HasChildren) + { + Debug.WriteLine($"机架号{stationNo}错误或容器非空,跳过初始化"); + return; + } + if (string.IsNullOrEmpty(grade) || grade == "不设置" || grade == "NG" ) + { + // 设置标签页文本 + SetTabPageText(stationNo, grade); + return; + } + + try + { + // 设置标签页文本 + SetTabPageText(stationNo, grade); + + // 初始化容器面板 + container.Controls.Clear(); + + //container.AutoScroll = true; + container.BackColor = Color.FromArgb(11, 20, 36); + container.SuspendLayout(); + container.Visible = false; + container.Dock = DockStyle.Fill; + container.Padding = new Padding(0); // 增加容器内边距 + + // 创建层级面板 + var layerPanel = CreateLayerPanel(stationNo, grade, layers, rows, cols); + + // 创建统计区域 + var statsGroup = CreateStatisticsGroupBox(stationNo, grade, out var statLabels); + _statisticsLabelsByLoc[stationNo] = statLabels; + statsGroup.Size = new Size(layerPanel.Width, 70); + statsGroup.Location = new System.Drawing.Point(0, layerPanel.Bottom + 5); + //statsGroup.Dock = DockStyle.Bottom; + + // 添加控件到容器 + container.Controls.Add(layerPanel); + container.Controls.Add(statsGroup); + + //container.AutoScrollMinSize = new Size(layerPanel.Width, statsGroup.Bottom); + //container.ClientSize = new Size(layerPanel.Width + 10, statsGroup.Bottom + 10); + // 恢复布局 + container.ResumeLayout(true); + container.Visible = true; + container.Invalidate(); + + + Debug.WriteLine($"机架号{stationNo}控件创建完成,总数:{layers * rows * cols}"); + } + catch (Exception ex) + { + Debug.WriteLine($"初始化机架号{stationNo}异常:{ex.Message}"); + LogHelper.Instance.WriteError($"初始化机架号{stationNo}电池控件异常:{ex}", "BatteryStatusLog"); + } + } + + /// + /// 创建层级面板 + /// + //创建分层的表格 + private TableLayoutPanel CreateLayerPanel(int stationNo, string grade, int layers, int rows, int cols) + { + // 布局参数 + int batterySize = 24; + int cellPadding = 2; + int cellSize = batterySize + cellPadding * 2; + int rowNumColWidth = 40; // 行号列宽度 + int layerColWidth = 40; // 层数列宽度 + + int totalColWidth = rowNumColWidth + (cellSize * cols); // 电池区域总列宽 + int totalPanelWidth = layerColWidth + totalColWidth + 10; // 整体总宽度(+10px余量) + int rowHeight = cellSize + cellPadding; // 每行高度 = 单元格高度 + int layerHeight = (rowHeight * rows) + 2; // 每层高度 = 表头 + 电池行 + int layerTotalHeight = rowHeight * rows + 6; // 每层总高度(+8px余量,确保最后一行显示) + + + //外层TableLayoutPanel:分层(包含表头+所有层) + TableLayoutPanel layerPanel = new TableLayoutPanel + { + RowCount = layers + 1, + ColumnCount = 2, + //Dock = DockStyle.Fill, // 顶部对齐,避免Fill压缩宽度 + BackColor = Color.Transparent, + CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, //TableLayoutPanelCellBorderStyle.None, + Margin = new Padding(0), + AutoSizeMode = AutoSizeMode.GrowAndShrink, + Size = new Size(totalPanelWidth, layerTotalHeight * layers + 35), + //Margin = new Padding(0, 0, 0, 10), + }; + + layerPanel.ColumnStyles.Clear(); + layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, layerColWidth)); + layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, totalColWidth)); + + // 设置行样式 + layerPanel.RowStyles.Clear(); + layerPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 25F)); //第一行 显示列号 + for (int i = 1; i <= layers; i++) + { + layerPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, layerTotalHeight)); + } + + // ========== 创建表头行 ========== + // 表头-第一列(文本:层数/列) + System.Windows.Forms.Label lblHeaderLayer = new System.Windows.Forms.Label + { + Text = "层", + TextAlign = ContentAlignment.MiddleCenter, + ForeColor = Color.White, + Dock = DockStyle.Fill, + Font = new Font("Microsoft YaHei", 9, FontStyle.Bold) + }; + layerPanel.Controls.Add(lblHeaderLayer, 0, 0); + + // 表头-第二列(列号容器) + TableLayoutPanel tblColHeader = new TableLayoutPanel + { + RowCount = 1, + ColumnCount = cols + 1, // 行号列 + 所有电池列 + Dock = DockStyle.Fill, + Size = new Size(totalColWidth, 25), + //AutoSize = true, + //AutoSizeMode = AutoSizeMode.GrowAndShrink, + //BackColor = Color.Transparent, + BackColor = Color.FromArgb(18, 30, 50), + Margin = new Padding(0), + CellBorderStyle = TableLayoutPanelCellBorderStyle.None + }; + + tblColHeader.ColumnStyles.Clear(); + tblColHeader.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, rowNumColWidth)); + for (int col = 1; col <= cols; col++) + { + tblColHeader.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize)); + } + + System.Windows.Forms.Label lblheaderCol = new System.Windows.Forms.Label + { + Text = "行/列", + TextAlign = ContentAlignment.MiddleCenter, + ForeColor = Color.White, + Dock = DockStyle.Fill, + Margin = new Padding(0), + Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + BackColor = Color.FromArgb(18, 30, 50), + }; + tblColHeader.Controls.Add(lblheaderCol, 0, 0); + + for (int col = 1; col <= cols; col++) + { + System.Windows.Forms.Label lblCol = new System.Windows.Forms.Label + { + Text = col.ToString(), + TextAlign = ContentAlignment.MiddleCenter, + ForeColor = Color.White, + Dock = DockStyle.Fill, + Margin = new Padding(0), + Font = new Font("Microsoft YaHei", 9, FontStyle.Bold) + }; + tblColHeader.Controls.Add(lblCol, col, 0); + } + + layerPanel.Controls.Add(tblColHeader, 1, 0); + //CreateBatteryControls(stationNo, grade, layerPanel, layers, rows, cols); + // 初始化控件字典 + if (!_batteryControlsByStationNo.ContainsKey(stationNo)) + { + _batteryControlsByStationNo[stationNo] = new Dictionary(); + } + + // ========== 遍历每层,创建电池控件 ========== + for (int layer = 1; layer <= layers; layer++) + { + // 层数标签(第一列) + System.Windows.Forms.Label lblLayer = new System.Windows.Forms.Label + { + Text = $"第{layer}层", + TextAlign = ContentAlignment.MiddleCenter, + ForeColor = Color.White, + Dock = DockStyle.Fill, + BackColor = Color.FromArgb(18, 30, 50), + Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + Margin = new Padding(0), + Padding = new Padding(0) + }; + layerPanel.Controls.Add(lblLayer, 0, layer); + + System.Windows.Forms.Panel pnlBatteryContainer = new System.Windows.Forms.Panel + { + //Dock = DockStyle.Fill, + //BackColor = Color.FromArgb(18, 30, 50), + //BorderStyle = BorderStyle.FixedSingle, // 层边框 + //Margin = new Padding(2), // 层之间的间距 + //Padding = new Padding(3) + Size = new Size(totalColWidth, layerTotalHeight), // 固定尺寸,和层高度一致 + BackColor = Color.FromArgb(18, 30, 50), + //BorderStyle = BorderStyle.FixedSingle, // 层边框 + Margin = new Padding(3), // 层之间间距(统一) + Padding = new Padding(1) + }; + + // 内层TableLayoutPanel:当前层的行和列 + TableLayoutPanel tblBattery = new TableLayoutPanel + { + //RowCount = totalRows, + //ColumnCount = totalCols + 1, + //Dock = DockStyle.Fill, // 填充容器 + //AutoSize = true, + //AutoSizeMode = AutoSizeMode.GrowAndShrink, + //BackColor = Color.Transparent, + //CellBorderStyle = TableLayoutPanelCellBorderStyle.None, + //Margin = new Padding(0), + //Padding = new Padding(5) + RowCount = rows, + ColumnCount = cols + 1, + Size = new Size(totalColWidth, layerTotalHeight - 2), + //Dock = DockStyle.Fill, + BackColor = Color.Transparent, + CellBorderStyle = TableLayoutPanelCellBorderStyle.None, + Margin = new Padding(0), + Padding = new Padding(0) + }; + + tblBattery.RowStyles.Clear(); + for (int r = 0; r < rows; r++) + { + tblBattery.RowStyles.Add(new RowStyle(SizeType.Absolute, rowHeight)); + } + + tblBattery.ColumnStyles.Clear(); + tblBattery.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, rowNumColWidth)); + for (int c = 1; c <= cols; c++) + { + tblBattery.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize)); + } + + // 遍历当前层的所有行和列,生成电池控件 + for (int row = 1; row <= rows; row++) + { + System.Windows.Forms.Label lblrow = new System.Windows.Forms.Label + { + Text = row.ToString(), + TextAlign = ContentAlignment.MiddleCenter, + ForeColor = Color.White, + Dock = DockStyle.Fill, + Margin = new Padding(0), + Font = new Font("Microsoft YaHei", 9, FontStyle.Bold) + }; + tblBattery.Controls.Add(lblrow, 0, row - 1); + } + + for (int row = 1; row <= rows; row++) + { + for (int col = 1; col <= cols; col++) + { + BatteryControl battery = new BatteryControl(grade, layer, row, col, "") + { + Name = $"BatteryControl_{stationNo}_{location}", + Size = new Size(batterySize, batterySize), + Margin = new Padding(cellPadding), + Anchor = AnchorStyles.None, + //Dock = DockStyle.None, + Dock = DockStyle.None, + Tag = $"{stationNo}-{location}", + Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular + }; + + // 绑定点击事件 + battery.OnBatteryClicked += OnBatteryControlClicked; + + // 添加到行列表格 + tblBattery.Controls.Add(battery, col, row - 1); + + // 加入全局管理字典 + string controlKey = $"{layer}-{row}-{col}"; + _batteryControlsByStationNo[stationNo][controlKey] = battery; + } + } + + pnlBatteryContainer.Controls.Add(tblBattery); + layerPanel.Controls.Add(pnlBatteryContainer, 1, layer); + } + return layerPanel; + } + + //创建一个整体的表格 + //private TableLayoutPanel CreateLayerPanel(int stationNo, string grade, int layers, int rows, int cols) + //{ + // // 布局参数 + // int batterySize = 24; + // int cellPadding = 2; + // int cellSize = batterySize + cellPadding * 2; + // int layerNumWidth = 50; + // int totalPanelWidth = layerNumWidth * 2 + (cellSize * cols) + 18; + // int totalPanelHeight = cellSize * rows * layers + 50; // 每层总高度(+8px余量,确保最后一行显示) + + // // 创建外层面板 + // var layerPanel = new TableLayoutPanel + // { + // RowCount = layers * rows + 1, + // ColumnCount = cols + 2, + // BackColor = Color.Transparent, + // CellBorderStyle = TableLayoutPanelCellBorderStyle.Single, + // Margin = new Padding(0), + // Size = new Size(totalPanelWidth, totalPanelHeight), + // Padding = new Padding(0) + // }; + + // // 设置列样式 + // layerPanel.ColumnStyles.Clear(); + // for (int i = 0; i < layerPanel.ColumnCount; i++) + // { + // if (i < 2) + // layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, layerNumWidth)); + // else + // layerPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellSize)); + // } + + + // // 设置行样式 + // layerPanel.RowStyles.Clear(); + // for (int i = 0; i < layerPanel.RowCount; i++) + // { + // layerPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, cellSize)); + // } + + // // 添加表头 + // //AddPanelHeaders(layerPanel, cols, layerNumWidth, cellSize); + // // 层数标签 + // var layerHeader = new Label + // { + // Text = "层", + // TextAlign = ContentAlignment.MiddleCenter, + // ForeColor = Color.White, + // BackColor = Color.FromArgb(18, 30, 50), + // Dock = DockStyle.Fill, + // Font = new Font("Microsoft YaHei", 9, FontStyle.Bold) + // }; + // layerPanel.Controls.Add(layerHeader, 0, 0); + + // // 行/列表头 + // var rowColHeader = new Label + // { + // Text = "行/列", + // TextAlign = ContentAlignment.MiddleCenter, + // ForeColor = Color.White, + // Dock = DockStyle.Fill, + // Margin = new Padding(0), + // Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + // BackColor = Color.FromArgb(18, 30, 50) + // }; + // layerPanel.Controls.Add(rowColHeader, 1, 0); + + // // 列号标签 + // for (int col = 1; col <= cols; col++) + // { + // var colLabel = new Label + // { + // Text = col.ToString(), + // TextAlign = ContentAlignment.MiddleCenter, + // ForeColor = Color.White, + // Dock = DockStyle.Fill, + // Margin = new Padding(0), + // Padding = new Padding(0), + // Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + // BackColor = Color.FromArgb(18, 30, 50) + // }; + // layerPanel.Controls.Add(colLabel, col + 1, 0); + // } + + // // 创建电池控件 + // //CreateBatteryControls(stationNo, grade, layerPanel, layers, rows, cols); + // // 初始化控件字典 + // if (!_batteryControlsByStationNo.ContainsKey(stationNo)) + // { + // _batteryControlsByStationNo[stationNo] = new Dictionary(); + // } + + // for (int layer = 0; layer < layers; layer++) + // { + // // 添加层数标签 + // var layerLabel = new Label + // { + // Text = $"第{layer + 1}层", + // TextAlign = ContentAlignment.MiddleCenter, + // ForeColor = Color.White, + // Dock = DockStyle.Fill, + // BackColor = Color.FromArgb(18, 30, 50), + // Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + // Margin = new Padding(0) + // }; + // layerPanel.Controls.Add(layerLabel, 0, layer * rows + 1); + // layerPanel.SetRowSpan(layerLabel, rows); + + // // 添加行号标签 + // for (int row = 1; row <= rows; row++) + // { + // var rowLabel = new Label + // { + // Text = row.ToString(), + // TextAlign = ContentAlignment.MiddleCenter, + // ForeColor = Color.White, + // Dock = DockStyle.Fill, + // Margin = new Padding(0), + // Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + // BackColor = Color.FromArgb(18, 30, 50) + // }; + // layerPanel.Controls.Add(rowLabel, 1, layer * rows + row); + + // for (int col = 1; col <= cols; col++) + // { + // string location = $"{layer}-{row}-{col}"; + // // 创建电池控件 + // var batteryControl = new BatteryControl(grade, layer, row, col, "", JinYuan.ControlLib.BatteryStatus.Init) + // { + // Name = $"BatteryControl_{stationNo}_{location}", + // Size = new Size(batterySize, batterySize), + // Margin = new Padding(cellPadding), + // Anchor = AnchorStyles.None, + // //Dock = DockStyle.None, + // Dock = DockStyle.Fill, + // Tag = $"{stationNo}-{location}", + // Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular + // }; + + // // 绑定点击事件 + // batteryControl.OnBatteryClicked += OnBatteryControlClicked; + + // // 添加到面板 + // layerPanel.Controls.Add(batteryControl, col + 1, row + layer * rows); + + // // 加入管理字典 + // string controlKey = $"{layer}-{row}-{col}"; + // _batteryControlsByStationNo[stationNo][controlKey] = batteryControl; + // } + // } + + // // 创建具体电池控件 + // //AddBatteryControlCells(stationNo, grade, layerPanel, layer, rows, cols, batterySize, cellPadding); + + + // } + + // return layerPanel; + //} + + /// + /// 创建电池控件 + /// + private void CreateBatteryControls(int stationNo, string grade, TableLayoutPanel layerPanel, int layers, int rows, int cols) + { + // 初始化控件字典 + if (!_batteryControlsByStationNo.ContainsKey(stationNo)) + { + _batteryControlsByStationNo[stationNo] = new Dictionary(); + } + + int cellPadding = 1; + int batterySize = 24; + int cellSize = batterySize + cellPadding * 2; + //int rowNumWidth = 40; + + for (int layer = 0; layer < layers; layer++) + { + // 添加层数标签 + var layerLabel = new Label + { + Text = $"第{layer + 1}层", + TextAlign = ContentAlignment.MiddleCenter, + ForeColor = Color.White, + Dock = DockStyle.Fill, + BackColor = Color.FromArgb(18, 30, 50), + Font = new Font("Microsoft YaHei", 9, FontStyle.Bold), + Margin = new Padding(0) + }; + layerPanel.Controls.Add(layerLabel, 0, layer * rows + 1); + layerPanel.SetRowSpan(layerLabel, rows); + + // 添加行号标签 + AddRowNumberLabels(layerPanel, layer, rows); + + // 创建具体电池控件 + AddBatteryControlCells(stationNo, grade, layerPanel, layer, rows, cols, batterySize, cellPadding); + } + + } + + /// + /// 添加电池控件单元格 + /// + private void AddBatteryControlCells(int stationNo, string grade, TableLayoutPanel layerPanel, + int layer, int rows, int cols, int batterySize, int cellPadding) + { + for (int row = 1; row <= rows; row++) + { + for (int col = 1; col <= cols; col++) + { + string location = $"{layer}-{row}-{col}"; + // 创建电池控件 + var batteryControl = new BatteryControl(grade, layer, row, col, "", JinYuan.ControlLib.BatteryStatus.Init) + { + Name = $"BatteryControl_{stationNo}_{location}", + Size = new Size(batterySize, batterySize), + Margin = new Padding(cellPadding), + Anchor = AnchorStyles.None, + //Dock = DockStyle.None, + Dock = DockStyle.Fill, + Tag = $"{stationNo}-{location}", + Style = SeeSharpTools.JY.GUI.LED.LedStyle.Circular + }; + + // 绑定点击事件 + batteryControl.OnBatteryClicked += OnBatteryControlClicked; + + // 添加到面板 + layerPanel.Controls.Add(batteryControl, col+1, row + layer * rows); + + // 加入管理字典 + string controlKey = $"{layer}-{row}-{col}"; + _batteryControlsByStationNo[stationNo][controlKey] = batteryControl; + } + } + } + + /// + /// 创建统计信息GroupBox + /// + private GroupBoxEX CreateStatisticsGroupBox(int stationNo, string grade, out List