Commit 78de907a 几米阳光

增加压紧轴计量检测功能

1 个父辈 27e78cae
......@@ -35,6 +35,8 @@
<add key ="Config_Pwd" value ="123456"/>
<!--出库等待料盘拿走的时间,秒-->
<add key ="OutStoreWaitSeconds" value ="600"/>
<!--压紧轴对应1mm的脉冲-->
<add key="ComAxisChangeValue" value="800" />
</appSettings>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
......
......@@ -48,7 +48,7 @@ namespace OnlineStore.ACSingleStore
txtMiddleSpeed.Text = (middle.TargetSpeed / 5).ToString();
txtInOutSpeed.Text = (inout.TargetSpeed / 5).ToString();
txtUpDownSpeed.Text = (updown.TargetSpeed / 5).ToString();
txtComSpeed.Text = (ACStoreManager.store.Config.CompressAxis_EndSpeed/5).ToString();
txtComSpeed.Text = (StoreManager.Config.CompressAxis_EndSpeed/5).ToString();
timer1.Start();
}
/// <summary>
......@@ -132,7 +132,7 @@ namespace OnlineStore.ACSingleStore
{
if (this.btnInOutMove.BackColor .Equals(System.Drawing.SystemColors.Control))
{
if (ACStoreManager.store.InOutAxisCanMove().Equals(false))
if (StoreManager.Store.InOutAxisCanMove().Equals(false))
{
MessageBox.Show("定位气缸不在下降端,不能移动进出轴", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
......@@ -219,7 +219,7 @@ namespace OnlineStore.ACSingleStore
{
if (btnInOutMovej.BackColor.Equals(System.Drawing.SystemColors.Control))
{
if (ACStoreManager.store.InOutAxisCanMove().Equals(false))
if (StoreManager.Store.InOutAxisCanMove().Equals(false))
{
MessageBox.Show("定位气缸不在下降端,不能移动进出轴", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
......
namespace OnlineStore.ACSingleStore
{
partial class FrmCamera
{
/// <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.timer1 = new System.Windows.Forms.Timer(this.components);
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
this.btnCloseCamera = new System.Windows.Forms.Button();
this.btnGetImage = new System.Windows.Forms.Button();
this.btnOpen = new System.Windows.Forms.Button();
this.hWindowControl1 = new HalconDotNet.HWindowControl();
this.btnExit = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// timer1
//
this.timer1.Interval = 5000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// richTextBox1
//
this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.richTextBox1.Location = new System.Drawing.Point(496, 216);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.Size = new System.Drawing.Size(165, 167);
this.richTextBox1.TabIndex = 4;
this.richTextBox1.Text = "";
//
// btnCloseCamera
//
this.btnCloseCamera.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnCloseCamera.Location = new System.Drawing.Point(523, 90);
this.btnCloseCamera.Name = "btnCloseCamera";
this.btnCloseCamera.Size = new System.Drawing.Size(135, 35);
this.btnCloseCamera.TabIndex = 3;
this.btnCloseCamera.Text = "关闭 ";
this.btnCloseCamera.UseVisualStyleBackColor = true;
this.btnCloseCamera.Click += new System.EventHandler(this.btnCloseCamera_Click);
//
// btnGetImage
//
this.btnGetImage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnGetImage.Location = new System.Drawing.Point(523, 51);
this.btnGetImage.Name = "btnGetImage";
this.btnGetImage.Size = new System.Drawing.Size(135, 35);
this.btnGetImage.TabIndex = 2;
this.btnGetImage.Text = "扫码测试";
this.btnGetImage.UseVisualStyleBackColor = true;
this.btnGetImage.Click += new System.EventHandler(this.btnGetImage_Click);
//
// btnOpen
//
this.btnOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnOpen.Location = new System.Drawing.Point(523, 12);
this.btnOpen.Name = "btnOpen";
this.btnOpen.Size = new System.Drawing.Size(135, 35);
this.btnOpen.TabIndex = 1;
this.btnOpen.Text = "打开 ";
this.btnOpen.UseVisualStyleBackColor = true;
this.btnOpen.Click += new System.EventHandler(this.btnOpen_Click);
//
// hWindowControl1
//
this.hWindowControl1.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.hWindowControl1.BackColor = System.Drawing.Color.Black;
this.hWindowControl1.BorderColor = System.Drawing.Color.Black;
this.hWindowControl1.ImagePart = new System.Drawing.Rectangle(0, 0, 640, 480);
this.hWindowControl1.Location = new System.Drawing.Point(12, 12);
this.hWindowControl1.Name = "hWindowControl1";
this.hWindowControl1.Size = new System.Drawing.Size(478, 371);
this.hWindowControl1.TabIndex = 5;
this.hWindowControl1.WindowSize = new System.Drawing.Size(478, 371);
//
// btnExit
//
this.btnExit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnExit.Location = new System.Drawing.Point(523, 168);
this.btnExit.Name = "btnExit";
this.btnExit.Size = new System.Drawing.Size(135, 35);
this.btnExit.TabIndex = 6;
this.btnExit.Text = "返回(&B)";
this.btnExit.UseVisualStyleBackColor = true;
this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
//
// FrmCamera
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.ClientSize = new System.Drawing.Size(670, 395);
this.Controls.Add(this.btnExit);
this.Controls.Add(this.hWindowControl1);
this.Controls.Add(this.richTextBox1);
this.Controls.Add(this.btnCloseCamera);
this.Controls.Add(this.btnGetImage);
this.Controls.Add(this.btnOpen);
this.Name = "FrmCamera";
this.Text = "二维码识别测试";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FrmCamera_FormClosed);
this.Load += new System.EventHandler(this.FrmCamera_Load);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button btnOpen;
private System.Windows.Forms.Button btnGetImage;
private System.Windows.Forms.Button btnCloseCamera;
private System.Windows.Forms.RichTextBox richTextBox1;
private System.Windows.Forms.Timer timer1;
private HalconDotNet.HWindowControl hWindowControl1;
private System.Windows.Forms.Button btnExit;
}
}
\ No newline at end of file

using HalconDotNet;
using OnlineStore.Common;
using OnlineStore.DeviceLibrary;
using OnlineStore.LoadCSVLibrary;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace OnlineStore.ACSingleStore
{
public partial class FrmCamera : FrmBase
{
private AC_SA_BoxBean store = null;
public FrmCamera(AC_SA_BoxBean store)
{
this.store = store;
InitializeComponent();
}
private void btnOpen_Click(object sender, EventArgs e)
{
HDevelopExport.CloseAllCamera();
store.KNDIOMove(IO_Type.CameraLight_Power, IO_VALUE.HIGH);
HDevelopExport.OpenAllCamera();
FormStatus(true);
}
private void FormStatus(bool open)
{
btnOpen.Enabled = !open;
btnCloseCamera.Enabled = open;
btnGetImage.Enabled = open;
timer1.Enabled = open;
}
private void btnGetImage_Click(object sender, EventArgs e)
{
List<string> allCodeList = new List<string>();
foreach (string cameraName in HDevelopExport.cameraNameList)
{
HObject ho_Image = HDevelopExport.GrabImage(cameraName);
List<string> codeList = HDevelopExport.GetCode(ho_Image);
allCodeList.AddRange(codeList);
}
if (allCodeList != null)
{
this.richTextBox1.Clear();
foreach (string str in allCodeList)
{
this.richTextBox1.AppendText(str);
}
}
}
private void btnCloseCamera_Click(object sender, EventArgs e)
{
store.KNDIOMove(IO_Type.CameraLight_Power, IO_VALUE.LOW);
HDevelopExport.CloseAllCamera();
FormStatus(false);
}
private void FrmCamera_Load(object sender, EventArgs e)
{
FormStatus(false);
}
private void FrmCamera_FormClosed(object sender, FormClosedEventArgs e)
{
if (btnCloseCamera.Enabled.Equals(true))
{
store.KNDIOMove(IO_Type.CameraLight_Power, IO_VALUE.LOW);
HDevelopExport.CloseAllCamera();
FormStatus(false);
}
}
private int preIndex = 0;
int dWidth = 0; int dHeight = 0;
private void timer1_Tick(object sender, EventArgs e)
{
preIndex++;
HObject ho_Image = null;
int index = preIndex % HDevelopExport.cameraNameList.Count;
ho_Image = HDevelopExport.GrabImage(HDevelopExport.cameraNameList[index]);
if (ho_Image != null)
{
if (dWidth <= 0)
{
HTuple width, height;
//int dWidth = 0; int dHeight = 0;
HOperatorSet.GetImageSize(ho_Image, out width, out height);
dWidth = (int)width.D;
dHeight = (int)height.D;
hWindowControl1.HalconWindow.SetPart(0, 0, dHeight, dWidth);
}
HOperatorSet.DispObj(ho_Image, hWindowControl1.HalconWindow);
List<string> codeList = HDevelopExport.GetCode(ho_Image);
if (codeList != null)
{
this.richTextBox1.Clear();
this.richTextBox1.AppendText(DateTime.Now.ToString()+ "读到二维码:" + "\r\n");
LogUtil.info("读取到的二维码列表" + "\r\n");
foreach (string str in codeList)
{
this.richTextBox1.AppendText(str + "\r\n");
LogUtil.info(str + "\r\n");
}
}
}
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
<?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="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>
\ No newline at end of file
namespace OnlineStore.ACSingleStore
{
partial class FrmLogin
{
/// <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(FrmLogin));
this.panel1 = new System.Windows.Forms.Panel();
this.txtPwd = new System.Windows.Forms.TextBox();
this.txtUserName = new System.Windows.Forms.TextBox();
this.btnCancel = new System.Windows.Forms.Button();
this.btnLogin = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.Anchor = System.Windows.Forms.AnchorStyles.None;
this.panel1.Controls.Add(this.txtPwd);
this.panel1.Controls.Add(this.txtUserName);
this.panel1.Controls.Add(this.btnCancel);
this.panel1.Controls.Add(this.btnLogin);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.label1);
this.panel1.Location = new System.Drawing.Point(229, 88);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(330, 230);
this.panel1.TabIndex = 0;
//
// txtPwd
//
this.txtPwd.Anchor = System.Windows.Forms.AnchorStyles.None;
this.txtPwd.Location = new System.Drawing.Point(145, 78);
this.txtPwd.MaxLength = 100;
this.txtPwd.Name = "txtPwd";
this.txtPwd.PasswordChar = '*';
this.txtPwd.Size = new System.Drawing.Size(100, 26);
this.txtPwd.TabIndex = 5;
//
// txtUserName
//
this.txtUserName.Anchor = System.Windows.Forms.AnchorStyles.None;
this.txtUserName.Location = new System.Drawing.Point(145, 32);
this.txtUserName.MaxLength = 100;
this.txtUserName.Name = "txtUserName";
this.txtUserName.Size = new System.Drawing.Size(100, 26);
this.txtUserName.TabIndex = 4;
//
// btnCancel
//
this.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.None;
this.btnCancel.Location = new System.Drawing.Point(170, 148);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(84, 33);
this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "取消(&C)";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnLogin
//
this.btnLogin.Anchor = System.Windows.Forms.AnchorStyles.None;
this.btnLogin.Location = new System.Drawing.Point(72, 148);
this.btnLogin.Name = "btnLogin";
this.btnLogin.Size = new System.Drawing.Size(84, 33);
this.btnLogin.TabIndex = 2;
this.btnLogin.Text = "登录(&L)";
this.btnLogin.UseVisualStyleBackColor = true;
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
//
// label2
//
this.label2.Anchor = System.Windows.Forms.AnchorStyles.None;
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(84, 78);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(51, 20);
this.label2.TabIndex = 1;
this.label2.Text = "密码:";
//
// label1
//
this.label1.Anchor = System.Windows.Forms.AnchorStyles.None;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(72, 41);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(65, 20);
this.label1.TabIndex = 0;
this.label1.Text = "用户名:";
//
// FrmLogin
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(793, 397);
this.Controls.Add(this.panel1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FrmLogin";
this.Text = "FrmLogin";
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
this.Load += new System.EventHandler(this.FrmLogin_Load);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.TextBox txtPwd;
private System.Windows.Forms.TextBox txtUserName;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnLogin;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
}
}
\ No newline at end of file
using OnlineStore.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace OnlineStore.ACSingleStore
{
public partial class FrmLogin : FrmBase
{
private string UserName = "admin".ToUpper();
private string UserPwd = "123456".ToUpper();
public FrmLogin()
{
string aa = ConfigAppSettings.GetValue(Setting_Init.UserName);
string ww = ConfigAppSettings.GetValue(Setting_Init.UserPwd);
if (!aa.Equals(""))
{
UserName = aa.ToUpper();
}
if (!ww.Equals(""))
{
UserPwd = ww;
}
InitializeComponent();
}
private void btnLogin_Click(object sender, EventArgs e)
{
string userName = txtUserName.Text.Trim();
string pwd = txtPwd.Text.Trim();
if (userName.ToUpper().Equals(UserName) && UserPwd.Equals(pwd))
{
FrmStoreBox lineStore = new FrmStoreBox();
this.Hide();
lineStore.ShowDialog();
this.Close();
}
else
{
if (!(userName.ToUpper().Equals(UserName)))
{
MessageBox.Show("请输入正确的用户名!");
txtUserName.Text = "";
txtUserName.Focus();
}
else
{
MessageBox.Show("请输入正确的密码!");
txtPwd.Focus();
txtPwd.Text = "";
}
}
}
private void FrmLogin_Load(object sender, EventArgs e)
{
this.AcceptButton = btnLogin;
string title = OnlineStore.Common.ConfigAppSettings.GetValue(Setting_Init.App_Title);
this.Text = title;
txtUserName.Focus();
int sizeH = this.Size.Height;
int sizeW = this.Size.Width;
int locationH=((sizeH-panel1.Size.Height)/2);
int locationW = (sizeH - panel1.Size.Width) / 2;
panel1.Size = new Size(locationW, locationH);
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
......@@ -75,5 +75,9 @@ namespace OnlineStore.Common
/// 出库等待料盘拿走的时间,秒
/// </summary>
public static string OutStoreWaitSeconds = "OutStoreWaitSeconds";
/// <summary>
/// 压紧轴1mm对应的脉冲
/// </summary>
public static string ComAxisChangeValue = "ComAxisChangeValue";
}
}
......@@ -58,7 +58,7 @@
<ItemGroup>
<Compile Include="acSingleStore\AC_SA_BoxBean.cs" />
<Compile Include="acSingleStore\AC_SA_BoxBean_Partial.cs" />
<Compile Include="acSingleStore\ACStoreManager.cs" />
<Compile Include="acSingleStore\StoreManager.cs" />
<Compile Include="halcon\CodeManager.cs" />
<Compile Include="KangNaiDe\AITcpClient.cs" />
<Compile Include="KangNaiDe\KNDAIManager.cs" />
......@@ -67,14 +67,12 @@
<Compile Include="PanasonicServo\ACCMDManager.cs" />
<Compile Include="PanasonicServo\ACServerManager.cs" />
<Compile Include="PanasonicServo\ACServerManager_Partial.cs" />
<Compile Include="ShuoKe\MeteringSignalBean.cs" />
<Compile Include="ShuoKe\ShuoKeController.cs" />
<Compile Include="store\LineMoveP.cs" />
<Compile Include="store\LineAlarm.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="store\IOUtil.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="store\model\AxisAlarmInfo.cs" />
<Compile Include="store\model\FixtureCodeInfo.cs" />
......@@ -87,7 +85,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="store\KTK_Store.cs" />
<Compile Include="store\StoreManager.cs">
<Compile Include="store\StoreStep.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
......
......@@ -9,6 +9,7 @@ using System.Diagnostics;
using log4net;
using System.Reflection;
using OnlineStore.Common;
using OnlineStore.LoadCSVLibrary;
namespace OnlineStore.DeviceLibrary
{
......
using OnlineStore.Common;
using OnlineStore.LoadCSVLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
namespace OnlineStore.DeviceLibrary
{
/// <summary>
/// 压紧机构计量检测信号处理
/// </summary>
public class MeteringSignal
{
public static int ComAxisChangeValue = ConfigAppSettings.GetIntValue(Setting_Init.ComAxisChangeValue);
/// <summary>
/// 信号变化次数
/// </summary>
public static int SignalChangeCount=0;
public static int TragetChangeCount = 1;
public static IO_VALUE PreSignalValue = IO_VALUE.LOW;
private static System.Timers.Timer timer = null;
public static void StartCheck(int targetPositon,int currPosition)
{
int count = Math.Abs(targetPositon - currPosition)/ComAxisChangeValue;
StartCheck(count);
}
private static void StartCheck(int targetCount)
{
TragetChangeCount = targetCount;
if (timer == null)
{
timer = new System.Timers.Timer();
timer.Interval = 50;
timer.AutoReset = true;
timer.Elapsed += Timer_Elapsed;
timer.Enabled = false;
}
LogUtil.info("开始压紧轴计量检测,预计变化" + TragetChangeCount + "次");
IsInProcess = false;
PreSignalValue = IO_VALUE.LOW;
SignalChangeCount = 0;
}
public static void StopCheck()
{
timer.Stop();
}
private static bool IsInProcess = false;
protected static void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (IsInProcess) { return; }
IsInProcess = true;
IO_VALUE value = StoreManager.Store.KNDIOValue(IO_Type.CompressAxis_Check);
if (value.Equals(IO_VALUE.HIGH) && PreSignalValue.Equals(IO_VALUE.LOW))
{
SignalChangeCount++;
LogUtil.info("检测到信号变化,已经变化" + SignalChangeCount + "次");
}
PreSignalValue = value;
if (TragetChangeCount <= SignalChangeCount)
{
timer.Stop();
}
IsInProcess = false;
}
}
}
......@@ -282,26 +282,29 @@ namespace OnlineStore.DeviceLibrary
#region 逻辑判断
public static bool IsMoveEnd(int slvAddr, int targetPosition,DateTime time, out ShuoKeInfo shuokeInfo)
public static bool IsMoveEnd(int slvAddr, int targetPosition, DateTime time, out string msg)
{
shuokeInfo = GetStatus(slvAddr);
ShuoKeInfo shuokeInfo = GetStatus(slvAddr);
msg = " IsInMove【" + shuokeInfo.IsInMove + "】 ";
if (shuokeInfo.IsInMove == 0 && shuokeInfo.UpdateTime > time)
{
int position = GetABSPosition(slvAddr);
msg += "位置【" + position + "】";
if (Math.Abs(position - targetPosition) < 10)
{
return true;
}
else
{
LogUtil.info("【" + PortName + "】 目标位置【"+targetPosition+"】当前位置【"+position+"】,已经不再运动中");
LogUtil.info("【" + PortName + "】 目标位置【" + targetPosition + "】当前位置【" + position + "】,已经不再运动中");
}
}
return false;
}
public static bool IsHomeMoveEnd(int slvAddr, DateTime time, out ShuoKeInfo shuokeInfo)
public static bool IsHomeMoveEnd(int slvAddr, DateTime time, out string msg)
{
shuokeInfo = GetStatus(slvAddr);
ShuoKeInfo shuokeInfo = GetStatus(slvAddr);
msg = " IsInMove【" + shuokeInfo.IsInMove + "】Org【" + shuokeInfo.Org + "】";
if (shuokeInfo.IsInMove == 0 && shuokeInfo.UpdateTime > time && shuokeInfo.Org == 0)
{
return true;
......
类型,说明,名称,属性值,设备名称,默认值,描述,电器定义,代码定义,SlaveID,
DI,急停,SuddenStop_BTN,200,192.168.200.10,0,急停,X01,DI-01,0,
DI,复位,Reset_BTN,201,192.168.200.10,0,复位,X02,DI-02,0,
DI,自动,AutoRun_Single,202,192.168.200.10,0,自动,X03,DI-03,0,
DI,自动,AutoRun_Signal,202,192.168.200.10,0,自动,X03,DI-03,0,
DI,气压检测,Airpressure_Check,203,192.168.200.10,0,气压检测,X04,DI-04,0,
DI,料盘检测1(进料口),TrayCheck_Door,204,192.168.200.10,0,料盘检测1(进料口),X05,DI-05,0,
DI,料盘检测2(料叉),TrayCheck_Fixture,205,192.168.200.10,0,料盘检测2(料叉),X06,DI-06,0,
......@@ -19,7 +19,7 @@ DO,自动指示灯,AutoRun_HddLed,100,192.168.200.10,0,自动指示灯,Y01,DO-01,0,
DO,故障指示灯,Alarm_HddLed,101,192.168.200.10,0,故障指示灯,Y02,DO-02,0,
DO,待机指示灯,RunSign_HddLed,102,192.168.200.10,0,待机指示灯,Y03,DO-03,0,
DO,吹气SOL ON,StartOrStopBlow,103,192.168.200.10,0,吹气SOL ON,Y04,DO-04,0,
DO,料仓运转ON,Run_Sign,104,192.168.200.10,0,料仓运转ON,Y05,DO-05,0,
DO,料仓运转ON,Run_Signal,104,192.168.200.10,0,料仓运转ON,Y05,DO-05,0,
DO,轴2刹车电源ON,Axis_Brake,105,192.168.200.10,0,轴2刹车电源ON,Y06,DO-06,0,
DO,进料口门上升SOL,Door_Up,106,192.168.200.10,0,进料口门上升SOL,Y07,DO-07,0,
DO,进料口门下降SOL,Door_Down,107,192.168.200.10,0,进料口门下降SOL,Y08,DO-08,0,
......
......@@ -161,7 +161,7 @@ namespace OnlineStore.DeviceLibrary
if (IsHasCompress_Axis)
{
if (ShuoKeControls.isRun == false && (!ACStoreManager.OpenShuoKe(this)))
if (ShuoKeControls.isRun == false && (!StoreManager.OpenShuoKe(this)))
{
LogUtil.info(StoreName + "打开驱动器串口失败,启动失败!");
return false;
......@@ -459,6 +459,7 @@ namespace OnlineStore.DeviceLibrary
if (IsHasCompress_Axis)
{
LogUtil.debug("压紧轴绝对运动目标位置:"+targetPosition);
MeteringSignal.StartCheck(targetPosition, ShuoKeControls.GetABSPosition(Config.CompressAxis_Slv));
StoreMove.WaitList.Add(WaitResultInfo.WaitShuoKe(Config.CompressAxis_Slv, targetPosition, false));
ShuoKeControls.AbsMove(Config.CompressAxis_Slv, targetPosition);
Thread.Sleep(100);
......@@ -555,7 +556,7 @@ namespace OnlineStore.DeviceLibrary
public bool RunAxis(bool isCheck)
{
KNDIOMove(IO_Type.Run_Sign, IO_VALUE.HIGH);
KNDIOMove(IO_Type.Run_Signal, IO_VALUE.HIGH);
Thread.Sleep(1000);
//打开所有轴
foreach (ConfigMoveAxis moveAxis in moveAxisList)
......@@ -638,7 +639,7 @@ namespace OnlineStore.DeviceLibrary
ACServerManager.ColsePort(axis.DeviceName);
}
Thread.Sleep(100);
KNDIOMove(IO_Type.Run_Sign, IO_VALUE.LOW);
KNDIOMove(IO_Type.Run_Signal, IO_VALUE.LOW);
}
private int GetAlarmCodeByAxis(ConfigMoveAxis axis)
......@@ -685,7 +686,6 @@ namespace OnlineStore.DeviceLibrary
{
ShuoKeControls.ClosePort();
}
HumitureServer.StopTemperateServer();
LogUtil.info(LOGGER, StoreName + ",停止运行,总运行时间:" + span.ToString());
}
......@@ -933,7 +933,7 @@ namespace OnlineStore.DeviceLibrary
if (storeRunStatus.Equals(StoreRunStatus.Wait))
{
//取新的Io状态
IO_VALUE autoSingle = KNDIOValue(IO_Type.AutoRun_Single);
IO_VALUE autoSingle = KNDIOValue(IO_Type.AutoRun_Signal);
if (ConfigAppSettings.GetIntValue(Setting_Init.App_AutoRun) .Equals( 1))
{
if (autoSingle.Equals(IO_VALUE.HIGH) && lastAutoRun.Equals(IO_VALUE.LOW))
......@@ -1080,12 +1080,12 @@ namespace OnlineStore.DeviceLibrary
else if (storeRunStatus.Equals(StoreRunStatus.Runing))
{
//判断是否需要出入库
if (StoreMove.MoveType.Equals(StoreMoveType.None)&&alarmType.Equals(StoreAlarmType.None))
if (StoreMove.MoveType.Equals(StoreMoveType.None) && alarmType.Equals(StoreAlarmType.None))
{
IO_VALUE checkIO = KNDIOValue(IO_Type.TrayCheck_Door);
//判断料门口是否有料
if ((checkIO.Equals(IO_VALUE.HIGH))&&GetHeight()>0)
if ((checkIO.Equals(IO_VALUE.HIGH)) && GetHeight() > 0 && KNDIOValue(IO_Type.TrayCheck_Fixture).Equals(IO_VALUE.LOW))
{
if (IsScanCode)
{
......@@ -1102,7 +1102,7 @@ namespace OnlineStore.DeviceLibrary
//BeginScannering();
//判断料盘尺寸
if (GetSize()<=7)
if (GetSize() <= 7)
{
LogUtil.info(StoreName + "检测到寸料盘,开始扫码");
GetCameraCode();
......@@ -1110,7 +1110,7 @@ namespace OnlineStore.DeviceLibrary
else
{
LogUtil.info(StoreName + "检测到大于7寸的料盘,请放入正确的料盘");
IsScanCode = false ;
IsScanCode = false;
}
}
}
......@@ -1537,14 +1537,6 @@ namespace OnlineStore.DeviceLibrary
public int GetSize()
{
return 7;
//double ai1Value = KNDAIManager.ConvertAI(KNDAIManager.GetAIValue(Config.AIDevice_IP, 1), Config.AIDI1_DefaultPosition);
//double ai2Value = KNDAIManager.ConvertAI(KNDAIManager.GetAIValue(Config.AIDevice_IP, 2), Config.AIDI2_DefaultPosition);
//double ai3Value = KNDAIManager.ConvertAI(KNDAIManager.GetAIValue(Config.AIDevice_IP, 3), Config.AIDI3_DefaultPosition);
//if (ai1Value > 14 && ai2Value > 14 && ai3Value > 14)
//{
// return 13;
//}
//return 7;
}
public int GetHeight()
{
......@@ -1716,7 +1708,7 @@ namespace OnlineStore.DeviceLibrary
//HumitureServer.RandomData(Config.GetTempAddrList());
isInProcess = true;
if (ACStoreManager.IsConnectServer)
if (StoreManager.IsConnectServer)
{
try
{
......
......@@ -163,37 +163,20 @@ namespace OnlineStore.DeviceLibrary
else if (wait.WaitType == 3)
{
wait.IsEnd = (span.TotalMilliseconds >= wait.TimeMSeconds);
}else if (wait.WaitType == 7)
}
else if (wait.WaitType == 7)
{
wait.IsEnd = (wait.HeightValue.Equals(GetHeight()));
if (wait.IsEnd)
{
LogUtil.info("等待height="+ wait.HeightValue+"完成");
LogUtil.info("等待height=" + wait.HeightValue + "完成");
}
}
else if (wait.WaitType == 5)
{
ShuoKeInfo info = null;
if (wait.IsHomeMove)
{
wait.IsEnd = ShuoKeControls.IsHomeMoveEnd(wait.SlvAddr, StoreMove.LastSetpTime,out info);
}
else
{
wait.IsEnd = ShuoKeControls.IsMoveEnd(wait.SlvAddr,wait.TargetPosition, StoreMove.LastSetpTime, out info);
}
if (!wait.IsEnd)
{
if (info == null) {
NotOkMsg += "info=null;";
} else
{
NotOkMsg += "" +info.ToShowStr();
}
//ShuoKeControls.GetStatus(wait.SlvAddr);
}
string msg = "";
wait.IsEnd = ShuoKeIsEnd(wait, out msg);
NotOkMsg = NotOkMsg +" "+ msg;
}
if (wait.IsEnd)
{
......@@ -218,24 +201,42 @@ namespace OnlineStore.DeviceLibrary
}
else if (span.TotalSeconds > StoreMove.TimeOutSeconds)
{
if (NotOkMsg.Equals(""))
WarnMsg = StoreName + "【" + StoreMove.MoveType + "】【" + StoreMove.MoveStep + "】等待超时 [" + NotOkMsg
+ "]已等待[" + Math.Round(span.TotalSeconds, 1) + "]秒";
LogUtil.error(LOGGER, WarnMsg);
Alarm(StoreAlarmType.IoSingleTimeOut, "", WarnMsg, StoreMove.MoveType);
}
}
private bool ShuoKeIsEnd(WaitResultInfo wait, out string msg)
{
WarnMsg = StoreName + "等待超时【" + StoreMove.MoveType + "】【" + StoreMove.MoveStep + "】已等待【" + Math.Round(span.TotalSeconds) + "】秒";
foreach (WaitResultInfo wait in list)
bool result = false;
msg = "";
if (wait.IsHomeMove)
{
WarnMsg = WarnMsg + "\r\n" + wait.ToStr();
result = ShuoKeControls.IsHomeMoveEnd(wait.SlvAddr, StoreMove.LastSetpTime, out msg);
}
LogUtil.error(LOGGER, WarnMsg, 12);
else
{
bool isend = ShuoKeControls.IsMoveEnd(wait.SlvAddr, wait.TargetPosition, StoreMove.LastSetpTime, out msg);
if (isend)
{
bool isCheckOk = (MeteringSignal.TragetChangeCount <= MeteringSignal.SignalChangeCount);
if (isCheckOk)
{
MeteringSignal.StopCheck();
return true;
}
else
{
WarnMsg = StoreName + "【" + StoreMove.MoveType + "】【" + StoreMove.MoveStep + "】等待超时 [" + NotOkMsg
+ "]已等待[" + Math.Round(span.TotalSeconds, 1) + "]秒";
LogUtil.error(LOGGER, WarnMsg);
msg = "压紧轴计量检测目标【" + MeteringSignal.SignalChangeCount + "】实际【" + MeteringSignal.TragetChangeCount + "】";
LogUtil.error("压紧轴已经停止运动,但是 " + msg);
}
Alarm(StoreAlarmType.IoSingleTimeOut, "", WarnMsg, StoreMove.MoveType);
}
}
return false;
}
#endregion
......@@ -743,7 +744,7 @@ namespace OnlineStore.DeviceLibrary
}
public bool InOutAxisCanMove()
{
if (ACStoreManager.store.Config.IsHasLocationCylinder.Equals(0))
if (StoreManager.Store.Config.IsHasLocationCylinder.Equals(0))
{
return true;
}
......
......@@ -11,13 +11,22 @@ using System.Windows.Forms;
namespace OnlineStore.DeviceLibrary
{
public class ACStoreManager
public class StoreManager
{
/// <summary>
/// 当前出入库的模式
/// </summary>
public static int CurrInOutType = 0;
private static string api_communication = "service/store/communication"; //流水线状态通信接口
private static string api_nextFeeder = "service/store/nextFeeder"; // 出库站位列表切换接口
public static readonly ILog LOGGER = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static AC_SA_BoxBean store = null;
public static AC_SA_BoxBean Store = null;
public static AC_SA_Config Config = null;
private static bool isInit = false;
public static bool IsConnectServer=!ConfigAppSettings.GetValue(Setting_Init.http_server).Equals("");
public ACStoreManager()
public static bool IsConnectServer = !ConfigAppSettings.GetValue(Setting_Init.http_server).Equals("");
public StoreManager()
{
}
public static bool OpenShuoKe(AC_SA_BoxBean box)
......@@ -34,7 +43,7 @@ namespace OnlineStore.DeviceLibrary
}
else
{
LogUtil.error(LOGGER, box.StoreName + "打开硕科步进控制器【" + box.Config.CompressAxis_PortName + "】失败,启动失败!");
LogUtil.error(box.StoreName + "打开硕科步进控制器【" + box.Config.CompressAxis_PortName + "】失败,启动失败!");
return false;
}
}
......@@ -91,11 +100,11 @@ namespace OnlineStore.DeviceLibrary
LogUtil.info(LOGGER, "加载位置文件:" + positionConfigFile);
CSVPositionReader<ACStorePosition>.ReloadCSVFile(positionConfigFile);
}
AC_SA_BoxBean storeBean = new AC_SA_BoxBean((AC_SA_Config)storeConfig);
storeBean.CID = CID;
Config = (AC_SA_Config)storeConfig;
Store = new AC_SA_BoxBean(Config);
Store.CID = CID;
LogUtil.info(LOGGER, "加载料仓完成!");
store = storeBean;
return store;
return Store;
}
}
}
......@@ -105,7 +114,7 @@ namespace OnlineStore.DeviceLibrary
MessageBox.Show(ex.ToString(), "加载配置错误(请检查配置)");
Application.Exit();
}
return store;
return Store;
}
/// <summary>
/// 修改了料仓配置,更新缓存,更新配置文件(只能更新PRO的配置)
......@@ -124,14 +133,45 @@ namespace OnlineStore.DeviceLibrary
{
LOGGER.Error("保存配置文件失败:" + configFile);
}
store.Config = storeConfig;
store.MoveAxisConfig();
Store.Config = storeConfig;
Store.MoveAxisConfig();
}
catch (Exception ex)
{
LOGGER.Error("出错:", ex);
}
}
public static string GetPostApi(string host)
{
if (host == "")
{
host = ConfigAppSettings.GetValue(Setting_Init.http_server);
}
if (!host.StartsWith("http://"))
{
host = "http://" + host;
}
if (!host.EndsWith("/"))
{
host = host + "/";
}
return host + api_communication;
}
public static string GetNextFeederApi(string host)
{
if (host == "")
{
host = ConfigAppSettings.GetValue(Setting_Init.http_server);
}
if (!host.StartsWith("http://"))
{
host = "http://" + host;
}
if (!host.EndsWith("/"))
{
host = host + "/";
}
return host + api_nextFeeder;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OnlineStore.DeviceLibrary
{
public enum IO_VALUE
{
/// <summary>
/// 低位
/// </summary>
LOW = 0,
/// <summary>
/// 高位
/// </summary>
HIGH = 1,
}
}
......@@ -15,96 +15,6 @@ using System.Windows.Forms;
namespace OnlineStore.DeviceLibrary
{
/// <summary>
/// 料仓管理类(加载料仓配置)
/// </summary>
public class StoreManager
{
private static string api_communication = "service/store/communication"; //流水线状态通信接口
private static string api_nextFeeder = "service/store/nextFeeder"; // 出库站位列表切换接口
private static Color storeMoveColor = Color.Blue;
public static readonly ILog LOGGER = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static Dictionary<int, StoreConfig> storeConfigMap = new Dictionary<int, StoreConfig>();
//private static Dictionary<int, object> storeMap = new Dictionary<int, object>();
private static bool isInit = false;
public StoreManager()
{
}
public static void CheckEnum(Type type)
{
if (type.IsEnum)
{
List<int> valueList = new List<int>();
foreach (int item in Enum.GetValues(type))
{
if (valueList.Contains(item))
{
LogUtil.error(LOGGER, type.Name+"枚举值:"+item +"重复存在,请检查代码!");
Application.Exit();
break;
}
valueList.Add(item);
}
}
}
public static string GetPostApi(string host)
{
if (host == "")
{
host = ConfigAppSettings.GetValue(Setting_Init.http_server);
}
if (!host.StartsWith("http://"))
{
host = "http://" + host;
}
if (!host.EndsWith("/"))
{
host = host + "/";
}
return host + api_communication;
}
public static string GetNextFeederApi(string host)
{
if (host == "")
{
host = ConfigAppSettings.GetValue(Setting_Init.http_server);
}
if (!host.StartsWith("http://"))
{
host = "http://" + host;
}
if (!host.EndsWith("/"))
{
host = host + "/";
}
return host + api_nextFeeder;
}
public static void UpdateConfig(AC_SA_Config lineConfig)
{
try
{
//位置配置到文件中
string appPath = Application.StartupPath;
string configFile = appPath + ConfigAppSettings.GetValue(Setting_Init.Store_ConfigPath);
bool result = CSVConfigReader.SaveBoxPosition(configFile, lineConfig);
if (!result)
{
LOGGER.Error("保存配置文件失败:" + configFile);
}
}
catch (Exception ex)
{
LOGGER.Error("出错:", ex);
}
}
}
/// <summary>
/// 等待启动/已经停止,初始化完成, 正常运行中,可以进行新的处理,忙碌,重置
......
......@@ -539,7 +539,7 @@ namespace OnlineStore.LoadCSVLibrary
MustHaveDOList = new List<string>();
MustHaveDIList.Add(IO_Type.SuddenStop_BTN);
MustHaveDIList.Add(IO_Type.Reset_BTN);
MustHaveDIList.Add(IO_Type.AutoRun_Single);
MustHaveDIList.Add(IO_Type.AutoRun_Signal);
MustHaveDIList.Add(IO_Type.Airpressure_Check);
MustHaveDIList.Add(IO_Type.TrayCheck_Door);
MustHaveDIList.Add(IO_Type.TrayCheck_Fixture);
......@@ -564,7 +564,7 @@ namespace OnlineStore.LoadCSVLibrary
MustHaveDOList.Add(IO_Type.Alarm_HddLed);
MustHaveDOList.Add(IO_Type.RunSign_HddLed);
MustHaveDOList.Add(IO_Type.StartOrStopBlow);
MustHaveDOList.Add(IO_Type.Run_Sign);
MustHaveDOList.Add(IO_Type.Run_Signal);
MustHaveDOList.Add(IO_Type.Door_Up);
MustHaveDOList.Add(IO_Type.Door_Down);
//MustHaveDOList.Add(IO_Type.LocationCylinder_Down);
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!