using BLL; using MiniExcelLibs; using Model; using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Web; namespace FineUIPro.Web.HJGL.NDT { public partial class NDTBatchUnitImport : PageBase { private static readonly string[] TemplateColumns = { "序号", "委托编号", "管线号", "检件焊口号", "焊工号", "检测总数", "合格数", "是否合格", "评定级别", "缺陷", "返修位置", "备注", "检测日期", "报告日期" }; private string UnitWorkId { get { return Convert.ToString(ViewState["UnitWorkId"]); } set { ViewState["UnitWorkId"] = value; } } private string NDTType { get { return Convert.ToString(ViewState["NDTType"]); } set { ViewState["NDTType"] = value; } } private string ImportCacheKey { get { return Convert.ToString(ViewState["ImportCacheKey"]); } set { ViewState["ImportCacheKey"] = value; } } private List ImportItems { get { return Session[ImportCacheKey] as List ?? new List(); } set { Session[ImportCacheKey] = value; } } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { UnitWorkId = Request.QueryString["unitWorkId"]; NDTType = Request.QueryString["type"]; ImportCacheKey = "NDTBatchUnitImport_" + Guid.NewGuid().ToString("N"); ImportItems = new List(); WBS_UnitWork unitWork = Funs.DB.WBS_UnitWork.FirstOrDefault(x => x.UnitWorkId == UnitWorkId && x.ProjectId == CurrUser.LoginProjectId && x.SuperUnitWork == null); if (unitWork == null) { btnAudit.Enabled = false; btnSave.Enabled = false; btnDownLoad.Enabled = false; ShowNotify("单位工程不存在或不属于当前项目!", MessageBoxIcon.Warning); return; } lblUnitWork.Text = unitWork.UnitWorkCode + " " + unitWork.UnitWorkName; BindGrid(); } } protected void btnDownLoad_Click(object sender, EventArgs e) { string templatePath = Server.MapPath("~/" + Const.NDTBatchUnitImportTemplateUrl.Replace("\\", "/")); if (!File.Exists(templatePath)) { ShowNotify("检测结果导入模板不存在,请联系管理员!", MessageBoxIcon.Error); return; } FileInfo info = new FileInfo(templatePath); Response.ClearContent(); Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode("检测结果导入模板.xlsx", System.Text.Encoding.UTF8)); Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; Response.ContentEncoding = System.Text.Encoding.UTF8; Response.AddHeader("Content-Length", info.Length.ToString()); Response.TransmitFile(templatePath, 0, info.Length); Response.Flush(); Response.Close(); } protected void btnAudit_Click(object sender, EventArgs e) { if (!fuAttachUrl.HasFile) { ShowNotify("请选择要导入的 Excel 文件!", MessageBoxIcon.Warning); return; } string extension = Path.GetExtension(fuAttachUrl.FileName).ToLowerInvariant(); if (extension != ".xlsx") { ShowNotify("只能导入 .xlsx 文件!", MessageBoxIcon.Warning); return; } string rootPath = Server.MapPath("~/"); string uploadDirectory = Path.Combine(rootPath, Const.ExcelUrl); if (!Directory.Exists(uploadDirectory)) { Directory.CreateDirectory(uploadDirectory); } string filePath = Path.Combine(uploadDirectory, Funs.GetNewFileName() + extension); try { fuAttachUrl.PostedFile.SaveAs(filePath); DataTable table = MiniExcel.QueryAsDataTable(filePath, useHeaderRow: true); List errors; List importItems = ParseImportItems(table, out errors); if (errors.Count > 0) { ImportItems = new List(); BindGrid(); ShowErrors(errors); return; } ImportItems = importItems; BindGrid(); ShowNotify("审核完成,共 " + importItems.Count + " 条,请确认后提交导入!", MessageBoxIcon.Success); } catch (Exception ex) { ImportItems = new List(); BindGrid(); ShowNotify("读取导入文件失败:" + ex.Message, MessageBoxIcon.Error); } finally { if (File.Exists(filePath)) { File.Delete(filePath); } } } protected void btnSave_Click(object sender, EventArgs e) { if (!CommonService.GetAllButtonPowerList(CurrUser.LoginProjectId, CurrUser.PersonId, Const.HJGL_NDTBatchMenuId, Const.BtnSave)) { ShowNotify("您没有这个权限,请与管理员联系!", MessageBoxIcon.Warning); return; } List importItems = ImportItems; if (importItems.Count == 0) { ShowNotify("请先审核要导入的文件!", MessageBoxIcon.Warning); return; } try { Batch_NDEImportService.Import(CurrUser.LoginProjectId, UnitWorkId, CurrUser.PersonId, importItems); Session.Remove(ImportCacheKey); ShowNotify("成功导入 " + importItems.Count + " 条检测结果!", MessageBoxIcon.Success); PageContext.RegisterStartupScript(ActiveWindow.GetHidePostBackReference()); } catch (Exception ex) { ShowNotify("导入失败:" + ex.Message, MessageBoxIcon.Error); } } protected void Grid1_PageIndexChange(object sender, GridPageEventArgs e) { Grid1.PageIndex = e.NewPageIndex; BindGrid(); } private List ParseImportItems(DataTable table, out List errors) { errors = new List(); List result = new List(); if (table == null || table.Rows.Count == 0) { errors.Add("导入数据为空!"); return result; } List missingColumns = TemplateColumns.Where(x => !table.Columns.Contains(x)).ToList(); if (missingColumns.Count > 0) { errors.Add("导入 Excel 格式错误,缺少列:" + string.Join("、", missingColumns)); return result; } List trustItems = GetUnitWorkTrustItems(); Dictionary trustMap = Funs.DB.View_Batch_BatchTrust .Where(x => x.ProjectId == CurrUser.LoginProjectId && x.UnitWorkId == UnitWorkId) .ToList() .Where(IsCurrentNDTType) .GroupBy(x => Normalize(x.TrustBatchCode)) .ToDictionary(x => x.Key, x => x.First()); HashSet importedTrustBatchIds = new HashSet(Funs.DB.HJGL_Batch_NDE .Where(x => x.ProjectId == CurrUser.LoginProjectId && x.UnitWorkId == UnitWorkId) .Select(x => x.TrustBatchId) .ToList()); Dictionary defectMap = Funs.DB.Base_Defect .ToList() .GroupBy(x => Normalize(x.DefectName)) .ToDictionary(x => x.Key, x => x.First()); HashSet rowKeys = new HashSet(StringComparer.OrdinalIgnoreCase); for (int index = 0; index < table.Rows.Count; index++) { DataRow row = table.Rows[index]; int excelRowNumber = index + 2; string trustBatchCode = GetCellValue(row, "委托编号"); string pipelineCode = GetCellValue(row, "管线号"); string weldJointCode = GetCellValue(row, "检件焊口号"); string totalFilmText = GetCellValue(row, "检测总数"); string passFilmText = GetCellValue(row, "合格数"); string filmDateText = GetCellValue(row, "检测日期"); string reportDateText = GetCellValue(row, "报告日期"); if (string.IsNullOrEmpty(trustBatchCode) && string.IsNullOrEmpty(pipelineCode) && string.IsNullOrEmpty(weldJointCode) && string.IsNullOrEmpty(totalFilmText) && string.IsNullOrEmpty(passFilmText) && string.IsNullOrEmpty(filmDateText) && string.IsNullOrEmpty(reportDateText)) { continue; } int errorCount = errors.Count; int sequence = index + 1; string sequenceText = GetCellValue(row, "序号"); if (!string.IsNullOrEmpty(sequenceText) && (!int.TryParse(sequenceText, out sequence) || sequence <= 0)) { errors.Add("第" + excelRowNumber + "行:序号必须为大于 0 的整数"); } View_Batch_BatchTrust trust = null; if (string.IsNullOrEmpty(trustBatchCode) || !trustMap.TryGetValue(Normalize(trustBatchCode), out trust)) { errors.Add("第" + excelRowNumber + "行:委托编号[" + trustBatchCode + "]不属于当前单位工程"); } else if (importedTrustBatchIds.Contains(trust.TrustBatchId)) { errors.Add("第" + excelRowNumber + "行:委托编号[" + trustBatchCode + "]已存在检测结果,不能重复导入"); } View_Batch_BatchTrustItem trustItem = null; if (trust != null) { trustItem = trustItems.FirstOrDefault(x => x.TrustBatchId == trust.TrustBatchId && Normalize(x.PipelineCode) == Normalize(pipelineCode) && Normalize(x.WeldJointCode) == Normalize(weldJointCode)); if (trustItem == null) { errors.Add("第" + excelRowNumber + "行:管线[" + pipelineCode + "]焊口[" + weldJointCode + "]不存在于该委托单"); } } string welderCode = GetCellValue(row, "焊工号"); if (trustItem != null && !string.IsNullOrEmpty(welderCode) && Normalize(trustItem.WelderCode) != Normalize(welderCode)) { errors.Add("第" + excelRowNumber + "行:焊工号[" + welderCode + "]与委托明细不一致"); } int totalFilm; if (!int.TryParse(totalFilmText, out totalFilm) || totalFilm <= 0) { errors.Add("第" + excelRowNumber + "行:检测总数必须为大于 0 的整数"); } int passFilm; if (!int.TryParse(passFilmText, out passFilm) || passFilm < 0) { errors.Add("第" + excelRowNumber + "行:合格数必须为不小于 0 的整数"); } else if (totalFilm > 0 && passFilm > totalFilm) { errors.Add("第" + excelRowNumber + "行:合格数不能大于检测总数"); } string checkResultText = GetCellValue(row, "是否合格"); string checkResult = ConvertCheckResult(checkResultText); if (string.IsNullOrEmpty(checkResult)) { errors.Add("第" + excelRowNumber + "行:是否合格只能填写“合格”或“不合格”"); } string judgeGrade = ConvertJudgeGrade(GetCellValue(row, "评定级别")); if (judgeGrade == null) { errors.Add("第" + excelRowNumber + "行:评定级别只能填写Ⅰ、Ⅱ、Ⅲ、Ⅳ、Ⅴ或1-5"); } string defectText = GetCellValue(row, "缺陷"); List defectIds = new List(); if (!string.IsNullOrEmpty(defectText)) { foreach (string defectName in SplitDefects(defectText)) { Base_Defect defect; if (!defectMap.TryGetValue(Normalize(defectName), out defect)) { errors.Add("第" + excelRowNumber + "行:缺陷[" + defectName + "]不存在"); } else { defectIds.Add(Convert.ToString(defect.DefectId)); } } } string rowKey = Normalize(trustBatchCode) + "|" + Normalize(pipelineCode) + "|" + Normalize(weldJointCode); if (!rowKeys.Add(rowKey)) { errors.Add("第" + excelRowNumber + "行:同一委托、管线和焊口在文件中重复"); } // 两个日期均为非必填列;兼容 Excel 日期单元格、序列值和常见日期文本。 DateTime? filmDate = ParseOptionalDate(row, "检测日期", excelRowNumber, errors); DateTime? reportDate = ParseOptionalDate(row, "报告日期", excelRowNumber, errors); if (errors.Count == errorCount && trust != null && trustItem != null) { result.Add(new UnitWorkNDEImportItem { RowNumber = sequence, TrustBatchId = trust.TrustBatchId, TrustBatchCode = trust.TrustBatchCode, TrustBatchItemId = trustItem.TrustBatchItemId, PipelineCode = trustItem.PipelineCode, WeldJointCode = trustItem.WeldJointCode, WelderCode = trustItem.WelderCode, TotalFilm = totalFilm, PassFilm = passFilm, CheckResult = checkResult, CheckResultText = checkResultText == "是" ? "合格" : checkResultText == "否" ? "不合格" : checkResultText, JudgeGrade = judgeGrade, CheckDefects = string.Join(",", defectIds.Distinct()), CheckDefectsText = defectText, RepairLocation = GetCellValue(row, "返修位置"), Remark = GetCellValue(row, "备注"), FilmDate = filmDate, ReportDate = reportDate }); } } if (result.Count == 0 && errors.Count == 0) { errors.Add("导入数据为空!"); } return result; } private List GetUnitWorkTrustItems() { return Funs.DB.View_Batch_BatchTrustItem .Where(x => x.ProjectId == CurrUser.LoginProjectId && x.UnitWorkId == UnitWorkId && x.PipelineCode !=null) .ToList() .Where(IsCurrentNDTType) .ToList(); } private bool IsCurrentNDTType(View_Batch_BatchTrustItem item) { return NDTType == "R" ? item.TrustType == "R" : string.IsNullOrEmpty(item.TrustType); } private bool IsCurrentNDTType(View_Batch_BatchTrust item) { return NDTType == "R" ? item.TrustType == "R" : string.IsNullOrEmpty(item.TrustType); } private void BindGrid() { List items = ImportItems; Grid1.RecordCount = items.Count; Grid1.DataSource = items.Skip(Grid1.PageIndex * Grid1.PageSize).Take(Grid1.PageSize).ToList(); Grid1.DataBind(); } private void ShowErrors(IEnumerable errors) { Alert alert = new Alert { Message = string.Join("
", errors.Distinct().Select(HttpUtility.HtmlEncode)), Target = Target.Self }; alert.Show(); } private static string GetCellValue(DataRow row, string columnName) { return Convert.ToString(row[columnName]).Replace("\n", "").Replace("\t", "").Replace("\r", "").Trim(); } private static DateTime? ParseOptionalDate(DataRow row, string columnName, int excelRowNumber, ICollection errors) { object rawValue = row[columnName]; string value = Convert.ToString(rawValue).Trim(); if (rawValue == null || rawValue == DBNull.Value || string.IsNullOrEmpty(value)) { return null; } if (rawValue is DateTime) { return ((DateTime)rawValue).Date; } double oaDate; if (double.TryParse(value, out oaDate)) { try { return DateTime.FromOADate(oaDate).Date; } catch (ArgumentException) { // 无效序列值继续按日期文本处理,最终给出统一提示。 } } DateTime date; if (DateTime.TryParse(value, out date)) { return date.Date; } errors.Add("第" + excelRowNumber + "行:" + columnName + "格式错误,应填写有效日期"); return null; } private static string Normalize(string value) { return (value ?? string.Empty).Replace(" ", string.Empty).Trim().ToUpperInvariant(); } private static string ConvertCheckResult(string value) { if (value == "合格" || value == "是") { return "1"; } if (value == "不合格" || value == "否") { return "2"; } return string.Empty; } private static string ConvertJudgeGrade(string value) { switch (value) { case "": return string.Empty; case "Ⅰ": case "1": return "Ⅰ"; case "Ⅱ": case "2": return "Ⅱ"; case "Ⅲ": case "3": return "Ⅲ"; case "Ⅳ": case "4": return "Ⅳ"; case "Ⅴ": case "5": return "Ⅴ"; default: return null; } } private static IEnumerable SplitDefects(string value) { return value.Split(new[] { ',', ',', '、', ';', ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !string.IsNullOrEmpty(x)); } } }