Files
SGGL_SHJ/SGGL/FineUIPro.Web/HJGL/WeldingManage/WeldMatMatch.aspx.cs
T
lpf bb6615ebb0 feat(hjgl): 完善焊前检查和防腐检查流程
焊前检查需要同时覆盖下料、组对和防腐检查,并支持移动端查询与保存。
扩展焊前检查模型、服务和页面字段,补充检查结果、不合格原因、整改要求、
附件和防腐检查记录,便于按焊口和材料追溯检查过程。
2026-07-07 10:40:21 +08:00

1217 lines
53 KiB
C#

using BLL;
using FineUIPro.Web.DataShow;
using Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
namespace FineUIPro.Web.HJGL.WeldingManage
{
public partial class WeldMatMatch : PageBase
{
public int pageSize = PipelineService.pageSize;
public string WarehouseId
{
get
{
return (string)ViewState["WarehouseId"];
}
set
{
ViewState["WarehouseId"] = value;
}
}
public string PipeArea
{
get
{
return (string)ViewState["PipeArea"];
}
set
{
ViewState["PipeArea"] = value;
}
}
public Dictionary<string, string> dicSeclectPipeLine
{
get
{
return (Dictionary<string, string>)ViewState["dicSeclectPipeLine"];
}
set
{
ViewState["dicSeclectPipeLine"] = value;
}
}
public List<Model.Tw_PipeMatMatchOutput> tw_PipeMatMatchOutputs
{
get
{
return (List<Model.Tw_PipeMatMatchOutput>)ViewState["tw_PipeMatMatchOutputs"];
}
set
{
ViewState["tw_PipeMatMatchOutputs"] = value;
}
}
public Dictionary<string, HashSet<string>> priorityWeldJoints
{
get
{
var value = ViewState["priorityWeldJoints"] as Dictionary<string, HashSet<string>>;
if (value == null)
{
value = new Dictionary<string, HashSet<string>>();
ViewState["priorityWeldJoints"] = value;
}
return value;
}
set
{
ViewState["priorityWeldJoints"] = value;
}
}
/// <summary>
/// 页面首次加载时初始化仓库、流水段、匹配状态和左侧WBS管线树。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void Page_Load(object sender, EventArgs e)
{
//ctlAuditFlow.Url = BLL.Project_SysSetService.GetAvevaNetUrl(this.CurrUser.LoginProjectId);
if (!IsPostBack)
{
tw_PipeMatMatchOutputs = new List<Model.Tw_PipeMatMatchOutput>();
PipeArea = Request.Params["PipeArea"];
drpWarehouse.DataTextField = "Key";
drpWarehouse.DataValueField = "Value";
drpWarehouse.DataSource = BLL.TwInOutplanmasterService.GetWarehouseCode(this.CurrUser.LoginProjectId);
drpWarehouse.DataBind();
drpWarehouse_SelectedIndexChanged(null, null);
HJGL_MaterialService.materialStockItems_FIELD = new List<Model.MaterialStockItem>();
HJGL_MaterialService.materialStockItems_SHOP = new List<Model.MaterialStockItem>();
dicSeclectPipeLine = new Dictionary<string, string>();
priorityWeldJoints = new Dictionary<string, HashSet<string>>();
var pipeline = (from x in Funs.DB.HJGL_Pipeline
where x.ProjectId == this.CurrUser.LoginProjectId
select x.FlowingSection).Distinct().ToList();
this.drpFlowingSection.DataTextField = "Value";
this.drpFlowingSection.DataValueField = "Value";
this.drpFlowingSection.DataSource = pipeline;
this.drpFlowingSection.DataBind();
Funs.FineUIPleaseSelect(drpFlowingSection);
this.InitTreeMenu();//加载树
}
}
#region --
/// <summary>
/// 加载树
/// </summary>
private void InitTreeMenu()
{
this.tvControlItem.Nodes.Clear();
TreeNode rootNode1 = new TreeNode();
rootNode1.NodeID = "1";
rootNode1.Text = "建筑工程";
rootNode1.CommandName = "建筑工程";
rootNode1.Selectable = false;
rootNode1.EnableCheckBox = false;
this.tvControlItem.Nodes.Add(rootNode1);
TreeNode rootNode2 = new TreeNode();
rootNode2.NodeID = "2";
rootNode2.Text = "安装工程";
rootNode2.CommandName = "安装工程";
rootNode2.Expanded = true;
rootNode2.EnableCheckBox = false;
this.tvControlItem.Nodes.Add(rootNode2);
var unitWorkList = (from x in Funs.DB.WBS_UnitWork
where x.ProjectId == this.CurrUser.LoginProjectId
&& x.SuperUnitWork == null && x.UnitId != null && x.ProjectType != null
select x).ToList();
List<Model.WBS_UnitWork> unitWork1 = null;
List<Model.WBS_UnitWork> unitWork2 = null;
unitWork1 = (from x in unitWorkList where x.ProjectType == "1" select x).ToList();
unitWork2 = (from x in unitWorkList where x.ProjectType == "2" select x).ToList();
if (unitWork1.Count() > 0)
{
foreach (var q in unitWork1)
{
int a = GetUnitWorkTestPackagePipelineCount(q.UnitWorkId);
var unitNamesUnitIds = BLL.UnitService.getUnitNamesUnitIds(q.UnitId);
TreeNode tn1 = new TreeNode();
tn1.NodeID = q.UnitWorkId;
tn1.Text = q.UnitWorkName + "【" + a.ToString() + "】" + "管线";
tn1.ToolTip = "施工单位:" + unitNamesUnitIds;
tn1.CommandName = "单位工程";
tn1.EnableExpandEvent = true;
tn1.EnableClickEvent = true;
tn1.EnableCheckBox = false;
rootNode1.Nodes.Add(tn1);
if (a > 0)
{
BindTestPackageNodes(tn1);
}
}
}
if (unitWork2.Count() > 0)
{
foreach (var q in unitWork2)
{
int a = GetUnitWorkTestPackagePipelineCount(q.UnitWorkId);
var unitNamesUnitIds = BLL.UnitService.getUnitNamesUnitIds(q.UnitId);
TreeNode tn2 = new TreeNode();
tn2.NodeID = q.UnitWorkId;
tn2.Text = q.UnitWorkName + "【" + a.ToString() + "】" + "管线";
if (q.UnitWorkId == this.hdUnitWorkId.Text)
{
tn2.Expanded = true;
}
tn2.ToolTip = "施工单位:" + unitNamesUnitIds;
tn2.CommandName = "单位工程";
tn2.EnableExpandEvent = true;
tn2.EnableClickEvent = true;
tn2.EnableCheckBox = false;
rootNode2.Nodes.Add(tn2);
if (a > 0)
{
BindTestPackageNodes(tn2);
}
}
}
}
/// <summary>
/// 按分页方式向试压包节点追加管线子节点。
/// </summary>
/// <param name="node">需要加载管线的试压包树节点。</param>
private void BindNodes(TreeNode node)
{
var pipeline = GetTestPackagePipelineList(node.NodeID);
if (!node.Text.Contains("|"))
{
node.Text += "|" + pipeline.Count();
}
int pageindex = int.Parse(node.CommandName.Split('|')[0]);
int pageCount = int.Parse(node.CommandName.Split('|')[1]);
if (pageindex <= pageCount)
{
pipeline = pipeline.Skip(pageSize * (pageindex - 1)).Take(pageSize).ToList();
foreach (var item in pipeline)
{
TreeNode newNode = new TreeNode();
newNode.Text = item.PipelineCode;
newNode.NodeID = item.PipelineId;
newNode.CommandName = "管线";
newNode.EnableClickEvent = true;
node.Nodes.Add(newNode);
}
if (pageindex < pageCount)
{
TreeNode newNode = new TreeNode();
newNode.Text = "加载";
newNode.NodeID = SQLHelper.GetNewID();
newNode.CommandName = "加载";
newNode.Icon = Icon.ArrowDown;
newNode.EnableClickEvent = true;
node.Nodes.Add(newNode);
}
}
}
/// <summary>
/// 统计单位工程下各试压包可参与材料匹配的管线数量。
/// </summary>
/// <param name="unitWorkId">单位工程ID。</param>
/// <returns>可参与材料匹配的管线数量。</returns>
private int GetUnitWorkTestPackagePipelineCount(string unitWorkId)
{
var testPackageIds = (from x in Funs.DB.PTP_TestPackage
where x.ProjectId == this.CurrUser.LoginProjectId && x.UnitWorkId == unitWorkId
select x.PTP_ID).ToList();
return testPackageIds.Select(x => GetTestPackagePipelineList(x).Count()).Sum();
}
/// <summary>
/// 为单位工程节点绑定包含管线的试压包节点。
/// </summary>
/// <param name="unitWorkNode">单位工程树节点。</param>
private void BindTestPackageNodes(TreeNode unitWorkNode)
{
var testPackages = (from x in Funs.DB.PTP_TestPackage
where x.ProjectId == this.CurrUser.LoginProjectId
&& x.UnitWorkId == unitWorkNode.NodeID
orderby x.TestPackageNo
select x).ToList();
foreach (var item in testPackages)
{
int pipelineCount = GetTestPackagePipelineList(item.PTP_ID).Count();
if (pipelineCount == 0)
{
continue;
}
TreeNode newNode = new TreeNode();
newNode.Text = (string.IsNullOrEmpty(item.TestPackageNo) ? "未知" : item.TestPackageNo) + "【" + pipelineCount.ToString() + "】管线";
newNode.NodeID = item.PTP_ID;
newNode.CommandName = 1 + "|" + Funs.GetEndPageNumber(pipelineCount, pageSize);
newNode.EnableClickEvent = true;
newNode.EnableExpandEvent = true;
newNode.EnableCheckBox = false;
unitWorkNode.Nodes.Add(newNode);
TreeNode loadNode = new TreeNode();
loadNode.Text = "加载管线...";
loadNode.NodeID = "加载管线...";
loadNode.EnableCheckBox = false;
newNode.Nodes.Add(loadNode);
}
}
/// <summary>
/// 获取指定试压包下当前仓库、区域和筛选条件内尚未完成出库的管线。
/// </summary>
/// <param name="ptpId">试压包ID。</param>
/// <returns>符合材料匹配入口条件的管线列表。</returns>
private List<Model.HJGL_Pipeline> GetTestPackagePipelineList(string ptpId)
{
var completeInOutPlanDetailRelationList = from x in Funs.DB.Tw_InOutPlanDetail_Relation
join y in Funs.DB.Tw_InOutPlanMaster on x.InOutPlanMasterId equals y.Id
where y.State == (int)TwConst.State. && y.WarehouseId == drpWarehouse.SelectedValue
select x;
var pipeline = (from x in Funs.DB.HJGL_Pipeline
join p in Funs.DB.PTP_PipelineList on x.PipelineId equals p.PipelineId
join y in completeInOutPlanDetailRelationList on x.PipelineId equals y.PipelineId into temp
from y in temp.DefaultIfEmpty()
where y == null
&& p.PTP_ID == ptpId
&& x.ProjectId == this.CurrUser.LoginProjectId
&& x.PipeArea == PipeArea
&& x.PipelineCode.Contains(this.txtPipelineCode.Text.Trim())
&& x.WarehouseId == WarehouseId
orderby x.PipelineCode
select x).ToList();
if (!string.IsNullOrEmpty(drpFlowingSection.SelectedValue) && drpFlowingSection.SelectedValue != Const._Null)
{
pipeline = pipeline.Where(x => x.FlowingSection == drpFlowingSection.SelectedValue).ToList();
}
return pipeline.Distinct().ToList();
}
/// <summary>
/// 展开试压包节点时懒加载管线节点。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">树节点事件参数。</param>
protected void tvControlItem_TreeNodeExpanded(object sender, TreeNodeEventArgs e)
{
if (e.Node.Nodes[0].NodeID == "加载管线...")
{
e.Node.Nodes.Clear();
BindNodes(e.Node);
}
}
/// <summary>
/// 按当前筛选条件重新加载左侧WBS管线树。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnTreeFind_Click(object sender, EventArgs e)
{
this.InitTreeMenu();
}
#endregion --
#region TreeView
/// <summary>
/// 点击TreeView
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void tvControlItem_NodeCommand(object sender, TreeCommandEventArgs e)
{
if (e.CommandName == "加载")
{
string CommandName = e.Node.ParentNode.CommandName;
e.Node.ParentNode.CommandName = (int.Parse(CommandName.Split('|')[0]) + 1) + "|" + int.Parse(CommandName.Split('|')[1]);
e.Node.ParentNode.Nodes.Remove(e.Node);
BindNodes(e.Node.ParentNode);
}
}
#endregion TreeView
#region
/// <summary>
/// 绑定管线匹配汇总。重新匹配会刷新 Grid2,需要把用户原来勾选的管线恢复回来。
/// </summary>
/// <param name="keepSelectedPipelineIds">需要保留选中状态的管线ID</param>
private void BindGrid2(IEnumerable<string> keepSelectedPipelineIds = null)
{
var output = TwArrivalStatisticsService.GetPipeMatch(tw_PipeMatMatchOutputs)
// Grid2 默认展示按管线整体匹配率倒序,便于优先处理齐套率高的管线。
.OrderByDescending(x => x.MatchRate ?? 0)
.ThenBy(x => x.UnitWorkName)
.ThenBy(x => x.PipelineCode)
.ToList();
Grid2.DataSource = output;
Grid2.DataBind();
// “优先匹配选中焊口”会重新计算匹配结果,重新绑定后要继续保留原管线选中状态。
var keepSelectedList = keepSelectedPipelineIds == null ? new List<string>() : keepSelectedPipelineIds.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
var selectList = new List<string>();
for (int i = 0; i < Grid2.Rows.Count; i++)
{
var model = Grid2.Rows[i].DataItem as Tw_PipeMatchOutput;
if (model.MatchRate >= 1)
{
Grid2.Rows[i].RowCssClass = "green";
selectList.Add(model.PipelineId);
}
else
{
Grid2.Rows[i].RowCssClass = "red";
}
}
if (cbSelectCom.Checked)
{
selectList.AddRange(keepSelectedList);
Grid2.SelectedRowIDArray = selectList.Distinct().ToArray();
}
else if (keepSelectedList.Any())
{
Grid2.SelectedRowIDArray = keepSelectedList.ToArray();
}
}
/// <summary>
/// 绑定已加入匹配的管线列表,并标识正在出库中的管线。
/// </summary>
private void BindGrid3()
{
Grid3.DataSource = dicSeclectPipeLine;
Grid3.DataBind();
for (int i = 0; i < Grid3.Rows.Count; i++)
{
var model = Grid3.Rows[i].DataItem;
var model2 = JsonConvert.DeserializeObject<Dictionary<string, string>>(JsonConvert.SerializeObject(model));
string pipeid = model2.First().Value;
var relationModle = TwInoutplandetailRelationService.GetByPipelineId(pipeid, drpWarehouse.SelectedValue);
if (relationModle != null)
{
Grid3.Rows[i].RowCssClass = "yellow";
}
}
}
#endregion
#region
/// <summary>
/// 绑定 Grid2 当前选中管线的材料匹配明细,设置行颜色、优先焊口选中状态和可生成任务单合计。
/// </summary>
private void BindMaterialDetail()
{
var selectedPipelineIds = Grid2.SelectedRowIDArray == null
? new List<string>()
: Grid2.SelectedRowIDArray.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
if (!selectedPipelineIds.Any() && !string.IsNullOrEmpty(Grid2.SelectedRowID))
{
selectedPipelineIds.Add(Grid2.SelectedRowID);
}
// 任务单只允许从未生成任务单的焊口材料中选择,避免重复生成焊接任务。
var tb = GetNoTaskMaterialDetails()
.Where(x => selectedPipelineIds.Contains(x.PipelineId))
// 明细固定按管线号、预制组件号、焊口号、材料编码排序,便于同一焊口材料连续展示。
.OrderBy(x => x.PipelineCode)
.ThenBy(x => x.PrefabricatedComponents)
.ThenBy(x => x.WeldJointCode)
.ThenBy(x => x.MaterialCode)
.ToList();
Grid1.DataSource = tb;
Grid1.DataBind();
var selectList = new List<string>();
// 明细行绿色必须以数据库已反写字段判断,不能用本次匹配结果中的 MatchMaterialCode。
var confirmedPipeLineMatIds = GetConfirmedPipeLineMatIds(tb);
for (int i = 0; i < Grid1.Rows.Count; i++)
{
var model = Grid1.Rows[i].DataItem as Tw_PipeMatMatchOutput;
if (model == null)
{
continue;
}
bool isPriority = IsPriorityWeldJoint(model.PipelineId, model.WeldJointId);
if (isPriority)
{
selectList.Add(model.Id);
}
if (IsMaterialCodeConfirmed(model, confirmedPipeLineMatIds))
{
Grid1.Rows[i].RowCssClass = "green";
}
else if (isPriority)
{
Grid1.Rows[i].RowCssClass = "priority";
}
else if (model.MatchRate < 1 || model.MatchRate == null)
{
Grid1.Rows[i].RowCssClass = "red";
}
}
Grid1.SelectedRowIDArray = selectList.ToArray();
BindTaskWeldJointSummary(tb);
}
/// <summary>
/// 在材料明细底部汇总当前明细中真正可生成任务单的焊口数量。
/// </summary>
/// <param name="materialDetails">当前展示的材料匹配明细。</param>
private void BindTaskWeldJointSummary(List<Tw_PipeMatMatchOutput> materialDetails)
{
// 合计行复用生成任务单的同一套判断,保证页面显示数量和按钮实际生成数量一致。
int taskWeldJointCount = GetTaskWeldJointIdsFromMaterialDetails(materialDetails).Count;
JObject summary = new JObject();
summary.Add("PipelineCode", "合计");
summary.Add("PrefabricatedComponents", "可生成任务单焊口数:");
summary.Add("WeldJointCode", taskWeldJointCount.ToString());
Grid1.SummaryData = summary;
}
/// <summary>
/// 获取还没有生成焊接任务单的材料匹配明细。
/// </summary>
private List<Tw_PipeMatMatchOutput> GetNoTaskMaterialDetails()
{
var matchOutputs = tw_PipeMatMatchOutputs ?? new List<Tw_PipeMatMatchOutput>();
var weldJointIds = matchOutputs
.Where(x => !string.IsNullOrEmpty(x.WeldJointId))
.Select(x => x.WeldJointId)
.Distinct()
.ToList();
if (!weldJointIds.Any())
{
return matchOutputs;
}
// HJGL_WeldTask 已存在的焊口不再显示到待生成任务单的材料明细里。
var taskWeldJointIds = Funs.DB.HJGL_WeldTask
.Where(x => weldJointIds.Contains(x.WeldJointId))
.Select(x => x.WeldJointId)
.Distinct()
.ToList();
return matchOutputs
.Where(x => string.IsNullOrEmpty(x.WeldJointId) || !taskWeldJointIds.Contains(x.WeldJointId))
.ToList();
}
/// <summary>
/// 判断焊口是否被用户设置为当前管线的本次优先匹配焊口。
/// </summary>
/// <param name="pipelineId">管线ID。</param>
/// <param name="weldJointId">焊口ID。</param>
/// <returns>已设置优先匹配返回 true,否则返回 false。</returns>
private bool IsPriorityWeldJoint(string pipelineId, string weldJointId)
{
return !string.IsNullOrEmpty(pipelineId)
&& !string.IsNullOrEmpty(weldJointId)
&& priorityWeldJoints.ContainsKey(pipelineId)
&& priorityWeldJoints[pipelineId].Contains(weldJointId);
}
/// <summary>
/// 获取材料明细中已持久化反写材料主编码的管线材料ID集合。
/// </summary>
/// <param name="materialDetails">材料匹配明细。</param>
/// <returns>已反写材料主编码的管线材料ID集合。</returns>
private HashSet<string> GetConfirmedPipeLineMatIds(IEnumerable<Tw_PipeMatMatchOutput> materialDetails)
{
// 已反写材料主编码的唯一可信来源是 HJGL_PipeLineMat.MaterialCode。
var pipeLineMatIds = materialDetails == null
? new List<string>()
: materialDetails
.Where(x => x != null && !string.IsNullOrEmpty(x.PipeLineMatId))
.Select(x => x.PipeLineMatId)
.Distinct()
.ToList();
if (!pipeLineMatIds.Any())
{
return new HashSet<string>();
}
var confirmedIds = Funs.DB.HJGL_PipeLineMat
.Where(x => pipeLineMatIds.Contains(x.PipeLineMatId) && x.MaterialCode != null && x.MaterialCode != "")
.Select(x => x.PipeLineMatId)
.ToList();
return new HashSet<string>(confirmedIds);
}
/// <summary>
/// 判断单条材料明细是否已经反写材料主编码。
/// </summary>
/// <param name="model">材料匹配明细。</param>
/// <param name="confirmedPipeLineMatIds">已反写材料主编码的管线材料ID集合。</param>
/// <returns>已反写返回 true,否则返回 false。</returns>
private bool IsMaterialCodeConfirmed(Tw_PipeMatMatchOutput model, HashSet<string> confirmedPipeLineMatIds)
{
return model != null
&& confirmedPipeLineMatIds != null
&& !string.IsNullOrEmpty(model.PipeLineMatId)
&& confirmedPipeLineMatIds.Contains(model.PipeLineMatId);
}
/// <summary>
/// 显示材料匹配颜色和任务单生成规则说明。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnMatchHelp_Click(object sender, EventArgs e)
{
Alert.ShowInTop("1、管线绿色为匹配率100%,明细绿色为已反写材料主编码,红色为匹配率小于100%,蓝色为手动优先焊口。<br/>2、一个焊口可能对应多条材料明细,该焊口全部有效明细已反写材料主编码后才允许一键生成任务单。<br/>3、焊口已进行焊前准备,匹配了焊评才能生成任务单", "说明", MessageBoxIcon.Information);
}
/// <summary>
/// 将本次优先匹配焊口状态转换为匹配服务需要的管线-焊口列表结构。
/// </summary>
/// <returns>管线ID到优先焊口ID列表的映射。</returns>
private Dictionary<string, List<string>> GetPriorityWeldJointList()
{
return priorityWeldJoints
.Where(x => x.Value != null && x.Value.Any())
.ToDictionary(x => x.Key, x => x.Value.ToList());
}
/// <summary>
/// 重新计算材料匹配结果,并在刷新管线汇总后恢复原有管线勾选状态。
/// </summary>
private void RefreshMatchResult()
{
// 重新匹配库存会刷新管线汇总表,先暂存选择状态,绑定完成后再恢复。
var keepSelectedPipelineIds = Grid2.SelectedRowIDArray == null ? new List<string>() : Grid2.SelectedRowIDArray.ToList();
tw_PipeMatMatchOutputs = TwArrivalStatisticsService.GetPipeMatMatch(
this.CurrUser.LoginProjectId,
dicSeclectPipeLine.Keys.ToList(),
drpWarehouse.SelectedValue,
GetPriorityWeldJointList());
BindGrid3();
BindGrid2(keepSelectedPipelineIds);
}
/// <summary>
/// 点击材料匹配管线汇总行时刷新该管线的材料明细。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">Grid行点击事件参数。</param>
protected void Grid2_RowClick(object sender, GridRowClickEventArgs e)
{
BindMaterialDetail();
}
/// <summary>
/// 记录材料明细排序字段,并按当前选中管线重新绑定明细。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">Grid排序事件参数。</param>
protected void Grid1_Sort(object sender, GridSortEventArgs e)
{
Grid1.SortDirection = e.SortDirection;
Grid1.SortField = e.SortField;
if (tw_PipeMatMatchOutputs != null && tw_PipeMatMatchOutputs.Any())
{
BindMaterialDetail();
}
}
#endregion
#region
/// <summary>
/// 仓库切换后刷新当前仓库ID并重新加载左侧管线树。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void drpWarehouse_SelectedIndexChanged(object sender, EventArgs e)
{
WarehouseId = Base_WarehouseService.GetWarehouseList(this.CurrUser.LoginProjectId)
.Where(x => x.WarehouseId == drpWarehouse.SelectedValue || x.WarehouseName == drpWarehouse.SelectedValue)
.Select(x => x.WarehouseId)
.FirstOrDefault();
this.InitTreeMenu();//加载树
}
/// <summary>
/// 打开单位工程材料匹配统计窗口。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnStatisticsMat_Click(object sender, EventArgs e)
{
Model.WBS_UnitWork unitWork = BLL.UnitWorkService.GetUnitWorkByUnitWorkId(this.tvControlItem.SelectedNodeID);
if (unitWork != null)
{
PageContext.RegisterStartupScript(Window2.GetShowReference(String.Format("WeldMatMatchGet.aspx?UnitWorkId={0}&&PipeArea={1}", this.tvControlItem.SelectedNodeID, PipeArea, "匹配 - ")));
}
else
{
ShowNotify("请先选择单位工程!", MessageBoxIcon.Warning);
}
}
/// <summary>
/// 按树节点获取可加入本次匹配的管线。单位工程节点会展开到其下所有试压包,再套用当前仓库、区域和页面筛选条件。
/// </summary>
/// <param name="node">左侧树节点。</param>
/// <returns>符合材料匹配入口条件的管线列表。</returns>
private List<Model.HJGL_Pipeline> GetMatchPipelinesByTreeNode(TreeNode node)
{
if (node == null)
{
return new List<Model.HJGL_Pipeline>();
}
if (node.CommandName == "管线")
{
var pipeline = PipelineService.GetPipelineByPipelineId(node.NodeID);
return pipeline == null ? new List<Model.HJGL_Pipeline>() : new List<Model.HJGL_Pipeline> { pipeline };
}
if (node.CommandName == "单位工程")
{
var testPackageIds = (from x in Funs.DB.PTP_TestPackage
where x.ProjectId == this.CurrUser.LoginProjectId
&& x.UnitWorkId == node.NodeID
select x.PTP_ID).ToList();
return testPackageIds
.SelectMany(x => GetTestPackagePipelineList(x))
.GroupBy(x => x.PipelineId)
.Select(x => x.First())
.OrderBy(x => x.PipelineCode)
.ToList();
}
if (!string.IsNullOrEmpty(node.CommandName) && node.CommandName.Contains("|"))
{
return GetTestPackagePipelineList(node.NodeID);
}
return new List<Model.HJGL_Pipeline>();
}
/// <summary>
/// 将左侧勾选管线或当前选中主项/试压包下的管线加入本次材料匹配范围并刷新匹配结果。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnAddPipelineMatchMat_Click(object sender, EventArgs e)
{
int addCount = 0;
var selectNodes = tvControlItem.GetCheckedNodes();
foreach (var node in selectNodes)
{
if (dicSeclectPipeLine.Where(x => x.Key == node.NodeID).Count() == 0 && node.CommandName == "管线")
{
dicSeclectPipeLine.Add(node.NodeID, node.Text);
addCount++;
}
}
var selectedNodePipelines = GetMatchPipelinesByTreeNode(tvControlItem.SelectedNode);
foreach (var pipeline in selectedNodePipelines)
{
if (pipeline != null && !dicSeclectPipeLine.ContainsKey(pipeline.PipelineId))
{
dicSeclectPipeLine.Add(pipeline.PipelineId, pipeline.PipelineCode);
addCount++;
}
}
if (addCount == 0)
{
ShowNotify("未找到可新增的匹配管线!", MessageBoxIcon.Warning);
return;
}
RefreshMatchResult();
}
/// <summary>
/// 从本次材料匹配范围移除选中管线,并清理对应的优先焊口状态。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnDeletePipelineMatchMat_Click(object sender, EventArgs e)
{
if (Grid3.SelectedRowIDArray != null && Grid3.SelectedRowIDArray.Any())
{
foreach (string rowId in Grid3.SelectedRowIDArray)
{
dicSeclectPipeLine.Remove(rowId);
priorityWeldJoints.Remove(rowId);
var node = tvControlItem.FindNode(rowId);
if (node != null)
{
node.Checked = false;
}
}
RefreshMatchResult();
}
}
/// <summary>
/// 匹配
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnMatchMat_Click(object sender, EventArgs e)
{
BindMaterialDetail();
}
/// <summary>
/// 优先匹配选中焊口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnPriorityComponents_Click(object sender, EventArgs e)
{
string selectedPipelineId = Grid2.SelectedRowID;
if (string.IsNullOrEmpty(selectedPipelineId))
{
ShowNotify("请先在材料匹配列表选择管线!", MessageBoxIcon.Warning);
return;
}
// 页面上的焊口选择来自 Grid1 材料明细;Grid3 是左侧已加入匹配的管线列表。
var selectedWeldJoints = new HashSet<string>();
foreach (int rowIndex in Grid1.SelectedRowIndexArray)
{
if (Grid1.DataKeys[rowIndex].Length < 4)
{
continue;
}
string pipelineId = Grid1.DataKeys[rowIndex][1]?.ToString();
string weldJointId = Grid1.DataKeys[rowIndex][3]?.ToString();
if (pipelineId == selectedPipelineId && !string.IsNullOrEmpty(weldJointId))
{
selectedWeldJoints.Add(weldJointId);
}
}
if (selectedWeldJoints.Any())
{
priorityWeldJoints[selectedPipelineId] = selectedWeldJoints;
}
else
{
priorityWeldJoints.Remove(selectedPipelineId);
}
// 优先焊口会触发重新匹配,当前管线也必须继续保持选中,方便后续生成任务单。
var keepSelectedPipelineIds = Grid2.SelectedRowIDArray == null ? new List<string>() : Grid2.SelectedRowIDArray.ToList();
if (!keepSelectedPipelineIds.Contains(selectedPipelineId))
{
keepSelectedPipelineIds.Add(selectedPipelineId);
}
RefreshMatchResult();
Grid2.SelectedRowIDArray = keepSelectedPipelineIds.Distinct().ToArray();
BindMaterialDetail();
}
/// <summary>
/// 将当前选中管线的匹配结果反写到管线材料主编码。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnConfirmMaterialCode_Click(object sender, EventArgs e)
{
if (Grid2.SelectedRowIDArray == null || !Grid2.SelectedRowIDArray.Any())
{
ShowNotify("请先选择需要保存匹配结果的管线!", MessageBoxIcon.Warning);
return;
}
if (tw_PipeMatMatchOutputs == null || !tw_PipeMatMatchOutputs.Any())
{
RefreshMatchResult();
}
var selectedPipelineIds = Grid2.SelectedRowIDArray.ToList();
var matchedMaterials = tw_PipeMatMatchOutputs
.Where(x => selectedPipelineIds.Contains(x.PipelineId))
.ToList();
if (!matchedMaterials.Any())
{
ShowNotify("未找到保存的材料匹配明细!", MessageBoxIcon.Warning);
return;
}
int count = BLL.PipelineMatService.UpdateMaterialCodeByMatchOutputs(matchedMaterials);
ShowNotify("已保存材料主编码" + count.ToString() + "条!", MessageBoxIcon.Success);
RefreshMatchResult();
if (Grid2.SelectedRowIDArray.Any())
{
BindMaterialDetail();
}
}
/// <summary>
/// 清除 Grid2 当前选中管线中已反写到管线材料表的材料主编码。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnClearMaterialCode_Click(object sender, EventArgs e)
{
if (Grid2.SelectedRowIDArray == null || !Grid2.SelectedRowIDArray.Any())
{
ShowNotify("请先选择需要清除匹配结果的管线!", MessageBoxIcon.Warning);
return;
}
if (tw_PipeMatMatchOutputs == null || !tw_PipeMatMatchOutputs.Any())
{
RefreshMatchResult();
}
var selectedPipelineIds = Grid2.SelectedRowIDArray.ToList();
var pipeLineMatIds = tw_PipeMatMatchOutputs
.Where(x => selectedPipelineIds.Contains(x.PipelineId))
.Select(x => x.PipeLineMatId)
.Distinct()
.ToList();
if (!pipeLineMatIds.Any())
{
ShowNotify("未找到需要清除的材料匹配明细!", MessageBoxIcon.Warning);
return;
}
int count = BLL.PipelineMatService.ClearMaterialCodeByPipeLineMatIds(pipeLineMatIds);
ShowNotify("已清除材料主编码" + count.ToString() + "条!", MessageBoxIcon.Success);
RefreshMatchResult();
if (Grid2.SelectedRowIDArray.Any())
{
BindMaterialDetail();
}
}
/// <summary>
/// 按 Grid2 选中管线下可生成任务单的焊口批量生成焊接任务单。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
protected void btnGenTask_Click(object sender, EventArgs e)
{
if (Grid2.SelectedRowIDArray == null || !Grid2.SelectedRowIDArray.Any())
{
ShowNotify("请先在材料匹配列表中选择需要生成任务单的管线!", MessageBoxIcon.Warning);
return;
}
// 生成任务单按 Grid2 勾选管线批量取焊口,不再要求用户在 Grid1 明细逐条勾选。
var selectedWeldJointIds = GetTaskWeldJointIdsFromSelectedPipelines();
if (!selectedWeldJointIds.Any())
{
ShowNotify("选中管线中没有已反写材料主编码的可生成任务单焊口!", MessageBoxIcon.Warning);
return;
}
if (SaveTask(selectedWeldJointIds))
{
ShowNotify("生成任务单成功!", MessageBoxIcon.Warning);
// Alert.Show("生成任务单成功!", MessageBoxIcon.Warning);
Grid1.DataSource = null;
Grid1.DataBind();
BindTaskWeldJointSummary(new List<Tw_PipeMatMatchOutput>());
Grid2.DataSource = null;
Grid2.DataBind();
Grid3.DataSource = null;
Grid3.DataBind();
}
}
/// <summary>
/// 根据已通过材料齐套和任务单条件过滤的焊口生成焊接任务单。
/// </summary>
/// <param name="selectedWeldJointIds">待生成任务单的焊口ID集合。</param>
/// <returns>生成成功返回 true;校验失败或无可生成焊口返回 false。</returns>
private bool SaveTask(HashSet<string> selectedWeldJointIds)
{
if (selectedWeldJointIds == null || !selectedWeldJointIds.Any())
{
ShowNotify("选中管线中没有已反写材料主编码的可生成任务单焊口!", MessageBoxIcon.Warning);
return false;
}
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 = GetTaskableWeldJointRows(selectedWeldJointIdList);
Dictionary<string, string> unitworkTaskCode = new Dictionary<string, string>();
Dictionary<string, string> unitworkSerialNumber = new Dictionary<string, string>();
Dictionary<int, string> matchPipeline = new Dictionary<int, string>();
// 生成任务单仍保留管线在匹配结果中的排序,用于任务单列表按管线顺序展示。
for (int rowIndex = 0; rowIndex < Grid2.Rows.Count; rowIndex++)
{
matchPipeline.Add(rowIndex + 1, Grid2.Rows[rowIndex].RowID);
}
if (!selectRowId.Any())
{
ShowNotify("未找到可生成任务单的焊口!", MessageBoxIcon.Warning);
return false;
}
foreach (var weldjoint in selectRowId)
{
string canWeldingRodName = string.Empty;
string canWeldingWireName = string.Empty;
Model.HJGL_WeldTask NewTask = new Model.HJGL_WeldTask();
NewTask.ProjectId = this.CurrUser.LoginProjectId;
NewTask.UnitWorkId = PipelineService.GetPipelineByPipelineId(weldjoint.PipelineId)?.UnitWorkId;
NewTask.UnitId = this.CurrUser.UnitId;
if (unitworkTaskCode.FirstOrDefault(x => x.Key == NewTask.UnitWorkId).Value != null)
{
NewTask.TaskCode = unitworkTaskCode.FirstOrDefault(x => x.Key == NewTask.UnitWorkId).Value;
}
else
{
NewTask.TaskCode = BLL.WeldTaskService.GetTaskCodeByDate(this.CurrUser.LoginProjectId, DateTime.Now.Date.ToString("yyyy-MM-dd"), NewTask.UnitWorkId, this.CurrUser.UnitId);
unitworkTaskCode.Add(NewTask.UnitWorkId, NewTask.TaskCode);
}
if (unitworkSerialNumber.FirstOrDefault(x => x.Key == NewTask.UnitWorkId).Value != null)
{
NewTask.SerialNumber = unitworkSerialNumber.FirstOrDefault(x => x.Key == NewTask.UnitWorkId).Value;
}
else
{
NewTask.SerialNumber = BLL.WeldTaskService.GetSerialNumberByDate(this.CurrUser.LoginProjectId, DateTime.Now.Date.ToString("yyyy-MM-dd"), NewTask.UnitWorkId, this.CurrUser.UnitId);
unitworkSerialNumber.Add(NewTask.UnitWorkId, NewTask.SerialNumber);
}
NewTask.WeldTaskId = SQLHelper.GetNewID();
NewTask.WeldJointId = weldjoint.WeldJointId;
var oldWeldTask = BLL.WeldTaskService.GetWeldTaskByWeldJointId(NewTask.WeldJointId);
if (oldWeldTask != null)
{
ShowNotify("所选焊口已存在任务单,无法保存!", MessageBoxIcon.Warning);
return false;
}
Model.HJGL_WeldJoint weldJoint = BLL.WeldJointService.GetWeldJointByWeldJointId(NewTask.WeldJointId);
if (weldJoint != null)
{
NewTask.PipeLineSortIndex = matchPipeline.FirstOrDefault(x => x.Value == weldJoint.PipelineId).Key;
NewTask.WeldingRod = weldJoint.WeldingRod;
NewTask.WeldingWire = weldJoint.WeldingWire;
//获取可替代焊丝焊条
var mat = BLL.Base_MaterialService.GetMaterialByMaterialId(weldJoint.Material1Id);
string matClass = mat.MaterialClass;
var matRod = weldingRods.FirstOrDefault(x => x.ConsumablesId == weldJoint.WeldingRod);
if (matRod != null)
{
foreach (var item in weldingRods)
{
if (matClass == "Fe-1" || matClass == "Fe-3")
{
if (IsCoverClass(matRod.SteelType, item.SteelType))
{
canWeldingRodName = canWeldingRodName + item.ConsumablesName + ",";
}
}
else
{
if (matRod.SteelType == item.SteelType)
{
canWeldingRodName = canWeldingRodName + item.ConsumablesName + ",";
}
}
}
if (!string.IsNullOrEmpty(canWeldingRodName))
{
NewTask.CanWeldingRodName = canWeldingRodName.Substring(0, canWeldingRodName.Length - 1);
}
}
var matWire = weldingWires.FirstOrDefault(x => x.ConsumablesId == weldJoint.WeldingWire);
if (matWire != null)
{
foreach (var item in weldingWires)
{
if (matClass == "Fe-1" || matClass == "Fe-3")
{
if (IsCoverClass(matWire.SteelType, item.SteelType))
{
canWeldingWireName = canWeldingWireName + item.ConsumablesName + ",";
}
}
else
{
if (matWire.SteelType == item.SteelType)
{
canWeldingWireName = canWeldingWireName + item.ConsumablesName + ",";
}
}
}
if (!string.IsNullOrEmpty(canWeldingWireName))
{
NewTask.CanWeldingWireName = canWeldingWireName.Substring(0, canWeldingWireName.Length - 1);
}
}
}
NewTask.JointAttribute = weldJoint.JointAttribute;
NewTask.TaskDate = DateTime.Now.Date;
NewTask.Tabler = this.CurrUser.PersonId;
NewTask.TableDate = DateTime.Now;
weldJoint.WeldingMode = "手动";
BLL.WeldJointService.UpdateWeldJoint(weldJoint);
BLL.WeldTaskService.AddWeldTask(NewTask);
}
return true;
}
/// <summary>
/// 按任务单实际生成规则过滤可生成任务单的焊口视图数据。
/// </summary>
/// <param name="weldJointIds">候选焊口ID集合。</param>
/// <returns>符合任务单生成条件的焊口视图数据。</returns>
private List<Model.View_HJGL_NoWeldJointFind> GetTaskableWeldJointRows(IEnumerable<string> weldJointIds)
{
var weldJointIdList = weldJointIds == null
? new List<string>()
: weldJointIds.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
if (!weldJointIdList.Any())
{
return new List<Model.View_HJGL_NoWeldJointFind>();
}
// 合计行和生成按钮必须共用同一套可生成条件:未生成日报、未生成任务单、已维护焊接方法。
var taskableRows = (from x in Funs.DB.View_HJGL_NoWeldJointFind
where weldJointIdList.Contains(x.WeldJointId)
&& x.WeldingDailyId == null
&& x.WeldTaskId == null
&& x.WeldingMethodCode != null
select x).ToList();
if (PipeArea == "1")
{
// 工厂预制材料匹配只允许预制口生成任务单,现场安装页面不套用该限制。
taskableRows = taskableRows.Where(x => x.JointAttribute == "预制口").ToList();
}
return taskableRows;
}
/// <summary>
/// 从 Grid2 选中的管线中收集可生成任务单的焊口ID。
/// </summary>
/// <returns>可生成任务单的焊口ID集合。</returns>
private HashSet<string> GetTaskWeldJointIdsFromSelectedPipelines()
{
// Grid2 的选中管线是任务单生成范围,Grid1 当前展示哪条管线不影响批量生成。
var selectedPipelineIds = Grid2.SelectedRowIDArray == null
? new HashSet<string>()
: new HashSet<string>(Grid2.SelectedRowIDArray.Where(x => !string.IsNullOrEmpty(x)));
if (!selectedPipelineIds.Any())
{
return new HashSet<string>();
}
var materialDetails = GetNoTaskMaterialDetails()
// 生成任务单只校验参与匹配的有效材料明细,零用量材料不参与焊口材料齐套判断。
.Where(x => selectedPipelineIds.Contains(x.PipelineId) && !string.IsNullOrEmpty(x.WeldJointId) && (x.NeedNum ?? 0) > 0)
.ToList();
return GetTaskWeldJointIdsFromMaterialDetails(materialDetails);
}
/// <summary>
/// 根据材料明细判断焊口是否材料齐套且满足任务单生成条件。
/// </summary>
/// <param name="materialDetails">候选材料匹配明细。</param>
/// <returns>可生成任务单的焊口ID集合。</returns>
private HashSet<string> GetTaskWeldJointIdsFromMaterialDetails(List<Tw_PipeMatMatchOutput> materialDetails)
{
if (materialDetails == null || !materialDetails.Any())
{
return new HashSet<string>();
}
materialDetails = materialDetails
.Where(x => x != null && !string.IsNullOrEmpty(x.WeldJointId) && (x.NeedNum ?? 0) > 0)
.ToList();
// 同一焊口可能有多条有效材料明细,所有明细都反写材料主编码后才算可生成任务单。
var confirmedPipeLineMatIds = GetConfirmedPipeLineMatIds(materialDetails);
var weldJointIds = materialDetails
.GroupBy(x => x.WeldJointId)
.Where(x => x.All(y => IsMaterialCodeConfirmed(y, confirmedPipeLineMatIds)))
.Select(x => x.Key);
// 材料齐套后还要继续套用任务单视图条件,保证合计数量和点击生成按钮的实际范围一致。
return new HashSet<string>(GetTaskableWeldJointRows(weldJointIds).Select(x => x.WeldJointId));
}
/// <summary>
/// 判断焊材钢号类别是否能覆盖母材类别。
/// </summary>
/// <param name="wpsClass">焊材钢号类别。</param>
/// <param name="matClass">母材类别。</param>
/// <returns>能覆盖返回 true,否则返回 false。</returns>
private bool IsCoverClass(string wpsClass, string matClass)
{
bool isCover = false;
int wpsSn = 0;
int matSn = 0;
if (wpsClass.Length > 2 && matClass.Length > 2)
{
string wpsPre = wpsClass.Substring(0, wpsClass.Length - 2);
string matPre = matClass.Substring(0, matClass.Length - 2);
string wps = wpsClass.Substring(wpsClass.Length - 1, 1);
wpsSn = Funs.GetNewInt(wps).HasValue ? Funs.GetNewInt(wps).Value : 0;
string mat = matClass.Substring(matClass.Length - 1, 1);
matSn = Funs.GetNewInt(mat).HasValue ? Funs.GetNewInt(mat).Value : 0;
if (wpsPre == matPre && matSn >= wpsSn)
{
return true;
}
}
return isCover;
}
#endregion
}
}