diff --git a/SGGL/BLL/CLGL/TwInOutplandetailRelationService.cs b/SGGL/BLL/CLGL/TwInOutplandetailRelationService.cs
index 7ce7ca5e..5f05d8c3 100644
--- a/SGGL/BLL/CLGL/TwInOutplandetailRelationService.cs
+++ b/SGGL/BLL/CLGL/TwInOutplandetailRelationService.cs
@@ -102,6 +102,7 @@ namespace BLL
MaterialCode = newtable.MaterialCode,
PrefabricatedComponents = newtable.PrefabricatedComponents,
Number = newtable.Number,
+ // 领料出库由焊接任务单焊口驱动,关联明细需要保存焊口ID用于后续追溯。
WeldJointId = newtable.WeldJointId,
};
Funs.DB.Tw_InOutPlanDetail_Relation.InsertOnSubmit(table);
@@ -134,6 +135,7 @@ namespace BLL
table.MaterialCode = newtable.MaterialCode;
table.PrefabricatedComponents = newtable.PrefabricatedComponents;
table.Number = newtable.Number;
+ // 更新关联明细时同步维护焊口ID,避免出库申请修改后丢失焊口归属。
table.WeldJointId = newtable.WeldJointId;
Funs.DB.SubmitChanges();
}
diff --git a/SGGL/BLL/CLGL/TwInOutplanmasterService.cs b/SGGL/BLL/CLGL/TwInOutplanmasterService.cs
index 539252f2..0a610bb6 100644
--- a/SGGL/BLL/CLGL/TwInOutplanmasterService.cs
+++ b/SGGL/BLL/CLGL/TwInOutplanmasterService.cs
@@ -992,7 +992,8 @@ namespace BLL
.Select(e => e.WeldJointId)
.Distinct()
.ToList();
- //领料出库需要排除散件材料
+ // 领料出库按当前任务单焊口取料,避免同一管线其他未下任务单焊口的材料被带出。
+ // 这里只取已反写 MaterialCode 的材料;未匹配主编码的材料无法生成库存出库明细。
var allMaterDatial = (from x in db.HJGL_PipeLineMat
join y in db.HJGL_MaterialCodeLib on x.MaterialCode equals y.MaterialCode
where pipelineList.Contains(x.PipelineId)
@@ -1063,6 +1064,7 @@ namespace BLL
};
TwInOutplandetailService.Add(detail);
}
+ // 管件申请单只保存单位为“个”的材料关联,并同步记录焊口ID,便于追溯出库材料归属。
var twinoutplandetailRelationList = MaterDatial.Where(x => x.MaterialUnit.Contains("个")).Select(x => new Tw_InOutPlanDetail_Relation
{
PipelineId = x.PipelineId,
@@ -1103,6 +1105,7 @@ namespace BLL
};
TwInOutplandetailService.Add(detail);
}
+ // 管段申请单只保存单位为“米”的材料关联,并同步记录焊口ID,避免关联明细跨单据混写。
var twinoutplandetailRelationList = MaterDatial.Where(x => x.MaterialUnit.Contains("米")).Select(x => new Tw_InOutPlanDetail_Relation
{
PipelineId = x.PipelineId,
diff --git a/SGGL/FineUIPro.Web/File/Excel/DataIn/焊接日报导入模板.xlsx b/SGGL/FineUIPro.Web/File/Excel/DataIn/焊接日报导入模板.xlsx
new file mode 100644
index 00000000..580097e0
Binary files /dev/null and b/SGGL/FineUIPro.Web/File/Excel/DataIn/焊接日报导入模板.xlsx differ
diff --git a/SGGL/FineUIPro.Web/FineUIPro.Web.csproj b/SGGL/FineUIPro.Web/FineUIPro.Web.csproj
index dd0f9e5d..29e8444e 100644
--- a/SGGL/FineUIPro.Web/FineUIPro.Web.csproj
+++ b/SGGL/FineUIPro.Web/FineUIPro.Web.csproj
@@ -1699,6 +1699,7 @@
+
@@ -11413,6 +11414,13 @@
WeldingPlanIn.aspx
+
+ WeldReportIn.aspx
+ ASPXCodeBehind
+
+
+ WeldReportIn.aspx
+
WeldJointBatchEdit.aspx
ASPXCodeBehind
@@ -17182,7 +17190,7 @@
-
+
@@ -17208,4 +17216,4 @@
-->
-
\ No newline at end of file
+
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldMatMatch.aspx.cs b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldMatMatch.aspx.cs
index b188911d..a3b0c7c2 100644
--- a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldMatMatch.aspx.cs
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldMatMatch.aspx.cs
@@ -405,6 +405,10 @@ namespace FineUIPro.Web.HJGL.WeldingManage
Grid1.DataSource = dt;
Grid1.DataBind();
}
+ ///
+ /// 绑定管线匹配汇总。重新匹配会刷新 Grid2,需要把用户原来勾选的管线恢复回来。
+ ///
+ /// 需要保留选中状态的管线ID
void BindGrid2(IEnumerable keepSelectedPipelineIds = null)
{
//var result = tw_PipeMatMatchOutputs
@@ -435,6 +439,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
Rate = Math.Round((decimal)output.Average(item => item.MatchRate) * 100, 2);
lbRate.Text = "匹配率:" + Rate.ToString() + "%";
}*/
+ // “优先匹配选中焊口”会重新计算匹配结果,重新绑定后要继续保留原管线选中状态。
var keepSelectedList = keepSelectedPipelineIds == null ? new List() : keepSelectedPipelineIds.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
var selectList = new List();
for (int i = 0; i < Grid2.Rows.Count; i++)
@@ -503,6 +508,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
private void BindMaterialDetail(string pipelineId)
{
+ // 任务单只允许从未生成任务单的焊口材料中选择,避免重复生成焊接任务。
var tb = GetNoTaskMaterialDetails()
.Where(x => x.PipelineId == pipelineId)
.ToList();
@@ -532,6 +538,9 @@ namespace FineUIPro.Web.HJGL.WeldingManage
Grid1.SelectedRowIDArray = selectList.ToArray();
}
+ ///
+ /// 获取还没有生成焊接任务单的材料匹配明细。
+ ///
private List GetNoTaskMaterialDetails()
{
var matchOutputs = tw_PipeMatMatchOutputs ?? new List();
@@ -545,6 +554,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
return matchOutputs;
}
+ // HJGL_WeldTask 已存在的焊口不再显示到待生成任务单的材料明细里。
var taskWeldJointIds = Funs.DB.HJGL_WeldTask
.Where(x => weldJointIds.Contains(x.WeldJointId))
.Select(x => x.WeldJointId)
@@ -572,6 +582,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
private void RefreshMatchResult()
{
+ // 重新匹配库存会刷新管线汇总表,先暂存选择状态,绑定完成后再恢复。
var keepSelectedPipelineIds = Grid2.SelectedRowIDArray == null ? new List() : Grid2.SelectedRowIDArray.ToList();
tw_PipeMatMatchOutputs = TwArrivalStatisticsService.GetPipeMatMatch(
this.CurrUser.LoginProjectId,
@@ -756,6 +767,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
return;
}
+ // 页面上的焊口选择来自 Grid1 材料明细;Grid3 是左侧已加入匹配的管线列表。
var selectedWeldJoints = new HashSet();
foreach (int rowIndex in Grid1.SelectedRowIndexArray)
{
@@ -781,6 +793,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
priorityWeldJoints.Remove(selectedPipelineId);
}
+ // 优先焊口会触发重新匹配,当前管线也必须继续保持选中,方便后续生成任务单。
var keepSelectedPipelineIds = Grid2.SelectedRowIDArray == null ? new List() : Grid2.SelectedRowIDArray.ToList();
if (!keepSelectedPipelineIds.Contains(selectedPipelineId))
{
@@ -865,6 +878,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
var weldingRods = from x in Funs.DB.Base_Consumables where x.ConsumablesType == "2" select x;
var weldingWires = from x in Funs.DB.Base_Consumables where x.ConsumablesType == "1" select x;
var selectedWeldJointIdList = selectedWeldJointIds.ToList();
+ // 任务单按用户在材料匹配明细中勾选的焊口生成,不再按整条管线生成。
var selectRowId = (from x in Funs.DB.View_HJGL_NoWeldJointFind
where selectedWeldJointIdList.Contains(x.WeldJointId) && x.WeldingDailyId == null &&
x.WeldTaskId == null && x.WeldingMethodCode != null
@@ -873,6 +887,7 @@ namespace FineUIPro.Web.HJGL.WeldingManage
Dictionary unitworkTaskCode = new Dictionary();
Dictionary unitworkSerialNumber = new Dictionary();
Dictionary matchPipeline = new Dictionary();
+ // 生成任务单仍保留管线在匹配结果中的排序,用于任务单列表按管线顺序展示。
for (int rowIndex = 0; rowIndex < Grid2.Rows.Count; rowIndex++)
{
matchPipeline.Add(rowIndex + 1, Grid2.Rows[rowIndex].RowID);
@@ -996,6 +1011,9 @@ namespace FineUIPro.Web.HJGL.WeldingManage
return true;
}
+ ///
+ /// 从材料匹配明细 Grid1 中提取用户选中的焊口ID。
+ ///
private HashSet GetSelectedWeldJointIdsFromGrid1()
{
var selectedWeldJointIds = new HashSet();
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx
index 7653e2cb..fac609da 100644
--- a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx
@@ -298,6 +298,9 @@
+
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.cs b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.cs
index 4f99ed04..269c9052 100644
--- a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.cs
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.cs
@@ -481,6 +481,21 @@ namespace FineUIPro.Web.HJGL.WeldingManage
}
}
+ ///
+ /// 焊接日报导入
+ ///
+ protected void btnMenuImport_Click(object sender, EventArgs e)
+ {
+ if (CommonService.GetAllButtonPowerList(this.CurrUser.LoginProjectId, this.CurrUser.PersonId, Const.HJGL_WeldReportMenuId, Const.BtnAdd))
+ {
+ PageContext.RegisterStartupScript(Window1.GetShowReference("WeldReportIn.aspx", "导入焊接日报"));
+ }
+ else
+ {
+ ShowNotify("您没有这个权限,请与管理员联系!", MessageBoxIcon.Warning);
+ }
+ }
+
///
/// 删除按钮
///
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.designer.cs b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.designer.cs
index ba616267..d8bee4a9 100644
--- a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.designer.cs
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReport.aspx.designer.cs
@@ -380,6 +380,15 @@ namespace FineUIPro.Web.HJGL.WeldingManage {
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
///
protected global::FineUIPro.MenuButton btnMenuEdit;
+
+ ///
+ /// btnMenuImport 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.MenuButton btnMenuImport;
///
/// btnMenuOut 控件。
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx
new file mode 100644
index 00000000..45cad033
--- /dev/null
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx
@@ -0,0 +1,93 @@
+<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WeldReportIn.aspx.cs" Inherits="FineUIPro.Web.HJGL.WeldingManage.WeldReportIn" %>
+
+
+
+
+
+
+ 焊接日报导入
+
+
+
+
+
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx.cs b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx.cs
new file mode 100644
index 00000000..feecd54f
--- /dev/null
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx.cs
@@ -0,0 +1,745 @@
+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;
+ }
+ }
+ }
+ }
+}
diff --git a/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx.designer.cs b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx.designer.cs
new file mode 100644
index 00000000..6fdcd3b3
--- /dev/null
+++ b/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldReportIn.aspx.designer.cs
@@ -0,0 +1,116 @@
+//------------------------------------------------------------------------------
+// <自动生成>
+// 此代码由工具生成。
+//
+// 对此文件的更改可能导致不正确的行为,如果
+// 重新生成代码,则所做更改将丢失。
+// 自动生成>
+//------------------------------------------------------------------------------
+
+namespace FineUIPro.Web.HJGL.WeldingManage
+{
+
+
+ public partial class WeldReportIn
+ {
+
+ ///
+ /// form1 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::System.Web.UI.HtmlControls.HtmlForm form1;
+
+ ///
+ /// PageManager1 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.PageManager PageManager1;
+
+ ///
+ /// SimpleForm1 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Form SimpleForm1;
+
+ ///
+ /// Toolbar2 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Toolbar Toolbar2;
+
+ ///
+ /// hdFileName 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.HiddenField hdFileName;
+
+ ///
+ /// btnDownLoad 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Button btnDownLoad;
+
+ ///
+ /// btnAudit 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Button btnAudit;
+
+ ///
+ /// btnImport 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Button btnImport;
+
+ ///
+ /// fuAttachUrl 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.FileUpload fuAttachUrl;
+
+ ///
+ /// lblBottom 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Label lblBottom;
+
+ ///
+ /// Grid1 控件。
+ ///
+ ///
+ /// 自动生成的字段。
+ /// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
+ ///
+ protected global::FineUIPro.Grid Grid1;
+ }
+}