内部供应链管理系统,可见性






4.78/5 (29投票s)
内部供应链管理系统的目标是可视化组织在其工作流程中产生的活动和事件,并提供上游和下游活动的概览。
介绍
内部供应链,通过200多个3D图表报告实现可见性 第二部分本文重点关注内部供应链管理流程的可见性。其主要目标是可视化工作流程中发生的活动和事件,并提供上下游活动的全面视图。它包括入库、出库和生产操作,并可细分为原材料、在制品和成品及其内在操作。
Visibility
在供应链管理中,信息的可见性至关重要。系统按日期和物料提供基于上下文的即时库存,以及即时库存的历史记录。画布图例提供了一个光谱,用于区分和可视化精炼上下文(已过滤)的即时库存。要详细查看即时库存物料,可以通过将鼠标悬停在相关条形图上进行提取。

入库操作事件
通过勾选“入库事件”复选框来检查原材料入库事件。因此,提取了与精炼上下文(已过滤)相关的物料事件。通过将鼠标悬停在相关的事件条形图上可获得详细视图。

物料入库与生产操作转换
物料入库和操作转换的全面视图有两个主要路径或阶段。第一个从“在途”开始,对应于已发出物料采购订单但正在等待物料交付的情况。当在途物料收到时,它会被记录在物料库存中。当库存受到任何方式的污染时,就会执行入库物料的处置或报废操作,将物料转换为报废状态。物料操作转换与生产操作相互关联。有两种操作路径,它们都通过调用作业来启动。当作业状态设置为“待处理”时,将为该作业保留物料库存,并在作业状态变为“当前”时发货进行生产。当作业即将直接进入制造阶段时,可以将其设置为“当前作业”。在作业制造过程完成后,状态将设置为“已完成”,生产出的成品将进入QA部门,然后进入成品库存。

在制品生产操作
在制品是原材料和成品操作层之间的中间层,因此它充当它们之间的缓冲,通过作业规范将它们绑定在一起而不是连接起来。作业规范包括生产操作所需的成品以及生产商品消耗的原材料。作业有两个状态,第一个是“待处理作业”,表示已保留物料库存但未发货至制造阶段,因此物料库存没有物理转换。这种延迟可能是由于在建立作业时缺乏物料库存。
Visibility
可以按日期、按精炼上下文实时查看作业及其不同阶段。作业状态由一个光谱表示,该光谱与待处理、制造和QA阶段相关。在在制品视图中,每种颜色都对应一个相应的事件。通过将鼠标悬停在相关的事件上可以查看每个事件的详细信息。这建立了作业的全面视图。


生产操作事件
作业状态的更改会生成生产事件,这些事件由颜色光谱表示,这些颜色光谱与待处理、制造和QA阶段相关。除了作业状态外,每个光谱颜色也对应一个事件。通过将鼠标悬停在相关的事件条形图上可以查看每个事件的详细信息。

生产操作转换
操作转换与生产操作相互关联。有两种操作路径,它们都通过调用作业来启动。当作业状态设置为“待处理作业”时,表示作业将在稍后执行。当作业即将进入制造阶段时,可以将其设置为“当前作业”。在作业制造过程完成后,状态将设置为“已完成”,生产出的成品将进入QA部门,然后进入成品库存。

成品出库与生产操作
该系统勾勒出内部工作流程和成品。成品是增值库存,它消耗非增值产品(原材料)。该部分执行的操作会改变物料的即时库存。
Visibility
在供应链管理中,信息的可见性至关重要。它按日期和商品提供上下文即时库存,以及即时库存的历史记录。画布图例提供了一个光谱,用于区分和可视化该精炼上下文的即时库存。要详细查看即时库存商品,可以通过将鼠标悬停在相关的条形图上进行提取。

出库操作事件
通过勾选“事件”复选框来检查成品出库事件。因此,提取了与精炼上下文相关的物料事件。通过将鼠标悬停在相关的事件条形图上可获得其详细视图。

成品出库与生产操作转换
成品出库和操作转换的全面视图有两个主要路径或阶段。第一个从“待处理阶段”开始,对应于为生产保留物料的情况,这也称为“待处理作业”。当物料收到并存入物料库存时,在适当的时候会启动作业,这会 dẫn đến 下一个阶段,即制造阶段。在作业完成后,会生产出成品,并转移到成品库存中。当库存受到任何方式的污染时,就会执行出库成品的处置或报废操作,将物料转换为报废。

