xiaochanghai 1 year ago
parent 81d0c2c67a
commit ca04e0cc65
  1. 7
      Tiobon.Core.sln
  2. 115
      Tiobon.PublishHelper/Frm/Form1.Designer.cs
  3. 20
      Tiobon.PublishHelper/Frm/Form1.cs
  4. 136
      Tiobon.PublishHelper/Frm/Form1.resx
  5. 187
      Tiobon.PublishHelper/Frm/Form_DevServer.Designer.cs
  6. 100
      Tiobon.PublishHelper/Frm/Form_DevServer.cs
  7. 123
      Tiobon.PublishHelper/Frm/Form_DevServer.resx
  8. 239
      Tiobon.PublishHelper/Frm/Form_DevServer_Item.Designer.cs
  9. 96
      Tiobon.PublishHelper/Frm/Form_DevServer_Item.cs
  10. 120
      Tiobon.PublishHelper/Frm/Form_DevServer_Item.resx
  11. 186
      Tiobon.PublishHelper/Frm/Form_Hospital.Designer.cs
  12. 188
      Tiobon.PublishHelper/Frm/Form_Hospital.cs
  13. 123
      Tiobon.PublishHelper/Frm/Form_Hospital.resx
  14. 241
      Tiobon.PublishHelper/Frm/Form_Hospital_Item.Designer.cs
  15. 119
      Tiobon.PublishHelper/Frm/Form_Hospital_Item.cs
  16. 120
      Tiobon.PublishHelper/Frm/Form_Hospital_Item.resx
  17. 17
      Tiobon.PublishHelper/Program.cs
  18. 84
      Tiobon.PublishHelper/Src/CmdHelper.cs
  19. 72
      Tiobon.PublishHelper/Src/DevServer.cs
  20. 105
      Tiobon.PublishHelper/Src/DockerCommand.cs
  21. 125
      Tiobon.PublishHelper/Src/OprateLog.cs
  22. 79
      Tiobon.PublishHelper/Src/PublishServer.cs
  23. 503
      Tiobon.PublishHelper/Src/SftpHelper.cs
  24. 249
      Tiobon.PublishHelper/Src/SshHelper.cs
  25. 610
      Tiobon.PublishHelper/Src/Utility.cs
  26. 56
      Tiobon.PublishHelper/Src/ZipHelper.cs
  27. 33
      Tiobon.PublishHelper/Tiobon.PublishHelper.csproj

@ -68,6 +68,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tiobon.Core.OPS.Tool", "Tio
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tiobon.Core.PublishHelper", "Tiobon.Core.PublishHelper\Tiobon.Core.PublishHelper.csproj", "{27648B22-ECC7-4B2F-BB85-A86C03B6ED05}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tiobon.PublishHelper", "Tiobon.PublishHelper\Tiobon.PublishHelper.csproj", "{16F70A02-56E3-480B-AF2D-2E9429D05A92}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -150,6 +152,10 @@ Global
{27648B22-ECC7-4B2F-BB85-A86C03B6ED05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{27648B22-ECC7-4B2F-BB85-A86C03B6ED05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27648B22-ECC7-4B2F-BB85-A86C03B6ED05}.Release|Any CPU.Build.0 = Release|Any CPU
{16F70A02-56E3-480B-AF2D-2E9429D05A92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16F70A02-56E3-480B-AF2D-2E9429D05A92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16F70A02-56E3-480B-AF2D-2E9429D05A92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16F70A02-56E3-480B-AF2D-2E9429D05A92}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -163,6 +169,7 @@ Global
{BA7081E8-08F2-4CC2-ACD9-E878C0CDE313} = {047A9723-9AAC-42E3-8C69-B3835F15FF96}
{1C0E27D6-B516-4D30-B559-C9097476DEEC} = {047A9723-9AAC-42E3-8C69-B3835F15FF96}
{27648B22-ECC7-4B2F-BB85-A86C03B6ED05} = {047A9723-9AAC-42E3-8C69-B3835F15FF96}
{16F70A02-56E3-480B-AF2D-2E9429D05A92} = {047A9723-9AAC-42E3-8C69-B3835F15FF96}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB40D0C5-E3EA-4A9B-86C2-38F0BB33FC04}

@ -0,0 +1,115 @@
namespace Tiobon.PublishHelper
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
toolStrip1 = new ToolStrip();
toolStripDropDownButton1 = new ToolStripDropDownButton();
toolStripMenuItem2 = new ToolStripMenuItem();
statusStrip1 = new StatusStrip();
toolStripStatusLabel1 = new ToolStripStatusLabel();
toolStripStatusLabel2 = new ToolStripStatusLabel();
toolStrip1.SuspendLayout();
statusStrip1.SuspendLayout();
SuspendLayout();
//
// toolStrip1
//
toolStrip1.Items.AddRange(new ToolStripItem[] { toolStripDropDownButton1 });
toolStrip1.Location = new Point(0, 0);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(800, 25);
toolStrip1.TabIndex = 0;
toolStrip1.Text = "toolStrip1";
//
// toolStripDropDownButton1
//
toolStripDropDownButton1.DisplayStyle = ToolStripItemDisplayStyle.Text;
toolStripDropDownButton1.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem2 });
toolStripDropDownButton1.Image = (Image)resources.GetObject("toolStripDropDownButton1.Image");
toolStripDropDownButton1.ImageTransparentColor = Color.Magenta;
toolStripDropDownButton1.Name = "toolStripDropDownButton1";
toolStripDropDownButton1.Size = new Size(45, 22);
toolStripDropDownButton1.Text = "管理";
//
// toolStripMenuItem2
//
toolStripMenuItem2.Name = "toolStripMenuItem2";
toolStripMenuItem2.Size = new Size(180, 22);
toolStripMenuItem2.Text = "开发服务器";
toolStripMenuItem2.Click += toolStripMenuItem2_Click;
//
// statusStrip1
//
statusStrip1.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel1, toolStripStatusLabel2 });
statusStrip1.Location = new Point(0, 428);
statusStrip1.Name = "statusStrip1";
statusStrip1.Size = new Size(800, 22);
statusStrip1.TabIndex = 1;
statusStrip1.Text = "statusStrip1";
//
// toolStripStatusLabel1
//
toolStripStatusLabel1.Name = "toolStripStatusLabel1";
toolStripStatusLabel1.Size = new Size(131, 17);
toolStripStatusLabel1.Text = "toolStripStatusLabel1";
//
// toolStripStatusLabel2
//
toolStripStatusLabel2.Name = "toolStripStatusLabel2";
toolStripStatusLabel2.Size = new Size(131, 17);
toolStripStatusLabel2.Text = "toolStripStatusLabel2";
//
// Form1
//
AutoScaleDimensions = new SizeF(7F, 17F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(statusStrip1);
Controls.Add(toolStrip1);
Name = "Form1";
Text = "开发工具";
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
statusStrip1.ResumeLayout(false);
statusStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private ToolStrip toolStrip1;
private ToolStripDropDownButton toolStripDropDownButton1;
private ToolStripMenuItem toolStripMenuItem2;
private StatusStrip statusStrip1;
private ToolStripStatusLabel toolStripStatusLabel1;
private ToolStripStatusLabel toolStripStatusLabel2;
}
}

@ -0,0 +1,20 @@
namespace Tiobon.PublishHelper
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region 开发服务器配置
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
using (Form_DevServer f = new Form_DevServer())
{
f.ShowDialog();
}
}
#endregion
}
}

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="toolStripDropDownButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
AAAAAElFTkSuQmCC
</value>
</data>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>129, 17</value>
</metadata>
</root>

@ -0,0 +1,187 @@
namespace Tiobon.PublishHelper
{
partial class Form_DevServer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.gb_Main = new System.Windows.Forms.GroupBox();
this.listView_Dev = new System.Windows.Forms.ListView();
this.DevName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.IP = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.UserName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.Password = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SuPassword = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.Port = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.contextMenuStrip_ListView = new System.Windows.Forms.ContextMenuStrip(this.components);
this.tsmi_Insert = new System.Windows.Forms.ToolStripMenuItem();
this.tsmi_Edit = new System.Windows.Forms.ToolStripMenuItem();
this.tsmi_Delete = new System.Windows.Forms.ToolStripMenuItem();
this.tsmi_Hospital = new System.Windows.Forms.ToolStripMenuItem();
this.gb_Main.SuspendLayout();
this.contextMenuStrip_ListView.SuspendLayout();
this.SuspendLayout();
//
// gb_Main
//
this.gb_Main.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.gb_Main.Controls.Add(this.listView_Dev);
this.gb_Main.Location = new System.Drawing.Point(12, 12);
this.gb_Main.Name = "gb_Main";
this.gb_Main.Size = new System.Drawing.Size(776, 426);
this.gb_Main.TabIndex = 0;
this.gb_Main.TabStop = false;
//
// listView_Dev
//
this.listView_Dev.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.DevName,
this.IP,
this.UserName,
this.Password,
this.SuPassword,
this.Port});
this.listView_Dev.ContextMenuStrip = this.contextMenuStrip_ListView;
this.listView_Dev.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView_Dev.FullRowSelect = true;
this.listView_Dev.GridLines = true;
this.listView_Dev.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.listView_Dev.HideSelection = false;
this.listView_Dev.Location = new System.Drawing.Point(3, 17);
this.listView_Dev.MultiSelect = false;
this.listView_Dev.Name = "listView_Dev";
this.listView_Dev.Size = new System.Drawing.Size(770, 406);
this.listView_Dev.TabIndex = 0;
this.listView_Dev.UseCompatibleStateImageBehavior = false;
this.listView_Dev.View = System.Windows.Forms.View.Details;
this.listView_Dev.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.listView_Dev_MouseDoubleClick);
//
// DevName
//
this.DevName.Text = "名称";
this.DevName.Width = 100;
//
// IP
//
this.IP.Text = "Ip";
this.IP.Width = 150;
//
// UserName
//
this.UserName.Text = "用户名";
this.UserName.Width = 150;
//
// Password
//
this.Password.Text = "密码";
this.Password.Width = 150;
//
// SuPassword
//
this.SuPassword.Text = "Su密码";
this.SuPassword.Width = 150;
//
// Port
//
this.Port.Text = "端口";
this.Port.Width = 50;
//
// contextMenuStrip_ListView
//
this.contextMenuStrip_ListView.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.tsmi_Insert,
this.tsmi_Edit,
this.tsmi_Delete,
this.tsmi_Hospital});
this.contextMenuStrip_ListView.Name = "contextMenuStrip_Main";
this.contextMenuStrip_ListView.Size = new System.Drawing.Size(142, 92);
//
// tsmi_Insert
//
this.tsmi_Insert.Name = "tsmi_Insert";
this.tsmi_Insert.Size = new System.Drawing.Size(141, 22);
this.tsmi_Insert.Text = "新增(&N)";
this.tsmi_Insert.Click += new System.EventHandler(this.tsmi_Insert_Click);
//
// tsmi_Edit
//
this.tsmi_Edit.Name = "tsmi_Edit";
this.tsmi_Edit.Size = new System.Drawing.Size(141, 22);
this.tsmi_Edit.Text = "编辑(&E)";
this.tsmi_Edit.Click += new System.EventHandler(this.tsmi_Edit_Click);
//
// tsmi_Delete
//
this.tsmi_Delete.Name = "tsmi_Delete";
this.tsmi_Delete.Size = new System.Drawing.Size(141, 22);
this.tsmi_Delete.Text = "删除(&D)";
this.tsmi_Delete.Click += new System.EventHandler(this.tsmi_Delete_Click);
//
// tsmi_Hospital
//
this.tsmi_Hospital.Name = "tsmi_Hospital";
this.tsmi_Hospital.Size = new System.Drawing.Size(141, 22);
this.tsmi_Hospital.Text = "项目管理(&H)";
this.tsmi_Hospital.Click += new System.EventHandler(this.tsmi_Hospital_Click);
//
// Form_DevServer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.gb_Main);
this.Name = "Form_DevServer";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "开发服务器";
this.Load += new System.EventHandler(this.Form_DevServer_Load);
this.gb_Main.ResumeLayout(false);
this.contextMenuStrip_ListView.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox gb_Main;
private System.Windows.Forms.ListView listView_Dev;
private System.Windows.Forms.ColumnHeader DevName;
private System.Windows.Forms.ColumnHeader IP;
private System.Windows.Forms.ColumnHeader UserName;
private System.Windows.Forms.ColumnHeader Password;
private System.Windows.Forms.ColumnHeader SuPassword;
private System.Windows.Forms.ColumnHeader Port;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip_ListView;
private System.Windows.Forms.ToolStripMenuItem tsmi_Insert;
private System.Windows.Forms.ToolStripMenuItem tsmi_Edit;
private System.Windows.Forms.ToolStripMenuItem tsmi_Delete;
private System.Windows.Forms.ToolStripMenuItem tsmi_Hospital;
}
}

