using System; using System.Data; using System.Drawing; using System.Windows.Forms; using UAS_MES_NEW.DataOperate; using UAS_MES_NEW.Entity; using UAS_MES_NEW.PublicForm; using UAS_MES_NEW.PublicMethod; namespace UAS_MES_NEW.Query { public partial class Query_LoadMan : Form { AutoSizeFormClass asc = new AutoSizeFormClass(); DataHelper dh = SystemInf.dh; DataTable Dbfind; public Query_LoadMan() { InitializeComponent(); } private void Query_LoadMan_Load(object sender, EventArgs e) { asc.controllInitializeSize(this); //线别放大镜 li_code.TableName = "line"; li_code.SelectField = "li_code # 线别编号,li_name # 线别名称"; li_code.FormName = Name; li_code.SetValueField = new string[] { "li_code" }; li_code.Condition = "li_statuscode='AUDITED'"; li_code.DbChange += Li_code_DbChange; //初始提示 OperateResult.AppendText(">>请选择线别,输入人员编号后回车执行" + (UpLoadMan.Checked ? "上线" : "下线") + ";下线也可勾选列表后点\"确认下线\"批量处理\n", Color.Black); LoadGridData(); em_code.Focus(); } private void Query_LoadMan_SizeChanged(object sender, EventArgs e) { asc.controlAutoSize(this); } private void Li_code_DbChange(object sender, EventArgs e) { Dbfind = li_code.ReturnData; BaseUtil.SetFormValue(this.Controls, Dbfind); //切换线别后刷新当前线别的在线人员 LoadGridData(); em_code.Focus(); } /// /// 人员编号输入框,回车后按选中的模式执行上线/下线 /// 兼容两种输入格式:①只输入工号(名称从 SOPEMPLOYEEDETAIL 查) ②扫描/输入「工号/人员姓名」(直接解析,不再查表) /// private void em_code_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode != Keys.Enter) return; //阻止回车继续冒泡到 SnCollectionBox / EnterTextBox 的回车逻辑 //(SnCollectionBox 的 KeyDown 里有一句 this.SelectAll(),会受消息顺序影响; // 另配 Em_code_KeyPress 拦掉字符级回车,双保险,不让内置逻辑有机会执行) e.SuppressKeyPress = true; e.Handled = true; HandleEmCode(); } /// /// 字符级拦截:SnCollectionBox/EnterTextBox 内部的回车处理挂在 KeyDown 上,不监听 KeyPress, /// 而扫描枪以 Tab 结尾或手工回车都会先产生字符级 \r。 /// 这里直接把 \r 吞掉并调用统一处理,SnCollectionBox 的回车逻辑(含 SelectAll)就完全不会触发, /// 从而不必改动该公共控件。 /// private void Em_code_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == '\r' || e.KeyChar == '\n') { e.Handled = true; HandleEmCode(); } } /// /// 上线/下线的统一处理入口(由回车、字符级 \r 两处触发,故用 _emBusy 防止同一次回车重复执行) /// private bool _emBusy = false; private void HandleEmCode() { if (_emBusy) return; _emBusy = true; try { DoEmCode(); } finally { _emBusy = false; } } private void DoEmCode() { string linecode = li_code.Text.Trim(); string emcode = ""; string emname = ""; //解析输入内容:扫描枪输出「工号/人员姓名」两段格式,手工输入则只有工号 if (!SplitEmInfo(em_code.Text, out emcode, out emname)) { OperateResult.AppendText("<<扫描内容格式有误,应为「工号/人员姓名」\n", Color.Red, em_code); return; } if (emcode == "") { OperateResult.AppendText("<<人员编号不能为空\n", Color.Red, em_code); return; } if (UpLoadMan.Checked) { //上线:必须选择线别 if (linecode == "") { OperateResult.AppendText("<<请先选择线别\n", Color.Red, li_code); return; } //上线:扫描格式已带姓名则直接用;只输入工号时才去 SOPEMPLOYEEDETAIL 取名称 if (emname == "") { //同一 sed_emcode 可能多条,取最大值聚合 emname = dh.getFieldDataByCondition("SOPEMPLOYEEDETAIL", "max(sed_emname)", "sed_emcode='" + emcode + "'").ToString().Trim(); if (emname == "") { OperateResult.AppendText("<<" + emcode + "人员编号不存在\n", Color.Red, em_code); em_code.Clear(); em_code.Focus(); return; } } //一个人只能同时一条线上线:若已在别的线体上线,先把原线体自动下线,再在新线体上线 DataTable dtOn = (DataTable)dh.ExecuteSql("select lm_linecode from loadman where lm_emcode='" + emcode + "' and lm_downtime is null", "select"); if (dtOn.Rows.Count > 0) { string oldLineCode = dtOn.Rows[0]["lm_linecode"].ToString(); //当前所在线体与新线体相同,提示已上线,不再重复插入 if (oldLineCode == linecode) { OperateResult.AppendText("<<" + emcode + "已在" + linecode + "上线,不允许重复上线\n", Color.Red, em_code); em_code.Clear(); em_code.Focus(); return; } //自动下线原线体 dh.ExecuteSql("update loadman set lm_downtime=sysdate where lm_emcode='" + emcode + "' and lm_downtime is null", "update"); OperateResult.AppendText(">>" + emcode + "已从" + oldLineCode + "自动下线\n", Color.Black); } dh.ExecuteSql("insert into loadman(lm_id,lm_linecode,lm_emcode,lm_emname,lm_uptime,lm_inman)" + "values(loadman_seq.nextval,'" + linecode + "','" + emcode + "','" + emname + "',sysdate,'" + User.UserName + "')", "insert"); OperateResult.AppendText("<<" + emcode + " " + emname + " 在" + linecode + "上线成功\n", Color.Green, em_code); } else { //下线:一个人同一时间只有一条在线记录,直接按人员下线 DataTable dtOn = (DataTable)dh.ExecuteSql("select lm_linecode from loadman where lm_emcode='" + emcode + "' and lm_downtime is null", "select"); if (dtOn.Rows.Count == 0) { OperateResult.AppendText("<<" + emcode + "当前不在任何线上,无法下线\n", Color.Red, em_code); em_code.Clear(); em_code.Focus(); return; } dh.ExecuteSql("update loadman set lm_downtime=sysdate where lm_emcode='" + emcode + "' and lm_downtime is null", "update"); //姓名优先取扫描解析出的,否则用 loadman 里记录的名称 string downName = emname == "" ? dh.getFieldDataByCondition("loadman", "max(lm_emname)", "lm_emcode='" + emcode + "' and lm_downtime is null").ToString().Trim() : emname; OperateResult.AppendText("<<" + emcode + (downName == "" ? "" : " " + downName) + " 已从" + dtOn.Rows[0]["lm_linecode"].ToString() + "下线\n", Color.Green, em_code); } //数据变更后刷新 LoadGridData(); em_code.Clear(); em_code.Focus(); } /// /// 解析人员输入内容,兼容两种格式: /// ①「工号/人员姓名」(扫描枪常用格式,分隔符支持 / \ 全角/ 竖线 | ,也兼容空格和中文顿号) → 工号与姓名都带出 /// ②只有工号(手工输入) → 姓名返回空串,由调用方决定是否去 SOPEMPLOYEEDETAIL 查 /// 分隔符在首尾或出现多次时视为格式错误,返回 false /// private bool SplitEmInfo(string input, out string emcode, out string emname) { emcode = ""; emname = ""; if (input == null) return true; string text = input.Trim(); if (text == "") return true; string[] sep = new string[] { "/", "\\", "/", "|", "|", " ", " ", "、" }; string[] parts = text.Split(sep, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) return true; emcode = parts[0].Trim(); if (parts.Length > 1) emname = parts[1].Trim(); //带分隔符却没解析出两段,说明格式不对(如以分隔符开头或多余分隔符) if (text.IndexOfAny(new char[] { '/', '\\', '/', '|', '|', ' ', ' ', '、' }) >= 0 && (emcode == "" || emname == "")) return false; return true; } /// /// 判断DGV中是否有勾选的行 /// private bool IfCheckRow() { for (int i = 0; i < DGV.Rows.Count; i++) { if (DGV.Rows[i].Cells["choose"].Value != null && DGV.Rows[i].Cells["choose"].FormattedValue.ToString() == "True") { return true; } } return false; } /// /// 批量下线:把DGV中勾选的行按 lm_id 逐条置 lm_downtime=sysdate /// (DGV只加载未下线记录,勾选行必然在线,直接按主键更新即可) /// private void ConfirmDown_Click(object sender, EventArgs e) { if (!IfCheckRow()) { OperateResult.AppendText("<<请先勾选需要下线的人员\n", Color.Red, em_code); return; } DataGridViewRow row; string lmId; string emcode; string emname; string linecode; int sucCount = 0; int failCount = 0; for (int i = 0; i < DGV.Rows.Count; i++) { row = DGV.Rows[i]; //只处理勾选且有主键的行 if (row.Cells["choose"].FormattedValue == null || row.Cells["choose"].FormattedValue.ToString() != "True") continue; if (row.Cells["lm_id"].Value == null || row.Cells["lm_id"].Value.ToString() == "") continue; lmId = row.Cells["lm_id"].Value.ToString(); emcode = row.Cells["lm_emcode"].Value == null ? "" : row.Cells["lm_emcode"].Value.ToString(); emname = row.Cells["lm_emname"].Value == null ? "" : row.Cells["lm_emname"].Value.ToString(); linecode = row.Cells["lm_linecode"].Value == null ? "" : row.Cells["lm_linecode"].Value.ToString(); try { dh.ExecuteSql("update loadman set lm_downtime=sysdate where lm_id='" + lmId + "' and lm_downtime is null", "update"); sucCount++; OperateResult.AppendText("<<" + emcode + " " + emname + " 已从" + linecode + "下线\n", Color.Green); } catch (Exception ex) { failCount++; OperateResult.AppendText("<<" + emcode + " " + emname + " 下线失败:" + ex.Message + "\n", Color.Red); } } OperateResult.AppendText(">>本次下线成功 " + sucCount + " 人" + (failCount > 0 ? ",失败 " + failCount + " 人" : "") + "\n", Color.Black); //刷新后勾选状态会因重新绑定被清空,属预期 LoadGridData(); em_code.Focus(); } private void UpLoadMan_CheckedChanged(object sender, EventArgs e) { if (UpLoadMan.Checked) { OperateResult.AppendText(">>已切换到上线模式,输入人员编号回车上线\n", Color.Black); em_code.Focus(); } } private void DownLoadMan_CheckedChanged(object sender, EventArgs e) { if (DownLoadMan.Checked) { OperateResult.AppendText(">>已切换到下线模式,输入人员编号回车下线,或勾选列表后点\"确认下线\"批量下线\n", Color.Black); em_code.Focus(); } } /// /// 刷新DGV:只取未下线的人员,已选线别时只显示当前线别 /// 人员名称直接取 loadman.lm_emname(上线时已写入),不再关联 SOPEMPLOYEEDETAIL; /// 兼容历史数据:lm_emname 为空时才回退到 SOPEMPLOYEEDETAIL 取名称 /// (SOPEMPLOYEEDETAIL 同一 sed_emcode 可能有多条,先按其聚合去重;上线时间 to_char 到秒) /// private void LoadGridData() { string sql = "select lm.lm_id,lm.lm_linecode,lm.lm_emcode,lm.lm_emname," + "nvl(lm.lm_emname,se.sed_emname) emname," + "to_char(lm.lm_uptime,'yyyy-mm-dd hh24:mi:ss') lm_uptime,lm.lm_inman from loadman lm" + " left join (select sed_emcode,max(sed_emname) sed_emname from SOPEMPLOYEEDETAIL group by sed_emcode) se on lm.lm_emcode=se.sed_emcode" + " where lm.lm_downtime is null"; if (li_code.Text != "") sql += " and lm.lm_linecode='" + li_code.Text + "'"; sql += " order by lm.lm_uptime desc"; DataTable dt = (DataTable)dh.ExecuteSql(sql, "select"); BaseUtil.FillDgvWithDataTable(DGV, dt); } } }