内部工作
Bars.cs
类是此应用程序的核心。它派生自 System.Windows.Forms.Control
类。它代表相对于时间的工作流程、相对于日期的事件和数量以及相对于数量和日期的即时库存。促成可视化的事件是 OnPaintBackground
、Bar_MouseMove
、OnMouseClick
和 Bar_MouseLeave
方法。
OnPaintBackground
此方法绘制条形图用户界面。它按步骤执行其功能,并分别调用 MakeScale
、IdentifyBarContext
、GenerateCurrentContextBarResutset
和 GenerateBars
。它消耗 barArrayList
在条形图框上绘制条形图,该条形图框在调用 GenerateCurrentContextBarResutset
方法时填充。
string filter = "";
Bar[] barArray;
ArrayList barArrayList;
float temp = 0;
private static Mutex mut = new Mutex();
System.Data.DataRow[] rows;
protected override void OnPaintBackground(PaintEventArgs pevent)
{
mut.WaitOne();
pevent.Graphics.SmoothingMode =Systtem.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Rectangle translateRect = this.Bounds;
PaintEventArgs pe = new PaintEventArgs(pevent.Graphics, translateRect);
this.InvokePaintBackground(this.Parent, pe);
// calibrate scale on the bar frame
MakeScale(pevent);
// contains all bargrid's bar data
barArrayList = new ArrayList();
// user to shift scale initial reference point
temp = (m_ValueDifference * 100) * m_ValuePerPixel;
if ( Form1.data != null)
{
System.Windows.Forms.Control cont =
this.Parent.Controls.Find("Tag", true)[0];
cont.BackColor = System.Drawing.SystemColors.Control;
cont.ForeColor = Color.Black;
if (!IdentifyBarContext(cont))
return;
GenerateCurrentContextBarResutset(cont);
}
else
// data is not initialized abort no need to go further
return;
GenerateBars(pevent);
mut.ReleaseMutex();
}
MakeScale
OnPaintBackground
方法 MakeScale
方法。此方法根据当前选择的尺寸校准条形图框上的刻度。其目的是增强条形图框上的刻度读取。
// Celebrated bar frame
protected void MakeScale(PaintEventArgs pe)
{
FindFontBounds();
Bitmap Bitmap= new Bitmap(Width, Height, pe.Graphics);
Graphics ggr = Graphics.FromImage(Bitmap);
ggr.FillRectangle(new SolidBrush(System.Drawing.Color.Transparent),
ientRectangle);
ggr.SmoothingMode = SmoothingMode.HighQuality;
ggr.PixelOffsetMode = PixelOffsetMode.HighQuality;
GraphicsPath gp = new GraphicsPath();
ggr.SetClip(ClientRectangle);
String valueText = "";
SizeF boundingBox;
Int32 counter1 = 0;
Int32 scaleValueUnit = 0;
Int32 scaleTemValueUnit = 0;
Int32 scaleUnit = 0;
while (scaleUnit <= 720)
{
ggr.DrawLine(new Pen(System.Drawing.Color.Gray, 2),
(Single)scaleValueUnit,
(Single)0,
(Single)scaleValueUnit,
(Single)35);
valueText = "";
boundingBox = ggr.MeasureString(valueText,
Font, -1, StringFormat.GenericTypographic);
scaleUnit++;
scaleTemValueUnit = Convert.ToInt32(scaleTemValueUnit +
_ValuePerPixel * 10));
scaleValueUnit = Convert.ToInt32(scaleValueUnit + (100 * m_ValuePerPixel));
counter1++;
}
pe.Graphics.DrawImageUnscaled(Bitmap, 0, 0);
pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
pe.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
}
IdentifyBarContext
校准条形图框后,会调用 IdentifyBarContext
方法。此方法识别需要绘制条形图的条形图的上下文。MainForm.data
由 MainForm
填充,但它包含 MainForm
上下文的记录,不适用于条形图上下文。此方法会过滤掉当前条形图上下文的记录。
// identifying current bar context
bool IdentifyBarContext(System.Windows.Forms.Control cont)
{
switch (perspective_ID)
{
// Raw material current bar context
case 0:
if (option_ID == 0)
filter = " Goods_ID =" + iD;
if (option_ID == 1)
filter = " Date = #" + cont.Text + "#";
rows = MainForm.data.Tables["GoodsCurrent"].Select(filter);
break;
// Work in progress current bar context
case 1:
filter = " Job_ID = " + iD;
rows = MainForm.data.Tables["JobByDate"].Select(filter);
break;
// Finished goods current bar context
case 2:
if (option_ID == 0)
filter = " Goods_ID =" + iD;
if (option_ID == 1)
filter = " Date = #" + cont.Text + "#";
rows = MainForm.data.Tables["GoodsCurrent"].Select(filter);
break;
}
return true;
}
GenerateCurrentContextBarResutset
在下一步中,会调用 GenerateCurrentContextBarResutset
方法。它生成与精炼上下文对应的 resultset
。它为每个条形图的状态、阶段或转换分配颜色。