@ -0,0 +1,100 @@
using System.Data;
namespace Tiobon.PublishHelper
{
public partial class Form_DevServer : Form
{
public Form_DevServer()
{
InitializeComponent();
}
private void Form_DevServer_Load(object sender, EventArgs e)
{
RefreshView();
}
private void tsmi_Insert_Click(object sender, EventArgs e)
{
using (Form_DevServer_Item f = new Form_DevServer_Item("新增"))
{
f.ShowDialog();
}
Utility.SaveDevServer();
RefreshView();
}
private void tsmi_Edit_Click(object sender, EventArgs e)
{
if (this.listView_Dev.SelectedItems.Count <= 0)
return;
using (Form_DevServer_Item f = new Form_DevServer_Item($"编辑 - {this.listView_Dev.SelectedItems[0].Text}"))
{
f.ShowDialog();
}
Utility.SaveDevServer();
RefreshView();
}
private void tsmi_Delete_Click(object sender, EventArgs e)
{
if (this.listView_Dev.SelectedItems.Count <= 0)
{
return;
}
if (MessageBox.Show("是否确认删除?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
var item = Utility.m_DevServers.Where(o => o.Name == this.listView_Dev.SelectedItems[0].Text).FirstOrDefault();
if (!(item is null))
{
Utility.m_DevServers.Remove(item);
Utility.SaveDevServer();
RefreshView();
}
}
private void RefreshView()
{
listView_Dev.Items.Clear();
Utility.m_DevServers.ForEach(o =>
{
ListViewItem item = new ListViewItem();
item.SubItems[0].Text = o.Name;
item.SubItems.Add(o.Ip);
item.SubItems.Add(o.UserName);
item.SubItems.Add(o.Password);
item.SubItems.Add(o.SuPassword);
item.SubItems.Add(o.Port.ToString());
listView_Dev.Items.Add(item);
});
}
private void tsmi_Hospital_Click(object sender, EventArgs e)
{
if (this.listView_Dev.SelectedItems.Count <= 0)
{
return;
}
using (Form_Hospital f = new Form_Hospital(this.listView_Dev.SelectedItems[0].Text))
{
f.ShowDialog();
}
Utility.SaveDevServer();
}
private void listView_Dev_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (this.listView_Dev.SelectedItems.Count <= 0)
{
return;
}
using (Form_Hospital f = new Form_Hospital(this.listView_Dev.SelectedItems[0].Text))
{
f.ShowDialog();
}
Utility.SaveDevServer();
}
}
}

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="contextMenuStrip_ListView.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

@ -0,0 +1,239 @@
namespace Tiobon.PublishHelper
{
partial class Form_DevServer_Item
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.gb_main = new System.Windows.Forms.GroupBox();
this.txt_UserName = new System.Windows.Forms.TextBox();
this.lbl_UserName = new System.Windows.Forms.Label();
this.txt_Port = new System.Windows.Forms.TextBox();
this.lbl_Port = new System.Windows.Forms.Label();
this.txt_SuPassword = new System.Windows.Forms.TextBox();
this.lbl_SuPassword = new System.Windows.Forms.Label();
this.txt_Password = new System.Windows.Forms.TextBox();
this.lbl_Password = new System.Windows.Forms.Label();
this.txt_Ip = new System.Windows.Forms.TextBox();
this.lbl_Ip = new System.Windows.Forms.Label();
this.txt_Name = new System.Windows.Forms.TextBox();
this.lbl_Name = new System.Windows.Forms.Label();
this.btn_Ok = new System.Windows.Forms.Button();
this.btn_Cancel = new System.Windows.Forms.Button();
this.gb_main.SuspendLayout();
this.SuspendLayout();
//
// gb_main
//
this.gb_main.Controls.Add(this.txt_UserName);
this.gb_main.Controls.Add(this.lbl_UserName);
this.gb_main.Controls.Add(this.txt_Port);
this.gb_main.Controls.Add(this.lbl_Port);
this.gb_main.Controls.Add(this.txt_SuPassword);
this.gb_main.Controls.Add(this.lbl_SuPassword);
this.gb_main.Controls.Add(this.txt_Password);
this.gb_main.Controls.Add(this.lbl_Password);
this.gb_main.Controls.Add(this.txt_Ip);
this.gb_main.Controls.Add(this.lbl_Ip);
this.gb_main.Controls.Add(this.txt_Name);
this.gb_main.Controls.Add(this.lbl_Name);
this.gb_main.Location = new System.Drawing.Point(12, 12);
this.gb_main.Name = "gb_main";
this.gb_main.Size = new System.Drawing.Size(270, 219);
this.gb_main.TabIndex = 0;
this.gb_main.TabStop = false;
//
// txt_UserName
//
this.txt_UserName.Location = new System.Drawing.Point(105, 86);
this.txt_UserName.Name = "txt_UserName";
this.txt_UserName.Size = new System.Drawing.Size(144, 21);
this.txt_UserName.TabIndex = 16;
this.txt_UserName.Text = "huhangmed";
//
// lbl_UserName
//
this.lbl_UserName.AutoSize = true;
this.lbl_UserName.Location = new System.Drawing.Point(22, 89);
this.lbl_UserName.Name = "lbl_UserName";
this.lbl_UserName.Size = new System.Drawing.Size(47, 12);
this.lbl_UserName.TabIndex = 17;
this.lbl_UserName.Text = "用户名:";
this.lbl_UserName.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_Port
//
this.txt_Port.Location = new System.Drawing.Point(105, 185);
this.txt_Port.Name = "txt_Port";
this.txt_Port.Size = new System.Drawing.Size(144, 21);
this.txt_Port.TabIndex = 14;
this.txt_Port.Text = "22";
//
// lbl_Port
//
this.lbl_Port.AutoSize = true;
this.lbl_Port.Location = new System.Drawing.Point(22, 188);
this.lbl_Port.Name = "lbl_Port";
this.lbl_Port.Size = new System.Drawing.Size(53, 12);
this.lbl_Port.TabIndex = 15;
this.lbl_Port.Text = "SSH端口:";
this.lbl_Port.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_SuPassword
//
this.txt_SuPassword.Location = new System.Drawing.Point(105, 152);
this.txt_SuPassword.Name = "txt_SuPassword";
this.txt_SuPassword.Size = new System.Drawing.Size(144, 21);
this.txt_SuPassword.TabIndex = 12;
this.txt_SuPassword.Text = "Huhang@2019";
//
// lbl_SuPassword
//
this.lbl_SuPassword.AutoSize = true;
this.lbl_SuPassword.Location = new System.Drawing.Point(22, 155);
this.lbl_SuPassword.Name = "lbl_SuPassword";
this.lbl_SuPassword.Size = new System.Drawing.Size(47, 12);
this.lbl_SuPassword.TabIndex = 13;
this.lbl_SuPassword.Text = "SU密码:";
this.lbl_SuPassword.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_Password
//
this.txt_Password.Location = new System.Drawing.Point(105, 119);
this.txt_Password.Name = "txt_Password";
this.txt_Password.Size = new System.Drawing.Size(144, 21);
this.txt_Password.TabIndex = 10;
this.txt_Password.Text = "Huhangmed@2019";
//
// lbl_Password
//
this.lbl_Password.AutoSize = true;
this.lbl_Password.Location = new System.Drawing.Point(22, 122);
this.lbl_Password.Name = "lbl_Password";
this.lbl_Password.Size = new System.Drawing.Size(35, 12);
this.lbl_Password.TabIndex = 11;
this.lbl_Password.Text = "密码:";
this.lbl_Password.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_Ip
//
this.txt_Ip.Location = new System.Drawing.Point(105, 53);
this.txt_Ip.Name = "txt_Ip";
this.txt_Ip.Size = new System.Drawing.Size(144, 21);
this.txt_Ip.TabIndex = 8;
this.txt_Ip.Text = "192.168.8.72";
//
// lbl_Ip
//
this.lbl_Ip.AutoSize = true;
this.lbl_Ip.Location = new System.Drawing.Point(22, 56);
this.lbl_Ip.Name = "lbl_Ip";
this.lbl_Ip.Size = new System.Drawing.Size(59, 12);
this.lbl_Ip.TabIndex = 9;
this.lbl_Ip.Text = "服务器IP:";
this.lbl_Ip.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_Name
//
this.txt_Name.Location = new System.Drawing.Point(105, 20);
this.txt_Name.Name = "txt_Name";
this.txt_Name.Size = new System.Drawing.Size(144, 21);
this.txt_Name.TabIndex = 6;
this.txt_Name.Text = "dev-72";
//
// lbl_Name
//
this.lbl_Name.AutoSize = true;
this.lbl_Name.Location = new System.Drawing.Point(22, 23);
this.lbl_Name.Name = "lbl_Name";
this.lbl_Name.Size = new System.Drawing.Size(71, 12);
this.lbl_Name.TabIndex = 7;
this.lbl_Name.Text = "服务器名称:";
this.lbl_Name.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// btn_Ok
//
this.btn_Ok.Location = new System.Drawing.Point(36, 249);
this.btn_Ok.Name = "btn_Ok";
this.btn_Ok.Size = new System.Drawing.Size(75, 23);
this.btn_Ok.TabIndex = 1;
this.btn_Ok.Text = "确定(&O)";
this.btn_Ok.UseVisualStyleBackColor = true;
this.btn_Ok.Click += new System.EventHandler(this.btn_Ok_Click);
//
// btn_Cancel
//
this.btn_Cancel.Location = new System.Drawing.Point(186, 249);
this.btn_Cancel.Name = "btn_Cancel";
this.btn_Cancel.Size = new System.Drawing.Size(75, 23);
this.btn_Cancel.TabIndex = 2;
this.btn_Cancel.Text = "取消(&C)";
this.btn_Cancel.UseVisualStyleBackColor = true;
this.btn_Cancel.Click += new System.EventHandler(this.btn_Cancel_Click);
//
// Form_DevServer_Item
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(296, 284);
this.Controls.Add(this.btn_Cancel);
this.Controls.Add(this.btn_Ok);
this.Controls.Add(this.gb_main);
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(312, 323);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(312, 323);
this.Name = "Form_DevServer_Item";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "新增";
this.Load += new System.EventHandler(this.Form_DevServer_Item_Load);
this.gb_main.ResumeLayout(false);
this.gb_main.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox gb_main;
private System.Windows.Forms.TextBox txt_SuPassword;
private System.Windows.Forms.Label lbl_SuPassword;
private System.Windows.Forms.TextBox txt_Password;
private System.Windows.Forms.Label lbl_Password;
private System.Windows.Forms.TextBox txt_Ip;
private System.Windows.Forms.Label lbl_Ip;
private System.Windows.Forms.TextBox txt_Name;
private System.Windows.Forms.Label lbl_Name;
private System.Windows.Forms.TextBox txt_Port;
private System.Windows.Forms.Label lbl_Port;
private System.Windows.Forms.Button btn_Ok;
private System.Windows.Forms.Button btn_Cancel;
private System.Windows.Forms.TextBox txt_UserName;
private System.Windows.Forms.Label lbl_UserName;
}
}

