using MiniExcelLibs; using BLL; using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; namespace FineUIPro.Web.HJGL.WeldingManage { public partial class WeldReportIn : PageBase { private const string TemplateRelativePath = @"File\Excel\DataIn\焊接日报导入模板.xlsx"; // 基础日报字段始终必填,点口相关字段按是否点口单独校验。 private static readonly string[] RequiredColumns = { "管线号", "焊口号", "盖面焊工", "打底焊工", "焊接日期", "焊接位置", "是否点口" }; // 只有是否点口为 是/1/true 时,才要求委托信息完整;评定级别允许为空,填写时再校验格式。 private static readonly string[] PointRequiredColumns = { "委托单号", "委托日期", "检测单位" }; // 模板表头必须完整,避免用户使用旧模板或列名被误改后发生错列导入。 private static readonly string[] RequiredHeaders = { "管线号", "焊口号", "盖面焊工", "打底焊工", "焊接日期", "焊接位置", "是否点口", "委托单号", "委托日期", "检测单位", "检测单号", "检测日期", "报告日期", "检测总数", "合格数", "是否合格", "评定级别", "缺陷", "返修位置" }; private string initPath = Const.ExcelUrl; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { hdFileName.Text = string.Empty; BindGrid(new List()); } } protected void btnAudit_Click(object sender, EventArgs e) { try { string filePath = SaveUploadFile(); if (string.IsNullOrEmpty(filePath)) { return; } var rows = ReadAndValidate(filePath); BindGrid(rows); string errlog = JoinErrors(rows); if (string.IsNullOrEmpty(errlog)) { ShowNotify("审核完成,请点击导入!", MessageBoxIcon.Success); } else { Alert.ShowInTop(errlog, MessageBoxIcon.Warning); } } catch (Exception ex) { Alert.ShowInTop(ex.Message, MessageBoxIcon.Warning); } } protected void btnImport_Click(object sender, EventArgs e) { try { if (string.IsNullOrEmpty(hdFileName.Text.Trim())) { ShowNotify("请先审核要导入的文件!", MessageBoxIcon.Warning); return; } string filePath = Path.Combine(Server.MapPath("~/"), initPath, hdFileName.Text.Trim()); var rows = ReadAndValidate(filePath); BindGrid(rows); string errlog = JoinErrors(rows); if (!string.IsNullOrEmpty(errlog)) { Alert.ShowInTop("请先将错误数据修正,再重新导入提交!" + errlog, MessageBoxIcon.Warning); return; } foreach (ImportRow row in rows) { ImportOneRow(row); } BLL.LogService.AddLog(this.CurrUser.PersonId, "导入焊接日报"); ShowNotify("导入成功!", MessageBoxIcon.Success); PageContext.RegisterStartupScript(ActiveWindow.GetHidePostBackReference()); } catch (Exception ex) { Alert.ShowInTop(ex.Message, MessageBoxIcon.Warning); } } protected void btnDownLoad_Click(object sender, EventArgs e) { string path = Funs.RootPath + TemplateRelativePath; FileInfo info = new FileInfo(path); if (!info.Exists) { Alert.ShowInTop("未找到导入模板!", MessageBoxIcon.Warning); return; } string filename = "焊接日报导入模板.xlsx"; long fileSize = info.Length; System.Web.HttpContext.Current.Response.Clear(); System.Web.HttpContext.Current.Response.ContentType = "application/x-zip-compressed"; System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + System.Web.HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8)); System.Web.HttpContext.Current.Response.AddHeader("Content-Length", fileSize.ToString()); System.Web.HttpContext.Current.Response.TransmitFile(path, 0, fileSize); System.Web.HttpContext.Current.Response.Flush(); System.Web.HttpContext.Current.Response.Close(); } private string SaveUploadFile() { if (!fuAttachUrl.HasFile) { ShowNotify("请您选择Excel文件!", MessageBoxIcon.Warning); return string.Empty; } string extension = Path.GetExtension(fuAttachUrl.FileName).Trim().ToLower(); if (extension != ".xlsx") { ShowNotify("只可以选择xlsx文件!", MessageBoxIcon.Warning); return string.Empty; } string rootPath = Server.MapPath("~/"); string initFullPath = Path.Combine(rootPath, initPath); if (!Directory.Exists(initFullPath)) { Directory.CreateDirectory(initFullPath); } hdFileName.Text = BLL.Funs.GetNewFileName() + extension; string filePath = Path.Combine(initFullPath, hdFileName.Text); fuAttachUrl.PostedFile.SaveAs(filePath); return filePath; } private List ReadAndValidate(string filePath) { if (!File.Exists(filePath)) { throw new Exception("导入文件不存在,请重新上传!"); } // 使用模板第一行作为表头读取;后续取值按列名匹配,不依赖 Excel 列顺序。 DataTable table = MiniExcel.QueryAsDataTable(filePath, useHeaderRow: true); ValidateHeaders(table); var rows = new List(); for (int i = 0; i < table.Rows.Count; i++) { DataRow dataRow = table.Rows[i]; if (IsEmptyRow(dataRow)) { continue; } // RowIndex 保留 Excel 原始行号,便于把错误信息定位回用户文件。 ImportRow row = new ImportRow { SerialNo = rows.Count + 1, RowIndex = i + 2, PipelineCode = GetCell(dataRow, "管线号"), WeldJointCode = GetCell(dataRow, "焊口号"), CoverWelderCode = GetCell(dataRow, "盖面焊工"), BackingWelderCode = GetCell(dataRow, "打底焊工"), WeldingDateText = GetCell(dataRow, "焊接日期"), WeldingLocationCode = GetCell(dataRow, "焊接位置"), IsPointText = GetCell(dataRow, "是否点口"), TrustBatchCode = GetCell(dataRow, "委托单号"), TrustDateText = GetCell(dataRow, "委托日期"), NDEUnitName = GetCell(dataRow, "检测单位"), NDECode = GetCell(dataRow, "检测单号"), NDEDateText = GetCell(dataRow, "检测日期"), ReportDateText = GetCell(dataRow, "报告日期"), TotalFilmText = GetCell(dataRow, "检测总数"), PassFilmText = GetCell(dataRow, "合格数"), CheckResultText = GetCell(dataRow, "是否合格"), JudgeGrade = GetCell(dataRow, "评定级别"), DefectNames = GetCell(dataRow, "缺陷"), RepairLocation = GetCell(dataRow, "返修位置") }; rows.Add(row); } if (rows.Count == 0) { throw new Exception("导入数据为空!"); } ValidateRows(rows); return rows; } private void ValidateHeaders(DataTable table) { foreach (string header in RequiredHeaders) { if (!table.Columns.Cast().Any(x => x.ColumnName.Trim() == header)) { throw new Exception("导入Excel格式错误,缺少列:" + header); } } } private void ValidateRows(List rows) { var duplicateKeys = rows.GroupBy(x => x.PipelineCode + "|" + x.WeldJointCode) .Where(x => !string.IsNullOrEmpty(x.Key.Trim('|')) && x.Count() > 1) .SelectMany(x => x.Select(y => y.RowIndex)) .ToList(); foreach (ImportRow row in rows) { // 先校验基础必填项,保证后续业务查询有最小输入条件。 foreach (string col in RequiredColumns) { if (string.IsNullOrEmpty(GetValueByColumn(row, col))) { row.AddError(col + "为必填项"); } } if (duplicateKeys.Contains(row.RowIndex)) { row.AddError("文件内存在重复管线号和焊口号"); } // 点口行才进入委托必填校验;非点口行允许只导入焊接日报数据。 row.IsPoint = ParseBoolean(row.IsPointText, row); if (row.IsPoint == true) { foreach (string col in PointRequiredColumns) { if (string.IsNullOrEmpty(GetValueByColumn(row, col))) { row.AddError(col + "为必填项"); } } } row.WeldingDate = ParseDate(row.WeldingDateText, "焊接日期", row); row.TrustDate = ParseDate(row.TrustDateText, "委托日期", row, row.IsPoint == true); row.NDEDate = ParseDate(row.NDEDateText, "检测日期", row, false); row.ReportDate = ParseDate(row.ReportDateText, "报告日期", row, false); row.TotalFilm = ParseInt(row.TotalFilmText, "检测总数", row, false); row.PassFilm = ParseInt(row.PassFilmText, "合格数", row, false); row.CheckResult = ParseCheckResult(row.CheckResultText, row); ValidateJudgeGrade(row); ValidateBusinessData(row); } } // 校验 Excel 中的业务引用是否能匹配系统现有基础数据。 private void ValidateBusinessData(ImportRow row) { if (string.IsNullOrEmpty(row.PipelineCode) || string.IsNullOrEmpty(row.WeldJointCode)) { return; } row.Joint = Funs.DB.View_HJGL_WeldJoint.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.PipelineCode == row.PipelineCode && x.WeldJointCode == row.WeldJointCode); if (row.Joint == null) { row.AddError("管线号和焊口号对应的焊口不存在"); return; } if (!string.IsNullOrEmpty(row.Joint.WeldingDailyId)) { row.AddError("焊口已生成焊接日报"); } row.Pipeline = Funs.DB.HJGL_Pipeline.FirstOrDefault(x => x.PipelineId == row.Joint.PipelineId); if (row.Pipeline == null) { row.AddError("焊口关联管线不存在"); } row.CoverWelder = Funs.DB.SitePerson_Person.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.WelderCode == row.CoverWelderCode); if (row.CoverWelder == null) { row.AddError("盖面焊工不存在"); } row.BackingWelder = Funs.DB.SitePerson_Person.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.WelderCode == row.BackingWelderCode); if (row.BackingWelder == null) { row.AddError("打底焊工不存在"); } row.WeldingLocation = Funs.DB.Base_WeldingLocation.FirstOrDefault(x => x.WeldingLocationCode == row.WeldingLocationCode); if (row.WeldingLocation == null) { row.AddError("焊接位置不存在"); } // 检测单位只服务点口委托链路,非点口行不因检测单位为空或不存在报错。 if (row.IsPoint == true && !string.IsNullOrEmpty(row.NDEUnitName)) { row.NDEUnit = (from x in Funs.DB.Base_Unit join y in Funs.DB.Project_ProjectUnit on x.UnitId equals y.UnitId where y.ProjectId == this.CurrUser.LoginProjectId && y.UnitType == BLL.Const.ProjectUnitType_5 && x.UnitName == row.NDEUnitName select x).FirstOrDefault(); if (row.NDEUnit == null) { row.AddError("检测单位不存在"); } } // 缺陷名称允许多个,用中英文逗号分隔,导入前转换为缺陷 ID 集合。 if (!string.IsNullOrEmpty(row.DefectNames)) { string[] names = row.DefectNames.Split(new[] { ',', ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string name in names.Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x))) { var defect = Funs.DB.Base_Defect.FirstOrDefault(x => x.DefectName == name); if (defect == null) { row.AddError("缺陷[" + name + "]不存在"); } else { row.DefectIds.Add(defect.DefectId.ToString()); } } } // 已存在的委托单必须与当前焊口所在单位工程和检测单位一致。 if (row.IsPoint == true && !string.IsNullOrEmpty(row.TrustBatchCode)) { var trust = Funs.DB.HJGL_Batch_BatchTrust.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.TrustBatchCode == row.TrustBatchCode); if (trust != null && row.Pipeline != null) { if (trust.UnitWorkId != row.Pipeline.UnitWorkId || trust.NDEUnit != row.NDEUnit?.UnitId) { row.AddError("委托单号已存在且单位工程或检测单位不一致"); } } } // 检测单号可复用,但复用时检测单位不能冲突。 if (row.IsPoint == true && !string.IsNullOrEmpty(row.NDECode)) { var nde = Funs.DB.HJGL_Batch_NDE.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.NDECode == row.NDECode); if (nde != null && row.NDEUnit != null && nde.NDEUnit != row.NDEUnit.UnitId) { row.AddError("检测单号已存在且检测单位不一致"); } } } private void ImportOneRow(ImportRow row) { var daily = GetOrCreateWeldingDaily(row); var weldJoint = Funs.DB.HJGL_WeldJoint.First(x => x.WeldJointId == row.Joint.WeldJointId); // 导入直接生成正式日报,同时把焊工、焊接位置等结果回填到焊口。 weldJoint.WeldingDailyId = daily.WeldingDailyId; weldJoint.WeldingDailyCode = daily.WeldingDailyCode; weldJoint.CoverWelderId = row.CoverWelder.PersonId; weldJoint.BackingWelderId = row.BackingWelder.PersonId; weldJoint.CoverWelderTeamGroupId = row.CoverWelder.TeamGroupId; weldJoint.BackingWelderTeamGroupId = row.BackingWelder.TeamGroupId; weldJoint.WeldingLocationId = row.WeldingLocation.WeldingLocationId; Funs.DB.SubmitChanges(); BLL.WeldJointService.UpdateWeldJointAddG(weldJoint.WeldJointId, weldJoint.JointAttribute, Const.BtnAdd); var batchC = BLL.Project_SysSetService.GetSysSetBySetId("5", this.CurrUser.LoginProjectId); if (batchC == null) { throw new Exception("请设置项目的组批条件"); } string batchErr = BLL.PointBatchService.AddBatchByWeldJointId(weldJoint.WeldJointId, row.WeldingDate, batchC.SetValue); if (!string.IsNullOrEmpty(batchErr)) { throw new Exception(batchErr); } BLL.HJGL_PipelineComponentjointService.UpdateStateByWeldJointId(weldJoint.WeldJointId, row.WeldingDate.Value); BLL.PipelineService.UpdataDateByWeldJointId(weldJoint.WeldJointId); // 点口行继续生成或复用委托、检测链路;非点口行到日报回填即结束。 if (row.IsPoint == true) { ImportPointTrustAndNDE(row, weldJoint); } } private Model.HJGL_WeldingDaily GetOrCreateWeldingDaily(ImportRow row) { var daily = Funs.DB.HJGL_WeldingDaily.FirstOrDefault(x => x.UnitWorkId == row.Joint.UnitWorkId && x.WeldingDate >= row.WeldingDate.Value.Date && x.WeldingDate < row.WeldingDate.Value.Date.AddDays(1)); if (daily != null) { return daily; } string personName = BLL.Person_PersonsService.GetPersonsNameById(this.CurrUser.PersonId); string perfix = string.Format("{0:yyyyMMdd}", row.WeldingDate.Value) + "-" + personName + "-"; daily = new Model.HJGL_WeldingDaily { WeldingDailyId = Guid.NewGuid().ToString(), WeldingDailyCode = BLL.SQLHelper.RunProcNewId("SpGetThreeNumber", "dbo.HJGL_WeldingDaily", "WeldingDailyCode", this.CurrUser.LoginProjectId, perfix), WeldingDate = row.WeldingDate.Value.Date, ProjectId = this.CurrUser.LoginProjectId, UnitWorkId = row.Joint.UnitWorkId, UnitId = row.Joint.UnitId, Tabler = this.CurrUser.PersonId, TableDate = DateTime.Now.Date, Remark = "焊接日报导入" }; BLL.WeldingDailyService.AddWeldingDaily(daily); return daily; } private void ImportPointTrustAndNDE(ImportRow row, Model.HJGL_WeldJoint weldJoint) { // 组批服务已按焊口生成点口批明细,这里只负责把点口状态推进到已点口。 var pointItem = Funs.DB.HJGL_Batch_PointBatchItem.FirstOrDefault(x => x.WeldJointId == weldJoint.WeldJointId); if (pointItem == null) { throw new Exception("焊口【" + row.WeldJointCode + "】未生成点口批明细"); } pointItem.PointState = "1"; pointItem.PointDate = DateTime.Now; Funs.DB.SubmitChanges(); var pointBatch = Funs.DB.HJGL_Batch_PointBatch.First(x => x.PointBatchId == pointItem.PointBatchId); var trust = GetOrCreateTrust(row, pointBatch); var trustItem = Funs.DB.HJGL_Batch_BatchTrustItem.FirstOrDefault(x => x.TrustBatchId == trust.TrustBatchId && x.WeldJointId == weldJoint.WeldJointId); // 同一委托单下同一焊口只保留一条委托明细,重复导入前已由日报校验拦截。 if (trustItem == null) { trustItem = new Model.HJGL_Batch_BatchTrustItem { TrustBatchItemId = SQLHelper.GetNewID(typeof(Model.HJGL_Batch_BatchTrustItem)), TrustBatchId = trust.TrustBatchId, PointBatchItemId = pointItem.PointBatchItemId, WeldJointId = weldJoint.WeldJointId, CreateDate = DateTime.Now }; Funs.DB.HJGL_Batch_BatchTrustItem.InsertOnSubmit(trustItem); } pointItem.IsBuildTrust = true; if (string.IsNullOrEmpty(trust.TopointBatch)) { trust.TopointBatch = pointBatch.PointBatchId; } else if (!trust.TopointBatch.Split(',').Contains(pointBatch.PointBatchId)) { trust.TopointBatch += "," + pointBatch.PointBatchId; } Funs.DB.SubmitChanges(); // 检测单号为空时只生成点口和委托信息,不创建检测结果。 if (!string.IsNullOrEmpty(row.NDECode)) { ImportNDE(row, trust, trustItem); } } private Model.HJGL_Batch_BatchTrust GetOrCreateTrust(ImportRow row, Model.HJGL_Batch_PointBatch pointBatch) { // 同项目内委托单号唯一,模板中相同委托单号应复用已有委托主表。 var trust = Funs.DB.HJGL_Batch_BatchTrust.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.TrustBatchCode == row.TrustBatchCode); if (trust != null) { return trust; } trust = new Model.HJGL_Batch_BatchTrust { TrustBatchId = SQLHelper.GetNewID(typeof(Model.HJGL_Batch_BatchTrust)), TrustBatchCode = row.TrustBatchCode, TrustDate = row.TrustDate, ProjectId = pointBatch.ProjectId, UnitId = pointBatch.UnitId, UnitWorkId = pointBatch.UnitWorkId, DetectionTypeId = pointBatch.DetectionTypeId, DetectionRateId = pointBatch.DetectionRateId, NDEUnit = row.NDEUnit.UnitId, PointBatchId = pointBatch.PointBatchId, TopointBatch = pointBatch.PointBatchId, IsAudit = true }; Funs.DB.HJGL_Batch_BatchTrust.InsertOnSubmit(trust); Funs.DB.SubmitChanges(); return trust; } private void ImportNDE(ImportRow row, Model.HJGL_Batch_BatchTrust trust, Model.HJGL_Batch_BatchTrustItem trustItem) { // 检测单主表按检测单号复用,明细按委托明细关联到具体焊口。 var nde = Funs.DB.HJGL_Batch_NDE.FirstOrDefault(x => x.ProjectId == this.CurrUser.LoginProjectId && x.NDECode == row.NDECode); if (nde == null) { nde = new Model.HJGL_Batch_NDE { NDEID = SQLHelper.GetNewID(typeof(Model.HJGL_Batch_NDE)), TrustBatchId = trust.TrustBatchId, ProjectId = trust.ProjectId, UnitId = trust.UnitId, UnitWorkId = trust.UnitWorkId, NDEUnit = row.NDEUnit.UnitId, NDECode = row.NDECode, NDEDate = row.NDEDate, AuditDate = row.ReportDate, NDEMan = this.CurrUser.PersonId }; Funs.DB.HJGL_Batch_NDE.InsertOnSubmit(nde); Funs.DB.SubmitChanges(); } var ndeItem = Funs.DB.HJGL_Batch_NDEItem.FirstOrDefault(x => x.TrustBatchItemId == trustItem.TrustBatchItemId); if (ndeItem == null) { ndeItem = new Model.HJGL_Batch_NDEItem { NDEItemID = SQLHelper.GetNewID(typeof(Model.HJGL_Batch_NDEItem)), NDEID = nde.NDEID, TrustBatchItemId = trustItem.TrustBatchItemId }; Funs.DB.HJGL_Batch_NDEItem.InsertOnSubmit(ndeItem); } ndeItem.DetectionTypeId = trust.DetectionTypeId; ndeItem.RequestDate = row.TrustDate; ndeItem.RepairLocation = row.RepairLocation; ndeItem.TotalFilm = row.TotalFilm; ndeItem.PassFilm = row.PassFilm; ndeItem.CheckResult = row.CheckResult; ndeItem.NDEReportNo = row.NDECode; ndeItem.FilmDate = row.NDEDate; ndeItem.ReportDate = row.ReportDate; ndeItem.SubmitDate = DateTime.Now; ndeItem.CheckDefects = row.DefectIds.Count > 0 ? string.Join(",", row.DefectIds) : null; ndeItem.JudgeGrade = row.JudgeGrade; Funs.DB.SubmitChanges(); } private void BindGrid(List rows) { Grid1.DataSource = rows; Grid1.DataBind(); } private string JoinErrors(List rows) { var errors = rows.Where(x => !string.IsNullOrEmpty(x.ErrorMessage)) .Select(x => "第" + x.RowIndex + "行:" + x.ErrorMessage); return string.Join("
", errors); } private string GetCell(DataRow row, string columnName) { // 模板列名可能带尾随空格,取值时统一 Trim 后按列名匹配。 DataColumn column = row.Table.Columns.Cast().FirstOrDefault(x => x.ColumnName.Trim() == columnName); if (column == null || row[column] == null) { return string.Empty; } return row[column].ToString().Trim(); } private bool IsEmptyRow(DataRow row) { return RequiredHeaders.All(x => string.IsNullOrEmpty(GetCell(row, x))); } private string GetValueByColumn(ImportRow row, string columnName) { switch (columnName) { case "管线号": return row.PipelineCode; case "焊口号": return row.WeldJointCode; case "盖面焊工": return row.CoverWelderCode; case "打底焊工": return row.BackingWelderCode; case "焊接日期": return row.WeldingDateText; case "焊接位置": return row.WeldingLocationCode; case "是否点口": return row.IsPointText; case "委托单号": return row.TrustBatchCode; case "委托日期": return row.TrustDateText; case "检测单位": return row.NDEUnitName; case "评定级别": return row.JudgeGrade; default: return string.Empty; } } private DateTime? ParseDate(string value, string columnName, ImportRow row, bool required = true) { if (string.IsNullOrEmpty(value)) { if (required) { row.AddError(columnName + "为必填项"); } return null; } DateTime? date = Funs.GetNewDateTime(value); if (date == null) { row.AddError(columnName + "格式错误"); } return date?.Date; } private int? ParseInt(string value, string columnName, ImportRow row, bool required = true) { if (string.IsNullOrEmpty(value)) { if (required) { row.AddError(columnName + "为必填项"); } return null; } int? result = Funs.GetNewInt(value); if (result == null) { row.AddError(columnName + "格式错误"); } return result; } private bool? ParseBoolean(string value, ImportRow row) { // 是否点口只接受明确布尔值,避免“是点口”的业务链路被模糊文本误触发。 if (value == "是" || value == "1" || value.Equals("true", StringComparison.OrdinalIgnoreCase)) { return true; } if (value == "否" || value == "0" || value.Equals("false", StringComparison.OrdinalIgnoreCase)) { return false; } row.AddError("是否点口格式错误"); return null; } private string ParseCheckResult(string value, ImportRow row) { if (string.IsNullOrEmpty(value)) { return null; } if (value == "合格") { return "1"; } if (value == "不合格") { return "2"; } row.AddError("是否合格格式错误"); return null; } private void ValidateJudgeGrade(ImportRow row) { string[] grades = { "Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ", "Ⅴ" }; if (!string.IsNullOrEmpty(row.JudgeGrade) && !grades.Contains(row.JudgeGrade)) { row.AddError("评定级别错误"); } } private class ImportRow { public int SerialNo { get; set; } public int RowIndex { get; set; } public string PipelineCode { get; set; } public string WeldJointCode { get; set; } public string CoverWelderCode { get; set; } public string BackingWelderCode { get; set; } public string WeldingDateText { get; set; } public string WeldingLocationCode { get; set; } public string IsPointText { get; set; } public string TrustBatchCode { get; set; } public string TrustDateText { get; set; } public string NDEUnitName { get; set; } public string NDECode { get; set; } public string NDEDateText { get; set; } public string ReportDateText { get; set; } public string TotalFilmText { get; set; } public string PassFilmText { get; set; } public string CheckResultText { get; set; } public string JudgeGrade { get; set; } public string DefectNames { get; set; } public string RepairLocation { get; set; } public DateTime? WeldingDate { get; set; } public DateTime? TrustDate { get; set; } public DateTime? NDEDate { get; set; } public DateTime? ReportDate { get; set; } public int? TotalFilm { get; set; } public int? PassFilm { get; set; } public bool? IsPoint { get; set; } public string CheckResult { get; set; } public Model.View_HJGL_WeldJoint Joint { get; set; } public Model.HJGL_Pipeline Pipeline { get; set; } public Model.SitePerson_Person CoverWelder { get; set; } public Model.SitePerson_Person BackingWelder { get; set; } public Model.Base_WeldingLocation WeldingLocation { get; set; } public Model.Base_Unit NDEUnit { get; set; } public List DefectIds { get; } = new List(); public string ErrorMessage { get; private set; } public void AddError(string error) { if (string.IsNullOrEmpty(ErrorMessage)) { ErrorMessage = error; } else { ErrorMessage += ";" + error; } } } } }