按日期的非事件原材料结果集
将讨论按日期生成原材料和作业 resultset
。在原材料方面,还有两种情况:非事件(即时库存)和事件场景。它通过分配相关条形图的长度和位置来量化库存。
#region Generate non Event raw material resultsets by date
if (!is_Event)
{
if (rows.Length == 0)
{
DataAccess.Access ac = new InventorySys.DataAccess.Access();
rows = ac.RawMaterialSingleCurrent( iD
, this.Parent.Controls.Find("Date", true)[0].Text).Tables[0].Select();
}
barArray = new Bar[5];
barArray[0].initial_Point = 0;
barArray[0].ID = Convert.ToInt32(rows[0]["Goods_ID"]);
// Incoming current
if (((Convert.ToInt32(rows[0]["Incomming_Current"])) - temp) > 3)
{
barArray[0].final_Point =
(Convert.ToInt32(rows[0]["Incomming_Current"]) - Convert.ToInt32
(rows[0]["Outgoing_Finished"]) -
Convert.ToInt32(rows[0]["Outgoing_Expected"]) –
Convert.ToInt32(rows[0]["Outgoing_Waste"] ) -
Convert.ToInt32(rows[0]["Outgoing_InProcess"])
- temp )* m_ValuePerPixel ;
barArray[0].color = Color.Green;
if( barArray[0].final_Point > 1 )
barArrayList.Add(barArray[0]);
}
else
{
barArray[0].final_Point = 0;
}
// Incoming Expected
barArray[1].initial_Point = barArray[0].final_Point++;
barArray[1].ID = Convert.ToInt32(rows[0]["Goods_ID"]);
if (((Convert.ToInt32(rows[0]["Incomming_Expected"])) - temp) > 3)
{
barArray[1].final_Point = barArray[1].initial_Point +
((Convert.ToInt32(rows[0]["Incomming_Expected"])
- temp) * m_ValuePerPixel);
barArray[1].color = Color.Orange;
if (barArray[1].final_Point > 1)
barArrayList.Add(barArray[1]);
}
else
{
barArray[1].final_Point = barArray[1].initial_Point;
}
// Outgoing Expected
barArray[2].initial_Point = barArray[1].final_Point++;
barArray[2].ID = Convert.ToInt32(rows[0]["Goods_ID"]);
if (((Convert.ToInt32(rows[0]["Outgoing_Expected"])) - temp) > 3)
{
barArray[2].final_Point = barArray[2].initial_Point +
((Convert.ToInt32(rows[0]["Outgoing_Expected"])
- temp) * m_ValuePerPixel);
barArray[2].color = Color.DarkBlue;
if (barArray[2].final_Point > 1)
barArrayList.Add(barArray[2]);
}
else
{
barArray[2].final_Point = barArray[2].initial_Point;
}
// Outgoing In-Process
barArray[3].initial_Point = barArray[2].final_Point++;
barArray[3].ID = Convert.ToInt32(rows[0]["Goods_ID"]);
if (((Convert.ToInt32(rows[0]["Outgoing_InProcess"])) - temp) > 3)
{
barArray[3].final_Point = barArray[3].initial_Point
+ (Convert.ToInt32(rows[0]["Outgoing_InProcess"])
- temp) * m_ValuePerPixel;;
barArray[3].color = Color.Yellow;
if (barArray[3].final_Point > 1)
{
barArrayList.Add(barArray[3]);
}
}
}
#endregion
按日期的事件原材料结果集
在事件场景中,所有物理或非物理的转换都显示在调色板中,其数量由条形图的长度表示。
#region Generate Event raw material resultsets by date
if (is_Event)
{
barArray = new Bar[rows.Length];
float temp_Initial_Point = 0;
for (int i = 0; i < rows.Length; i++)
{
barArray[i].final_Point = temp_Initial_Point +
(Convert.ToInt32(rows[i]["Unit"]) - temp ) * m_ValuePerPixel;;;
barArray[i].initial_Point = temp_Initial_Point - temp;
temp_Initial_Point = barArray[i].final_Point + temp;
barArray[i].ID = Convert.ToInt32(rows[i]["Transaction_ID"]);
// Incoming Expected
if (Convert.ToInt32(rows[i]["Transaction_Type_ID"]) == 1 &&
Convert.ToInt32(rows[i]["Transaction_Status_ID"]) == 2)
{
barArray[i].color = Color.Orange;
}
// Incoming Current
if (Convert.ToInt32(rows[i]["Transaction_Type_ID"]) == 1 &&
Convert.ToInt32(rows[i]["Transaction_Status_ID"]) == 1)
{
barArray[i].color = Color.Green;
}
// outgoing Expected
if (Convert.ToInt32(rows[i]["Transaction_Type_ID"]) == 2 &&
Convert.ToInt32(rows[i]["Transaction_Status_ID"]) ==2 )
{
barArray[i].color = Color.DarkBlue;
}
// outgoing In-Process
if (Convert.ToInt32(rows[i]["Transaction_Type_ID"]) == 2 &&
Convert.ToInt32(rows[i]["Transaction_Status_ID"]) == 3)
{
barArray[i].color = Color.Yellow;
}
// Outgoing Finished
if (Convert.ToInt32(rows[i]["Transaction_Type_ID"]) == 2 &&
Convert.ToInt32(rows[i]["Transaction_Status_ID"]) == 5)
{
barArray[i].color = Color.Black;
}
// Outgoing Waste
if (Convert.ToInt32(rows[i]["Transaction_Type_ID"]) == 2 &&
Convert.ToInt32(rows[i]["Transaction_Status_ID"]) == 6)
{
barArray[i].color = Color.Red;
}
if (barArray[i].final_Point > 1)
barArrayList.Add(barArray[i]);
}
}
#endregion
按日期的作业事件结果集
在此基于事件的场景中,状态以颜色表示,其消耗的时间由条形图的长度和在条形图框上的位置表示。
#region Generate job resultsets by date
TimeSpan ts = new TimeSpan();
ts = DateTime.Parse(rows[0]["Start_Date_Time"].ToString()) -
DateTime.Parse(Bars.m_Start_Date);
Bar[] barArrayFirst = new Bar[1];
barArrayFirst[0].initial_Point = (ts.Days + 1) * (100 * m_ValuePerPixel) +
(ts.Hours * Convert.ToSingle(2.5 * m_ValuePerPixel));
ts = DateTime.Parse(rows[0]["End_Date_Time"].ToString()) -
DateTime.Parse(Bars.m_Start_Date);
barArrayFirst[0].final_Point = (ts.Days + 1) * (100 * m_ValuePerPixel) +
(ts.Hours * Convert.ToSingle(2.5 * m_ValuePerPixel)); ;
barArrayFirst[0].ID = Convert.ToInt32(rows[0]["Job_ID"]);
barArrayFirst[0].Job_Transaction_ID = 0;
barArrayFirst[0].Is_Final_Job_Status = true;
// Expected
if (Convert.ToInt32(rows[0]["Status_ID"]) == 2)
{
cont.BackColor = Color.Orange;
cont.ForeColor = Color.Black;
barArrayFirst[0].color = Color.Orange;
}
// In-Progress
if (Convert.ToInt32(rows[0]["Status_ID"]) == 3)
{
cont.BackColor = Color.Green;
cont.ForeColor = Color.White;
barArrayFirst[0].color = Color.Black;
}
// Finished
if (Convert.ToInt32(rows[0]["Status_ID"]) == 5)
{
cont.BackColor = Color.Yellow;
cont.ForeColor = Color.Black;
barArrayFirst[0].color = Color.DimGray;
}
// Waste
if (Convert.ToInt32(rows[0]["Status_ID"]) == 6)
{
cont.BackColor = Color.Red;
cont.ForeColor = Color.White;
barArrayFirst[0].color = Color.Red;
}
if (barArrayFirst[0].final_Point > 1)
barArrayList.Add(barArrayFirst[0]);
rows = Form1.data.Tables["Job_TransactionByDate"].Select
( "Job_ID = " + rows[0]["Job_ID"].ToString() );
barArray = new Bar[rows.Length];
for (int i = 0; i < rows.Length; i++)
{
ts = DateTime.Parse(rows[i]["Start_Date_Time"].ToString())
- DateTime.Parse(Bars.m_Start_Date);
barArray[i].initial_Point = ( (ts.Days + 1) * (100 * m_ValuePerPixel))
+ (ts.Hours * Convert.ToSingle(2.5 * m_ValuePerPixel));
ts = DateTime.Parse(rows[i]["End_Date_Time"].ToString())
- DateTime.Parse(Bars.m_Start_Date);
barArray[i].final_Point = ((ts.Days + 1) * (100 * m_ValuePerPixel))
+ (ts.Hours * Convert.ToSingle(2.5 * m_ValuePerPixel));
barArray[i].ID = Convert.ToInt32(rows[i]["Job_ID"]);
barArray[i].Job_Transaction_ID =
Convert.ToInt32(rows[i]["Job_Transaction_ID"]);
barArray[i].Is_Final_Job_Status = false;
// Expected
if (Convert.ToInt32(rows[i]["Status_ID"]) == 2)
{
barArray[i].color = Color.DarkBlue;
}
// In-Progress
if (Convert.ToInt32(rows[i]["Status_ID"]) == 3)
{
barArray[i].color = Color.Black;
}
// Finished
if (Convert.ToInt32(rows[i]["Status_ID"]) == 5)
{
barArray[i].color = Color.DimGray;
}
// Waste
if (Convert.ToInt32(rows[i]["Status_ID"]) == 6)
{
barArray[i].color = Color.Red;
}
if (barArray[i].final_Point > 1)
barArrayList.Add(barArray[i]);
}
#endregion
GenerateBars
该方法消耗生成的 resultset
并通过绘制它们将它们放入视觉形式。实际的绘制在此处进行。
void GenerateBars(PaintEventArgs pevent)
{
int generatedBarCount = 0;
System.Drawing.Drawing2D.GraphicsPath path = new GraphicsPath();
Pen drawingPen = new Pen(Color.Gray);
Bar barStruct;
Color shadeColor, fillColor;
// defines magnitude of concern bar
int bar = 0;
Rectangle r = new Rectangle();
while (generatedBarCount < barArrayList.Count)
{
if (generatedBarCount >= barArrayList.Count)
goto Finish1;
barStruct = (Bar)barArrayList[generatedBarCount];
fillColor = barStruct.color;
shadeColor = barStruct.color;
bar = Convert.ToInt32(barStruct.final_Point) -
vert.ToInt32(barStruct.initial_Point);
r = new Rectangle(0, 0, bar, 18);
r.X = Convert.ToInt32(barStruct.initial_Point);
r.Y += 4;
i = i + bar;
path = new GraphicsPath();
path.AddRectangle(r);
PathGradientBrush brush = new PathGradientBrush(path);
brush.WrapMode = WrapMode.TileFlipX;
brush.SurroundColors = new Color[] { shadeColor };
brush.CenterColor = Color.White;
//Draw the bar Background
pevent.Graphics.FillPath(brush, path);
//...and border
pevent.Graphics.DrawPath(drawingPen, path);
generatedBarCount++;
brush.Dispose();
}
Finish1:
drawingPen.Dispose();
path.Dispose();
}
Bar_MouseMove
当鼠标移动到条形图框上时,会调用此事件方法。在此方法中,提取鼠标坐标以找到鼠标悬停的条形图。如果鼠标不在生成的条形图上,它将显示条形图上下文的信息。当鼠标在生成的条形图上时,将出现相应的弹出对话框,其中包含关于特定事件、作业或即时库存的信息。例如,如果鼠标悬停在事件条形图上,则弹出窗口将显示该特定事件的信息。
private void Bar_MouseMove(object sender, MouseEventArgs e)
{
// bar array is not initialize
if (barArrayList == null)
return;
// balloon dialog is not allowed to be open on hover
if (!Is_HoverEnable)
return;
System.Drawing.Point po = this.FindForm().PointToClient
stem.Windows.Forms.Control.MousePosition);
System.Drawing.Point po2 = this.PointToClient
stem.Windows.Forms.Control.MousePosition);
if (po.X == poLast.X && po.Y == poLast.Y)
return;
poLast = po;
// base balloon dialog is not null then dispose it
if (aForm != null)
aForm.Dispose();
float m_X = po2.X;
Bar barStruct;
int DisplayShift = Convert.ToInt32(temp / m_ValuePerPixel * 0.5);
#region Traversing current bar
for (int i = 0; i < barArrayList.Count; i++)
{
barStruct = (Bar)barArrayList[i];
// mouse is over generated bar
if (m_X >= barStruct.initial_Point && m_X <= barStruct.final_Point)
{
// Raw material balloon
if (perspective_ID == 0)
{
// Raw material non Event balloon dialog
if (!is_Event)
{
aForm = new GoodsBalloon(filter,
barStruct.color, rows);
}
// Raw material Event balloon dialog
else
{
aForm = new ActivityBalloon(barStruct.ID);
}
}
// Job balloon dialog
if (perspective_ID == 1)
{
aForm = new JobBalloon(barStruct.ID,
truct.Job_Transaction_ID);
}
// Finished Goods balloon
if (perspective_ID == 2)
{
// Finished Goods non Event balloon dialog
if (!is_Event)
{
aForm = new GoodsBalloon(filter,
barStruct.color, rows);
}
// Finished Goods Event balloon dialog
else
{
aForm = new ActivityBalloon(barStruct.ID);
}
}
// Displaying selected balloon dialog
aForm.setBalloonPosition(this.FindForm(), po);
aForm.Show();
this.Focus();
return;
}
}
#endregion
// mouse is not on generated bar
string tag = "";
string name = "";
switch (perspective_ID)
{
case 0:
tag = "Raw Material";
name = this.Parent.Controls.Find("Tag", true)[0].Text;
break;
case 1:
tag = "Job ID";
name = this.Parent.Controls.Find("Tag", true)[0].Text;
break;
case 2:
tag = "Finished Goods";
name = this.Parent.Controls.Find("Tag", true)[0].Text;
break;
}
aForm = new VacantBalloon(tag, name);
aForm.setBalloonPosition(this.FindForm(), po);
aForm.Show();
this.Focus();
}
OnMouseClick
当需要更改作业状态时,会调用此事件。可以通过单击相关的条形图来调用它,相应的弹出对话框将提示输入。
protected override void OnMouseClick(MouseEventArgs e)
{
float m_X = e.X;
Bar barStruct;
if (perspective_ID == 2 || perspective_ID == 1)
{
return;
}
for (int i = 0; i < barArrayList.Count; i++)
{
barStruct = (Bar)barArrayList[i];
if (m_X >= barStruct.initial_Point && m_X <= barStruct.final_Point)
{
# region
if (!Is_HoverEnable)
return;
if (aForm != null)
aForm.Dispose();
if (aFormConcreate != null)
aFormConcreate.Dispose();
System.Drawing.Point po = this.FindForm().PointToClient
(System.Windows.Forms.Control.MousePosition);
System.Drawing.Point poi = po;
if (perspective_ID == 1 && barStruct.Is_Final_Job_Status)
Control.JobStatusBalloon.ShowBox(barStruct, poi);
#endregion
}
}
base.OnMouseClick(e);
}
Bar_MouseLeave
当鼠标离开当前条形图框时调用该事件,它将销毁当前弹出对话框。
public void Bar_MouseLeave(object sender, EventArgs e)
{
if (aForm != null)
aForm.Dispose();
}