@ -0,0 +1,96 @@
using System.Data;
namespace Tiobon.PublishHelper
{
public partial class Form_DevServer_Item : Form
{
bool b_edit = false;
public Form_DevServer_Item(string name)
{
InitializeComponent();
this.Text = name;
b_edit = this.Text != "新增";
}
private void Form_DevServer_Item_Load(object sender, EventArgs e)
{
if (b_edit)
{
var item = Utility.m_DevServers.Where(o => o.Name == this.Text.Split(new string[] { " - " }, StringSplitOptions.RemoveEmptyEntries)[1]).FirstOrDefault();
if (!(item is null))
{
this.txt_Name.Text = item.Name;
this.txt_Ip.Text = item.Ip;
this.txt_UserName.Text = item.UserName;
this.txt_Password.Text = item.Password;
this.txt_SuPassword.Text = item.SuPassword;
this.txt_Port.Text = item.Port.ToString();
}
}
}
private void btn_Ok_Click(object sender, EventArgs e)
{
foreach (var control in gb_main.Controls)
{
if (control is TextBox)
{
var textBox = control as TextBox;
if (string.IsNullOrEmpty(textBox.Text.Trim()))
{
MessageBox.Show($"{textBox.Name},不允许为空!", "提示");
return;
}
}
}
var devServer = new DevServer
{
Name = this.txt_Name.Text.Trim(),
Ip = this.txt_Ip.Text.Trim(),
UserName = this.txt_UserName.Text.Trim(),
Password = this.txt_Password.Text.Trim(),
SuPassword = this.txt_SuPassword.Text.Trim(),
Port = int.Parse(this.txt_Port.Text),
Hospitals = new List<Hospital>()
};
if (b_edit)
{
var nameOld = this.Text.Split(new string[] { " - " }, StringSplitOptions.RemoveEmptyEntries)[1];
if (nameOld != this.txt_Name.Text.Trim())
{
if (Utility.m_DevServers.Any(o => o.Name == this.txt_Name.Text.Trim()))
{
MessageBox.Show($"服务器名称已存在!", "提示");
return;
}
Utility.m_DevServers.Add(devServer);
}
else
{
var item = Utility.m_DevServers.Where(o => o.Name == this.txt_Name.Text.Trim()).FirstOrDefault();
if (!(item is null))
{
devServer.Hospitals = item.Hospitals;
Utility.m_DevServers.Remove(item);
Utility.m_DevServers.Add(devServer);
}
}
}
else
{
if (Utility.m_DevServers.Any(o => o.Name == this.txt_Name.Text.Trim()))
{
MessageBox.Show($"服务器名称已存在!", "提示");
return;
}
Utility.m_DevServers.Add(devServer);
}
this.Close();
}
private void btn_Cancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -0,0 +1,186 @@
namespace Tiobon.PublishHelper
{
partial class Form_Hospital
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.gb_Main = new System.Windows.Forms.GroupBox();
this.ll_Sync = new System.Windows.Forms.LinkLabel();
this.listView_Hospital = new System.Windows.Forms.ListView();
this.HospitalName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.FileName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.DefaultPort = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SCPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.WWWPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.contextMenuStrip_ListView = new System.Windows.Forms.ContextMenuStrip(this.components);
this.tsmi_Insert = new System.Windows.Forms.ToolStripMenuItem();
this.tsmi_Edit = new System.Windows.Forms.ToolStripMenuItem();
this.tsmi_Delete = new System.Windows.Forms.ToolStripMenuItem();
this.gb_Main.SuspendLayout();
this.contextMenuStrip_ListView.SuspendLayout();
this.SuspendLayout();
//
// gb_Main
//
this.gb_Main.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.gb_Main.Controls.Add(this.ll_Sync);
this.gb_Main.Controls.Add(this.listView_Hospital);
this.gb_Main.Location = new System.Drawing.Point(12, 12);
this.gb_Main.Name = "gb_Main";
this.gb_Main.Size = new System.Drawing.Size(776, 426);
this.gb_Main.TabIndex = 1;
this.gb_Main.TabStop = false;
//
// ll_Sync
//
this.ll_Sync.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.ll_Sync.AutoSize = true;
this.ll_Sync.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline;
this.ll_Sync.Location = new System.Drawing.Point(707, 2);
this.ll_Sync.Name = "ll_Sync";
this.ll_Sync.Size = new System.Drawing.Size(53, 12);
this.ll_Sync.TabIndex = 1;
this.ll_Sync.TabStop = true;
this.ll_Sync.Text = "同步项目";
this.ll_Sync.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.ll_Sync_LinkClicked);
//
// listView_Hospital
//
this.listView_Hospital.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.HospitalName,
this.FileName,
this.DefaultPort,
this.SCPath,
this.WWWPath});
this.listView_Hospital.ContextMenuStrip = this.contextMenuStrip_ListView;
this.listView_Hospital.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView_Hospital.FullRowSelect = true;
this.listView_Hospital.GridLines = true;
this.listView_Hospital.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.listView_Hospital.HideSelection = false;
this.listView_Hospital.Location = new System.Drawing.Point(3, 17);
this.listView_Hospital.MultiSelect = false;
this.listView_Hospital.Name = "listView_Hospital";
this.listView_Hospital.Size = new System.Drawing.Size(770, 406);
this.listView_Hospital.TabIndex = 0;
this.listView_Hospital.UseCompatibleStateImageBehavior = false;
this.listView_Hospital.View = System.Windows.Forms.View.Details;
this.listView_Hospital.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.listView_Hospital_MouseDoubleClick);
//
// HospitalName
//
this.HospitalName.Text = "项目名称";
this.HospitalName.Width = 175;
//
// FileName
//
this.FileName.Text = "文件夹名称";
this.FileName.Width = 87;
//
// DefaultPort
//
this.DefaultPort.Text = "默认端口(前三位)";
this.DefaultPort.Width = 120;
//
// SCPath
//
this.SCPath.Text = "本地后端代码路径";
this.SCPath.Width = 205;
//
// WWWPath
//
this.WWWPath.Text = "本地前端代码路径";
this.WWWPath.Width = 176;
//
// contextMenuStrip_ListView
//
this.contextMenuStrip_ListView.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.tsmi_Insert,
this.tsmi_Edit,
this.tsmi_Delete});
this.contextMenuStrip_ListView.Name = "contextMenuStrip_Main";
this.contextMenuStrip_ListView.Size = new System.Drawing.Size(119, 70);
//
// tsmi_Insert
//
this.tsmi_Insert.Name = "tsmi_Insert";
this.tsmi_Insert.Size = new System.Drawing.Size(118, 22);
this.tsmi_Insert.Text = "新增(&N)";
this.tsmi_Insert.Click += new System.EventHandler(this.tsmi_Insert_Click);
//
// tsmi_Edit
//
this.tsmi_Edit.Name = "tsmi_Edit";
this.tsmi_Edit.Size = new System.Drawing.Size(118, 22);
this.tsmi_Edit.Text = "编辑(&E)";
this.tsmi_Edit.Click += new System.EventHandler(this.tsmi_Edit_Click);
//
// tsmi_Delete
//
this.tsmi_Delete.Name = "tsmi_Delete";
this.tsmi_Delete.Size = new System.Drawing.Size(118, 22);
this.tsmi_Delete.Text = "删除(&D)";
this.tsmi_Delete.Click += new System.EventHandler(this.tsmi_Delete_Click);
//
// Form_Hospital
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.gb_Main);
this.Name = "Form_Hospital";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "项目配置";
this.Load += new System.EventHandler(this.Form_Hospital_Load);
this.gb_Main.ResumeLayout(false);
this.gb_Main.PerformLayout();
this.contextMenuStrip_ListView.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox gb_Main;
private System.Windows.Forms.ListView listView_Hospital;
private System.Windows.Forms.ColumnHeader HospitalName;
private System.Windows.Forms.ColumnHeader FileName;
private System.Windows.Forms.ColumnHeader DefaultPort;
private System.Windows.Forms.ColumnHeader SCPath;
private System.Windows.Forms.ColumnHeader WWWPath;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip_ListView;
private System.Windows.Forms.ToolStripMenuItem tsmi_Insert;
private System.Windows.Forms.ToolStripMenuItem tsmi_Edit;
private System.Windows.Forms.ToolStripMenuItem tsmi_Delete;
private System.Windows.Forms.LinkLabel ll_Sync;
}
}

@ -0,0 +1,188 @@
using System.Data;
namespace Tiobon.PublishHelper
{
public partial class Form_Hospital : Form
{
string devName = string.Empty;
public Form_Hospital(string name)
{
InitializeComponent();
devName = name;
}
private void Form_Hospital_Load(object sender, EventArgs e)
{
this.Text = $"医院管理 - {devName}";
RefreshView();
}
private void RefreshView()
{
listView_Hospital.Items.Clear();
Utility.m_DevServers.Where(o => o.Name == devName).FirstOrDefault()
?.Hospitals
?.ForEach(o =>
{
ListViewItem item = new ListViewItem();
item.SubItems[0].Text = o.Name;
item.SubItems.Add(o.FileName);
item.SubItems.Add(o.DefaultFort);
item.SubItems.Add(o.SCPath);
item.SubItems.Add(o.WWWPath);
listView_Hospital.Items.Add(item);
});
}
private void tsmi_Insert_Click(object sender, EventArgs e)
{
using (Form_Hospital_Item f = new Form_Hospital_Item(devName, "新增"))
{
f.ShowDialog();
}
Utility.SaveDevServer();
RefreshView();
}
private void tsmi_Edit_Click(object sender, EventArgs e)
{
if (this.listView_Hospital.SelectedItems.Count <= 0)
return;
using (Form_Hospital_Item f = new Form_Hospital_Item(devName, $"编辑 - {this.listView_Hospital.SelectedItems[0].Text}"))
{
f.ShowDialog();
}
Utility.SaveDevServer();
RefreshView();
}
private void tsmi_Delete_Click(object sender, EventArgs e)
{
if (this.listView_Hospital.SelectedItems.Count <= 0)
{
return;
}
if (MessageBox.Show("是否确认删除?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return;
}
var server = Utility.m_DevServers.Where(o => o.Name == devName).FirstOrDefault();
if (!(server is null))
{
var item = server.Hospitals.Where(o => o.Name == this.listView_Hospital.SelectedItems[0].Text).FirstOrDefault();
if (!(item is null))
{
server.Hospitals.Remove(item);
Utility.SaveDevServer();
RefreshView();
}
}
}
private void ll_Sync_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var server = Utility.m_DevServers.Where(o => o.Name == devName).FirstOrDefault();
if (server is null)
return;
if (!Utility.Ping(server.Ip))
{
MessageBox.Show("网络连接失败!", "提示");
return;
}
this.Cursor = Cursors.WaitCursor;
bool b_add = false;
try
{
bool b_dev = SftpHelper.Exists(server, $"/home/{server.UserName}/compose");
var hospitals = SftpHelper.ListDirectory(server, b_dev ? $"/home/{server.UserName}/compose" : $"/home/{server.UserName}").Select(o => o.Name).ToList();
hospitals.ForEach(hospitalName =>
{
if (hospitalName == (b_dev ? "sample" : "tools"))
return;
if (!b_dev)
{
if (!SftpHelper.Exists(server, $"/home/{server.UserName}/{hospitalName}/.env"))
{
Utility.SendLog("同步", $"发现 文件夹 {hospitalName} 不存在 .env 文件,跳过同步");
return;
}
}
var item = server.Hospitals.Where(o => o.FileName == hospitalName).FirstOrDefault();
var path = System.Environment.CurrentDirectory.Replace(@"\backend\src\Assistant\JianLian.HDIS.PublishHelper\bin\Debug", "");
//获取医院信息
var fname = Utility.GetTempFileName(".env");
bool b_suc = SftpHelper.DownloadFile(server, b_dev ? $"/home/{server.UserName}/compose/{hospitalName}/.env" : $"/home/{server.UserName}/{hospitalName}/.env", fname);
var content = File.ReadAllText(fname);
var datas = content.Split(new string[] { "\r", "\n", "=" }, StringSplitOptions.RemoveEmptyEntries);
var hospital = new Hospital
{
Name = b_dev ? datas[3] : hospitalName,
FileName = b_dev ? datas[3] : hospitalName,
DefaultFort = datas[1],
SCPath = $"{path}\\backend",
WWWPath = $""
};
if (item is null)
{
if (b_suc)
{
server.Hospitals.Add(hospital);
//新医院
Utility.SendLog("同步", $"发现新医院 {hospitalName} 端口 {hospital.DefaultFort}");
b_add = true;
}
}
else
{
//已有医院查看端口是否一致
if (item.DefaultFort != hospital.DefaultFort)
{
Utility.SendLog("同步", $"医院 {hospitalName} 端口号不一致 {item.DefaultFort},更新为实际端口号 {hospital.DefaultFort}");
item.DefaultFort = hospital.DefaultFort;
}
else
{
Utility.SendLog("同步", $"医院 {hospitalName} 端口号一致 {hospital.DefaultFort}");
}
}
});
var notExsit = new List<Hospital>();
server.Hospitals.ForEach(hospital =>
{
if (!hospitals.Contains(hospital.FileName))
{
notExsit.Add(hospital);
}
});
notExsit.ForEach(hospital =>
{
server.Hospitals.Remove(hospital);
//医院不存在
Utility.SendLog("同步", $"医院已经不存在 {hospital.FileName} 端口 {hospital.DefaultFort}");
});
}
catch (Exception ex)
{
Utility.SendLog("同步", $"同步失败:{ex}");
}
RefreshView();
Utility.SendLog("同步", $"同步完毕" + (b_add ? "请完善医院信息" : ""));
this.Cursor = Cursors.Default;
}
private void listView_Hospital_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (this.listView_Hospital.SelectedItems.Count <= 0)
return;
using (Form_Hospital_Item f = new Form_Hospital_Item(devName, $"编辑 - {this.listView_Hospital.SelectedItems[0].Text}"))
{
f.ShowDialog();
}
Utility.SaveDevServer();
RefreshView();
}
}
}

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="contextMenuStrip_ListView.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

