├── .gitattributes ├── .gitignore ├── AddDeviceWindow.xaml ├── AddDeviceWindow.xaml.cs ├── AddWindow.xaml ├── AddWindow.xaml.cs ├── Allocation.xaml ├── Allocation.xaml.cs ├── App.config ├── App.xaml ├── App.xaml.cs ├── DataBrige.cs ├── DatabaseOperation └── DbClass.cs ├── DevicePage ├── GeneralNetworkDevice.xaml └── GeneralNetworkDevice.xaml.cs ├── GitHubVersionChecker.cs ├── IPAM-NOTE.csproj ├── IPAM-NOTE.sln ├── IPAddressCalculations.cs ├── ImportWindow.xaml ├── ImportWindow.xaml.cs ├── LICENSE.txt ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── PortAllocation.xaml ├── PortAllocation.xaml.cs ├── PresetWindow ├── AddPreset.xaml └── AddPreset.xaml.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── README.md ├── Resources ├── ADD.png ├── ALLOCATION.png ├── DATAHELP.png ├── DONATION.png ├── Devices │ └── SWITCH1.png ├── HumanGreeting.png ├── IMPORT.png ├── LOGIN.png └── UI.png ├── UserControls ├── GridCanvas.xaml └── GridCanvas.xaml.cs ├── UserPages ├── About.xaml ├── About.xaml.cs ├── CabinetManage.xaml ├── CabinetManage.xaml.cs ├── DataPreset.xaml ├── DataPreset.xaml.cs ├── DatabaseBackup.xaml ├── DatabaseBackup.xaml.cs ├── DevicesPage.xaml ├── DevicesPage.xaml.cs ├── DonationPage.xaml ├── DonationPage.xaml.cs ├── HelpPage.xaml ├── HelpPage.xaml.cs ├── HumanGreeting.xaml ├── HumanGreeting.xaml.cs ├── IndexPage.xaml ├── IndexPage.xaml.cs ├── ModelPreset.xaml ├── ModelPreset.xaml.cs ├── NetworkManage.xaml ├── NetworkManage.xaml.cs ├── PeoplePreset.xaml └── PeoplePreset.xaml.cs ├── UserWindows ├── AddIndexWindow.xaml ├── AddIndexWindow.xaml.cs ├── DeviceImportWindow.xaml ├── DeviceImportWindow.xaml.cs ├── SetPasswordWindow.xaml ├── SetPasswordWindow.xaml.cs ├── TESTWindow.xaml ├── TESTWindow.xaml.cs ├── VerifyPasswordWindow.xaml └── VerifyPasswordWindow.xaml.cs ├── VersionCheck.cs ├── ViewMode.cs ├── ipam.ico └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | /Resources/UI.psd 365 | -------------------------------------------------------------------------------- /AddDeviceWindow.xaml: -------------------------------------------------------------------------------- 1 |  23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 51 | 52 | 53 | 57 | 58 | 59 | 62 | 67 | 70 | 71 | 72 | 73 | 76 | 77 | 80 | 85 | 88 | 89 | 90 | 91 | 92 | 96 | 97 | 100 | 105 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /AddDeviceWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Shapes; 15 | using IPAM_NOTE.DevicePage; 16 | 17 | namespace IPAM_NOTE 18 | { 19 | /// 20 | /// AddDeviceWindow.xaml 的交互逻辑 21 | /// 22 | public partial class AddDeviceWindow : Window 23 | { 24 | public AddDeviceWindow() 25 | { 26 | InitializeComponent(); 27 | GeneralNetworkDevice.CloseParentWindowRequested += GeneralNetworkDevice_CloseParentWindowRequested; ; 28 | } 29 | 30 | private void GeneralNetworkDevice_CloseParentWindowRequested(object sender, EventArgs e) =>Close(); 31 | 32 | 33 | 34 | private void TopControl_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 35 | { 36 | int index = TopControl.SelectedIndex; 37 | 38 | 39 | 40 | switch (index) 41 | { 42 | case 0: 43 | DevicePanel.Children.Clear(); 44 | GeneralNetworkDevice generalNetworkDevice = new GeneralNetworkDevice(); 45 | DevicePanel.Children.Add(generalNetworkDevice); 46 | 47 | 48 | break; 49 | 50 | case 1: 51 | 52 | break; 53 | } 54 | } 55 | 56 | private void AddDeviceWindow_OnClosing(object sender, CancelEventArgs e) 57 | { 58 | this.DialogResult = true; 59 | } 60 | 61 | 62 | private void AddDeviceWindow_OnLoaded(object sender, RoutedEventArgs e) 63 | { 64 | DevicePanel.Children.Clear(); 65 | GeneralNetworkDevice generalNetworkDevice = new GeneralNetworkDevice(); 66 | DevicePanel.Children.Add(generalNetworkDevice); 67 | 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /AddWindow.xaml: -------------------------------------------------------------------------------- 1 |  24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | 45 | 46 | 54 | 55 | 56 | 57 | 58 | 69 | 70 | 71 | 72 | 73 | 74 | 80 | 81 | 89 | 90 | 93 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 123 | 124 | 125 | 126 | 133 | 134 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 174 | 175 | 183 | 184 | 185 | 186 | 187 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 234 | 235 | 243 | 244 | 251 | 252 | 253 | 260 | 261 | 262 | 263 | 270 | 271 | 278 | 279 | 280 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /AddWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using IPAM_NOTE.DatabaseOperation; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data.SqlClient; 6 | using System.Data.SQLite; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Web.Hosting; 12 | using System.Windows; 13 | using System.Windows.Controls; 14 | using System.Windows.Data; 15 | using System.Windows.Documents; 16 | using System.Windows.Input; 17 | using System.Windows.Media; 18 | using System.Windows.Media.Imaging; 19 | using System.Windows.Shapes; 20 | 21 | namespace IPAM_NOTE 22 | { 23 | /// 24 | /// AddWindow.xaml 的交互逻辑 25 | /// 26 | public partial class AddWindow : Window 27 | { 28 | public AddWindow() 29 | { 30 | InitializeComponent(); 31 | } 32 | 33 | private DbClass dbClass; 34 | 35 | 36 | 37 | private void AddWindow_OnLoaded(object sender, RoutedEventArgs e) 38 | { 39 | LoadStatus=true; 40 | 41 | if (DataBrige.AddStatus==0) 42 | { 43 | this.Title = "添加网段"; 44 | 45 | 46 | } 47 | else 48 | { 49 | this.Title = "编辑网段信息"; 50 | IpTextBox.Text = DataBrige.TempAddress.Network; 51 | MaskText.Text = DataBrige.TempAddress.NetMask; 52 | IpDescription.Text = DataBrige.TempAddress.Description; 53 | 54 | CalculateNetMaskLocated(); 55 | 56 | IpTextBox.IsEnabled = false; 57 | MaskText.IsEnabled = false; 58 | MaskSlider.IsEnabled=false; 59 | UpdateIPCalculations(); 60 | } 61 | 62 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 63 | string dbName = "Address_database.db"; 64 | 65 | dbFilePath = dbFilePath + dbName; 66 | 67 | dbClass = new DbClass(dbFilePath); 68 | dbClass.OpenConnection(); 69 | 70 | 71 | } 72 | 73 | /// 74 | /// 保存新建的网段 75 | /// 76 | /// 77 | /// 78 | private void SaveButton_Click(object sender, RoutedEventArgs e) 79 | { 80 | //添加网段 81 | if (DataBrige.AddStatus == 0) 82 | { 83 | 84 | //判断是不是瞎几把写的IP地址 85 | if (IsValidIp(IpTextBox.Text) == true) 86 | { 87 | //计算IP 88 | UpdateIPCalculations(); 89 | 90 | //网段地址 91 | string ip = Network.Text; 92 | string netMask = MaskText.Text; 93 | 94 | if (IpDescription.Text != "") 95 | { 96 | string tableName; 97 | 98 | string sqlTemp = string.Format("SELECT COUNT(*) FROM Network WHERE `Network` = '{0}' AND `Netmask` = '{1}'", ip, netMask); 99 | 100 | 101 | 102 | int num = dbClass.ExecuteScalarTableNum(sqlTemp, dbClass.connection); 103 | 104 | //IP地址段已存在 105 | if (num > 0) 106 | { 107 | string msg = string.Format("已存在同配置网段{0}个,是否继续添加同配置网段?", num.ToString()); 108 | 109 | MessageBoxResult result = MessageBox.Show(msg, "确认", MessageBoxButton.YesNo, 110 | MessageBoxImage.Information); 111 | 112 | if (result == MessageBoxResult.Yes) 113 | { 114 | // 用户点击了"是"按钮,执行相关操作 115 | tableName = CreateTableName(ip,netMask) + "_" + (num + 1).ToString(); 116 | 117 | Console.WriteLine(tableName); 118 | 119 | //插入网段信息总表的数据 120 | string sql = string.Format( 121 | "INSERT INTO Network (TableName,Network,Netmask,Description,Del) VALUES ('{0}','{1}','{2}','{3}','{4}')", 122 | tableName, ip, netMask, IpDescription.Text, 0); 123 | 124 | dbClass.ExecuteQuery(sql); 125 | 126 | //创建表 127 | CreateTable(tableName); 128 | 129 | //装载初始化数据 130 | InitializedData(tableName); 131 | 132 | 133 | this.DialogResult = true; 134 | this.Close(); 135 | 136 | 137 | 138 | } 139 | else if (result == MessageBoxResult.No) 140 | { 141 | // 用户点击了"否"按钮,取消操作或进行其他处理 142 | 143 | 144 | } 145 | 146 | 147 | } 148 | else 149 | { 150 | 151 | tableName = CreateTableName(ip, netMask) + "_1"; 152 | 153 | Console.WriteLine(tableName); 154 | 155 | //插入网段信息总表的数据 156 | string sql = string.Format( 157 | "INSERT INTO Network (TableName,Network,Netmask,Description,Del) VALUES ('{0}','{1}','{2}','{3}','{4}')", 158 | tableName, ip, netMask, IpDescription.Text, 0); 159 | 160 | dbClass.ExecuteQuery(sql); 161 | 162 | //插入网段信息总表的数据 163 | 164 | //创建表 165 | CreateTable(tableName); 166 | 167 | //装载初始化数据 168 | InitializedData(tableName); 169 | 170 | 171 | this.DialogResult = true; 172 | this.Close(); 173 | 174 | 175 | 176 | } 177 | 178 | 179 | } 180 | else 181 | { 182 | 183 | MessageBox.Show("为了便于后期管理,必须填写网段说明!", "确定", MessageBoxButton.OK, MessageBoxImage.Information); 184 | 185 | 186 | } 187 | 188 | } 189 | else 190 | { 191 | MessageBox.Show("IP地址不合法,请检查IP地址是否正确!", "确定", MessageBoxButton.OK, MessageBoxImage.Information); 192 | } 193 | 194 | } 195 | else//编辑网段 196 | { 197 | 198 | 199 | if (IpDescription.Text!="") 200 | { 201 | string tableName = DataBrige.TempAddress.TableName; 202 | 203 | string sqlTemp = string.Format("UPDATE \"Network\" SET \"Description\" = '{0}' WHERE TableName = '{1}'", IpDescription.Text, tableName); 204 | 205 | Console.WriteLine(sqlTemp); 206 | 207 | dbClass.ExecuteQuery(sqlTemp); 208 | 209 | 210 | 211 | this.Close(); 212 | } 213 | 214 | 215 | 216 | 217 | 218 | } 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | } 227 | 228 | /// 229 | /// 判断是否是合法IP 230 | /// 231 | /// 232 | /// 233 | static bool IsValidIp(string ipAddress) 234 | { 235 | IPAddress address; 236 | return IPAddress.TryParse(ipAddress, out address); 237 | } 238 | 239 | /// 240 | /// 生成表名 241 | /// 242 | /// 243 | private string CreateTableName(string address,string netmask) 244 | { 245 | string name = Network.Text + "_" + MaskText.Text; 246 | name = "tb_" + name.Replace(".", "_"); 247 | 248 | return name; 249 | } 250 | 251 | /// 252 | /// 创建一张数据表 253 | /// 254 | /// 255 | /// 256 | private void CreateTable(string tableName) 257 | { 258 | string sql = string.Format( 259 | "CREATE TABLE IF NOT EXISTS {0} (Address INTEGER NOT NULL ,AddressStatus INTEGER , User VARCHAR ( 16 ),Description VARCHAR ( 80 ),HostName VARCHAR ( 64 ),MacAddress VARCHAR ( 20 ))", 260 | tableName); 261 | 262 | dbClass.ExecuteQuery(sql); 263 | 264 | 265 | } 266 | 267 | /// 268 | /// 填充网段表单初始数据 269 | /// 270 | private void InitializedData(string tableName) 271 | { 272 | string[] parts = Network.Text.Split('.'); 273 | 274 | //取出第一个IP 275 | int firstIp =Convert.ToInt32( parts[3]); 276 | 277 | 278 | parts = Broadcast.Text.Split('.'); 279 | 280 | //取出最后一个IP,广播IP 281 | int LastIp = Convert.ToInt32(parts[3]); 282 | 283 | 284 | 285 | int x = Convert.ToInt32(NumBox.Text); 286 | 287 | for (int i = 0; i < x; i++) 288 | { 289 | //IP地址锁定状态:0不可用IP,1可用IP 290 | int addressStatus = 0; 291 | 292 | int ip = firstIp + i; 293 | 294 | 295 | 296 | List lockip = new List(); 297 | 298 | if (ip == firstIp) 299 | { 300 | addressStatus = 0; 301 | 302 | } 303 | else 304 | { 305 | if (ip == LastIp ) 306 | { 307 | 308 | addressStatus = 3; 309 | } 310 | else 311 | { 312 | addressStatus = 1; 313 | } 314 | } 315 | 316 | string sql = string.Format("INSERT INTO `{0}` (`Address`, `AddressStatus`) VALUES ({1}, {2})", 317 | tableName, ip, addressStatus); 318 | 319 | 320 | //Console.WriteLine(sql); 321 | //异步执行 322 | dbClass.ExecuteQuery(sql); 323 | } 324 | 325 | 326 | } 327 | 328 | 329 | /// 330 | /// 传递窗口关闭信息 331 | /// 332 | /// 333 | /// 334 | private void AddWindow_OnClosing(object sender, CancelEventArgs e) 335 | { 336 | this.DialogResult = true; 337 | } 338 | 339 | 340 | /// 341 | /// 页面加载状态(页面未完成加载时不计算IP) 342 | /// 343 | public bool LoadStatus = false; 344 | 345 | 346 | 347 | /// 348 | /// 拖动滑条调整子网掩码 349 | /// 350 | /// 351 | /// 352 | private void MaskSlider_OnValueChanged(object sender, RoutedPropertyChangedEventArgs e) 353 | { 354 | if (LoadStatus == true) 355 | { 356 | //判断是不是瞎几把写的IP地址 357 | if (IsValidIp(IpTextBox.Text) == true) 358 | { 359 | UpdateIPCalculations(); 360 | } 361 | else 362 | { 363 | IpTextBox.Text = ""; 364 | MessageBox.Show("IP地址不合法,请检查IP地址是否正确!", "确定", MessageBoxButton.OK, MessageBoxImage.Information); 365 | } 366 | 367 | 368 | } 369 | 370 | 371 | } 372 | 373 | 374 | 375 | /// 376 | /// 计算子网掩码位数 377 | /// 378 | /// 379 | private void CalculateNetMaskLocated() 380 | { 381 | string ipStr = MaskText.Text; 382 | int index = ipStr.LastIndexOf(".") + 1; 383 | 384 | string strTemp = ipStr.Substring(index, ipStr.Length - index); 385 | 386 | if (strTemp == "0") 387 | { 388 | strTemp = "256"; 389 | } 390 | 391 | string str = Convert.ToString(Convert.ToInt32(strTemp), 2); 392 | 393 | 394 | 395 | index = str.IndexOf("0"); 396 | 397 | 398 | string str2 = str.Substring(index, str.Length - index); 399 | 400 | // MessageBox.Show(str2); 401 | 402 | 403 | 404 | MaskSlider.Value = 32 - str2.Length; 405 | } 406 | 407 | 408 | /// 409 | /// IP地址计算 410 | /// 411 | private void UpdateIPCalculations() 412 | { 413 | try 414 | { 415 | IPAddress ip; 416 | if (IPAddress.TryParse(IpTextBox.Text, out ip)) 417 | { 418 | int maskLength = (int)MaskSlider.Value; 419 | IPAddress mask = IPAddressCalculations.SubnetMaskFromPrefixLength(maskLength); 420 | MaskText.Text = mask.ToString(); 421 | 422 | IPAddress networkAddress = ip.GetNetworkAddress(mask); 423 | Network.Text = networkAddress.ToString(); 424 | 425 | IPAddress firstAddress = networkAddress.GetFirstUsable(ip.AddressFamily); 426 | First.Text = firstAddress.ToString(); 427 | 428 | IPAddress lastAddress = networkAddress.GetLastUsable(ip.AddressFamily, maskLength); 429 | 430 | Last.Text = lastAddress.ToString(); 431 | 432 | IPAddress broadcastAddress = networkAddress.GetBroadcastAddress(maskLength); 433 | Broadcast.Text = broadcastAddress.ToString(); 434 | 435 | 436 | long addressCount = IPAddressCalculations.AddressCount(maskLength); 437 | NumBox.Text = addressCount.ToString(); 438 | } 439 | } 440 | catch (Exception ex) 441 | { 442 | MessageBox.Show($"An error occurred: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); 443 | } 444 | } 445 | 446 | 447 | } 448 | 449 | } 450 | 451 | 452 | 453 | 454 | 455 | -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | using IPAM_NOTE.DatabaseOperation; 2 | using IPAM_NOTE.UserWindows; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Configuration; 6 | using System.Data; 7 | using System.Data.SQLite; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | using System.Windows; 12 | using System.Windows.Threading; 13 | 14 | namespace IPAM_NOTE 15 | { 16 | /// 17 | /// App.xaml 的交互逻辑 18 | /// 19 | public partial class App : Application 20 | { 21 | 22 | 23 | 24 | 25 | protected override void OnStartup(StartupEventArgs e) 26 | { 27 | 28 | 29 | base.OnStartup(e); 30 | 31 | //订阅全局异常信息 32 | this.DispatcherUnhandledException += App_DispatcherUnhandledException; 33 | 34 | 35 | // 检查 SQLite 数据库文件是否存在 36 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 37 | string dbName = "Address_database.db"; 38 | 39 | if (!Directory.Exists(dbFilePath)) 40 | { 41 | Directory.CreateDirectory(dbFilePath); 42 | } 43 | 44 | dbFilePath = Path.Combine(dbFilePath, dbName); 45 | 46 | 47 | if (!File.Exists(dbFilePath)) 48 | { 49 | // 如果数据库文件不存在,则创建一个新的数据库文件 50 | SQLiteConnection.CreateFile(dbFilePath); 51 | 52 | // 创建数据库表 53 | using (SQLiteConnection connection = new SQLiteConnection($"Data Source={dbFilePath};Version=3;")) 54 | { 55 | connection.Open(); 56 | using (SQLiteCommand command = new SQLiteCommand(connection)) 57 | { 58 | // 创建表的 SQL 语句 59 | command.CommandText = $"CREATE TABLE \"Devices\" (\r\n \"Id\" INTEGER PRIMARY KEY AUTOINCREMENT,\r\n \"TableName\" TEXT,\r\n \"Name\" TEXT,\r\n \"Model\" TEXT,\r\n \"Number\" TEXT,\r\n \"People\" TEXT,\r\n \"Date\" TEXT,\r\n \"Description\" TEXT,\r\n \"Eport\" integer,\r\n \"EportTag\" TEXT,\r\n \"Fport\" integer,\r\n \"FportTag\" TEXT,\r\n \"Mport\" integer,\r\n \"MportTag\" TEXT,\r\n \"Dport\" integer,\r\n \"DportTag\" TEXT\r\n);"; 60 | command.ExecuteNonQuery(); 61 | command.CommandText = "CREATE TABLE \"Network\" (\r\n \"Id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\r\n \"TableName\" TEXT,\r\n \"Network\" TEXT,\r\n \"Netmask\" TEXT,\r\n \"Description\" TEXT,\r\n \"Del\" TEXT\r\n)"; 62 | command.ExecuteNonQuery(); 63 | command.CommandText = $"CREATE TABLE \"User\" (\r\n \"Id\" INTEGER PRIMARY KEY AUTOINCREMENT,\r\n \"Password\" TEXT);"; 64 | command.ExecuteNonQuery(); 65 | command.CommandText = $"CREATE TABLE \"ModelPreset\" (\r\n \"Id\" INTEGER PRIMARY KEY AUTOINCREMENT, \r\n \"ModelType\" TEXT, \r\n \"Brand\" TEXT,\r\n \"Model\" TEXT,\r\n \"Ethernet\" TEXT,\r\n \"Fiber\" TEXT,\r\n \"Disk\" TEXT\r\n,,\r\n \"Manage\" TEXT\r\n);"; 66 | command.ExecuteNonQuery(); 67 | } 68 | } 69 | } 70 | 71 | 72 | 73 | } 74 | 75 | 76 | 77 | /// 78 | /// 全局异常处理 79 | /// 80 | /// 81 | /// 82 | private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 83 | { 84 | // 处理异常 85 | // 记录异常信息、显示友好的错误提示框等 86 | Console.WriteLine(e.Exception); 87 | e.Handled = true; // 标记为已处理,防止应用程序终止 88 | } 89 | 90 | 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /DataBrige.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using static IPAM_NOTE.ViewMode; 9 | 10 | namespace IPAM_NOTE 11 | { 12 | internal class DataBrige 13 | { 14 | public static ViewMode.AddressInfo TempAddress = new ViewMode.AddressInfo(0, "", "", "", "", ""); 15 | 16 | public static string SelectIp; 17 | 18 | public static ViewMode.IpAddressInfo IpAddress = new ViewMode.IpAddressInfo(0, 0, "", "", System.Net.NetworkInformation.IPStatus.Unknown, -1, "", "", "", ""); 19 | 20 | public static List ipAddressInfos = new List(); 21 | 22 | /// 23 | /// 当前软件版本号 24 | /// 25 | public static string Ver = "1.24"; 26 | 27 | /// 28 | /// 最新版本号 29 | /// 30 | public static string LatestVersion = "0"; 31 | 32 | /// 33 | /// 最新下载地址 34 | /// 35 | public static String DownloadUrl = ""; 36 | 37 | /// 38 | /// 0为新建网段,1为编辑网段 39 | /// 40 | public static int AddStatus = 0; 41 | 42 | /// 43 | /// 搜索框搜索后被选中的IP地址索引 44 | /// 45 | public static int SelectIndex; 46 | 47 | /// 48 | /// 搜索框搜索的网段INDEX 49 | /// 50 | public static int SelectNetwork; 51 | 52 | /// 53 | /// 正常加载=0,搜索加载=1 54 | /// 55 | public static int LoadType; 56 | 57 | /// 58 | /// 搜索时所选表格名字 59 | /// 60 | public static string SelectTableName; 61 | 62 | 63 | //public static List ipAddressInfos = new List(); 64 | 65 | 66 | 67 | 68 | //搜索区网段列表 69 | public static ObservableCollection ComBoxAddressInfos = new ObservableCollection(); 70 | 71 | /// 72 | /// 数据导入界面,网段ComboBox数据源 73 | /// 74 | public static List ComboBoxAddressList = new List(); 75 | 76 | /// 77 | /// 被选择的按钮的标记 78 | /// 79 | public static int SelectButtonTag; 80 | 81 | /// 82 | /// 搜索的类型,0为全局搜索,1为指定搜索 83 | /// 84 | public static int SearchType; 85 | 86 | 87 | /// 88 | /// 全局搜索时点击搜索结果被选中的表项 89 | /// 90 | public static ViewMode.SearchInfo SelectSearchInfo = new ViewMode.SearchInfo(); 91 | 92 | 93 | /// 94 | /// 全局搜索时候获取的结果列表 95 | /// 96 | public static List searchInfos = new List(); 97 | 98 | 99 | /// 100 | /// 分配或者释放模式,0为未选择状态、1为选择未分配地址准备分配,2为选择已分配地址准备释放 101 | /// 102 | public static int SelectMode = 0; 103 | 104 | 105 | /// 106 | /// 多选模式下一并被选择的IP 107 | /// 108 | public static List SelectedIpAddress = new List(); 109 | 110 | 111 | /// 112 | /// 更新信息 113 | /// 114 | public static string UpdateInfos = ""; 115 | 116 | 117 | //----------------------------DevicesPage----------------------------------- 118 | 119 | //获取到的设备信息列表 120 | public static List DeviceInfos = new List(); 121 | 122 | 123 | /// 124 | /// 从数据库获取到的设备端口信息列表 125 | /// 126 | public static List DevicePortInfos = new List(); 127 | 128 | /// 129 | /// 所选设备端口的标签 130 | /// 131 | public static string SelectDeviceButtonTag; 132 | 133 | 134 | 135 | /// 136 | /// 点击设备列表时临时存储当前所选设备的对应信息 137 | /// 138 | public static ViewMode.DeviceInfo SelectDeviceInfo; 139 | 140 | 141 | /// 142 | /// 点击端口按钮后临时存储所选端口对应的信息 143 | /// 144 | public static ViewMode.DevicePortInfo SelectDevicePortInfo; 145 | 146 | 147 | /// 148 | /// 0为添加设备,1为编辑设备 149 | /// 150 | public static int DeviceAddStatus = 0; 151 | 152 | 153 | /// 154 | /// 设备端口的选择模式,0为未选择状态,1为已选择未分配端口准备分配,2为已选择已分配端口准备释放 155 | /// 156 | public static int SelectDevicePortMode = 0; 157 | 158 | /// 159 | /// 多选模式下首次选择的端口类型,E,F,M,D 160 | /// 161 | public static string SelectDevicePortType = ""; 162 | 163 | 164 | /// 165 | /// 多选模式下首次选择的端口状态,0未分配,1已分配 166 | /// 167 | public static string SelectDevicePortStatus = "-1"; 168 | 169 | /// 170 | /// 多选模式下,一次选择的多个端口清单 171 | /// 172 | public static List portList = new List();//批量选择的端口号 173 | 174 | /// 175 | /// 设备端口列表显示还是图形显示,0为图形,1为列表 176 | /// 177 | public static int GraphicsMode = 0; 178 | 179 | 180 | /// 181 | /// 搜索的设备表名 182 | /// 183 | public static string SearchDeviceTableName; 184 | 185 | /// 186 | /// 点击设备列表时候的设备表名 187 | /// 188 | public static string SelectDeviceTableName; 189 | 190 | 191 | /// 192 | /// 全局搜索到的设备信息清单 193 | /// 194 | public static List SearchDeviceInfos = new List(); 195 | 196 | 197 | /// 198 | /// 设备信息加载方式,0为正常加载,1为搜索加载 199 | /// 200 | public static int DeviceLoadType; 201 | 202 | 203 | /// 204 | /// 设备端口信息搜索方式,0为全局搜索,1为指定搜索 205 | /// 206 | public static int DeviceSearchType = -1; 207 | 208 | 209 | 210 | /// 211 | /// 设备列表,显示在搜索筛选框 212 | /// 213 | public static List DevicesList = new List(); 214 | 215 | 216 | /// 217 | /// 表示点击标签是编辑还是访问,0为访问,1为编辑 218 | /// 219 | public static int EditMode = 0; 220 | 221 | 222 | /// 223 | /// 表示当前选中的导航标签,-1为未选择 224 | /// 225 | public static int SelectIndexTag = -1; 226 | 227 | //----------------------------ModelPreset----------------------------------- 228 | 229 | /// 230 | /// 型号预设列表 231 | /// 232 | public static List ModelPresetInfos = new List(); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /DatabaseOperation/DbClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Common; 4 | using System.Data.SqlClient; 5 | using System.Data.SQLite; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using MaterialDesignThemes.Wpf.Transitions; 12 | 13 | namespace IPAM_NOTE.DatabaseOperation 14 | { 15 | internal class DbClass 16 | { 17 | 18 | 19 | public SQLiteConnection connection; 20 | 21 | 22 | public DbClass(string dbPath) 23 | { 24 | 25 | connection = new SQLiteConnection($"Data Source={dbPath};Version=3;"); 26 | 27 | 28 | } 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | public void OpenConnection() 37 | { 38 | if (connection.State != System.Data.ConnectionState.Open) 39 | { 40 | connection.Open(); 41 | } 42 | } 43 | 44 | 45 | public void CloseConnection() 46 | { 47 | if (connection.State != System.Data.ConnectionState.Closed) 48 | { 49 | connection.Close(); 50 | } 51 | } 52 | 53 | public void CreateTable(string query) 54 | { 55 | SQLiteCommand command = new SQLiteCommand(query, connection); 56 | command.ExecuteNonQuery(); 57 | } 58 | 59 | 60 | public SQLiteDataReader ExecuteQuery(string query) 61 | { 62 | 63 | Console.WriteLine(query); 64 | using (SQLiteCommand command = new SQLiteCommand(query, connection)) 65 | { 66 | using (SQLiteDataReader reader = command.ExecuteReader()) 67 | { 68 | return reader; 69 | } 70 | } 71 | } 72 | 73 | 74 | 75 | 76 | // 执行 SQL 查询函数 77 | static void ExecuteSql(SQLiteConnection connection, string sqlQuery) 78 | { 79 | // 创建命令对象 80 | using (SQLiteCommand command = new SQLiteCommand(sqlQuery, connection)) 81 | { 82 | try 83 | { 84 | // 执行 SQL 命令 85 | int rowsAffected = command.ExecuteNonQuery(); 86 | 87 | // 输出受影响的行数 88 | Console.WriteLine($"Rows Affected: {rowsAffected}"); 89 | } 90 | catch (Exception ex) 91 | { 92 | // 处理异常 93 | Console.WriteLine($"Error executing SQL query: {ex.Message}"); 94 | } 95 | } 96 | } 97 | 98 | 99 | 100 | /// 101 | /// 查询表中的数据数量,返回数据条数 102 | /// 103 | /// 104 | /// 105 | public int ExecuteScalarTableNum(string sql,SQLiteConnection connection) 106 | { 107 | 108 | 109 | 110 | using (SQLiteCommand command = new SQLiteCommand(sql,connection)) 111 | { 112 | // 使用 ExecuteScalar 获取总行数 113 | int rowCount = Convert.ToInt32(command.ExecuteScalar()); 114 | 115 | return rowCount; 116 | 117 | //MessageBox.Show( GlobalFunction.IpAddressConvert.IpToDecimal(IpTextBox.Text).ToString()); 118 | 119 | } 120 | 121 | 122 | 123 | 124 | } 125 | 126 | 127 | /// 128 | /// 异步插入数据 129 | /// 130 | /// 131 | /// 132 | public async Task InsertDataAsync(string sql) 133 | { 134 | using (connection) 135 | { 136 | await connection.OpenAsync(); 137 | 138 | using (SQLiteCommand command = connection.CreateCommand()) 139 | { 140 | 141 | command.CommandText = sql; 142 | 143 | // 异步执行插入操作 144 | await command.ExecuteNonQueryAsync(); 145 | } 146 | } 147 | } 148 | 149 | 150 | // 检测表是否存在 151 | public bool IsTableExists(string tableName) 152 | { 153 | 154 | 155 | using (SQLiteCommand command = new SQLiteCommand(connection)) 156 | { 157 | command.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}';"; 158 | using (SQLiteDataReader reader = command.ExecuteReader()) 159 | { 160 | return reader.HasRows; // 如果有行,则表存在,否则不存在 161 | } 162 | } 163 | 164 | } 165 | 166 | 167 | /// 168 | /// 创建设备表 169 | /// 170 | /// 171 | public void CreateTableIfNotExists(string tableName) 172 | { 173 | if (!IsTableExists(tableName)) 174 | { 175 | 176 | using (SQLiteCommand command = new SQLiteCommand(connection)) 177 | { 178 | // 创建表的 SQL 语句 179 | command.CommandText = $"CREATE TABLE \"Devices\" (\r\n \"Id\" INTEGER PRIMARY KEY AUTOINCREMENT,\r\n \"TableName\" TEXT,\r\n \"Name\" TEXT,\r\n \"Model\" TEXT,\r\n \"Number\" TEXT,\r\n \"People\" TEXT,\r\n \"Date\" TEXT,\r\n \"Description\" TEXT,\r\n \"Eport\" integer,\r\n \"EportTag\" TEXT,\r\n \"Fport\" integer,\r\n \"FportTag\" TEXT,\r\n \"Mport\" integer,\r\n \"MportTag\" TEXT,\r\n \"Dport\" integer,\r\n \"DportTag\" TEXT\r\n);"; 180 | command.ExecuteNonQuery(); 181 | } 182 | 183 | } 184 | } 185 | 186 | 187 | /// 188 | /// 创建用户表 189 | /// 190 | /// 191 | public void CreateTableIfNotExistsUser(string tableName) 192 | { 193 | if (!IsTableExists(tableName)) 194 | { 195 | 196 | using (SQLiteCommand command = new SQLiteCommand(connection)) 197 | { 198 | // 创建表的 SQL 语句 199 | command.CommandText = $"CREATE TABLE \"{tableName}\" (\r\n \"Id\" INTEGER PRIMARY KEY AUTOINCREMENT,\r\n \"Password\" TEXT);"; 200 | command.ExecuteNonQuery(); 201 | 202 | } 203 | 204 | } 205 | } 206 | 207 | 208 | 209 | /// 210 | /// 创建设备型号预设表 211 | /// 212 | /// 213 | public void CreateModelPresetIfNotExists(string tableName) 214 | { 215 | if (!IsTableExists(tableName)) 216 | { 217 | 218 | using (SQLiteCommand command = new SQLiteCommand(connection)) 219 | { 220 | // 创建表的 SQL 语句 221 | command.CommandText = $"CREATE TABLE \"ModelPreset\" (\r\n \"Id\" INTEGER PRIMARY KEY AUTOINCREMENT, \r\n \"ModelType\" TEXT, \r\n \"Brand\" TEXT,\r\n \"Model\" TEXT,\r\n \"Ethernet\" TEXT,\r\n \"Fiber\" TEXT,\r\n \"Disk\" TEXT\r\n,,\r\n \"Manage\" TEXT\r\n);"; 222 | 223 | command.ExecuteNonQuery(); 224 | } 225 | 226 | } 227 | } 228 | 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /GitHubVersionChecker.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | 10 | namespace IPAM_NOTE 11 | { 12 | public class GitHubVersionChecker 13 | { 14 | private readonly string _repositoryOwner; 15 | private readonly string _repositoryName; 16 | 17 | public GitHubVersionChecker(string repositoryOwner, string repositoryName) 18 | { 19 | _repositoryOwner = repositoryOwner; 20 | _repositoryName = repositoryName; 21 | } 22 | 23 | public async Task GetLatestVersionAsync() 24 | { 25 | try 26 | { 27 | string apiUrl = $"https://api.github.com/repos/{_repositoryOwner}/{_repositoryName}/releases/latest"; 28 | 29 | using (HttpClient client = new HttpClient()) 30 | { 31 | client.DefaultRequestHeaders.Add("User-Agent", "YourAppName"); 32 | HttpResponseMessage response = await client.GetAsync(apiUrl); 33 | response.EnsureSuccessStatusCode(); 34 | 35 | string json = await response.Content.ReadAsStringAsync(); 36 | var release = JsonConvert.DeserializeObject(json); 37 | 38 | return release.TagName; 39 | } 40 | } 41 | catch (Exception ex) 42 | { 43 | // 处理异常 44 | Console.WriteLine($"An error occurred: {ex.Message}"); 45 | return null; 46 | } 47 | } 48 | 49 | public async Task GetDownloadUrlAsync() 50 | { 51 | try 52 | { 53 | string apiUrl = $"https://api.github.com/repos/{_repositoryOwner}/{_repositoryName}/releases/latest"; 54 | 55 | using (HttpClient client = new HttpClient()) 56 | { 57 | client.DefaultRequestHeaders.Add("User-Agent", @"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"); 58 | HttpResponseMessage response = await client.GetAsync(apiUrl); 59 | response.EnsureSuccessStatusCode(); 60 | 61 | string json = await response.Content.ReadAsStringAsync(); 62 | var release = JsonConvert.DeserializeObject(json); 63 | 64 | // 遍历附件列表,找到下载链接 65 | foreach (var asset in release.Assets) 66 | { 67 | if (!string.IsNullOrEmpty(asset.DownloadUrl)) 68 | { 69 | return asset.DownloadUrl; 70 | } 71 | } 72 | 73 | // 如果找不到下载链接,返回 null 74 | return null; 75 | } 76 | } 77 | catch (Exception ex) 78 | { 79 | // 处理异常 80 | Console.WriteLine($"An error occurred: {ex.Message}"); 81 | return null; 82 | } 83 | } 84 | 85 | public async Task GetReleaseBodyAsync() 86 | { 87 | try 88 | { 89 | string apiUrl = $"https://api.github.com/repos/{_repositoryOwner}/{_repositoryName}/releases/latest"; 90 | 91 | using (HttpClient client = new HttpClient()) 92 | { 93 | client.DefaultRequestHeaders.Add("User-Agent", @"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"); 94 | HttpResponseMessage response = await client.GetAsync(apiUrl); 95 | response.EnsureSuccessStatusCode(); 96 | 97 | string json = await response.Content.ReadAsStringAsync(); 98 | var release = JsonConvert.DeserializeObject(json); 99 | 100 | return release.Body; 101 | } 102 | } 103 | catch (Exception ex) 104 | { 105 | // 处理异常 106 | Console.WriteLine($"An error occurred: {ex.Message}"); 107 | return ""; 108 | } 109 | } 110 | 111 | 112 | private class GitHubRelease 113 | { 114 | [JsonProperty("tag_name")] 115 | public string TagName { get; set; } 116 | 117 | [JsonProperty("assets")] 118 | public List Assets { get; set; } 119 | 120 | [JsonProperty("body")] 121 | public string Body { get; set; } 122 | } 123 | 124 | private class GitHubAsset 125 | { 126 | [JsonProperty("browser_download_url")] 127 | public string DownloadUrl { get; set; } 128 | } 129 | 130 | 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /IPAM-NOTE.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34622.214 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPAM-NOTE", "IPAM-NOTE.csproj", "{89472C4D-6B61-46F3-A976-6F78F15A06FF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {89472C4D-6B61-46F3-A976-6F78F15A06FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {89472C4D-6B61-46F3-A976-6F78F15A06FF}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {89472C4D-6B61-46F3-A976-6F78F15A06FF}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {89472C4D-6B61-46F3-A976-6F78F15A06FF}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {3ABE76A3-E3B6-41E5-A538-994CD6D02E3D} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /IPAddressCalculations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace IPAM_NOTE 9 | { 10 | public static class IPAddressCalculations 11 | { 12 | 13 | public static long AddressCount(int maskLength) 14 | { 15 | return (long)Math.Pow(2, 32 - maskLength); 16 | } 17 | 18 | public static IPAddress SubnetMaskFromPrefixLength(int prefixLength) 19 | { 20 | uint subnet = 0xffffffff; 21 | subnet <<= (32 - prefixLength); 22 | byte[] bytes = BitConverter.GetBytes(subnet); 23 | Array.Reverse(bytes); 24 | return new IPAddress(bytes); 25 | } 26 | 27 | public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask) 28 | { 29 | byte[] ipBytes = address.GetAddressBytes(); 30 | byte[] maskBytes = subnetMask.GetAddressBytes(); 31 | 32 | byte[] result = new byte[ipBytes.Length]; 33 | for (int i = 0; i < ipBytes.Length; i++) 34 | { 35 | result[i] = (byte)(ipBytes[i] & maskBytes[i]); 36 | } 37 | 38 | return new IPAddress(result); 39 | } 40 | 41 | public static IPAddress GetFirstUsable(this IPAddress networkAddress, System.Net.Sockets.AddressFamily addressFamily) 42 | { 43 | byte[] bytes = networkAddress.GetAddressBytes(); 44 | bytes[bytes.Length - 1] += 1; // Increment last byte 45 | return new IPAddress(bytes); 46 | } 47 | 48 | public static IPAddress GetLastUsable(this IPAddress networkAddress, System.Net.Sockets.AddressFamily addressFamily, int maskLength) 49 | { 50 | byte[] bytes = networkAddress.GetAddressBytes(); 51 | int usableAddresses = (int)Math.Pow(2, 32 - maskLength) - 2; // Calculate the number of usable addresses 52 | int lastByteIndex = bytes.Length - 1; 53 | int carry = usableAddresses / 256; 54 | bytes[lastByteIndex] += (byte)(usableAddresses % 256); // Add remainder to last byte 55 | for (int i = lastByteIndex - 1; i >= 0 && carry > 0; i--) 56 | { 57 | int sum = bytes[i] + carry; 58 | bytes[i] = (byte)(sum % 256); 59 | carry = sum / 256; 60 | } 61 | return new IPAddress(bytes); 62 | } 63 | 64 | 65 | public static IPAddress GetBroadcastAddress(this IPAddress networkAddress, int maskLength) 66 | { 67 | byte[] bytes = networkAddress.GetAddressBytes(); 68 | int lastByteIndex = bytes.Length - 1; 69 | int subnetBits = 32 - maskLength; 70 | 71 | for (int i = 0; i < subnetBits; i++) 72 | { 73 | int byteIndex = i / 8; 74 | int bitOffset = i % 8; 75 | bytes[lastByteIndex - byteIndex] |= (byte)(1 << bitOffset); 76 | } 77 | 78 | return new IPAddress(bytes); 79 | } 80 | 81 | 82 | public static int CalculateSubnetMaskLength(IPAddress subnetMask) 83 | { 84 | byte[] bytes = subnetMask.GetAddressBytes(); 85 | uint mask = BitConverter.ToUInt32(bytes.Reverse().ToArray(), 0); 86 | int maskLength = 0; 87 | while (mask != 0) 88 | { 89 | maskLength++; 90 | mask <<= 1; 91 | } 92 | return maskLength; 93 | } 94 | 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ImportWindow.xaml: -------------------------------------------------------------------------------- 1 |  23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 44 | 45 | 51 | 52 | 53 | 62 | 63 | 64 | 65 | 66 | 67 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 106 | 107 | 113 | 114 | 115 | 116 | 117 | 128 | 129 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 166 | 167 | 173 | 174 | 175 | 176 | 182 | 183 | 184 | 185 | 186 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("IPAM-NOTE")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("IPAM-NOTE")] 15 | [assembly: AssemblyCopyright("Copyright © 2024")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // 将 ComVisible 设置为 false 会使此程序集中的类型 20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请设置 25 | //.csproj 文件中的 CultureYouAreCodingWith 26 | //在 中。例如,如果你使用的是美国英语。 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(未在页面中找到资源时使用, 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(未在页面中找到资源时使用, 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 52 | //通过使用 "*",如下所示: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace IPAM_NOTE.Properties 12 | { 13 | 14 | 15 | /// 16 | /// 强类型资源类,用于查找本地化字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// 返回此类使用的缓存 ResourceManager 实例。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("IPAM_NOTE.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 重写当前线程的 CurrentUICulture 属性,对 56 | /// 使用此强类型资源类的所有资源查找执行重写。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace IPAM_NOTE.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IPAM-NOTE 2 | 需要多用户版本的请查看我的另一项目 SIPAM https://github.com/yaobus/SIPAM.git 3 | 4 | 5 | 鉴于在论坛有不少网友没有多用户的IP地址分配记录需求 6 | 7 | 只需要一个本地运行的单用户IP地址分配记录功能 8 | 9 | 于是就有了这个项目IPAM-NOTE(IP地址分配记录本) 10 | 11 | 功能纯粹、界面简洁、无广告、解压即用...... 12 | 13 | 添加网段界面如下: 14 | 15 | ![添加网段](https://github.com/yaobus/ProjectData/blob/main/ipam-note/01.png) 16 | 17 | 分配地址界面如下 18 | ![添加网段](https://github.com/yaobus/ProjectData/blob/main/ipam-note/00.png) 19 | 20 | 网段图形化界面如下(鼠标悬停可查看被选中IP的分配信息): 21 | ![添加网段](https://github.com/yaobus/ProjectData/blob/main/ipam-note/02.png) 22 | 23 | 列表显示网段IP详细信息: 24 | ![图形化](https://github.com/yaobus/ProjectData/blob/main/ipam-note/03.png) 25 | 26 | 图形化界面单击地址或列表界面双击地址可以弹出地址分配窗口 27 | 28 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/04.png) 29 | 30 | 31 | 批量地址检测 32 | 33 | ![地址检测](https://github.com/yaobus/ProjectData/blob/main/ipam-note/06.png) 34 | 35 | EXCEL导出界面 36 | ![地址分配]([https://github.com/yaobus/ProjectData/blob/main/ipam-note/%E5%AF%BC%E5%87%BA.png]) 37 | 38 | 搜索界面 39 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/%E6%90%9C%E7%B4%A2%E7%95%8C%E9%9D%A2.png) 40 | 41 | UI帮助界面 42 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/helpui.png) 43 | 44 | 数据导入界面 45 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/import.png) 46 | 47 | 数据导入帮助界面 48 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/heipimport.png) 49 | 50 | 51 | 数据还原界面 52 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/restore.png) 53 | 54 | 其他界面 55 | ![地址分配](https://github.com/yaobus/ProjectData/blob/main/ipam-note/05.png) 56 | -------------------------------------------------------------------------------- /Resources/ADD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/ADD.png -------------------------------------------------------------------------------- /Resources/ALLOCATION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/ALLOCATION.png -------------------------------------------------------------------------------- /Resources/DATAHELP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/DATAHELP.png -------------------------------------------------------------------------------- /Resources/DONATION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/DONATION.png -------------------------------------------------------------------------------- /Resources/Devices/SWITCH1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/Devices/SWITCH1.png -------------------------------------------------------------------------------- /Resources/HumanGreeting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/HumanGreeting.png -------------------------------------------------------------------------------- /Resources/IMPORT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/IMPORT.png -------------------------------------------------------------------------------- /Resources/LOGIN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/LOGIN.png -------------------------------------------------------------------------------- /Resources/UI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaobus/IPAM-NOTE/bb0b543b2a10350be71c20d67f23adc660256ae0/Resources/UI.png -------------------------------------------------------------------------------- /UserControls/GridCanvas.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /UserControls/GridCanvas.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace IPAM_NOTE.UserControls 17 | { 18 | /// 19 | /// GridCanvas.xaml 的交互逻辑 20 | /// 21 | public partial class GridCanvas : UserControl 22 | { 23 | private bool isDragging = false; 24 | private Point lastPosition; 25 | private bool isDraggingCanvas = false; 26 | private bool isDraggingContent = false; 27 | private Point lastCanvasPosition; 28 | private Point lastContentPosition; 29 | 30 | public GridCanvas() 31 | { 32 | InitializeComponent(); 33 | 34 | } 35 | private void GridCanvas_OnLoaded(object sender, RoutedEventArgs e) 36 | { 37 | DrawGrid(); 38 | } 39 | 40 | private void DrawGrid() 41 | { 42 | double width = canvas.ActualWidth; 43 | double height = canvas.ActualHeight; 44 | double gridSizeInInches = 0.2; // 网格大小(英寸) 45 | double strongLineInterval = 10; // 每隔多少条线显示一根更明显的线条 46 | double strongLineThickness = 0.3; // 更明显的线条的粗细 47 | 48 | // 将网格大小转换为像素值 49 | double gridSizeInPixels = gridSizeInInches * 100; // 1 英寸 = 96 像素 50 | 51 | canvas.Children.Clear(); // 清空之前的网格 52 | 53 | for (double x = 0; x < width; x += gridSizeInPixels) 54 | { 55 | Line line = new Line 56 | { 57 | X1 = x, 58 | Y1 = 0, 59 | X2 = x, 60 | Y2 = height, 61 | Stroke = Brushes.LightGray, 62 | StrokeThickness = (x % (gridSizeInPixels * strongLineInterval) == 0) ? strongLineThickness : 0.1 63 | }; 64 | 65 | canvas.Children.Add(line); 66 | } 67 | 68 | for (double y = 0; y < height; y += gridSizeInPixels) 69 | { 70 | Line line = new Line 71 | { 72 | X1 = 0, 73 | Y1 = y, 74 | X2 = width, 75 | Y2 = y, 76 | Stroke = Brushes.LightGray, 77 | StrokeThickness = (y % (gridSizeInPixels * strongLineInterval) == 0) ? strongLineThickness : 0.1 78 | }; 79 | 80 | canvas.Children.Add(line); 81 | } 82 | } 83 | 84 | 85 | 86 | 87 | private void Canvas_OnMouseRightButtonDown(object sender, MouseButtonEventArgs e) 88 | { 89 | // 右键按下时开始拖动操作 90 | if (e.RightButton == MouseButtonState.Pressed) 91 | { 92 | if (Keyboard.Modifiers == ModifierKeys.None) 93 | { 94 | // 只拖动内容 95 | isDraggingContent = true; 96 | lastContentPosition = e.GetPosition(contentContainer); 97 | contentContainer.CaptureMouse(); 98 | } 99 | else 100 | { 101 | // 拖动整个画布 102 | isDraggingCanvas = true; 103 | lastCanvasPosition = e.GetPosition(canvas); 104 | canvas.CaptureMouse(); 105 | } 106 | } 107 | } 108 | 109 | private void Canvas_OnMouseRightButtonUp(object sender, MouseButtonEventArgs e) 110 | { 111 | // 右键释放时停止拖动操作 112 | isDraggingCanvas = false; 113 | isDraggingContent = false; 114 | canvas.ReleaseMouseCapture(); 115 | contentContainer.ReleaseMouseCapture(); 116 | } 117 | 118 | private void Canvas_OnMouseMove(object sender, MouseEventArgs e) 119 | { 120 | if (isDraggingCanvas) 121 | { 122 | // 如果正在拖动整个画布,则根据鼠标移动的距离调整画布的位置 123 | Point newPosition = e.GetPosition(canvas); 124 | double deltaX = newPosition.X - lastCanvasPosition.X; 125 | double deltaY = newPosition.Y - lastCanvasPosition.Y; 126 | 127 | Canvas.SetLeft(contentContainer, Canvas.GetLeft(contentContainer) + deltaX); 128 | Canvas.SetTop(contentContainer, Canvas.GetTop(contentContainer) + deltaY); 129 | 130 | lastCanvasPosition = newPosition; 131 | } 132 | else if (isDraggingContent) 133 | { 134 | // 如果正在拖动内容,则根据鼠标移动的距离调整内容容器的位置 135 | Point newPosition = e.GetPosition(contentContainer); 136 | double deltaX = newPosition.X - lastContentPosition.X; 137 | double deltaY = newPosition.Y - lastContentPosition.Y; 138 | 139 | Canvas.SetLeft(contentContainer, Canvas.GetLeft(contentContainer) + deltaX); 140 | Canvas.SetTop(contentContainer, Canvas.GetTop(contentContainer) + deltaY); 141 | 142 | lastContentPosition = newPosition; 143 | } 144 | } 145 | 146 | 147 | 148 | private void Canvas_OnMouseWheel(object sender, MouseWheelEventArgs e) 149 | { 150 | // 获取当前鼠标相对于 Canvas 左上角的位置 151 | Point mousePosition = e.GetPosition(canvas); 152 | 153 | // 获取鼠标滚轮滚动的增量 154 | int delta = e.Delta; 155 | 156 | // 定义缩放比例的增量,可以根据实际需求进行调整 157 | double scaleIncrement = 0.1; 158 | 159 | // 获取当前 Canvas 的缩放变换 160 | ScaleTransform scaleTransform = canvas.RenderTransform as ScaleTransform; 161 | if (scaleTransform == null) 162 | { 163 | // 如果没有缩放变换,则创建一个新的缩放变换,并应用到 Canvas 上 164 | scaleTransform = new ScaleTransform(1.0, 1.0); 165 | canvas.RenderTransform = scaleTransform; 166 | } 167 | 168 | // 计算新的缩放比例 169 | double newScale = delta > 0 ? scaleTransform.ScaleX + scaleIncrement : scaleTransform.ScaleX - scaleIncrement; 170 | 171 | // 设置缩放比例的上下限,可以根据实际需求进行调整 172 | double minScale = 1; 173 | double maxScale = 3.0; 174 | newScale = Math.Max(minScale, Math.Min(maxScale, newScale)); 175 | 176 | // 计算缩放前后画布左上角的偏移量 177 | double offsetXBeforeScale = Canvas.GetLeft(contentContainer); 178 | double offsetYBeforeScale = Canvas.GetTop(contentContainer); 179 | double offsetXAfterScale = offsetXBeforeScale * newScale; 180 | double offsetYAfterScale = offsetYBeforeScale * newScale; 181 | 182 | // 计算鼠标位置相对于画布左上角的偏移量 183 | double deltaX = mousePosition.X - offsetXBeforeScale; 184 | double deltaY = mousePosition.Y - offsetYBeforeScale; 185 | 186 | // 计算缩放后的位置偏移量 187 | double offsetXDelta = offsetXAfterScale - deltaX; 188 | double offsetYDelta = offsetYAfterScale - deltaY; 189 | 190 | // 应用新的缩放比例到 Canvas 上 191 | scaleTransform.ScaleX = newScale; 192 | scaleTransform.ScaleY = newScale; 193 | 194 | // 同时对内容容器应用相同的缩放变换 195 | contentContainer.LayoutTransform = new ScaleTransform(newScale, newScale); 196 | 197 | // 根据缩放后的位置调整画布,以保持鼠标位置不变 198 | Canvas.SetLeft(contentContainer, offsetXDelta); 199 | Canvas.SetTop(contentContainer, offsetYDelta); 200 | } 201 | 202 | // 当用户调整窗口大小时,重新绘制网格线等内容以适应新的大小 203 | private void GridCanvas_OnSizeChanged(object sender, SizeChangedEventArgs e) 204 | { 205 | DrawGrid(); 206 | } 207 | } 208 | 209 | } 210 | 211 | 212 | -------------------------------------------------------------------------------- /UserPages/About.xaml: -------------------------------------------------------------------------------- 1 |  18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 42 | 43 | 44 | 45 | 52 | 53 | 59 | 66 | 67 | 77 | 78 | 108 | 109 | 116 | 117 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 140 | 141 | 142 | 145 | 148 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /UserPages/DatabaseBackup.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | using Path = System.IO.Path; 18 | 19 | namespace IPAM_NOTE.UserPages 20 | { 21 | /// 22 | /// DatabaseBackup.xaml 的交互逻辑 23 | /// 24 | public partial class DatabaseBackup : UserControl 25 | { 26 | public DatabaseBackup() 27 | { 28 | InitializeComponent(); 29 | } 30 | 31 | List backupList = new List(); 32 | 33 | private void BackupListView_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 34 | { 35 | 36 | Console.WriteLine(BackupListView.SelectedIndex); 37 | 38 | if (BackupListView.SelectedIndex != -1) 39 | { 40 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\Backup"; 41 | 42 | string fileName = backupList[BackupListView.SelectedIndex].FileName; 43 | 44 | BakPath.Text = Path.Combine(dbFilePath, fileName); 45 | 46 | RestoreBackup.IsEnabled = true; 47 | 48 | 49 | } 50 | else 51 | { 52 | RestoreBackup.IsEnabled = false; 53 | } 54 | 55 | 56 | 57 | } 58 | 59 | 60 | 61 | /// 62 | /// 回滚备份 63 | /// 64 | /// 65 | /// 66 | private void RestoreBackup_OnClick(object sender, RoutedEventArgs e) 67 | { 68 | 69 | string destinationFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\Address_database.db"; 70 | 71 | string backupFilePath = BakPath.Text; 72 | 73 | RestoreDataBasseBackup(backupFilePath, destinationFilePath); 74 | 75 | 76 | } 77 | 78 | private void RestoreDataBasseBackup(string backupFilePath, string destinationFilePath) 79 | { 80 | try 81 | { 82 | File.Copy(backupFilePath, destinationFilePath, true); // 复制备份文件到目标位置并覆盖源文件 83 | MessageBox.Show("数据库恢复完成,程序即将重启", "注意", MessageBoxButton.OK, MessageBoxImage.Information); 84 | 85 | RestartApplication(); 86 | } 87 | catch (Exception ex) 88 | { 89 | Console.WriteLine("文件恢复失败:" + ex.Message); 90 | } 91 | } 92 | 93 | private void RestartApplication() 94 | { 95 | // 获取当前应用程序的可执行文件路径 96 | string appPath = Process.GetCurrentProcess().MainModule.FileName; 97 | 98 | // 启动另一个实例你的软件 99 | Process.Start(appPath); 100 | 101 | // 关闭当前实例 102 | Environment.Exit(0); 103 | } 104 | 105 | 106 | private void OpenFolder(string folderPath) 107 | { 108 | try 109 | { 110 | Process.Start(folderPath); 111 | } 112 | catch (Exception ex) 113 | { 114 | Console.WriteLine("无法打开文件夹:" + ex.Message); 115 | } 116 | } 117 | 118 | private void BackupFile_OnClick(object sender, RoutedEventArgs e) 119 | { 120 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\Backup"; 121 | OpenFolder(dbFilePath); 122 | } 123 | 124 | private void DatabaseBackup_OnLoaded(object sender, RoutedEventArgs e) 125 | { 126 | backupList.Clear(); 127 | 128 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 129 | 130 | string backupDirectoryPath = System.IO.Path.Combine(dbFilePath, "Backup"); 131 | 132 | 133 | string[] backupFiles = Directory.GetFiles(backupDirectoryPath, "*.bak") 134 | .OrderByDescending(f => File.GetLastWriteTime(f)) 135 | .Take(20) 136 | .ToArray(); 137 | 138 | 139 | for (int i = 0; i < backupFiles.Length; i++) 140 | { 141 | string fileName = System.IO.Path.GetFileName(backupFiles[i]); 142 | DateTime backupTime = File.GetLastWriteTime(backupFiles[i]); 143 | backupList.Add(new ViewMode.BackupInfo 144 | { 145 | Index = i + 1, 146 | FileName = fileName, 147 | BackupTime = backupTime.ToString("yyyy年M月d日HH:mm") 148 | }); 149 | } 150 | 151 | 152 | BackupListView.ItemsSource = backupList; 153 | } 154 | 155 | 156 | 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /UserPages/DonationPage.xaml: -------------------------------------------------------------------------------- 1 |  16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /UserPages/DonationPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace IPAM_NOTE.UserPages 17 | { 18 | /// 19 | /// DonationPage.xaml 的交互逻辑 20 | /// 21 | public partial class DonationPage : UserControl 22 | { 23 | public DonationPage() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UserPages/HelpPage.xaml: -------------------------------------------------------------------------------- 1 |  18 | 21 | 22 | 26 | 27 | 28 | 29 | 34 | 39 | 44 | 45 | 46 | 47 | 50 | 51 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 69 | 74 | 79 | 80 | 81 | 82 | 83 | 84 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 102 | 107 | 112 | 113 | 114 | 115 | 116 | 117 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 130 | 131 | 132 | 137 | 142 | 147 | 148 | 149 | 150 | 151 | 152 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 165 | 166 | 167 | 172 | 177 | 182 | 183 | 184 | 185 | 186 | 187 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 200 | 201 | 202 | 207 | 212 | 217 | 218 | 219 | 220 | 221 | 222 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 239 | 244 | 249 | 250 | 251 | 252 | 253 | 254 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 271 | 276 | 281 | 282 | 283 | 284 | 285 | 286 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | -------------------------------------------------------------------------------- /UserPages/HelpPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace IPAM_NOTE.UserPages 17 | { 18 | /// 19 | /// HelpPage.xaml 的交互逻辑 20 | /// 21 | public partial class HelpPage : UserControl 22 | { 23 | public HelpPage() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UserPages/HumanGreeting.xaml: -------------------------------------------------------------------------------- 1 |  16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /UserPages/HumanGreeting.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace IPAM_NOTE.UserPages 17 | { 18 | /// 19 | /// HumanGreeting.xaml 的交互逻辑 20 | /// 21 | public partial class HumanGreeting : UserControl 22 | { 23 | public HumanGreeting() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UserPages/IndexPage.xaml: -------------------------------------------------------------------------------- 1 |  17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 56 | 57 | 67 | 68 | 78 | 79 | 80 | 81 | 82 | 83 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 104 | 105 | 106 | 107 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 130 | 131 | 141 | 142 | 150 | 151 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /UserPages/ModelPreset.xaml: -------------------------------------------------------------------------------- 1 |  19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 35 | 36 | 41 | 42 | 48 | 49 | 77 | 78 | 108 | 109 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 144 | 145 | 146 | 150 | 151 | 154 | 158 | 162 | 165 | 168 | 171 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /UserPages/ModelPreset.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SQLite; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | using IPAM_NOTE.DatabaseOperation; 17 | using IPAM_NOTE.PresetWindow; 18 | using static IPAM_NOTE.ViewMode; 19 | 20 | namespace IPAM_NOTE.UserPages 21 | { 22 | /// 23 | /// ModelPreset.xaml 的交互逻辑 24 | /// 25 | public partial class ModelPreset : UserControl 26 | { 27 | public ModelPreset() 28 | { 29 | InitializeComponent(); 30 | } 31 | private DbClass dbClass; 32 | private void ModelPreset_OnLoaded(object sender, RoutedEventArgs e) 33 | { 34 | ModelPresetList.ItemsSource = DataBrige.ModelPresetInfos; 35 | 36 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 37 | 38 | string dbName = "Address_database.db"; 39 | 40 | 41 | dbFilePath = dbFilePath + dbName; 42 | 43 | 44 | 45 | dbClass = new DbClass(dbFilePath); 46 | dbClass.OpenConnection(); 47 | 48 | dbClass.CreateModelPresetIfNotExists("ModelPreset"); //检查表单是否创建 49 | 50 | 51 | LoadModelPreset(dbClass.connection); 52 | 53 | } 54 | 55 | private void AddButton_OnClick(object sender, RoutedEventArgs e) 56 | { 57 | 58 | 59 | AddPreset addPreset = new AddPreset(); 60 | 61 | if (addPreset.ShowDialog() == true) 62 | { 63 | 64 | // 当子窗口关闭后执行这里的代码 65 | LoadModelPreset(dbClass.connection); 66 | 67 | } 68 | 69 | } 70 | 71 | /// 72 | /// 加载设备信息列表 73 | /// 74 | /// 75 | public void LoadModelPreset(SQLiteConnection connection) 76 | { 77 | DataBrige.ModelPresetInfos.Clear(); 78 | ModelPresetList.ItemsSource = null; 79 | try 80 | { 81 | string query = "SELECT * FROM ModelPreSet"; 82 | 83 | SQLiteCommand command = new SQLiteCommand(query, connection); 84 | SQLiteDataReader reader = command.ExecuteReader(); 85 | 86 | int i = 0; 87 | 88 | 89 | 90 | while (reader.Read()) 91 | { 92 | i++; 93 | // 读取数据行中的每一列 94 | 95 | int id = i; 96 | string modelType = reader["ModelType"].ToString(); 97 | string brand = reader["Brand"].ToString(); 98 | string model = reader["Model"].ToString(); 99 | int ethernet = Convert.ToInt32(reader["Ethernet"].ToString()); 100 | int fiber = Convert.ToInt32(reader["Fiber"].ToString()); 101 | int disk = Convert.ToInt32(reader["Disk"].ToString()); 102 | int Manage = Convert.ToInt32(reader["Manage"].ToString()); 103 | DataBrige.ModelPresetInfos.Add(new ModelPresetInfo(id, modelType, brand, model, ethernet, fiber, disk, Manage)); 104 | 105 | 106 | } 107 | 108 | ModelPresetList.ItemsSource = DataBrige.ModelPresetInfos; 109 | 110 | reader.Close(); 111 | } 112 | catch (Exception ex) 113 | { 114 | MessageBox.Show($"Error: {ex.Message}"); 115 | } 116 | } 117 | 118 | 119 | 120 | private void ModelPresetList_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 121 | { 122 | if (ModelPresetList.SelectedIndex != -1) 123 | { 124 | MinusButton.IsEnabled = true; 125 | } 126 | } 127 | 128 | 129 | private void MinusButton_OnClick(object sender, RoutedEventArgs e) 130 | { 131 | string type = DataBrige.ModelPresetInfos[ModelPresetList.SelectedIndex].ModelType; 132 | string brand= DataBrige.ModelPresetInfos[ModelPresetList.SelectedIndex].Brand; 133 | string model = DataBrige.ModelPresetInfos[ModelPresetList.SelectedIndex].Model; 134 | 135 | string sql = $"DELETE FROM \"ModelPreset\" WHERE ModelType = '{type}' AND Brand = '{brand}' AND Model = '{model}'"; 136 | 137 | dbClass.ExecuteQuery(sql); 138 | LoadModelPreset(dbClass.connection); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /UserPages/PeoplePreset.xaml: -------------------------------------------------------------------------------- 1 |  19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 35 | 36 | 41 | 42 | 48 | 49 | 77 | 78 | 108 | 109 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 144 | 145 | 146 | 150 | 151 | 154 | 158 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /UserPages/PeoplePreset.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SQLite; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using IPAM_NOTE.DatabaseOperation; 6 | using IPAM_NOTE.PresetWindow; 7 | using static IPAM_NOTE.ViewMode; 8 | 9 | namespace IPAM_NOTE.UserPages 10 | { 11 | /// 12 | /// ModelPreset.xaml 的交互逻辑 13 | /// 14 | public partial class PeoplePreset : UserControl 15 | { 16 | public PeoplePreset() 17 | { 18 | InitializeComponent(); 19 | } 20 | private DbClass dbClass; 21 | private void ModelPreset_OnLoaded(object sender, RoutedEventArgs e) 22 | { 23 | PeoplePresetList.ItemsSource = DataBrige.ModelPresetInfos; 24 | 25 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 26 | 27 | string dbName = "Address_database.db"; 28 | 29 | 30 | dbFilePath = dbFilePath + dbName; 31 | 32 | 33 | 34 | dbClass = new DbClass(dbFilePath); 35 | dbClass.OpenConnection(); 36 | 37 | dbClass.CreateModelPresetIfNotExists("ModelPreset"); //检查表单是否创建 38 | 39 | 40 | LoadModelPreset(dbClass.connection); 41 | 42 | } 43 | 44 | private void AddButton_OnClick(object sender, RoutedEventArgs e) 45 | { 46 | 47 | 48 | AddPreset addPreset = new AddPreset(); 49 | 50 | if (addPreset.ShowDialog() == true) 51 | { 52 | 53 | // 当子窗口关闭后执行这里的代码 54 | LoadModelPreset(dbClass.connection); 55 | 56 | } 57 | 58 | } 59 | 60 | /// 61 | /// 加载设备信息列表 62 | /// 63 | /// 64 | public void LoadModelPreset(SQLiteConnection connection) 65 | { 66 | DataBrige.ModelPresetInfos.Clear(); 67 | PeoplePresetList.ItemsSource = null; 68 | try 69 | { 70 | string query = "SELECT * FROM ModelPreSet"; 71 | 72 | SQLiteCommand command = new SQLiteCommand(query, connection); 73 | SQLiteDataReader reader = command.ExecuteReader(); 74 | 75 | int i = 0; 76 | 77 | 78 | 79 | while (reader.Read()) 80 | { 81 | i++; 82 | // 读取数据行中的每一列 83 | 84 | int id = i; 85 | string modelType = reader["ModelType"].ToString(); 86 | string brand = reader["Brand"].ToString(); 87 | string model = reader["Model"].ToString(); 88 | int ethernet = Convert.ToInt32(reader["Ethernet"].ToString()); 89 | int fiber = Convert.ToInt32(reader["Fiber"].ToString()); 90 | int disk = Convert.ToInt32(reader["Disk"].ToString()); 91 | int Manage = Convert.ToInt32(reader["Manage"].ToString()); 92 | DataBrige.ModelPresetInfos.Add(new ModelPresetInfo(id, modelType, brand, model, ethernet, fiber, disk, Manage)); 93 | 94 | 95 | } 96 | 97 | PeoplePresetList.ItemsSource = DataBrige.ModelPresetInfos; 98 | 99 | reader.Close(); 100 | } 101 | catch (Exception ex) 102 | { 103 | MessageBox.Show($"Error: {ex.Message}"); 104 | } 105 | } 106 | 107 | 108 | 109 | private void PeoplePresetList_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 110 | { 111 | if (PeoplePresetList.SelectedIndex != -1) 112 | { 113 | MinusButton.IsEnabled = true; 114 | } 115 | } 116 | 117 | 118 | private void MinusButton_OnClick(object sender, RoutedEventArgs e) 119 | { 120 | string type = DataBrige.ModelPresetInfos[PeoplePresetList.SelectedIndex].ModelType; 121 | string brand= DataBrige.ModelPresetInfos[PeoplePresetList.SelectedIndex].Brand; 122 | string model = DataBrige.ModelPresetInfos[PeoplePresetList.SelectedIndex].Model; 123 | 124 | string sql = $"DELETE FROM \"ModelPreset\" WHERE ModelType = '{type}' AND Brand = '{brand}' AND Model = '{model}'"; 125 | 126 | dbClass.ExecuteQuery(sql); 127 | LoadModelPreset(dbClass.connection); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /UserWindows/AddIndexWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SQLite; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Shapes; 15 | using IPAM_NOTE.DatabaseOperation; 16 | 17 | namespace IPAM_NOTE.UserWindows 18 | { 19 | /// 20 | /// AddIndexWindow.xaml 的交互逻辑 21 | /// 22 | public partial class AddIndexWindow : Window 23 | { 24 | public AddIndexWindow() 25 | { 26 | InitializeComponent(); 27 | } 28 | 29 | private DbClass dbClass; 30 | 31 | private void AddIndexWindow_OnLoaded(object sender, RoutedEventArgs e) 32 | { 33 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 34 | string dbName = "Address_database.db"; 35 | 36 | dbFilePath = dbFilePath + dbName; 37 | 38 | dbClass = new DbClass(dbFilePath); 39 | 40 | dbClass.OpenConnection(); 41 | 42 | 43 | 44 | 45 | //判断是编辑还是新建标签 46 | if (DataBrige.EditMode == 1) //编辑模式 47 | { 48 | DeviceBlock.Text = DataBrige.SelectDeviceInfo.Name + " " + DataBrige.SelectDeviceInfo.Number; 49 | ModelTextBlock.Text = "型号:" + DataBrige.SelectDeviceInfo.Model; 50 | DescriptionBlock.Text = "备注:" + DataBrige.SelectDeviceInfo.Description; 51 | 52 | TypeBlock.Text = "当前选中导航标签:" + DataBrige.SelectIndexTag.ToString(); 53 | 54 | string sql = 55 | $"SELECT * FROM {DataBrige.SelectDeviceInfo.TableName} WHERE PortType='I' AND PortNumber ={DataBrige.SelectIndexTag}"; 56 | 57 | SQLiteCommand command = new SQLiteCommand(sql, dbClass.connection); 58 | SQLiteDataReader reader = command.ExecuteReader(); 59 | 60 | ViewMode.DevicePortInfo info = null; 61 | 62 | while (reader.Read()) 63 | { 64 | string portType = reader["PortType"].ToString(); 65 | string portNumber = reader["PortNumber"].ToString(); 66 | int portStatus = Convert.ToInt32(reader["PortStatus"]); 67 | string portTag1 = reader["PortTag1"].ToString(); 68 | string portTag2 = reader["PortTag2"].ToString(); 69 | string portTag3 = reader["PortTag3"].ToString(); 70 | string description = reader["Description"].ToString(); 71 | 72 | 73 | NameBox.Text = portTag1; 74 | UrlBox.Text = portTag2; 75 | DescriptionBox.Text = description; 76 | 77 | if (portStatus == 0) 78 | { 79 | EnableBox.IsChecked = false; 80 | 81 | } 82 | else 83 | { 84 | EnableBox.IsChecked = true; 85 | } 86 | 87 | 88 | } 89 | } 90 | else 91 | { 92 | 93 | 94 | int num = CalculateIndexId(DataBrige.SelectDeviceInfo.TableName); 95 | 96 | TypeBlock.Text = "当前新建快速访问标签第" + (num) + "个"; 97 | } 98 | 99 | 100 | } 101 | 102 | 103 | /// 104 | /// 保存导航标签配置 105 | /// 106 | /// 107 | /// 108 | private void SaveButton_OnClick(object sender, RoutedEventArgs e) 109 | { 110 | 111 | int enable; 112 | 113 | if (EnableBox.IsChecked == true) 114 | { 115 | enable = 1; 116 | } 117 | else 118 | { 119 | enable = 0; 120 | } 121 | 122 | string tableName = DataBrige.SelectDeviceInfo.TableName; 123 | 124 | 125 | if (NameBox.Text != "" && UrlBox.Text != "") 126 | { 127 | string sql; 128 | 129 | if (DataBrige.EditMode == 0)//新建 130 | { 131 | //计算已有导航标签数量 132 | 133 | string sqlTemp = string.Format($"SELECT COUNT(*) FROM {tableName} WHERE `PortType` = 'I'"); 134 | 135 | 136 | int num = CalculateIndexId(tableName); 137 | 138 | Console.WriteLine("num:"+num); 139 | 140 | sql = $"INSERT INTO \"{tableName}\" (\"PortType\", \"PortNumber\", \"PortStatus\", \"PortTag1\", \"PortTag2\", \"Description\") VALUES ('I', '{num}',{enable}, '{NameBox.Text}', '{UrlBox.Text}', '{DescriptionBox.Text}')"; 141 | 142 | Console.WriteLine(sql); 143 | } 144 | else 145 | { 146 | 147 | sql = $"UPDATE {tableName} SET \"PortStatus\" = '{enable}', \"PortTag1\" = '{NameBox.Text}' , \"PortTag2\" = '{UrlBox.Text}' , \"PortTag3\" = '', \"Description\" = '{DescriptionBox.Text}' WHERE (PortType = 'I' AND PortNumber = '{DataBrige.SelectIndexTag}')"; 148 | 149 | } 150 | 151 | 152 | dbClass.ExecuteQuery(sql); //写入快速访问标签信息 153 | 154 | //DataBrige.DevicePortInfos.Add(new ViewMode.DevicePortInfo("I",(num+1).ToString(),enable,NameBox.Text,UrlBox.Text,"",DescriptionBox.Text)); 155 | 156 | 157 | this.DialogResult = true; 158 | this.Close(); 159 | } 160 | else 161 | { 162 | MessageBox.Show("请完整填写标签信息", "必要信息不完整", MessageBoxButton.OK, MessageBoxImage.Warning); 163 | } 164 | 165 | 166 | } 167 | 168 | 169 | /// 170 | /// 171 | /// 172 | private int CalculateIndexId(string tableName) 173 | { 174 | //计算已有导航标签数量 175 | 176 | string sqlTemp = string.Format($"SELECT PortNumber FROM {tableName} WHERE PortType ='I'"); 177 | SQLiteCommand command = new SQLiteCommand(sqlTemp,dbClass.connection); 178 | SQLiteDataReader reader = command.ExecuteReader(); 179 | 180 | List idList = new List(); 181 | 182 | while (reader.Read()) 183 | { 184 | idList.Add(Convert.ToInt32(reader["PortNumber"])); 185 | } 186 | 187 | 188 | return FindMissingNumber(idList); 189 | } 190 | 191 | 192 | /// 193 | /// 寻找遗失的数值 194 | /// 195 | /// 196 | /// 197 | /// 198 | public static int FindMissingNumber(List numbers) 199 | { 200 | if (numbers == null || numbers.Count == 0) 201 | { 202 | Console.WriteLine("List cannot be null or empty"); 203 | 204 | } 205 | else 206 | { 207 | int max = numbers.Max(); 208 | 209 | for (int i = 1; i <= max; i++) 210 | { 211 | if (!numbers.Contains(i)) 212 | { 213 | return i; 214 | 215 | } 216 | } 217 | 218 | } 219 | 220 | 221 | return numbers.Count + 1; 222 | } 223 | 224 | 225 | /// 226 | /// 自动添加http:// 227 | /// 228 | /// 229 | /// 230 | private void UrlBox_OnMouseLeave(object sender, MouseEventArgs e) 231 | { 232 | UrlBox.Text = AddHttpIfNeeded(UrlBox.Text); 233 | } 234 | 235 | 236 | static string AddHttpIfNeeded(string input) 237 | { 238 | if (!input.Contains("https://") && !input.Contains("http://")) 239 | { 240 | // 如果字符串中不存在 "https://" 或 "http://", 添加 "https://" 241 | input = "http://" + input; 242 | } 243 | return input; 244 | } 245 | 246 | 247 | /// 248 | /// 删除标签 249 | /// 250 | /// 251 | /// 252 | private void ReleaseButton_OnClick(object sender, RoutedEventArgs e) 253 | { 254 | string sql = $"DELETE FROM {DataBrige.SelectDeviceTableName} WHERE (PortType = 'I' AND PortNumber = {DataBrige.SelectIndexTag})"; 255 | dbClass.ExecuteQuery(sql); //写入快速访问标签信息 256 | this.DialogResult=true; 257 | this.Close(); 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /UserWindows/DeviceImportWindow.xaml: -------------------------------------------------------------------------------- 1 |  22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 43 | 44 | 50 | 51 | 52 | 61 | 62 | 63 | 64 | 65 | 66 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 105 | 106 | 112 | 113 | 114 | 115 | 116 | 127 | 128 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 165 | 166 | 172 | 173 | 174 | 175 | 181 | 182 | 183 | 184 | 185 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /UserWindows/DeviceImportWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using CsvHelper; 2 | using IPAM_NOTE.DatabaseOperation; 3 | using Microsoft.Win32; 4 | using OfficeOpenXml; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Data.SQLite; 8 | using System.Globalization; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Net.NetworkInformation; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using System.Windows; 15 | using System.Windows.Controls; 16 | using System.Windows.Data; 17 | using System.Windows.Documents; 18 | using System.Windows.Input; 19 | using System.Windows.Media; 20 | using System.Windows.Media.Imaging; 21 | using System.Windows.Shapes; 22 | using static IPAM_NOTE.ImportWindow; 23 | using static IPAM_NOTE.ViewMode; 24 | 25 | namespace IPAM_NOTE.UserWindows 26 | { 27 | /// 28 | /// DeviceImportWindow.xaml 的交互逻辑 29 | /// 30 | public partial class DeviceImportWindow : Window 31 | { 32 | public DeviceImportWindow() 33 | { 34 | InitializeComponent(); 35 | } 36 | 37 | 38 | 39 | 40 | private void DeviceImportWindow_OnLoaded(object sender, RoutedEventArgs e) 41 | { 42 | DevicesComboBox.ItemsSource = DataBrige.DevicesList; 43 | } 44 | 45 | /// 46 | /// 导出模板 47 | /// 48 | /// 49 | /// 50 | private void ExportButton_OnClick(object sender, RoutedEventArgs e) 51 | { 52 | if (DevicesComboBox.SelectedIndex != -1) 53 | { 54 | ExcelPackage.LicenseContext = LicenseContext.NonCommercial; 55 | 56 | string tableName = DataBrige.DeviceInfos[DevicesComboBox.SelectedIndex].TableName; 57 | 58 | LoadDeviceConfig(tableName); 59 | 60 | 61 | 62 | // 创建 SaveFileDialog 实例 63 | SaveFileDialog saveFileDialog = new SaveFileDialog(); 64 | saveFileDialog.Filter = "Excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*"; 65 | saveFileDialog.FilterIndex = 1; 66 | saveFileDialog.RestoreDirectory = true; 67 | 68 | 69 | saveFileDialog.FileName = tableName + ".xlsx"; 70 | 71 | 72 | 73 | // 显示 SaveFileDialog 74 | bool? result = saveFileDialog.ShowDialog(); 75 | 76 | if (result == true) 77 | { 78 | // 获取用户选择的文件路径 79 | string filePath = saveFileDialog.FileName; 80 | ExportToExcel(DataBrige.DevicePortInfos, filePath); 81 | MessageBox.Show("设备内容导出完毕", "导出", MessageBoxButton.OK, MessageBoxImage.Information); 82 | } 83 | 84 | 85 | 86 | } 87 | else 88 | { 89 | MessageBox.Show("请先选择要导出的设备", "你是否遗忘了什么步骤?", MessageBoxButton.OK, MessageBoxImage.Information); 90 | } 91 | 92 | 93 | 94 | 95 | } 96 | 97 | 98 | 99 | public void ExportToExcel(List dataList, string filePath) 100 | { 101 | 102 | 103 | 104 | using (var package = new ExcelPackage()) 105 | { 106 | var sheet = package.Workbook.Worksheets.Add(DataBrige.DeviceInfos[DevicesComboBox.SelectedIndex].TableName); 107 | 108 | 109 | // 写入标题行 110 | sheet.Cells[1, 1].Value = "PortType"; 111 | sheet.Cells[1, 2].Value = "PortNumber"; 112 | sheet.Cells[1, 3].Value = "PortStatus"; 113 | sheet.Cells[1, 4].Value = "PortTag1"; 114 | sheet.Cells[1, 5].Value = "PortTag2"; 115 | sheet.Cells[1, 6].Value = "PortTag3"; 116 | sheet.Cells[1, 7].Value = "Description"; 117 | 118 | // 写入数据 119 | int rowIndex = 2; 120 | foreach (var info in dataList) 121 | { 122 | sheet.Cells[rowIndex, 1].Value = info.PortType; 123 | sheet.Cells[rowIndex, 2].Value = info.PortNumber; 124 | sheet.Cells[rowIndex, 3].Value = info.PortStatus; 125 | sheet.Cells[rowIndex, 4].Value = info.PortTag1; 126 | sheet.Cells[rowIndex, 5].Value = info.PortTag2; 127 | sheet.Cells[rowIndex, 6].Value = info.PortTag3; ; 128 | sheet.Cells[rowIndex, 7].Value = info.Description; ; 129 | rowIndex++; 130 | } 131 | 132 | 133 | // 保存Excel文件 134 | FileInfo excelFile = new FileInfo(filePath); 135 | 136 | 137 | 138 | package.SaveAs(excelFile); 139 | } 140 | 141 | 142 | 143 | 144 | 145 | } 146 | 147 | /// 148 | /// 加载IP地址表配置 149 | /// 150 | private void LoadDeviceConfig(string tableName) 151 | { 152 | 153 | string sql = string.Format("SELECT * FROM {0} ORDER BY PortType ASC", tableName); 154 | 155 | 156 | 157 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 158 | string dbName = "Address_database.db"; 159 | 160 | dbFilePath = dbFilePath + dbName; 161 | 162 | // 打开 SQLite 数据库连接 163 | string connectionString = string.Format("Data Source={0};Version=3;", dbFilePath); 164 | 165 | using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 166 | { 167 | connection.Open(); 168 | 169 | 170 | SQLiteCommand command = new SQLiteCommand(sql, connection); 171 | 172 | SQLiteDataReader reader = command.ExecuteReader(); 173 | 174 | DataBrige.DevicePortInfos.Clear(); 175 | 176 | 177 | while (reader.Read()) 178 | { 179 | string portType = reader["PortType"].ToString(); 180 | string portNumber = reader["PortNumber"].ToString(); 181 | int portStatus = Convert.ToInt32(reader["PortStatus"]); 182 | string portTag1 = reader["PortTag1"].ToString(); 183 | string portTag2 = reader["PortTag2"].ToString(); 184 | string portTag3 = reader["PortTag3"].ToString(); 185 | string description = reader["Description"].ToString(); 186 | 187 | 188 | 189 | DevicePortInfo portInfo = new DevicePortInfo(portType, portNumber, portStatus, portTag1, portTag2, 190 | portTag3, description); 191 | 192 | DataBrige.DevicePortInfos.Add(portInfo); 193 | } 194 | 195 | 196 | 197 | reader.Dispose(); 198 | 199 | 200 | 201 | } 202 | } 203 | 204 | 205 | /// 206 | /// 浏览CSV文件 207 | /// 208 | /// 209 | /// 210 | private void BrowseButton_OnClick(object sender, RoutedEventArgs e) 211 | { 212 | // 创建 OpenFileDialog 实例 213 | OpenFileDialog openFileDialog = new OpenFileDialog(); 214 | 215 | // 设置文件类型筛选,仅允许选择 CSV 文件 216 | openFileDialog.Filter = "CSV files (*.csv)|*.csv"; 217 | 218 | // 显示对话框并获取用户选择的结果 219 | bool? result = openFileDialog.ShowDialog(); 220 | 221 | // 如果用户选择了文件,则将文件路径加载到 TextBox 中 222 | if (result == true) 223 | { 224 | string selectedFilePath = openFileDialog.FileName; 225 | SourceData.Text = selectedFilePath; 226 | } 227 | } 228 | 229 | /// 230 | /// 导入数据 231 | /// 232 | /// 233 | /// 234 | private void ImportButton_OnClick(object sender, RoutedEventArgs e) 235 | { 236 | 237 | MessageBoxResult result = MessageBox.Show("注意!导入数据将覆盖数据库内原有数据,是否继续?\r\r\r如果导入之后出现异常可前往数据恢复页面\r进入之后选择'备份还原'即可看到恢复选项", "危险操作", MessageBoxButton.YesNo, 238 | MessageBoxImage.Warning); 239 | 240 | if (result == MessageBoxResult.Yes) 241 | { 242 | if (DevicesComboBox.SelectedIndex != -1 && File.Exists(SourceData.Text)) 243 | { 244 | string tableName = DataBrige.DeviceInfos[DevicesComboBox.SelectedIndex].TableName; 245 | 246 | ImportDataFromCsv(SourceData.Text, tableName); 247 | } 248 | else 249 | { 250 | MessageBox.Show("未选择被导入的网段或未找到被导入的CSV文件", "注意", MessageBoxButton.OK, MessageBoxImage.Error); 251 | } 252 | } 253 | } 254 | 255 | private void ImportDataFromCsv(string csvFilePath, string tableName) 256 | { 257 | ProgressBar.IsIndeterminate = true; 258 | string dbFilePath = AppDomain.CurrentDomain.BaseDirectory + @"db\"; 259 | string dbName = "Address_database.db"; 260 | 261 | dbFilePath = dbFilePath + dbName; 262 | 263 | // 打开 SQLite 数据库连接 264 | string connectionString = string.Format("Data Source={0};Version=3;", dbFilePath); 265 | 266 | try 267 | { 268 | // 检查CSV文件编码并转换为UTF-8 269 | string utf8CsvFilePath = CheckAndConvertCsvToUtf8(csvFilePath); 270 | 271 | 272 | using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 273 | { 274 | connection.Open(); 275 | 276 | // 创建一个 SQLiteCommand 对象来执行 SQL 查询和命令 277 | using (SQLiteCommand command = connection.CreateCommand()) 278 | { 279 | 280 | // 将 CSV 文件中的数据读取到一个列表中 281 | List records; 282 | 283 | using (var reader = new StreamReader(utf8CsvFilePath)) 284 | using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) 285 | { 286 | records = csv.GetRecords().ToList(); 287 | 288 | 289 | 290 | // 遍历 CSV 文件中的每一行数据 291 | foreach (var record in records) 292 | { 293 | // 从 CSV 记录中获取需要插入或更新到数据库的字段值 294 | string type = record.PortType; 295 | 296 | string number= record.PortNumber; 297 | 298 | 299 | 300 | // 检查数据库中是否已存在相同的 type和端口 301 | 302 | command.CommandText = string.Format($"SELECT COUNT(*) FROM {tableName} WHERE (PortType = '{type}' AND PortNumber = '{number}') "); 303 | 304 | int count = Convert.ToInt32(command.ExecuteScalar()); 305 | 306 | 307 | 308 | string portStatus = record.PortStatus; 309 | string portTag1 = record.PortTag1; 310 | string portTag2 = record.PortTag2; 311 | string portTag3 = record.PortTag3; 312 | string description = record.Description; 313 | 314 | 315 | if (count > 0) 316 | { 317 | // 数据库中已存在相同的 端口号,执行更新操作 318 | command.CommandText = 319 | string.Format( 320 | $"UPDATE {tableName} SET PortStatus = {portStatus}, PortTag1 = '{portTag1}',PortTag2 = '{portTag2}', PortTag3 = '{portTag3}', Description = '{description}' WHERE (PortType ='{type}' AND PortNumber='{number}')"); 321 | 322 | 323 | } 324 | else 325 | { 326 | // 数据库中不存在相同的 IpAddress,执行插入操作 327 | command.CommandText = 328 | string.Format( 329 | $"INSERT INTO {tableName} (PortType, PortNumber, PortTag1, PortTag2,PortTag3,Description) VALUES ({type}, {number}, {portTag1}, {portTag2}, {portTag3}, {description})"); 330 | } 331 | 332 | 333 | Console.WriteLine(command.CommandText); 334 | 335 | command.ExecuteNonQuery(); 336 | } 337 | 338 | ProgressBar.IsIndeterminate = false; 339 | } 340 | 341 | } 342 | 343 | MessageBox.Show("数据导入完毕,请检查数据是否正常。", "导入完成", MessageBoxButton.OK, 344 | MessageBoxImage.Information); 345 | connection.Close(); 346 | this.Close(); 347 | } 348 | } 349 | catch (Exception ex) 350 | { 351 | MessageBox.Show($"导入CSV文件时出错:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); 352 | } 353 | } 354 | 355 | private string CheckAndConvertCsvToUtf8(string csvFilePath) 356 | { 357 | // 检查文件编码 358 | Encoding encoding = GetCsvFileEncoding(csvFilePath); 359 | 360 | // 如果不是UTF-8,则转换为UTF-8并返回新的文件路径 361 | if (encoding != Encoding.UTF8) 362 | { 363 | string utf8CsvFilePath = System.IO.Path.GetTempFileName(); 364 | ConvertCsvToUtf8(csvFilePath, utf8CsvFilePath); 365 | return utf8CsvFilePath; 366 | } 367 | 368 | // 文件已经是UTF-8编码,直接返回原始文件路径 369 | return csvFilePath; 370 | } 371 | 372 | /// 373 | /// 检测CSV文件编码 374 | /// 375 | /// 376 | /// 377 | private Encoding GetCsvFileEncoding(string filePath) 378 | { 379 | using (var reader = new PinnedStreamReader(filePath)) 380 | { 381 | return reader.CurrentEncoding; 382 | } 383 | } 384 | 385 | /// 386 | /// 转换CSV为UTF-8编码 387 | /// 388 | /// 389 | /// 390 | private void ConvertCsvToUtf8(string sourceFilePath, string targetFilePath) 391 | { 392 | string csvContent = File.ReadAllText(sourceFilePath, Encoding.Default); 393 | File.WriteAllText(targetFilePath, csvContent, Encoding.UTF8); 394 | } 395 | 396 | 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /UserWindows/SetPasswordWindow.xaml: -------------------------------------------------------------------------------- 1 |  21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 39 | 40 | 48 | 54 | 58 | 59 | 67 | 68 | 77 | 80 | 85 | 86 | 87 | 95 | 96 | 105 | 106 | 109 | 114 | 115 | 116 | 117 | 118 | 126 | 127 | 136 |