using DevExpress.Utils.CodedUISupport; using DevExpress.Xpo.Logger; using HslCommunication; using NPOI.POIFS.NIO; using NPOI.SS.Formula.Functions; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Security.AccessControl; using System.Security.Principal; using System.Text; using System.Web.Services.Description; using System.Web.UI.WebControls; using System.Windows.Forms; using UAS_MES_NEW.CustomControl.ButtonUtil; using UAS_MES_NEW.DataOperate; using UAS_MES_NEW.Entity; using UAS_MES_NEW.PublicMethod; namespace UAS_MES_NEW.Make { public partial class Make_ParseLog : Form { public Make_ParseLog() { InitializeComponent(); } FileSystemWatcher watcher; LogStringBuilder sql = new LogStringBuilder(); DataTable Dbfind; DataTable dt; DataHelper dh; string currFileType = "", equiType = ""; string SN, omakeCode, oMsid, oErrorMessage = ""; List fileList = new List(); Timer ChangeWoTimer; string outFileMsg; private void Make_ParseLog_Load(object sender, EventArgs e) { dh = SystemInf.dh; Choose.Enabled = false; fileList.Add("E:\\AOIMes\\Mes"); fileList.Add("C:\\Users\\MI\\Desktop"); fileList.Add("C:\\Users\\MI\\Desktop"); ChangeWoTimer = new Timer(); ChangeWoTimer.Interval = 30000; ChangeWoTimer.Tick += ChangeWoFunc; watcher = new FileSystemWatcher(); watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite; watcher.Created += OnFileCreated; watcher.Changed += OnFileChanged; /*watcher.Deleted += OnFileChanged; watcher.Renamed += OnFileChanged;*/ //设置锁定工单 LockMakeCode.GetMakeCodeCtl(ma_code); ma_code.SetLockCheckBox(LockMakeCode); //工单号放大镜配置 ma_code.TableName = "make left join product on ma_prodcode=pr_code"; ma_code.SelectField = "ma_code # 工单号,pr_code # 产品编号,pr_detail # 产品名称"; ma_code.FormName = Name; ma_code.SetValueField = new string[] { "ma_code", "pr_code", "pr_detail" }; ma_code.Condition = "ma_statuscode='STARTED'"; ma_code.DbChange += Ma_code_DbChange; } private void Ma_code_DbChange(object sender, EventArgs e) { Dbfind = ma_code.ReturnData; BaseUtil.SetFormValue(this.Controls, Dbfind); //获取工单的其他信息 sql.Clear(); sql.Append("select ma_code,nvl(mcd_okqty,0) mcd_okqty,ma_prodcode as pr_code ,pr_detail,"); sql.Append("pr_spec,ma_qty - nvl(mcd_inqty, 0) mcd_remainqty from make left join makecraftdetail on "); sql.Append("mcd_maid=ma_id left join product on pr_code=ma_prodcode where ma_code='" + ma_code.Text + "' and mcd_stepcode='" + User.CurrentStepCode + "'"); dt = (DataTable)dh.ExecuteSql(sql.GetString(), "select"); if (dt.Rows.Count > 0) { BaseUtil.SetFormValue(this.Controls, dt); } } private void Device_SelectedIndexChanged(object sender, EventArgs e) { if (Device.SelectedIndex == -1) return; if(ChangeWoTimer.Enabled) ChangeWoTimer.Stop(); switch (Device.SelectedIndex) { case 0: currFileType = "Txt"; equiType = "AOI"; /*ChangeWoTimer.Start(); ChangeWoFunc(null, null);*/ break; case 1: currFileType = "jpg"; equiType = "Xray"; break; case 2: currFileType = "jpg"; equiType = "CCD"; break; } txtPath.Text = fileList[Device.SelectedIndex]; txtPath.Focus(); txtPath.SelectAll(); ma_code.Enabled = true; Choose.Enabled = true; txtPath.Enabled = false; } private void Choose_Click(object sender, EventArgs e) { using (var dialog = new FolderBrowserDialog()) { if (dialog.ShowDialog() == DialogResult.OK) { txtPath.Text = dialog.SelectedPath; txtPath.Enabled = false; Device.Enabled = false; watcher.EnableRaisingEvents = false; } } } private void claerBtn_Click(object sender, EventArgs e) { lstFiles.Items.Clear(); } private void allParse_Click(object sender, EventArgs e) { if (Device.SelectedIndex == -1) { Device.Focus(); Device.SelectAll(); MessageBox.Show(this.ParentForm, "请选择设备", "提示"); return; } if (String.IsNullOrEmpty(txtPath.Text)) { txtPath.Focus(); txtPath.SelectAll(); MessageBox.Show(this.ParentForm, "请选择解析路径", "提示"); return; } string[] txtFiles; if (equiType == "Xray") { if (string.IsNullOrEmpty(ma_code.Text)) { MessageBox.Show(this.ParentForm, "请选择工单", "提示"); return; } txtFiles = Directory.GetDirectories(txtPath.Text); if (txtFiles.Length == 0) { LogMessage(0, $"当前路径{txtPath.Text},没有{equiType}设备输出的文件夹"); return; } } else { txtFiles = Directory.GetFiles(txtPath.Text, $"*.{currFileType}"); if (txtFiles.Length == 0) { LogMessage(0, $"当前{txtPath.Text},没有{equiType}设备输出的{currFileType.ToLower()}文件"); return; } } RefreshFileList(); } private void onWatch_Click(object sender, EventArgs e) { if (Device.SelectedIndex == -1) { Device.Focus(); Device.SelectAll(); MessageBox.Show(this.ParentForm, "请选择设备", "提示"); return; } if (String.IsNullOrEmpty(txtPath.Text)) { txtPath.Focus(); txtPath.SelectAll(); MessageBox.Show(this.ParentForm, "请选择解析路径", "提示"); return; } if (equiType == "Xray") { if (string.IsNullOrEmpty(ma_code.Text)) { MessageBox.Show(this.ParentForm, "请选择工单", "提示"); return; } } try { watcher.Path = txtPath.Text; watcher.Filter = $"*.{currFileType}"; if (onWatch.Text == "开启解析") { watcher.EnableRaisingEvents = true; onWatch.Text = "关闭解析"; } else { watcher.EnableRaisingEvents = false; onWatch.Text = "开启解析"; } } catch (Exception ex) { MessageBox.Show(this.ParentForm, ex.Message, "警告"); } } private void OnFileCreated(object sender, FileSystemEventArgs e) { RefreshFileList(); } private void OnFileChanged(object sender, FileSystemEventArgs e) { if (e.ChangeType == WatcherChangeTypes.Changed) { RefreshFileList(); } } private void RefreshFileList() { if (lstFiles.InvokeRequired) { lstFiles.Invoke(new Action(RefreshFileList)); lstFiles.BeginInvoke(new Action(RefreshFileList)); return; } try { if (!Directory.Exists(txtPath.Text)) { LogMessage(0, $"目录不存在: {txtPath.Text}"); return; } string[] txtFiles; if (equiType == "Xray") { txtFiles = Directory.GetDirectories(txtPath.Text); } else { txtFiles = Directory.GetFiles(txtPath.Text, $"*.{currFileType}"); } if (txtFiles.Length == 0) { return; } foreach (string file in txtFiles) { if (equiType == "Xray") { if (Path.GetFileName(file).Contains("Log_")) { continue; } if (!Directory.Exists(file)) { LogMessage(0, $"文件夹不存在: {file}"); } outFileMsg = CheckFolderPermissions(file); if (outFileMsg != "OK") { LogMessage(0, outFileMsg); continue; } } else { if (!File.Exists(file)) { LogMessage(0, $"文件不存在: {file}"); } outFileMsg = CheckFileAccess(file); if (outFileMsg != "OK") { LogMessage(0, outFileMsg); continue; } if (File.ReadAllText(file).Length == 0) { continue; } } if (equiType == "AOI") { using (StreamReader SR = new StreamReader(file, Encoding.GetEncoding("GBK"))) { string Content = SR.ReadToEnd(); SR.Close(); SR.Dispose(); List logArr = new List() { }; string[] lines = Content.Split(new string[] { "\r\n" }, StringSplitOptions.None); int fileNum = string.IsNullOrEmpty(lines[lines.Length - 1]) ? lines.Length - 1 : lines.Length; Log itemLog = new Log() { }; foreach (var item in lines) { if (string.IsNullOrEmpty(item)) continue; if (Array.IndexOf(lines, item) == 1) itemLog.SN = item.Split(':')[1].ToString().Trim(); if (Array.IndexOf(lines, item) == 2) itemLog.TestTime = item.Split(':')[1].Split('.')[0].ToString().Trim(); if (Array.IndexOf(lines, item) == 3) itemLog.Result = item.Split(':')[1].ToString().Trim(); if (Array.IndexOf(lines, item) == 4) itemLog.Side = item.Split(':')[1].ToString().Trim(); if (item.IndexOf("元件位置") > -1) { LogItem list = new LogItem(); int ind = Array.IndexOf(lines, item); list.Location = lines[ind].Split(':')[1].ToString().Trim(); list.ReelNo = lines[ind + 1].Split(':')[1].ToString().Trim(); list.FirstType = lines[ind + 2].Split(':')[1].ToString().Trim(); list.SceondType = lines[ind + 3].Split(':')[1].ToString().Trim(); list.Name = lines[ind + 4].Split(':')[1].ToString().Trim(); itemLog.LogItemList.Add(list); } } logArr.Add(itemLog); if (logArr.Count == 0) { break; } if (InsertDb(logArr, file, fileNum)) { if (ConsoleLog(Content, file, logArr[0].SN)) { File.WriteAllText(file, string.Empty); File.Delete(file); } } } } else if (equiType == "Xray") { string[] floderFile = Directory.GetFiles(file, $"*.{currFileType}"); foreach(string floderFileItem in floderFile) { SN = Path.GetFileName(floderFileItem).Split('-')[0]; if (UploadImageToFtp(floderFileItem, SN)) { dh.ExecuteSql($@"INSERT INTO steptestmain (sm_id, sm_sn,sm_makecode,sm_stepcode,sm_indate,sm_machinecode,sm_result) VALUES ( steptestmain_seq.NEXTVAL,'{SN}','{ma_code.Text}','{User.UserSourceCode}', sysdate,'Xray', 'http://192.168.1.5:8088/ftp/xray/{DateTime.Now.ToString("yyyyMMdd")}/{Path.GetFileName(floderFileItem)}' )", "insert"); if (Array.IndexOf(floderFile, floderFileItem) == floderFile.Length - 1) { string newFloderName = Path.GetDirectoryName(file); Directory.Move(file, Path.Combine(newFloderName, "Log_" + Path.GetFileName(file))); } } } } else if(equiType == "CCD") { if (txtFiles.Length != 2) break; foreach (var fileItem in txtFiles) { string imageName = Path.GetFileName(fileItem); SN = imageName.Split('_')[0].ToString(); if (imageName.ToUpper().Contains("NG")) { if (UploadImageToFtp(fileItem, SN)) { dh.ExecuteSql($@"INSERT INTO steptestmain (sm_id, sm_sn,sm_makecode,sm_stepcode,sm_indate,sm_machinecode,sm_result) VALUES ( steptestmain_seq.NEXTVAL,'{SN}','{ma_code.Text}','{User.UserSourceCode}', sysdate,'CCD', 'http://192.168.1.5:8088/ftp/ccd/{SN}/{Path.GetFileName(fileItem)}' )", "insert"); } } string parentPath = Path.GetDirectoryName(file); string changeName = Path.Combine(parentPath, SN); if (!Directory.Exists(changeName)) { Directory.CreateDirectory(changeName); } File.Move(file, changeName); } } } } catch (Exception ex) { LogMessage(0, $"Error: 解析文件列表失败: {ex.Message}"); } } private bool InsertDb(List logs, string PathName, int fileNum) { try { StringBuilder sql = new StringBuilder(); StringBuilder details = new StringBuilder(); List param = new List() { }; foreach (var item in logs) { if (LogicHandler.CheckStepSNAndMacode(ma_code.Text, User.UserSourceCode, item.SN, User.UserCode, out omakeCode, out oMsid, out oErrorMessage)) { if (LogicHandler.SetStepResult(omakeCode, User.UserSourceCode, item.SN, "日志解析", "解析过站成功", User.UserCode, out oErrorMessage)) { string outMsg = ""; param.Add(omakeCode); param.Add(item.SN); param.Add(User.UserSourceCode); param.Add(item.Result.ToUpper()); param.Add(item.TestTime); param.Add(item.Side); param.Add(equiType); details.Clear(); foreach (LogItem LI in item.LogItemList) { details.Append($"{LI.Location}/{LI.ReelNo}/{LI.FirstType}/{LI.SceondType}/{LI.Name};"); } param.Add(details.ToString()); param.Add(outMsg); string[] paramList = param.ToArray(); dh.CallProcedure("cs_insert_testrejects", ref paramList); if (paramList[8].Substring(0, 2) == "OK") { LogMessage(1, $"文件: {item.SN} 采集成功, 测试结果为{item.Result},共{item.LogItemList.Count}条信息"); } else { LogMessage(1, paramList[8]); } param.Clear(); if (logs.IndexOf(item) == logs.Count - 1) { //string sqlStr = $@"select ma_code,nvl(mcd_okqty,0) mcd_okqty,ma_prodcode,pr_detail,ma_qty - nvl(mcd_okqty, 0) remain_qty // from make left join makecraftdetail on mcd_maid=ma_id left join product on pr_code = ma_prodcode // where ma_code='{omakeCode}' and mcd_stepcode='" + User.CurrentStepCode + "'"; //dt = (DataTable)dh.ExecuteSql(sqlStr, "select"); //BaseUtil.SetFormValue(Controls, dt); LogicHandler.DoCommandLog(Tag.ToString(), User.UserCode, omakeCode, User.UserLineCode, User.UserSourceCode, "日志解析", "日志解析过站成功", item.SN, ""); return true; } } else { LogMessage(0, $"处理过站NG:{oErrorMessage}"); break; } } else { LogMessage(0, $"过站核对NG:{oErrorMessage}"); break; } } return false; } catch (Exception ex) { LogMessage(0, $"Error,处理解析写入: {ex.Message}"); return false; } } private void ChangeWoFunc(object sender, EventArgs e) { try { sql.Clear(); sql.Append($"SELECT dl_macode FROM deviceline WHERE dl_linecode = '{User.UserLineCode}'"); dt = (DataTable)dh.ExecuteSql(sql.GetString(), "select"); if (dt.Rows.Count > 0 && !String.IsNullOrEmpty(dt.Rows[0]["dl_macode"].ToString())) { ma_code.Text = dt.Rows[0]["dl_macode"].ToString().Trim(); return; } LogMessage(0, $"NG,自动识别更新工单"); } catch (Exception ex) { LogMessage(0, $"Error,自动切换工单: {ex.Message}"); } } private bool ConsoleLog(string Content, string PathName,string SN) { try { string sourcePaht = Path.GetDirectoryName(PathName); string changeName = Path.Combine(sourcePaht, $"{SN}.{currFileType}"); string newFolderName = "Logs"; string newFolderPath = Path.Combine(sourcePaht, newFolderName); if (!Directory.Exists(newFolderPath)) { Directory.CreateDirectory(newFolderPath); } string newFileName = "Log_" + Path.GetFileName(changeName); string newFilePath = Path.Combine(newFolderPath, newFileName); File.AppendAllText(newFilePath, Content + Environment.NewLine); return true; } catch (Exception ex) { MessageBox.Show(this.ParentForm, ex.Message, "警告"); return false; } } private void LogMessage(int type, string message) { if (type == 0) { if (lstFiles.InvokeRequired) { lstFiles.Invoke(new Action(LogMessage), new object[] { type, message }); return; } lstFiles.Items.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}"); lstFiles.TopIndex = lstFiles.Items.Count - 1; } else { if (lstOk.InvokeRequired) { lstOk.Invoke(new Action(LogMessage), new object[] { type, message }); return; } lstOk.Items.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}"); lstOk.TopIndex = lstOk.Items.Count - 1; } } private void lstFiles_DrawItem(object sender, DrawItemEventArgs e) { if (e.Index < 0) return; e.DrawBackground(); string txt = lstFiles.Items[e.Index].ToString().ToUpper(); Brush color = Brushes.Black; if (txt.Contains("NG")) { color = Brushes.Red; } else if (txt.Contains("ERROR")) { color = Brushes.Red; } else { color = Brushes.Green; } e.DrawFocusRectangle(); e.Graphics.DrawString(lstFiles.Items[e.Index].ToString(), e.Font, color, e.Bounds, StringFormat.GenericDefault); } public bool UploadImageToFtp(string localFilePath, string Sn) { string ftpServer; //string ftpServer = "ftp://10.8.0.215:21/xray/"; //string ftpServer = "ftp://192.168.1.5:21/xray/"; ftpServer = equiType == "Xray" ? "ftp://10.8.0.215:21/xray/" : "ftp://10.8.0.215:21/ccd/"; ftpServer = equiType == "Xray" ? "ftp://192.168.1.5:21/xray/" : "ftp://192.168.1.5:21/ccd/"; string username = "vsftpd"; string password = "vsftpd3ef41637hy"; string currentDate = DateTime.Now.ToString("yyyyMMdd"); string ftpFullPath = $"{ftpServer.TrimEnd('/')}/{currentDate}"; /*string ftpFullPath = $"{ftpServer.TrimEnd('/')}/{Sn}";*/ string outResult = CreateFtpDirectoryIfNotExists(ftpFullPath, username, password); if (outResult.Substring(0, 2) == "NG") { LogMessage(0, outResult); return false; } string remoteFileName = Path.GetFileName(localFilePath); string uri = $"{ftpFullPath}/{remoteFileName}"; try { var request = (FtpWebRequest)WebRequest.Create(uri); request.Method = WebRequestMethods.Ftp.UploadFile; request.Credentials = new NetworkCredential(username, password); request.UsePassive = true; request.UseBinary = true; request.KeepAlive = false; using (var fileStream = File.OpenRead(localFilePath)) using (var requestStream = request.GetRequestStream()) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0) { requestStream.Write(buffer, 0, bytesRead); } } using (var response = (FtpWebResponse)request.GetResponse()) { LogMessage(1, $"文件: {localFilePath}上传成功,状态{response.StatusDescription}"); return true; } } catch (WebException ex) { if (ex.Response is FtpWebResponse response) { LogMessage(0, $"NG,FTP 错误码: {(int)response.StatusCode} - {response.StatusDescription}"); } else { LogMessage(0, $"NG,Web异常: {ex.Message}"); } return false; } catch (Exception ex) { LogMessage(0, $"NG,上传失败: {ex.Message}"); return false; } } private string CreateFtpDirectoryIfNotExists(string ftpDirectoryPath, string username, string password) { try { FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpDirectoryPath); request.Method = WebRequestMethods.Ftp.MakeDirectory; request.Credentials = new NetworkCredential(username, password); request.UsePassive = true; request.UseBinary = true; request.KeepAlive = false; using (FtpWebResponse response = (FtpWebResponse)request.GetResponse()) { response.Close(); return "OK,目录创建成功: " + response.StatusDescription; } } catch (WebException ex) { if (ex.Response is FtpWebResponse response && response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable) { return "OK,目录已存在: " + response.StatusDescription; } else { return "NG,创建目录时发生错误: " + ex.Message; } } } public string CheckFileAccess(string filePath) { try { using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None)) { return "OK"; } } catch (IOException ex) { return "NG,文件被占用: " + ex.Message; } catch (UnauthorizedAccessException ex) { return "NG,权限不足,无法访问文件: " + ex.Message; } catch (Exception ex) { return "NG," + ex.Message; } } public string CheckFolderPermissions(string path) { try { DirectorySecurity security = Directory.GetAccessControl(path); AuthorizationRuleCollection rules = security.GetAccessRules(true, true, typeof(NTAccount)); WindowsIdentity currentUser = WindowsIdentity.GetCurrent(); foreach (FileSystemAccessRule rule in rules) { if (rule.IdentityReference.Value == currentUser.Name || currentUser.Groups.Contains(rule.IdentityReference)) { Console.WriteLine($" {rule.IdentityReference.Value}"); Console.WriteLine($"权限类型: {rule.AccessControlType}"); Console.WriteLine($"具体权限: {rule.FileSystemRights}"); Console.WriteLine($"是否继承: {rule.IsInherited}"); } } return "OK"; } catch (UnauthorizedAccessException ex) { return $"NG,无权限访问文件夹: {ex.Message}"; } catch (DirectoryNotFoundException) { return "NG,文件夹不存在"; } catch (Exception ex) { return "NG," + ex.Message; } } public class Log { public string SN { set; get; } public string Result { set; get; } public string TestTime { set; get; } public string Side { set; get; } public List LogItemList { set; get; } = new List(); } public class LogItem { public string Location { set; get; } public string ReelNo { set; get; } public string FirstType { set; get; } public string SceondType { set; get; } public string Name { set; get; } } } }