@ -0,0 +1,241 @@
namespace Tiobon.PublishHelper
{
partial class Form_Hospital_Item
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.gb_main = new System.Windows.Forms.GroupBox();
this.lbl_www_default = new System.Windows.Forms.Label();
this.lbl_sc_default = new System.Windows.Forms.Label();
this.txt_Port = new System.Windows.Forms.TextBox();
this.lbl_Port = new System.Windows.Forms.Label();
this.txt_WWWPath = new System.Windows.Forms.TextBox();
this.lbl_WWWPath = new System.Windows.Forms.Label();
this.txt_SCPath = new System.Windows.Forms.TextBox();
this.lbl_SCPath = new System.Windows.Forms.Label();
this.txt_FileName = new System.Windows.Forms.TextBox();
this.lbl_FileName = new System.Windows.Forms.Label();
this.txt_Name = new System.Windows.Forms.TextBox();
this.lbl_Name = new System.Windows.Forms.Label();
this.btn_Ok = new System.Windows.Forms.Button();
this.btn_Cancel = new System.Windows.Forms.Button();
this.gb_main.SuspendLayout();
this.SuspendLayout();
//
// gb_main
//
this.gb_main.Controls.Add(this.lbl_www_default);
this.gb_main.Controls.Add(this.lbl_sc_default);
this.gb_main.Controls.Add(this.txt_Port);
this.gb_main.Controls.Add(this.lbl_Port);
this.gb_main.Controls.Add(this.txt_WWWPath);
this.gb_main.Controls.Add(this.lbl_WWWPath);
this.gb_main.Controls.Add(this.txt_SCPath);
this.gb_main.Controls.Add(this.lbl_SCPath);
this.gb_main.Controls.Add(this.txt_FileName);
this.gb_main.Controls.Add(this.lbl_FileName);
this.gb_main.Controls.Add(this.txt_Name);
this.gb_main.Controls.Add(this.lbl_Name);
this.gb_main.Location = new System.Drawing.Point(12, 12);
this.gb_main.Name = "gb_main";
this.gb_main.Size = new System.Drawing.Size(270, 190);
this.gb_main.TabIndex = 0;
this.gb_main.TabStop = false;
//
// lbl_www_default
//
this.lbl_www_default.AutoSize = true;
this.lbl_www_default.ForeColor = System.Drawing.Color.Red;
this.lbl_www_default.Location = new System.Drawing.Point(22, 171);
this.lbl_www_default.Name = "lbl_www_default";
this.lbl_www_default.Size = new System.Drawing.Size(59, 12);
this.lbl_www_default.TabIndex = 19;
this.lbl_www_default.Text = "(...\\www)";
//
// lbl_sc_default
//
this.lbl_sc_default.AutoSize = true;
this.lbl_sc_default.ForeColor = System.Drawing.Color.Red;
this.lbl_sc_default.Location = new System.Drawing.Point(22, 137);
this.lbl_sc_default.Name = "lbl_sc_default";
this.lbl_sc_default.Size = new System.Drawing.Size(53, 12);
this.lbl_sc_default.TabIndex = 18;
this.lbl_sc_default.Text = "(...\\sc)";
//
// txt_Port
//
this.txt_Port.Location = new System.Drawing.Point(105, 86);
this.txt_Port.Name = "txt_Port";
this.txt_Port.Size = new System.Drawing.Size(144, 21);
this.txt_Port.TabIndex = 16;
this.txt_Port.Text = "600";
//
// lbl_Port
//
this.lbl_Port.AutoSize = true;
this.lbl_Port.Location = new System.Drawing.Point(22, 89);
this.lbl_Port.Name = "lbl_Port";
this.lbl_Port.Size = new System.Drawing.Size(59, 12);
this.lbl_Port.TabIndex = 17;
this.lbl_Port.Text = "默认端口:";
this.lbl_Port.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_WWWPath
//
this.txt_WWWPath.Location = new System.Drawing.Point(105, 152);
this.txt_WWWPath.Name = "txt_WWWPath";
this.txt_WWWPath.Size = new System.Drawing.Size(144, 21);
this.txt_WWWPath.TabIndex = 12;
this.txt_WWWPath.Text = "E:\\code\\huhang\\ui\\www";
//
// lbl_WWWPath
//
this.lbl_WWWPath.AutoSize = true;
this.lbl_WWWPath.Location = new System.Drawing.Point(22, 155);
this.lbl_WWWPath.Name = "lbl_WWWPath";
this.lbl_WWWPath.Size = new System.Drawing.Size(59, 12);
this.lbl_WWWPath.TabIndex = 13;
this.lbl_WWWPath.Text = "前端路径:";
this.lbl_WWWPath.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_SCPath
//
this.txt_SCPath.Location = new System.Drawing.Point(105, 119);
this.txt_SCPath.Name = "txt_SCPath";
this.txt_SCPath.Size = new System.Drawing.Size(144, 21);
this.txt_SCPath.TabIndex = 10;
this.txt_SCPath.Text = "E:\\code\\huhang\\sc";
//
// lbl_SCPath
//
this.lbl_SCPath.AutoSize = true;
this.lbl_SCPath.Location = new System.Drawing.Point(22, 122);
this.lbl_SCPath.Name = "lbl_SCPath";
this.lbl_SCPath.Size = new System.Drawing.Size(59, 12);
this.lbl_SCPath.TabIndex = 11;
this.lbl_SCPath.Text = "后端路径:";
this.lbl_SCPath.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_FileName
//
this.txt_FileName.Location = new System.Drawing.Point(105, 53);
this.txt_FileName.Name = "txt_FileName";
this.txt_FileName.Size = new System.Drawing.Size(144, 21);
this.txt_FileName.TabIndex = 8;
this.txt_FileName.Text = "yiyou";
//
// lbl_FileName
//
this.lbl_FileName.AutoSize = true;
this.lbl_FileName.Location = new System.Drawing.Point(22, 56);
this.lbl_FileName.Name = "lbl_FileName";
this.lbl_FileName.Size = new System.Drawing.Size(71, 12);
this.lbl_FileName.TabIndex = 9;
this.lbl_FileName.Text = "文件夹名称:";
this.lbl_FileName.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txt_Name
//
this.txt_Name.Location = new System.Drawing.Point(105, 20);
this.txt_Name.Name = "txt_Name";
this.txt_Name.Size = new System.Drawing.Size(144, 21);
this.txt_Name.TabIndex = 6;
this.txt_Name.Text = "玉林市第一人民医院";
//
// lbl_Name
//
this.lbl_Name.AutoSize = true;
this.lbl_Name.Location = new System.Drawing.Point(22, 23);
this.lbl_Name.Name = "lbl_Name";
this.lbl_Name.Size = new System.Drawing.Size(59, 12);
this.lbl_Name.TabIndex = 7;
this.lbl_Name.Text = "医院名称:";
this.lbl_Name.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// btn_Ok
//
this.btn_Ok.Location = new System.Drawing.Point(30, 218);
this.btn_Ok.Name = "btn_Ok";
this.btn_Ok.Size = new System.Drawing.Size(75, 23);
this.btn_Ok.TabIndex = 1;
this.btn_Ok.Text = "确定(&O)";
this.btn_Ok.UseVisualStyleBackColor = true;
this.btn_Ok.Click += new System.EventHandler(this.btn_Ok_Click);
//
// btn_Cancel
//
this.btn_Cancel.Location = new System.Drawing.Point(177, 218);
this.btn_Cancel.Name = "btn_Cancel";
this.btn_Cancel.Size = new System.Drawing.Size(75, 23);
this.btn_Cancel.TabIndex = 2;
this.btn_Cancel.Text = "取消(&C)";
this.btn_Cancel.UseVisualStyleBackColor = true;
this.btn_Cancel.Click += new System.EventHandler(this.btn_Cancel_Click);
//
// Form_Hospital_Item
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(296, 256);
this.Controls.Add(this.btn_Cancel);
this.Controls.Add(this.btn_Ok);
this.Controls.Add(this.gb_main);
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(312, 295);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(312, 295);
this.Name = "Form_Hospital_Item";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "新增";
this.Load += new System.EventHandler(this.Form_Hospital_Item_Load);
this.gb_main.ResumeLayout(false);
this.gb_main.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox gb_main;
private System.Windows.Forms.TextBox txt_WWWPath;
private System.Windows.Forms.Label lbl_WWWPath;
private System.Windows.Forms.TextBox txt_SCPath;
private System.Windows.Forms.Label lbl_SCPath;
private System.Windows.Forms.TextBox txt_FileName;
private System.Windows.Forms.Label lbl_FileName;
private System.Windows.Forms.TextBox txt_Name;
private System.Windows.Forms.Label lbl_Name;
private System.Windows.Forms.Button btn_Ok;
private System.Windows.Forms.Button btn_Cancel;
private System.Windows.Forms.TextBox txt_Port;
private System.Windows.Forms.Label lbl_Port;
private System.Windows.Forms.Label lbl_www_default;
private System.Windows.Forms.Label lbl_sc_default;
}
}

