using System; using System.Collections.Generic; using System.Data; using Lskj.Business; using Lskj.Business.Impl; using Lskj.Core; using Lskj.Data; namespace Lskj.Control.Model { /// /// 审核改动日志处理类。 /// 用来比较单据主表原始数据和当前表头控件值,并把发生变化的字段写入 P_SystemAuditChangeLog。 /// public class AuditChangeLog { private const string TableName = "P_SystemAuditChangeLog"; private const int MaxOrderNumberLength = 50; private const int MaxTextLength = 500; /// /// 比较表头字段是否发生变化,并保存审核改动日志。 /// 返回 false 时,errorMessage 会一次性返回所有未记录成功的字段。 /// /// 改动前数据(单表数据或者单据主表数据) /// 控件 mycontrol /// 单号 /// 步骤号 /// 登录人id /// public static bool SaveHeaderChangeLog(DataRow drBillInfoMsg, MyControl controlObj, string orderNumber, string stepCode, string operatorId) { if (SystemInfo.Instance.AuditChangeRecord) { CreateModificationRecordTable(); string errorMessage = string.Empty; // 原始主表数据或控件对象为空时,没有可比较的数据,直接返回成功。 if (drBillInfoMsg == null || controlObj == null || controlObj.ControlModels == null) return true; List errorFields = new List(); // 遍历当前界面的表头控件模型,逐个比较可保存字段。 foreach (ControlModel model in controlObj.ControlModels) { string currentFieldName = model == null ? string.Empty : model.FieldName; try { // 只比较可保存、界面真实存在、原始主表行中也存在的普通字段。 if (!CanCompare(model, drBillInfoMsg, controlObj)) continue; // 旧值来自打开审核界面时加载出来的主表原始行。 string oldValue = GetRowValue(drBillInfoMsg, model.FieldName); // 新值来自当前界面控件值,也就是用户修改后的值。 string newValue = controlObj.GetControlValue(model); if (newValue == "****") continue; // 日期、数字、空值先做统一处理,避免显示格式不同造成误判。 if (IsSameValue(oldValue, newValue)) continue; // 字段确实发生变化后写入日志;相同单号、步骤、字段已存在时执行更新。 SaveChangeLog(orderNumber, model.FieldName, oldValue, newValue, stepCode, operatorId); } catch (Exception ex) { // 单个字段记录失败时先收集错误,继续处理后续字段,最后一次性提示。 errorFields.Add(GetErrorFieldName(model, currentFieldName) + "(" + ex.Message + ")"); } } if (errorFields.Count > 0) { errorMessage = "以下字段审核改动日志未记录:" + Environment.NewLine + string.Join(Environment.NewLine, errorFields.ToArray()); MessageUtil.Show(errorMessage); return false; } } return true; } /// /// 判断控件字段是否需要参与改动比较。 /// private static bool CanCompare(ControlModel model, DataRow drBillInfoMsg, MyControl controlObj) { if (model == null) return false; // 不保存的字段和图片控件不参与本次表头改动日志记录。 if (!model.IsSave || model.FieldType == ControlType.LabPic || model.FieldType == ControlType.LabPicEx) return false; if (string.IsNullOrWhiteSpace(model.FieldName)) return false; // 当前界面上没有真实控件的字段不参与比较。 if (controlObj.FindControl(model) == null) return false; // 原始主表行里必须存在同名数据库字段。 return drBillInfoMsg.Table != null && drBillInfoMsg.Table.Columns.Contains(model.FieldName); } /// /// 保存单个字段的改动记录。 /// 如果相同单号、相同步骤、相同字段已存在记录,则更新;否则新增。 /// private static void SaveChangeLog(string orderNumber, string fieldName, string oldValue, string newValue, string stepCode, string operatorId) { //orderNumber = orderNumber == null ? string.Empty : orderNumber; //fieldName = fieldName == null ? string.Empty : fieldName; //oldValue = oldValue == null ? string.Empty : oldValue; //newValue = newValue == null ? string.Empty : newValue; //orderNumber = orderNumber.Length > MaxOrderNumberLength ? orderNumber.Substring(0, MaxOrderNumberLength) : orderNumber; //fieldName = fieldName.Length > MaxTextLength ? fieldName.Substring(0, MaxTextLength) : fieldName; //oldValue = oldValue.Length > MaxTextLength ? oldValue.Substring(0, MaxTextLength) : oldValue; //newValue = newValue.Length > MaxTextLength ? newValue.Substring(0, MaxTextLength) : newValue; //orderNumber = orderNumber.Replace("'", "''"); //fieldName = fieldName.Replace("'", "''"); //oldValue = oldValue.Replace("'", "''"); //newValue = newValue.Replace("'", "''"); string sql = string.Format(@"if exists (select 1 from {0} where orderNumber = '{1}' and stepCode = {2} and fieldName = N'{3}') begin update {0} set oldValue = N'{4}', newValue = N'{5}', operatorId = N'{6}' where orderNumber =N'{1}' and stepCode = N'{2}' and fieldName = N'{3}' end else begin insert into {0} (orderNumber, fieldName, oldValue, newValue, stepCode, operatorId) values (N'{1}', N'{3}', N'{4}', N'{5}', N'{2}', N'{6}') end", TableName, orderNumber, stepCode, fieldName, oldValue, newValue, operatorId); SqlHelper.ExecuteNonQuery(sql); } /// /// 从原始主表行中读取字段旧值,数据库 NULL 统一按空字符串处理。 /// private static string GetRowValue(DataRow row, string fieldName) { if (row[fieldName] == DBNull.Value || row[fieldName] == null) return string.Empty; return row[fieldName] + ""; } /// /// 获取错误提示中展示的字段名称,优先显示控件标题,没有标题时显示字段名。 /// private static string GetErrorFieldName(ControlModel model, string fieldName) { if (model != null && !string.IsNullOrWhiteSpace(model.LabelText)) return model.LabelText + "[" + model.FieldName + "]"; return string.IsNullOrWhiteSpace(fieldName) ? "未知字段" : fieldName; } /// /// 判断两个值是否相同。 /// 优先按日期、数字进行值比较,最后再按普通字符串比较。 /// /// 原始值 /// 当前值 /// 两个值在统一格式后是否相同 public static bool IsSameValue(string oldValue, string newValue) { oldValue = NormalizeValue(oldValue); newValue = NormalizeValue(newValue); if (oldValue == string.Empty && newValue == string.Empty) return true; DateTime oldDate; DateTime newDate; if (DateTime.TryParse(oldValue, out oldDate) && DateTime.TryParse(newValue, out newDate)) return oldDate == newDate; decimal oldDecimal; decimal newDecimal; if (decimal.TryParse(oldValue, out oldDecimal) && decimal.TryParse(newValue, out newDecimal)) return oldDecimal == newDecimal; return oldValue == newValue; } /// /// 比较前统一处理 NULL 和首尾空格。 /// private static string NormalizeValue(string value) { return value == null ? string.Empty : value.Trim(); } /// /// 根据单号获取所有审核改动字段名。 /// /// 单号 /// 当前单号对应的审核改动字段名集合 public static List GetChangeLogFields(string orderNumber) { List fields = new List(); if (SystemInfo.Instance.AuditChangeRecord) { CreateModificationRecordTable(); orderNumber = orderNumber == null ? string.Empty : orderNumber.Replace("'", "''"); string sqlValue = string.Format(@" select distinct fieldName from {0} where orderNumber = N'{1}' order by fieldName", TableName, orderNumber); DataTable dataTable = SqlHelper.ExecuteDataTable(sqlValue); if (dataTable == null) return fields; foreach (DataRow row in dataTable.Rows) { string fieldName = row["fieldName"] + ""; if (!string.IsNullOrWhiteSpace(fieldName)) fields.Add(fieldName); } } return fields; } /// /// 创建修改记录表 /// public static void CreateModificationRecordTable() { if (!Lskj.Business.Impl.BaseImpl.HasExistsTable("P_SystemAuditChangeLog")) { string sqlValue = string.Format(@"CREATE TABLE P_SystemAuditChangeLog ( id BIGINT IDENTITY(1,1) NOT NULL PRIMARY KEY, orderNumber VARCHAR(50) NOT NULL, -- 单号 fieldName NVARCHAR(500) NOT NULL, -- 字段名称 oldValue NVARCHAR(500) NULL, -- 旧值(改动前) newValue NVARCHAR(500) NULL, -- 新值(改动后) stepCode INT NOT NULL, -- 步骤号 operatorId int NOT NULL -- 人员id(改动人) );"); BaseImpl.ExecSqlValue(sqlValue); } } } }