@ -0,0 +1,119 @@
using System.Data;
namespace Tiobon.PublishHelper
{
public partial class Form_Hospital_Item : Form
{
bool b_edit = false;
string devName = string.Empty;
Hospital hoipitalOld;
public Hospital m_Hoipital;
public Form_Hospital_Item(string devname, string name)
{
InitializeComponent();
this.Text = name;
devName = devname;
b_edit = this.Text != "新增";
var path = System.Environment.CurrentDirectory.Replace(@"\backend\src\Assistant\JianLian.HDIS.PublishHelper\bin\Debug", "");
this.txt_SCPath.Text = $"{path}\\backend";
this.txt_WWWPath.Text = $"{path}\\web";
}
private void Form_Hospital_Item_Load(object sender, EventArgs e)
{
if (b_edit)
{
hoipitalOld = Utility.m_DevServers
.Where(o => o.Name == devName)
.FirstOrDefault()
?.Hospitals
?.Where(o => o.Name == this.Text.Split(new string[] { " - " }, StringSplitOptions.RemoveEmptyEntries)[1])
.FirstOrDefault();
if (!(hoipitalOld is null))
{
this.txt_Name.Text = hoipitalOld.Name;
this.txt_FileName.Text = hoipitalOld.FileName;
this.txt_Port.Text = hoipitalOld.DefaultFort;
this.txt_SCPath.Text = hoipitalOld.SCPath;
this.txt_WWWPath.Text = hoipitalOld.WWWPath;
}
}
}
private void btn_Ok_Click(object sender, EventArgs e)
{
foreach (var control in gb_main.Controls)
{
if (control is TextBox)
{
var textBox = control as TextBox;
if (string.IsNullOrEmpty(textBox.Text.Trim()))
{
MessageBox.Show($"{textBox.Name},不允许为空!", "提示");
return;
}
}
}
int.TryParse(this.txt_Port.Text.Trim(), out int port);
if (port < 100 || port > 655)
{
MessageBox.Show($"端口配置不正确,端口取值范围[100,655]!", "提示");
return;
}
var server = Utility.m_DevServers.Where(o => o.Name == devName).FirstOrDefault();
if (server is null)
return;
m_Hoipital = new Hospital
{
Name = this.txt_Name.Text.Trim(),
FileName = this.txt_FileName.Text.Trim(),
DefaultFort = this.txt_Port.Text.Trim(),
SCPath = this.txt_SCPath.Text.Trim(),
WWWPath = this.txt_WWWPath.Text.Trim(),
};
if (b_edit)
{
server.Hospitals.Remove(hoipitalOld);
}
bool b_suc = false;
try
{
if (server.Hospitals.Any(o => o.Name == this.txt_Name.Text.Trim()))
{
MessageBox.Show($"医院名称已存在!", "提示");
return;
}
if (server.Hospitals.Any(o => o.FileName == this.txt_FileName.Text.Trim()))
{
MessageBox.Show($"文件夹已存在!", "提示");
return;
}
if (server.Hospitals.Any(o => o.DefaultFort == this.txt_Port.Text.Trim()))
{
MessageBox.Show($"端口已存在!", "提示");
return;
}
b_suc = true;
}
finally
{
if (!b_suc)
{
m_Hoipital = null;
if (b_edit)
{
server.Hospitals.Add(hoipitalOld);
}
}
}
server.Hospitals.Add(m_Hoipital);
this.Close();
}
private void btn_Cancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -0,0 +1,17 @@
namespace Tiobon.PublishHelper
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
}

@ -0,0 +1,84 @@
using System.Diagnostics;
namespace Tiobon.PublishHelper
{
/// <summary>
/// CmdHelper
/// </summary>
public class CmdHelper
{
/// <summary>
/// 指令Cmd命令
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static (bool, string) ExecCmd(string str)
{
string msg = string.Empty;
bool hasError = false;
bool completed = false;
string cmdCur = string.Empty;
using (Process m_Cmd = new Process())
{
m_Cmd.StartInfo.FileName = "cmd.exe";
m_Cmd.StartInfo.WorkingDirectory = ".";
m_Cmd.StartInfo.UseShellExecute = false;
m_Cmd.StartInfo.RedirectStandardInput = true;
m_Cmd.StartInfo.RedirectStandardOutput = true;
m_Cmd.StartInfo.CreateNoWindow = true;
m_Cmd.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
var res = e.Data;
if (res.Contains("\u001b"))
{
foreach (System.Text.RegularExpressions.Match item in Utility.m_RegexUb.Matches(res))
{
res = res.Replace(item.Value, "");
}
}
Utility.SendLog("", res);
if (res.Trim() != "Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted."
&& (res.Contains("ERR!") || res.Contains("ERROR") || res.Contains("error")))
{
msg = res;
hasError = true;
}
if (res.EndsWith("exit"))
{
completed = true;
}
}
});
m_Cmd.Start();
m_Cmd.BeginOutputReadLine();
str.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.ToList()
.ForEach(s =>
{
if (hasError)
return;
cmdCur = s;
m_Cmd.StandardInput.WriteLine(cmdCur);
});
int timecout = 60 * 15;
while (!completed && !hasError)
{
System.Threading.Thread.Sleep(1000);
if (--timecout < 0)
{
msg = $"指令执行超时:{str}";
hasError = true;
break;
}
}
}
return (hasError, msg);
}
}
}

@ -0,0 +1,72 @@
namespace Tiobon.PublishHelper;
/// <summary>
/// 服务器
/// </summary>
[Serializable]
public class Server
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// Ip
/// </summary>
public string Ip { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// Su密码
/// </summary>
public string SuPassword { get; set; }
/// <summary>
/// 端口
/// </summary>
public int Port { get; set; }
}
/// <summary>
/// 开发服务器
/// </summary>
[Serializable]
public class DevServer : Server
{
/// <summary>
/// 医院信息
/// </summary>
public List<Hospital> Hospitals { get; set; }
}
/// <summary>
/// 医院
/// </summary>
[Serializable]
public class Hospital
{
/// <summary>
/// 医院名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 文件夹名称
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 默认端口前三位
/// </summary>
public string DefaultFort { get; set; }
/// <summary>
/// 本地后端代码路径
/// </summary>
public string SCPath { get; set; }
/// <summary>
/// 本地前端代码路径
/// </summary>
public string WWWPath { get; set; }
}

@ -0,0 +1,105 @@
namespace Tiobon.PublishHelper
{
/// <summary>
/// Docker命令封装
/// </summary>
public class DockerCommand
{
/// <summary>
/// docker ps
/// </summary>
/// <param name="hospital"></param>
/// <returns></returns>
public static string GetDockerStatus(string hospital)
{
return $"sudo docker ps -a --format \"table {{{{.ID}}}}||{{{{.Names}}}}||{{{{.Image}}}}||{{{{.Command}}}}||{{{{.CreatedAt}}}}||{{{{.RunningFor}}}}||{{{{.Ports}}}}||{{{{.Status}}}}||{{{{.Networks}}}}\" | grep \"{hospital}_\"";
}
/// <summary>
/// docker containerName
/// </summary>
/// <param name="hospital"></param>
/// <param name="modelName"></param>
/// <returns></returns>
public static string GetDockerContainerName(string hospital, string modelName)
{
return $"sudo docker ps -a --format \"table {{{{.Names}}}}\" | grep \"{hospital}_{modelName}\"";
}
/// <summary>
/// docker logs
/// </summary>
/// <param name="hospital"></param>
/// <returns></returns>
public static string GetDockerLogs(string containerName)
{
return $"sudo docker logs {containerName} --tail=50";
}
/// <summary>
/// docker-compose down
/// </summary>
/// <param name="userName"></param>
/// <param name="hospital"></param>
/// <returns></returns>
public static string DockerComposeDown(string userName, string hospital, string suffix )
{
return $"cd /home/{userName}/ihdis{suffix}/{hospital};sudo docker-compose down";
}
/// <summary>
/// docker-compose up
/// </summary>
/// <param name="userName"></param>
/// <param name="hospital"></param>
/// <returns></returns>
public static string DockerComposeUp(string userName, string hospital, string suffix )
{
return $"cd /home/{userName}/ihdis{suffix}/{hospital};sudo docker-compose up -d";
}
/// <summary>
/// docker-compose restart
/// </summary>
/// <param name="userName"></param>
/// <param name="hospital"></param>
/// <returns></returns>
public static string DockerComposeRestart(string userName, string hospital, string suffix )
{
return $"cd /home/{userName}/ihdis{suffix}/{hospital};sudo docker-compose restart";
}
/// <summary>
/// docker-compose remove
/// </summary>
/// <param name="userName"></param>
/// <param name="hospital"></param>
/// <returns></returns>
public static string DockerComposeRemove(string userName, string hospital, string cname, string suffix )
{
return $"cd /home/{userName}/ihdis{suffix}/{hospital};sudo docker-compose stop {cname};sudo docker-compose rm -f {cname}";
}
/// <summary>
/// docker container restart
/// </summary>
/// <param name="containerId"></param>
/// <returns></returns>
public static string DockeContainerRestart(string containerId)
{
return $"sudo docker restart {containerId}";
}
/// <summary>
/// docker-compose restart container
/// </summary>
/// <param name="userName"></param>
/// <param name="hospital"></param>
/// <returns></returns>
public static string DockerComposeContainerRestart(string userName, string hospital, string container, string suffix )
{
return $"cd /home/{userName}/ihdis{suffix}/{hospital};sudo docker-compose restart {container}";
}
/// <summary>
/// docker container log
/// </summary>
/// <param name="containerId"></param>
/// <returns></returns>
public static string DockeContainerLog(string userName, string hospital, string container, string suffix )
{
return $"cd /home/{userName}/ihdis{suffix}/{hospital};sudo docker-compose logs {container}";
}
}
}

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tiobon.PublishHelper
{
/// <summary>
/// 操作记录
/// </summary>
[Serializable]
public class OprateLog
{
/// <summary>
/// 上一次选择的服务器
/// </summary>
public string ServerName { get; set; }
/// <summary>
/// 上一次选择的医院
/// </summary>
public string HospitalName { get; set; }
/// <summary>
/// webapi
/// </summary>
public bool Webapi { get; set; }
/// <summary>
/// hfs
/// </summary>
public bool Hfs { get; set; }
/// <summary>
/// rtm
/// </summary>
public bool Rtm { get; set; }
/// <summary>
/// job
/// </summary>
public bool Job { get; set; }
/// <summary>
/// web
/// </summary>
public bool Web { get; set; }
/// <summary>
/// pad
/// </summary>
public bool Pad { get; set; }
/// <summary>
/// remove
/// </summary>
public bool Remove { get; set; }
/// <summary>
/// build
/// </summary>
public bool Build { get; set; }
/// <summary>
/// 版本打包-开发服务器
/// </summary>
public string PackDevIp { get; set; }
/// <summary>
/// 版本打包-医院
/// </summary>
public string PackHospital { get; set; }
/// <summary>
/// 版本打包-发布服务器
/// </summary>
public string PackPublishIp { get; set; }
/// <summary>
/// 版本打包-版本
/// </summary>
public string PackVersion { get; set; }
/// <summary>
/// 版本打包-数据库脚本
/// </summary>
public bool PackDbFile { get; set; }
/// <summary>
/// 版本打包-打包前先执行发布
/// </summary>
public bool PackPublish { get; set; }
/// <summary>
/// 版本打包-Git
/// </summary>
public bool PackGit { get; set; }
/// <summary>
/// 版本打包-是否自动下载
/// </summary>
public bool PackDownload { get; set; }
/// <summary>
/// 版本打包-是否为升级包
/// </summary>
public bool PackUpgrade { get; set; }
/// <summary>
/// 版本打包-TS升级包
/// </summary>
public bool PackUpgradeTS { get; set; }
/// <summary>
/// 版本打包-TS升级包项目名称
/// </summary>
public string PackUpgradeTSCustom { get; set; }
/// <summary>
/// TS插件打包-项目地址
/// </summary>
public string TSPath { get; set; }
/// <summary>
/// TS插件打包-版本号
/// </summary>
public string TSVersion { get; set; }
/// <summary>
/// TS插件打包-保存位置
/// </summary>
public string TSSavePath { get; set; }
/// <summary>
/// TS插件打包-是否自定义
/// </summary>
public bool TSCustom { get; set; }
/// <summary>
/// TS插件打包-是否编译
/// </summary>
public bool TSBuild { get; set; }
/// <summary>
/// TS插件打包-自定义医院
/// </summary>
public string TSCustomHospitals { get; set; }
}
}

@ -0,0 +1,79 @@
namespace Tiobon.PublishHelper
{
/// <summary>
/// 发布服务器
/// </summary>
[Serializable]
public class PublishServer : Server
{
private List<VersionFolder> folders;
/// <summary>
/// 版本文件夹
/// </summary>
public List<VersionFolder> Folders
{
get { return folders; }
set
{
if (folders == null)
value = new List<VersionFolder>();
folders = value;
}
}
}
/// <summary>
/// 版本文件夹
/// </summary>
[Serializable]
public class VersionFolder
{
/// <summary>
/// 文件名称
/// </summary>
public string FolderName { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 文件大小
/// </summary>
public long Size { get; set; }
private List<VersionFile> files;
/// <summary>
/// 版本文件
/// </summary>
public List<VersionFile> Files
{
get { return files; }
set
{
if (files == null)
value = new List<VersionFile>();
files = value;
}
}
}
/// <summary>
/// 版本文件
/// </summary>
[Serializable]
public class VersionFile
{
/// <summary>
/// 文件名称
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 文件大小
/// </summary>
public long Size { get; set; }
}
}

@ -0,0 +1,503 @@
using System.Net;
using System.Text;
using FluentFTP;
using Renci.SshNet;
using Renci.SshNet.Sftp;
namespace Tiobon.PublishHelper
{
/// <summary>
/// SFTP操作类
/// </summary>
public class SftpHelper
{
#region 下载文件
/// <summary>
/// 下载单个文件
/// </summary>
/// <param name="server"></param>
/// <param name="remotePath"></param>
/// <param name="localFile"></param>
/// <param name="b_log"></param>
/// <returns></returns>
public static bool DownloadFile(Server server, string remoteFile, string localFile, bool b_log = false, Action<long, ulong> progress = null, Action completedAction = null)
{
bool b_suc = false;
try
{
if (!Utility.Ping(server.Ip, b_log))
{
return b_suc;
}
using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
{
sftp.Connect();
if (sftp.Exists(remoteFile))
{
if (b_log)
Utility.SendLog("下载", $"下载文件 {remoteFile}");
if (File.Exists(localFile))
{
File.Delete(localFile);
System.Threading.Thread.Sleep(50);
}
var sftFile = sftp.ListDirectory(remoteFile.Substring(0, remoteFile.LastIndexOf('/'))).Where(o => o.FullName == remoteFile).FirstOrDefault();
using (var file = File.OpenWrite(localFile))
{
sftp.DownloadFile(remoteFile, file, pro =>
{
progress?.Invoke(sftFile.Length, pro);
});
if (b_log)
Utility.SendLog("下载", $"成功 {remoteFile} =>> {localFile} len {file.Length} byte");
b_suc = true;
}
}
else
{
if (b_log)
Utility.SendLog("下载", $"文件不存在 {remoteFile}");
}
}
}
catch (Exception ex)
{
if (b_log)
Utility.SendLog("下载", $"下载文件失败:{remoteFile} {ex.Message}");
}
finally
{
completedAction?.Invoke();
}
return b_suc;
}
#endregion
#region 上传文件
/// <summary>
/// 上传单个文件
/// </summary>
/// <param name="server"></param>
/// <param name="localFile"></param>
/// <param name="remoteFile"></param>
/// <param name="progress"></param>
public static void UploadFile(Server server, string localFile, string remoteFile, Action<long, ulong> progress = null, bool create = false)
{
if (!Utility.Ping(server.Ip))
return;
try
{
FtpClient client = new FtpClient();
client.Host = server.Ip;
client.Port = server.Port;
client.Credentials = new NetworkCredential(server.UserName, server.SuPassword);
client.AutoConnect();
using (var file = File.OpenRead(localFile))
{
try
{
var len = file.Length;
client.UploadFile(localFile, remoteFile);
Utility.SendLog("上传", $"成功 {localFile} =>> {remoteFile} len {len} byte");
}
catch (Exception e)
{
Utility.SendLog("上传", $"失败 {remoteFile} 原因:{e}");
}
}
client.Disconnect();
}
catch (Exception E)
{
Utility.SendLog("上传", $"失败 {remoteFile} 原因:{E}");
}
#region 作废代码
//using (SftpClient sftp = new SftpClient(server.Ip, server.Port, server.UserName, server.SuPassword))
//{
// sftp.Connect();
// using (var file = File.OpenRead(localFile))
// {
// try
// {
// if (!sftp.Exists(remoteFile) && create)
// {
// sftp.Create(remoteFile);
// }
// var len = file.Length;
// sftp.UploadFile(file, remoteFile, pro =>
// {
// progress?.Invoke(len, pro);
// });
// Utility.SendLog("上传", $"成功 {localFile} =>> {remoteFile} len {len} byte");
// }
// catch (Exception e)
// {
// Utility.SendLog("上传", $"失败 {remoteFile} 原因:{e}");
// }
// }
//}
#endregion
}
/// <summary>
/// 批量上传文件
/// </summary>
/// <param name="server"></param>
/// <param name="localPath"></param>
/// <param name="remotePath"></param>
/// <param name="files"></param>
/// <param name="progress"></param>
public static void UploadFile(Server server, string localPath, string remotePath, List<string> files, Action<int, int> progress)
{
if (!Utility.Ping(server.Ip))
return;
try
{
progress(files.Count, 0);
FtpClient sftp = new FtpClient();
sftp.Host = server.Ip;
sftp.Port = server.Port;
sftp.Credentials = new NetworkCredential(server.UserName, server.SuPassword);
sftp.AutoConnect();
var count = files.Count;
var index = 0;
files?.ForEach(fname =>
{
if (Utility.m_StopPublish)
return;
var localFileName = $"{localPath}\\{fname}";
var remoteFileName = $"{remotePath}/{fname.Replace("\\", "/")}";
using (var file = File.OpenRead(localFileName))
{
var len = file.Length;
try
{
index++;
if (fname.Contains("\\"))
{
StringBuilder sb = new StringBuilder();
var ff = fname.Substring(0, fname.LastIndexOf("\\")).Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
ff.ToList().ForEach(f =>
{
sb.Append($"/{f}");
var fpath = $"{remotePath}{sb}";
if (!sftp.DirectoryExists(fpath))
{
sftp.CreateDirectory(fpath);
Utility.SendLog("上传", $"创建目录成功 {fpath}");
}
});
}
//sftp.UploadFile(file, remoteFileName);
sftp.UploadFile(localFileName, remoteFileName);
progress(count, index);
Utility.SendLog("上传", $"[{index}/{count}]成功 {localPath}\\{fname} =>> {remoteFileName} len {len} byte");
}
catch (Exception e)
{
Utility.SendLog("上传", $"[{index}/{count}] 失败 原因:{fname} {e}");
try
{
Utility.SendLog("重新上传", $"[{index}/{count}] {fname} ");
sftp.UploadFile(localFileName, remoteFileName);
progress(count, index);
Utility.SendLog("上传", $"[{index}/{count}]成功 {localPath}\\{fname} =>> {remoteFileName} len {len} byte");
}
catch (Exception E)
{
Utility.SendLog("上传", $"[{index}/{count}] 失败 原因:{fname} {E}");
}
}
}
});
sftp.Disconnect();
#region 作废代码
//using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
//{
// sftp.Connect();
// var count = files.Count;
// var index = 0;
// files?.ForEach(fname =>
// {
// if (Utility.m_StopPublish)
// return;
// var localFileName = $"{localPath}\\{fname}";
// var remoteFileName = $"{remotePath}/{fname.Replace("\\", "/")}";
// using (var file = File.OpenRead(localFileName))
// {
// try
// {
// index++;
// var len = file.Length;
// if (fname.Contains("\\"))
// {
// StringBuilder sb = new StringBuilder();
// var ff = fname.Substring(0, fname.LastIndexOf("\\")).Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
// ff.ToList().ForEach(f =>
// {
// sb.Append($"/{f}");
// var fpath = $"{remotePath}{sb}";
// if (!sftp.Exists(fpath))
// {
// sftp.CreateDirectory(fpath);
// Utility.SendLog("上传", $"创建目录成功 {fpath}");
// }
// });
// }
// sftp.UploadFile(file, remoteFileName);
// progress(count, index);
// Utility.SendLog("上传", $"[{index}/{count}]成功 {localPath}\\{fname} =>> {remoteFileName} len {len} byte");
// }
// catch (Exception e)
// {
// Utility.SendLog("上传", $"[{index}/{count}] 失败 原因:{fname} {e}");
// }
// }
// });
//}
#endregion
}
catch (Exception ex)
{
Utility.SendLog("", ex.ToString());
}
}
#endregion
#region 获取文件
/// <summary>
/// 获取当前目录的文件列表
/// </summary>
/// <param name="server"></param>
/// <param name="remotePath"></param>
/// <returns></returns>
public static List<SftpFile> ListFiles(Server server, string remotePath)
{
List<SftpFile> list = new List<SftpFile>();
//try
//{
// using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
// {
// sftp.Connect();
// list = sftp.ListDirectory(remotePath).Where(f => f.IsRegularFile).ToList();
// }
//}
//catch (Exception ex)
//{
// Utility.SendLog("", $"获取文件夹失败:{remotePath} {ex.Message}");
//}
return list;
}
public static List<FtpListItem> GetListing(Server server, string remotePath)
{
FtpClient sftp = new FtpClient();
sftp.Host = server.Ip;
sftp.Port = server.Port;
sftp.Credentials = new NetworkCredential(server.UserName, server.SuPassword);
sftp.AutoConnect();
List<FtpListItem> list = new List<FtpListItem>();
try
{
foreach (FtpListItem item in sftp.GetListing(remotePath))
{
list.Add(item);
// if this is a file
//if (item.Type == FtpFileSystemObjectType.File)
//{
// // get the file size
// long size = sftp.GetFileSize(item.FullName);
// // calculate a hash for the file on the server side (default algorithm)
// FtpHash hash = sftp.GetChecksum(item.FullName);
//}
//// get modified date/time of the file or folder
//DateTime time = sftp.GetModifiedTime(item.FullName);
}
sftp.Disconnect();
}
catch (Exception ex)
{
Utility.SendLog("", $"获取文件夹失败:{remotePath} {ex.Message}");
}
return list;
}
#endregion
#region 获取文件夹
/// <summary>
/// 获取当前目录的文件夹列表
/// </summary>
/// <param name="server"></param>
/// <param name="remotePath"></param>
/// <returns></returns>
public static List<SftpFile> ListDirectory(Server server, string remotePath)
{
List<SftpFile> list = new List<SftpFile>();
try
{
FtpClient sftp = new FtpClient();
sftp.Host = server.Ip;
sftp.Port = server.Port;
sftp.Credentials = new NetworkCredential(server.UserName, server.SuPassword);
sftp.AutoConnect();
sftp.GetListing();
//using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
//{
// sftp.Connect();
// list = sftp.ListDirectory(remotePath).Where(f => f.IsDirectory && f.Name != "." && f.Name != "..").ToList();
//}
}
catch (Exception ex)
{
Utility.SendLog("", $"获取文件夹失败:{remotePath} {ex.Message}");
}
return list;
}
#endregion
#region 文件/文件夹是否存在
/// <summary>
/// 文件/文件夹是否存在
/// </summary>
/// <param name="server"></param>
/// <param name="path"></param>
/// <param name="create"></param>
/// <returns></returns>
public static bool Exists(Server server, string path)
{
bool b_suc = false;
if (!Utility.Ping(server.Ip))
{
return b_suc;
}
try
{
//using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
//{
// sftp.Connect();
// b_suc = sftp.Exists(path);
//}
}
catch (Exception ex)
{
Utility.SendLog("", ex.ToString());
}
return b_suc;
}
public static void CreateDirectory(Server server, string path)
{
if (!Utility.Ping(server.Ip))
{
return;
}
try
{
using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
{
sftp.Connect();
if (!sftp.Exists(path))
{
sftp.CreateDirectory(path);
}
}
}
catch (Exception ex)
{
Utility.SendLog("", ex.ToString());
}
}
#endregion
#region 删除文件
/// <summary>
/// 删除文件
/// </summary>
/// <param name="server"></param>
/// <param name="path"></param>
/// <returns></returns>
public static bool Delete(Server server, string path)
{
bool b_suc = false;
if (!Utility.Ping(server.Ip))
return b_suc;
try
{
FtpClient sftp = new FtpClient();
sftp.Host = server.Ip;
sftp.Port = server.Port;
sftp.Credentials = new NetworkCredential(server.UserName, server.SuPassword);
sftp.AutoConnect();
//using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
//{
// sftp.Connect();
// if (sftp.FileExists(path))
// sftp.Delete(path);
// b_suc = true;
//}
}
catch (Exception ex)
{
Utility.SendLog("", ex.ToString());
}
return b_suc;
}
#endregion
#region 删除文件夹
/// <summary>
/// 删除文件夹
/// </summary>
/// <param name="server"></param>
/// <param name="path"></param>
/// <returns></returns>
public static bool DeleteDirectory(Server server, string path)
{
bool b_suc = false;
if (!Utility.Ping(server.Ip))
return b_suc;
try
{
FtpClient sftp = new FtpClient();
sftp.Host = server.Ip;
sftp.Port = server.Port;
sftp.Credentials = new NetworkCredential(server.UserName, server.SuPassword);
sftp.AutoConnect();
if (sftp.DirectoryExists(path))
sftp.DeleteDirectory(path);
sftp.Disconnect();
//using (SftpClient sftp = new SftpClient(server.Ip, server.Port, "root", server.SuPassword))
//{
// sftp.Connect();
// if (sftp.FileExists(path))
// sftp.Delete(path);
// b_suc = true;
//}
}
catch (Exception ex)
{
Utility.SendLog("", ex.ToString());
}
return b_suc;
}
#endregion
}
}

@ -0,0 +1,249 @@
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tiobon.PublishHelper
{
/// <summary>
/// SSHHelper
/// </summary>
public class SshHelper
{
#region 执行命令
/// <summary>
/// SSH执行命令返回结果
/// </summary>
/// <param name="server">服务器</param>
/// <param name="command">命令</param>
/// <param name="result">执行结果</param>
/// <param name="b_log">打印日志</param>
/// <returns></returns>
public static (bool Success, string Result) ExcuteCmd(Server server, string command, bool b_log = false)
{
bool b_suc = false;
string result = string.Empty;
try
{
//if (!Utility.Ping(server.Ip, b_log))
//{
// return (b_suc, result);
//}
using (SshClient ssh = new SshClient(server.Ip, server.Port, "root", server.SuPassword))
{
ssh.Connect();
if (b_log)
{
Utility.SendLog(command);
}
var cmd = ssh.RunCommand(command);
if (cmd.ExitStatus != 0)
{
result = cmd.Error;
}
else
{
b_suc = true;
result = $"{cmd.Result}{cmd.Error}";
}
}
}
catch (Exception ex)
{
result = ex.Message;
}
if (b_log)
{
if (!string.IsNullOrEmpty(result))
{
result
.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
.ToList()
.ForEach(
s =>
{
if (!string.IsNullOrEmpty(s.Trim()))
Utility.SendLog(s);
});
}
else
{
Utility.SendLog("success");
}
}
return (b_suc, result);
}
/// <summary>
/// SSH执行批量命令
/// </summary>
/// <param name="server">服务器</param>
/// <param name="commands">命令</param>
/// <param name="logFlag">日志标识</param>
/// <param name="action">完成以后的操作</param>
public static void ExcuteCmds(Server server, List<string> commands, string logFlag, Action completedAction = null)
{
string result = string.Empty;
try
{
Utility.SetProgressBarVisible(true);
Utility.SendLog(logFlag, "开始执行批量指令", true);
if (!Utility.Ping(server.Ip))
{
return;
}
using (SshClient ssh = new SshClient(server.Ip, server.Port, "root", server.SuPassword))
{
ssh.Connect();
int index = 0;
if (commands != null)
{
Utility.SetProgressBarValue(commands.Count, 0);
commands.ForEach(command =>
{
Utility.SendLog(logFlag, $"{command}");
var cmd = ssh.RunCommand(command);
if (cmd.ExitStatus != 0)
{
result = cmd.Error;
}
else
{
result = $"{cmd.Result}{cmd.Error}";
}
if (!string.IsNullOrEmpty(result))
{
result
.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
.ToList()
.ForEach(
s =>
{
if (!string.IsNullOrEmpty(s.Trim()))
Utility.SendLog(logFlag, s);
});
}
else
{
Utility.SendLog(logFlag, "success");
}
Utility.SetProgressBarValue(commands.Count, (ulong)++index);
});
}
}
completedAction?.Invoke();
}
catch (Exception ex)
{
Utility.SendLog(logFlag, $"{ex.Message}");
}
Utility.SetProgressBarVisible(false);
Utility.SendLog(logFlag, "执行批量指令完毕", true);
}
#endregion
#region 执行命令实时返回结果
public static bool m_InRtm = false;
private static object m_LockRtm = new object();
/// <summary>
/// 执行命令实时返回结果
/// </summary>
/// <param name="server"></param>
/// <param name="command"></param>
public static void ExcuteCmdRtm(Server server, string command)
{
lock (m_LockRtm)
{
if (m_InRtm)
{
Utility.SendLog("执行脚本", $"正在执行其他命令,请等待");
return;
}
else
{
m_InRtm = true;
}
}
try
{
if (!Utility.Ping(server.Ip))
{
return;
}
using (var client = new SshClient(server.Ip, server.Port, "root", server.SuPassword))
{
client.Connect();
Utility.SendLog("登录", $"[{server.Ip}]成功");
using (var stream = client.CreateShellStream("anything", 80, 24, 800, 600, 4096))
{
byte[] buffer = new byte[1000];
stream.WriteLine("pwd");
stream.BeginRead(buffer, 0, buffer.Length, null, null);
bool end = false;
stream.DataReceived += new EventHandler<Renci.SshNet.Common.ShellDataEventArgs>(
(o, ex) =>
{
var str = stream.Read();
if (str.Contains("\u001b"))
{
foreach (System.Text.RegularExpressions.Match item in Utility.m_RegexUb.Matches(str))
{
str = str.Replace(item.Value, "");
}
}
str
.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
.ToList()
.ForEach(
s =>
{
if (!string.IsNullOrEmpty(s.Trim()))
Utility.SendLog("", s);
});
end = str.Trim().EndsWith($"eucloud']#");
}
);
command = $"{command};cd /home/{server.UserName};".Replace(";;", ";");
Utility.SendLog("执行脚本", $"{command}");
stream.WriteLine(command);
int timecout = 5 * 60;
while (!end)
{
System.Threading.Thread.Sleep(1000);
if (--timecout < 0)
break;
}
Utility.SendLog("执行脚本", $"[{server.Ip}]完毕");
}
}
}
catch (Exception ex)
{
Utility.SendLog("执行脚本", $"{ex}");
}
finally
{
lock (m_LockRtm)
{
m_InRtm = false;
}
}
}
/// <summary>
/// 是否繁忙
/// </summary>
/// <returns></returns>
public static bool InRtmNow()
{
return m_InRtm;
}
#endregion
}
}

@ -0,0 +1,610 @@
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Text.RegularExpressions;
using ProtoBuf;
namespace Tiobon.PublishHelper
{
/// <summary>
/// 辅助类
/// </summary>
public class Utility
{
#region 参数
/// <summary>
/// 停止发布
/// </summary>
public static bool m_StopPublish = false;
/// <summary>
/// 替换控制指令
/// </summary>
public static System.Text.RegularExpressions.Regex m_RegexUb = new System.Text.RegularExpressions.Regex(@"\u001b\[\d+[A-z]");
/// <summary>
/// 测试服务器
/// </summary>
public static string m_TestServerIp = "192.168.8.60";
#endregion
#region 事件
/// <summary>
/// 记录日志
/// </summary>
public static Action<string, string> SendLogHandle;
public static void SendLog(string msg, bool status = false)
{
SendLogHandle("", msg);
if (status)
{
SetStatus(msg);
}
lock (m_Logs)
m_Logs.Add(msg);
}
public static void SendLog(string oprate, string msg, bool status = false)
{
SendLogHandle(oprate, msg);
if (status)
{
SetStatus(msg);
}
lock (m_Logs)
{
if (string.IsNullOrEmpty(oprate))
m_Logs.Add($"{msg}");
else
m_Logs.Add($"[{oprate}] {msg}");
}
}
/// <summary>
/// 设置进度条显示/隐藏
/// </summary>
public static Action<bool> SetProgressBarVisible;
/// <summary>
/// 设置进度条状态
/// </summary>
public static Action<long, ulong> SetProgressBarValue;
/// <summary>
/// 设置当前状态
/// </summary>
public static Action<string> SetStatus;
#endregion
#region 初始化
public static void Init()
{
ReadDevServer();
ReadPublishServer();
ReadOprateLog();
Thread log = new Thread(WriteLogger);
log.Start();
}
#endregion
#region 服务器管理
/// <summary>
/// 开发服务器列表
/// </summary>
public static List<DevServer> m_DevServers = new List<DevServer>();
/// <summary>
/// 保存开发服务器配置
/// </summary>
public static void SaveDevServer()
{
try
{
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\DevServers.dat";
if (File.Exists(fname))
File.Delete(fname);
using (FileStream fs = new FileStream(fname, FileMode.Create))
{
Serializer.Serialize(fs, m_DevServers);
}
}
catch { }
}
/// <summary>
/// 读取开发服务器配置
/// </summary>
public static void ReadDevServer()
{
try
{
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\DevServers.dat";
if (File.Exists(fname))
using (FileStream fs = new FileStream(fname, FileMode.Open))
{
m_DevServers = Serializer.Deserialize<List<DevServer>>(fs);
}
}
catch { }
if (m_DevServers is null)
m_DevServers = new List<DevServer>();
m_DevServers.ForEach(s =>
{
if (s.Hospitals is null)
{
s.Hospitals = new List<Hospital>();
}
});
}
/// <summary>
/// 发布服务器列表
/// </summary>
public static List<PublishServer> m_PublishServers = new List<PublishServer>();
/// <summary>
/// 保存发布服务器配置
/// </summary>
public static void SavePublishServer()
{
try
{
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\PublishServers.dat";
if (File.Exists(fname))
File.Delete(fname);
using (FileStream fs = new FileStream(fname, FileMode.Create))
{
Serializer.Serialize(fs, m_DevServers);
}
}
catch { }
}
/// <summary>
/// 读取发布服务器配置
/// </summary>
public static void ReadPublishServer()
{
try
{
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\PublishServers.dat";
if (File.Exists(fname))
{
using (FileStream fs = new FileStream(fname, FileMode.Open))
{
m_PublishServers = Serializer.Deserialize<List<PublishServer>>(fs);
}
}
}
catch { }
if (m_PublishServers is null)
{
m_PublishServers = new List<PublishServer>();
}
m_PublishServers.ForEach(s =>
{
if (s.Folders is null)
s.Folders = new List<VersionFolder>();
s.Folders.ForEach(f =>
{
if (f.Files is null)
f.Files = new List<VersionFile>();
});
});
}
#endregion
#region 操作记录
/// <summary>
/// 操作记录
/// </summary>
public static OprateLog m_OprateLog = new OprateLog();
/// <summary>
/// 保存操作记录
/// </summary>
public static void SaveOprateLog()
{
try
{
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\OprateLog.dat";
if (File.Exists(fname))
File.Delete(fname);
using (FileStream fs = new FileStream(fname, FileMode.Create))
{
Serializer.Serialize(fs, m_OprateLog);
}
}
catch { }
}
/// <summary>
/// 读取操作记录
/// </summary>
public static void ReadOprateLog()
{
try
{
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\OprateLog.dat";
if (File.Exists(fname))
{
using (FileStream fs = new FileStream(fname, FileMode.Open))
{
m_OprateLog = Serializer.Deserialize<OprateLog>(fs);
}
}
}
catch { }
if (m_OprateLog is null)
{
m_OprateLog = new OprateLog();
}
}
#endregion
#region Ping测试
/// <summary>
/// Ping测试
/// </summary>
/// <param name="ip"></param>
/// <param name="b_log"></param>
/// <returns></returns>
public static bool Ping(string ip, bool b_log = true)
{
bool b_suc = false;
try
{
using (Ping ping = new Ping())
{
b_suc = ping.Send(ip, 2000).Status == IPStatus.Success;
}
}
catch
{
b_suc = false;
}
if (!b_suc && b_log)
{
SendLog(ip, "ping失败,不继续执行其他远程操作指令");
}
return b_suc;
}
#endregion
#region 获取临时文件名
/// <summary>
/// 获取临时文件名
/// </summary>
/// <param name="fname"></param>
/// <param name="random"></param>
/// <returns></returns>
public static string GetTempFileName(string fname, bool random = true)
{
return $"{System.Environment.GetEnvironmentVariable("TEMP")}\\{fname}" + (random ? $"_{DateTime.Now.Ticks}" : "");
}
#endregion
#region 获取服务器状态
/// <summary>
/// 获取服务器状态
/// </summary>
/// <param name="server"></param>
/// <returns></returns>
public static (bool Success, double Cpu, double MemTotal, double MemUsed, double Disk) GetServerStatus(Server server)
{
var res = (false, 0, 0, 0, 0);
try
{
var (Success, Result) = SshHelper.ExcuteCmd(server, "cpu=`top -b -n 1 | awk 'NR>7{sum+=$9} END {print sum}'`\n mem=`free -m | awk 'NR==2{print $2,$3}'` \n disk=`df -h | grep \"home\" |awk '{{print $5}}'` \n echo \"$cpu,$mem,$disk\"", false);
if (Success)
{
//87,7981 4369,96%
var empties = Result.Trim('\n').Trim().Split(new string[] { "%", ",", " " }, StringSplitOptions.RemoveEmptyEntries);
if (empties.Length == 4)
{
return (true, double.Parse(empties[0]), double.Parse(empties[1]), double.Parse(empties[2]), double.Parse(empties[3]));
}
}
}
catch
{ }
return res;
}
#endregion
#region 日志
/// <summary>
/// 停止记录日志
/// </summary>
public static bool m_LogRun = true;
private static List<string> m_Logs = new List<string>();
/// <summary>
/// 日志线程
/// </summary>
private static void WriteLogger()
{
var path = AppDomain.CurrentDomain.BaseDirectory + "Log\\";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string fname = string.Empty;
var logs = new List<string>();
while (m_LogRun)
{
try
{
lock (m_Logs)
{
if (m_Logs.Count > 0)
{
m_Logs.ForEach(s => logs.Add(s));
fname = path + DateTime.Now.ToString("yyyy_MM_dd") + ".txt";
m_Logs.Clear();
}
}
if (logs.Count > 0)
{
WriteLoggerToFile(fname, logs);
logs.Clear();
}
}
catch
{
// ignored
}
finally
{
System.Threading.Thread.Sleep(3000);
}
}
}
/// <summary>
/// 日志写入文件
/// </summary>
/// <param name="fname">文件名</param>
/// <param name="logs">日志</param>
private static void WriteLoggerToFile(string fname, List<string> logs)
{
StringBuilder sb = new StringBuilder();
logs.ForEach(s => sb.AppendLine(DateTime.Now.ToString("HH:mm:ss") + "\t" + s));
if (!File.Exists(fname))
{
using (StreamWriter sw = File.CreateText(fname))
{
sw.Write(sb.ToString());
}
}
else
{
using (StreamWriter sw = File.AppendText(fname))
{
sw.Write(sb.ToString());
}
}
}
#endregion
#region 发布与打包锁
/// <summary>
/// 查询锁定文件
/// </summary>
/// <param name="server"></param>
/// <param name="hospital"></param>
/// <param name="oprate"></param>
/// <returns></returns>
public static bool LockDevFiles(Server server, string oprate)
{
bool b_in = false;
string lfname = GetTempFileName("lockfile");
string rfname = $"/tmp/lockfile";
if (SftpHelper.DownloadFile(server, rfname, lfname))
{
if (File.Exists(lfname))
{
SendLog(File.ReadAllText(lfname, Encoding.UTF8));
b_in = true;
}
}
else
{
File.WriteAllText(lfname, $"当前服务器 {server.Ip} 繁忙。用户 [{Environment.MachineName}] 正在 {oprate},请等待 [{Environment.MachineName}] 操作完毕...", Encoding.UTF8);
SftpHelper.UploadFile(server, lfname, rfname);
}
return b_in;
}
/// <summary>
/// 删除锁定文件
/// </summary>
/// <param name="server"></param>
public static void RemoveDevFiles(Server server)
{
SftpHelper.Delete(server, $"/tmp/lockfile");
}
#endregion
#region HTTP模板
public static CookieContainer m_Cookies = new CookieContainer();
public enum Compression
{
GZip,
Deflate,
None,
}
/// <summary>
/// 获取HttpWebRequest模板
/// </summary>
/// <param name="url">URL地址</param>
/// <param name="postdata">POST</param>
/// <param name="cookies">Cookies</param>
/// <returns></returns>
public static HttpWebRequest GetHttpRequest(string url, string postdata, CookieContainer cookies, string header = null)
{
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.CookieContainer = cookies;
request.ContentType = !string.IsNullOrEmpty(header) ? "application/json" : "application/x-www-form-urlencoded";
request.ServicePoint.ConnectionLimit = 300;
ServicePointManager.Expect100Continue = false;
request.Referer = url;
request.Accept = "*/*";
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)";
request.AllowAutoRedirect = true;
if (!string.IsNullOrEmpty(header))
request.Headers.Add("Authorization", header);
if (postdata != null && postdata != "")
{
request.Method = "POST";
byte[] byte_post = Encoding.Default.GetBytes(postdata);
request.ContentLength = byte_post.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(byte_post, 0, byte_post.Length);
}
}
else
{
request.Method = "GET";
}
return request;
}
/// <summary>
/// 提取HttpWebResponse文本内容
/// </summary>
/// <param name="resp">HttpWebResponse响应包</param>
/// <returns></returns>
public static string GetResponseContent(HttpWebResponse resp)
{
if (resp.StatusCode != HttpStatusCode.OK)
throw new Exception("远程服务器返回状态码: " + resp.StatusCode);
Encoding enc = Encoding.UTF8;
if (resp.CharacterSet != null && resp.CharacterSet != "")
enc = Encoding.GetEncoding(resp.CharacterSet);
Compression comp = Compression.None;
if (resp.ContentEncoding != null && resp.ContentEncoding.Trim().ToUpper() == "GZIP")
comp = Compression.GZip;
else if (resp.ContentEncoding != null && resp.ContentEncoding.Trim().ToUpper() == "DEFLATE")
comp = Compression.Deflate;
MemoryStream ms = new MemoryStream();
using (StreamWriter sw = new StreamWriter(ms, enc))
{
StreamReader sr;
switch (comp)
{
case Compression.GZip:
sr = new StreamReader(new System.IO.Compression.GZipStream(resp.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress), enc);
break;
case Compression.Deflate:
sr = new StreamReader(new System.IO.Compression.DeflateStream(resp.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress), enc);
break;
default:
sr = new StreamReader(resp.GetResponseStream(), enc);
break;
}
while (!sr.EndOfStream)
{
char[] buf = new char[16000];
int read = sr.ReadBlock(buf, 0, 16000);
StringBuilder sb = new StringBuilder();
sb.Append(buf, 0, read);
sw.Write(buf, 0, read);
}
sr.Close();
}
byte[] mbuf = ms.GetBuffer();
string sbuf = enc.GetString(mbuf);
return sbuf;
}
/// <summary>
/// 获取HttpWebRequest返回值
/// </summary>
/// <param name="url">URL地址</param>
/// <param name="postdata">PostData</param>
/// <returns></returns>
public static string GetHttpResult(string url, string postdata, string header = null)
{
try
{
HttpWebRequest request = GetHttpRequest(url, postdata, m_Cookies, header);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
m_Cookies.Add(response.Cookies);
return GetResponseContent(response);
}
catch
{
//Utilities.sendLog("连接 " + url + " 失败" + ex.Message);
return "";
}
}
/// <summary>
/// 获取HttpWebRequest返回值
/// </summary>
/// <param name="url">URL地址</param>
/// <param name="postdata">PostData</param>
/// <returns></returns>
public static Stream GetHttpResponse(string url, string postdata)
{
try
{
HttpWebRequest request = GetHttpRequest(url, postdata, m_Cookies);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return response.GetResponseStream();
}
catch
{
//Utilities.sendLog("连接 " + url + " 失败" + ex.Message);
return null;
}
}
/// <summary>
/// 去除HTML标记
/// </summary>
/// <param name="NoHTML">包括HTML的源码 </param>
/// <returns>已经去除后的文字</returns>
public static string RemoveHTMLFlag(string input)
{
input = Regex.Replace(input, @"<script[^>]*?>.*?</script>", "", RegexOptions.IgnoreCase);
Regex regex = new Regex("<.+?>", RegexOptions.IgnoreCase);
input = regex.Replace(input, "");
input = Regex.Replace(input, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"([\r\n])[\s]+", "", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"-->", "", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"<!--.*", "", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(iexcl|#161);", "\xa1", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(cent|#162);", "\xa2", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(pound|#163);", "\xa3", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&(copy|#169);", "\xa9", RegexOptions.IgnoreCase);
input = Regex.Replace(input, @"&#(\d+);", "", RegexOptions.IgnoreCase);
input.Replace("<", "");
input.Replace(">", "");
input.Replace("\r\n", "");
return input;
}
#endregion
}
}

@ -0,0 +1,56 @@
using ICSharpCode.SharpZipLib.Zip;
using System;
namespace Tiobon.PublishHelper
{
/// <summary>
/// 压缩文件帮助类
/// </summary>
public static class ZipHelper
{
/// <summary>
/// zip压缩文件
/// </summary>
/// <param name="fname">filename生成的文件的名称,如:C\123\123.zip</param>
/// <param name="path">directory要压缩的文件夹路径</param>
/// <returns></returns>
public static void ZipFiles(string fname, string path)
{
try
{
FastZip fz = new FastZip
{
CreateEmptyDirectories = true
};
fz.CreateZip(fname, path, true, "");
}
catch (Exception ex)
{
Utility.SendLog("压缩", $"压缩文件失败:{ex}");
}
}
/// <summary>
/// 添加压缩文件注释
/// </summary>
/// <param name="fname"></param>
/// <param name="comment"></param>
public static void SetComment(string fname, string comment)
{
try
{
using (ZipFile entry = new ZipFile(fname))
{
entry.BeginUpdate();
entry.SetComment(comment);
entry.CommitUpdate();
Utility.SendLog("压缩", $"添加注释成功 {fname}");
}
}
catch (Exception ex)
{
Utility.SendLog("压缩", $"添加注释失败:{ex}");
}
}
}
}

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentFTP" Version="50.0.1" />
<PackageReference Include="ICSharpCode.SharpZipLib.dll" Version="0.85.4.369" />
<PackageReference Include="protobuf-net" Version="3.2.30" />
<PackageReference Include="SSH.NET" Version="2024.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Frm\Form_DevServer.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="Frm\Form_DevServer_Item.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="Frm\Form_Hospital.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="Frm\Form_Hospital_Item.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>
Loading…
Cancel
Save