Workflow (3): Workflow transfer framework code

Workflow (2): workflow flow chart design_Sneko's Blog-CSDN Blog

Workflow flow framework code

Workflow start, sign for or verify, send out, return, withdraw, close and other process processing

1. Create the entity class WorkFlow_Trace corresponding to the workflow link tracking table

The source program of WorkFlow_Trace.cs is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WorkFlowDemo
{
    /// <summary>
    /// 工作流跟踪数据表
    /// </summary>
    public class WorkFlow_Trace
    {
        #region 实体属性

        /// <summary>
        /// 主键自增编号
        /// </summary>
        public int? CoreId { get; set; }

        /// <summary>
        /// 上一跟踪编号:-1代表根节点
        /// </summary>
        public int? ParentCoreId { get; set; }

        /// <summary>
        /// 模组码
        /// </summary>
        public string Barcode { get; set; }

        /// <summary>
        /// 工单号
        /// </summary>
        public string WorkOrder { get; set; }

        /// <summary>
        /// 操作工序编码
        /// </summary>
        public string Operation { get; set; }

        /// <summary>
        /// 操作工序名称
        /// </summary>
        public string OperationName { get; set; }

        /// <summary>
        /// 处理开始时间
        /// </summary>
        public DateTime? ProcessStartTime { get; set; }

        /// <summary>
        /// 处理结束时间
        /// </summary>
        public DateTime? ProcessEndTime { get; set; }

        /// <summary>
        /// 状态【Queue排队中,Working工作中,Completed完成,DirectDelivery直送-拉状态,Abolished作废的】
        /// </summary>
        public string WorkStatus { get; set; }

        /// <summary>
        /// 创建人
        /// </summary>
        public string CreateName { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime? CreateTime { get; set; }

        /// <summary>
        /// 是否完工下料
        /// </summary>
        public int? IsAllCompleted { get; set; }

        #endregion
    }
}

2. New database operation class SugarClient

The source program of SugarClient.cs is as follows:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using SqlSugar;
namespace WorkFlowDemo
{
    /// <summary>
    /// SqlSugar客户端操作数据库
    /// </summary>
    public class SugarClient
    {
        /// <summary>
        /// 添加一行数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int Insert<T>(T obj) where T : class, new()
        {
            using (SqlSugarClient sugarClient = SugarDao.GetInstance())
            {
                return sugarClient.Insertable(obj).ExecuteCommand();
            }
        }

        /// <summary>
        /// 更新一行数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int Update<T>(T obj) where T : class, new()
        {
            using (SqlSugarClient sugarClient = SugarDao.GetInstance())
            {
                return sugarClient.Updateable(obj).ExecuteCommand();
            }
        }
    }
}

3. WorkFlowEngineUtil for key workflow start, send, and finish classes

The source program of WorkFlowEngineUtil.cs is as follows:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WorkFlowDemo
{
    /// <summary>
    /// 工作流启动、流转(送出)、完成、办结【比如由组件装配工序 自动 流转到 拍照工序】
    /// 斯内科 2023-03-28
    /// </summary>
    public class WorkFlowEngineUtil
    {
        /// <summary>
        /// 启动工作流:找到工艺路线的起始工序,然后将其设置为排队中即可
        /// 返回元组:第一项代表错误号【为0代表OK】,第二项代表当前操作工序环节,第三项代表错误信息
        /// </summary>
        /// <param name="barcode"></param>
        /// <returns></returns>
        public static Tuple<int, string, string> StartWorkFlow(string barcode)
        {
            string sqlStart = "select * from process_router where PreviousOperationName='' or PreviousOperationName is null";
            DataTable dtStart = RawSql.GetDataTable(sqlStart, null);
            if (dtStart == null || dtStart.Rows.Count < 1)
            {
                return Tuple.Create(10001, "", $"没有配置工艺路线【process_router】的起始工序,模组码【{barcode}】");
            }
            string operation = dtStart.Rows[0]["Operation"].ToString();
            string operationName = dtStart.Rows[0]["OperationName"].ToString();
            string workOrder = "WorkOrder001";
            WorkFlow_Trace workFlow_Trace = new WorkFlow_Trace()
            {
                ParentCoreId = -1,
                Barcode = barcode,
                WorkOrder = workOrder,
                Operation = operation,
                OperationName = operationName,
                ProcessStartTime = DateTime.Now,
                WorkStatus = "Queue",
                CreateName = "test",
                CreateTime = DateTime.Now,
                IsAllCompleted = 0
            };
            int result = SugarClient.Insert(workFlow_Trace);
            if (result <= 0)
            {
                return Tuple.Create(10002, operationName, $"启动工作流失败,模组码【{barcode}】");
            } 
            return Tuple.Create(0, operationName, $"启动工作流成功,模组码【{barcode}】,起始环节【{workFlow_Trace.OperationName}】,状态【{workFlow_Trace.WorkStatus}】");
        }

        /// <summary>
        /// 进站校验,查看是否在该工序的排队中,如果不在排队中,就报错。如果在排队Queue中,就将其修改为工作Working中
        /// </summary>
        /// <param name="barcode"></param>
        /// <param name="operationName"></param>
        /// <returns></returns>
        public static Tuple<int, string> Inbound(string barcode, string operationName)
        {
            //进站校验,查看是否在该工序的排队中,如果不在排队中,就报错。如果在排队Queue中,就将其修改为工作Working中
            string sql = "select * from workflow_trace where barcode=@Barcode";
            DataTable dtStart = RawSql.GetDataTable(sql, new Dictionary<string, object>() { { "Barcode", barcode } });
            if (dtStart == null || dtStart.Rows.Count < 1)
            {
                return Tuple.Create(10003, $"模组条码不存在,查看是否已删除或者工作流未启动,模组码【{barcode}】");
            }
            DataRow[] dataRows = dtStart.Select("WorkStatus='Queue'", "CoreId desc");
            if (dataRows == null || dataRows.Length < 1)
            {
                return Tuple.Create(10004, $"模组条码不在排队中,请检查是否已完成。模组码【{barcode}】");
            }
            string coreId = dataRows[0]["CoreId"].ToString();
            string queueOperationName = dataRows[0]["OperationName"].ToString();
            if (queueOperationName != operationName)
            {
                return Tuple.Create(10005, $"模组不在【{operationName}】的排队中,它在【{queueOperationName}】的排队中,模组码【{barcode}】");
            }
            string sqlUpdateStatus = "update workflow_trace set WorkStatus='Working' where CoreId=@CoreId";
            RawSql.ExecuteCommand(sqlUpdateStatus, new Dictionary<string, object>() { { "CoreId", coreId } });            
            return Tuple.Create(0, $"进站校验成功,已将模组状态设置为工作中,模组码【{barcode}】");
        }

        /// <summary>
        /// 先判断当前环节是否在工作中,如果在工作中,就将状态设置为完成,并自动送出到下一个环节。
        /// 如果当前环节无下一个环节,则自动完成工序【下料】,并自动办结Archive
        /// </summary>
        /// <param name="barcode"></param>
        /// <param name="operationName"></param>
        /// <returns></returns>
        public static Tuple<int, string, string> SendNext(string barcode, string operationName)
        {
            //送出:update当前环节为已完成,然后新建下一环节
            string sql = "select * from workflow_trace where barcode=@Barcode";
            DataTable dt = RawSql.GetDataTable(sql, new Dictionary<string, object>() { { "Barcode", barcode } });
            if (dt == null || dt.Rows.Count < 1)
            {
                return Tuple.Create(10006, "", $"模组条码不存在,查看是否已删除或者工作流未启动,模组码【{barcode}】");
            }
            DataRow[] dataRows = dt.Select("WorkStatus='Working'", "CoreId desc");
            if (dataRows == null || dataRows.Length < 1)
            {
                return Tuple.Create(10007, "", $"模组条码不在工作中,请检查是否在【{operationName}】工作中。模组码【{barcode}】");
            }
            string coreId = dataRows[0]["CoreId"].ToString();
            string workingOperationName = dataRows[0]["OperationName"].ToString();
            if (workingOperationName != operationName)
            {
                return Tuple.Create(10008, workingOperationName, $"模组不在【{operationName}】的工作中,它在【{workingOperationName}】的工作中,模组码【{barcode}】");
            }
            string sqlFinish = "update workflow_trace set WorkStatus='Completed',ProcessEndTime=@ProcessEndTime where CoreId=@CoreId";
            RawSql.ExecuteCommand(sqlFinish,
                new Dictionary<string, object>() { { "CoreId", coreId }, { "ProcessEndTime", DateTime.Now } });

            //找出当前环节的下一个环节,如果当前环节无下一个环节,则自动下料完成
            string sqlNext = "select * from process_router where PreviousOperationName=@PreviousOperationName";
            DataTable dtNext = RawSql.GetDataTable(sqlNext, new Dictionary<string, object>() { { "PreviousOperationName", operationName } });
            if (dtNext == null || dtNext.Rows.Count < 1)
            {
                //办结
                string sqlArchive = "update workflow_trace set IsAllCompleted='1' where CoreId=@CoreId";
                RawSql.ExecuteCommand(sqlArchive, new Dictionary<string, object>() { { "CoreId", coreId } });
                //办结表迁移
                Tuple<int, string> tupleArchive = Archive(barcode);
                if (tupleArchive.Item1 != 0)
                {
                    return Tuple.Create(tupleArchive.Item1, "", tupleArchive.Item2); ;
                }
                return Tuple.Create(0, "", $"当前工序【{operationName}】已经是终结工序,已生产完成,模组码【{barcode}】");
            }
            string nextOperation = dtNext.Rows[0]["Operation"].ToString();
            string nextOperationName = dtNext.Rows[0]["OperationName"].ToString();
            string workOrder = dataRows[0]["WorkOrder"].ToString();

            WorkFlow_Trace workFlow_Trace = new WorkFlow_Trace()
            {
                ParentCoreId = int.Parse(coreId),
                Barcode = barcode,
                WorkOrder = workOrder,
                Operation = nextOperation,
                OperationName = nextOperationName,
                ProcessStartTime = DateTime.Now,
                WorkStatus = "Queue",
                CreateName = "test",
                CreateTime = DateTime.Now,
                IsAllCompleted = 0
            };
            int result = SugarClient.Insert(workFlow_Trace);
            if (result <= 0)
            {
                return Tuple.Create(10009, nextOperationName, $"从工序【{operationName}】自动流转到下一工序【{nextOperationName}】失败,模组码【{barcode}】");
            }
            return Tuple.Create(0, nextOperationName, $"流转成功,已将模组从工序【{operationName}】自动流转到下一工序【{nextOperationName}】的排队中,模组码【{barcode}】");
        }

        /// <summary>
        /// 办结归档表,将已完成的工作流工序数据迁移到表【workflow_trace_archive】中,可以在历史记录中查看
        /// 先删除workflow_trace_archive的当前条码数据
        /// 然后将workflow_trace的数据迁移到workflow_trace_archive,最后删除表workflow_trace_archive的数据
        /// </summary>
        /// <param name="barcode"></param>
        /// <returns></returns>
        public static Tuple<int, string> Archive(string barcode)
        {
            string sql = "select * from workflow_trace where barcode=@Barcode";
            DataTable dt = RawSql.GetDataTable(sql, new Dictionary<string, object>() { { "Barcode", barcode } });
            if (dt == null || dt.Rows.Count < 1)
            {
                return Tuple.Create(10010, $"模组条码不存在,查看是否已删除或已办结或者工作流未启动,模组码【{barcode}】");
            }
            string sqlArchive = $@"delete from workflow_trace_archive where Barcode=@Barcode;
insert into workflow_trace_archive select * from workflow_trace where Barcode=@Barcode;
delete from workflow_trace where Barcode=@Barcode;";
            RawSql.ExecuteCommand(sqlArchive, new Dictionary<string, object>() { { "Barcode", barcode } });
            return Tuple.Create(0, $"已办结归档成功,模组码【{barcode}】");
        }
    }
}

4. Create a new test winform form FormFlowTest, as shown in the figure:

 FormFlowTest.Designer.cs source program is as follows:


namespace WorkFlowDemo
{
    partial class FormFlowTest
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.rtxbDisplay = new System.Windows.Forms.RichTextBox();
            this.btnFlowTest = new System.Windows.Forms.Button();
            this.label1 = new System.Windows.Forms.Label();
            this.txtBarcode = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // rtxbDisplay
            // 
            this.rtxbDisplay.Location = new System.Drawing.Point(319, 12);
            this.rtxbDisplay.Name = "rtxbDisplay";
            this.rtxbDisplay.Size = new System.Drawing.Size(703, 492);
            this.rtxbDisplay.TabIndex = 0;
            this.rtxbDisplay.Text = "";
            // 
            // btnFlowTest
            // 
            this.btnFlowTest.Font = new System.Drawing.Font("宋体", 13F);
            this.btnFlowTest.Location = new System.Drawing.Point(78, 88);
            this.btnFlowTest.Name = "btnFlowTest";
            this.btnFlowTest.Size = new System.Drawing.Size(111, 55);
            this.btnFlowTest.TabIndex = 1;
            this.btnFlowTest.Text = "流转测试";
            this.btnFlowTest.UseVisualStyleBackColor = true;
            this.btnFlowTest.Click += new System.EventHandler(this.btnFlowTest_Click);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font("宋体", 13F);
            this.label1.Location = new System.Drawing.Point(17, 13);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(134, 18);
            this.label1.TabIndex = 2;
            this.label1.Text = "条码或流程编号";
            // 
            // txtBarcode
            // 
            this.txtBarcode.Font = new System.Drawing.Font("宋体", 13F);
            this.txtBarcode.Location = new System.Drawing.Point(12, 45);
            this.txtBarcode.Name = "txtBarcode";
            this.txtBarcode.Size = new System.Drawing.Size(274, 27);
            this.txtBarcode.TabIndex = 3;
            this.txtBarcode.Text = "WorkFlow123456";
            // 
            // FormFlowTest
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1034, 516);
            this.Controls.Add(this.txtBarcode);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.btnFlowTest);
            this.Controls.Add(this.rtxbDisplay);
            this.Name = "FormFlowTest";
            this.Text = "流转测试";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.RichTextBox rtxbDisplay;
        private System.Windows.Forms.Button btnFlowTest;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.TextBox txtBarcode;
    }
}

5. Test the FormFlowTest.cs program as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WorkFlowDemo
{
    public partial class FormFlowTest : Form
    {
        public FormFlowTest()
        {
            InitializeComponent();
            rtxbDisplay.ReadOnly = true;
        }

        /// <summary>
        /// 显示文本框内容
        /// </summary>
        /// <param name="message"></param>
        private void DisplayContent(string message)
        {
            this.BeginInvoke(new Action(() =>
            {
                if (rtxbDisplay.TextLength > 10240)
                {
                    rtxbDisplay.Clear();
                }
                rtxbDisplay.AppendText($"{DateTime.Now.ToString("HH:mm:ss.fff")}->{message}\n");
                rtxbDisplay.ScrollToCaret();
            }));
        }

        /// <summary>
        /// 按钮激活或屏蔽
        /// </summary>
        /// <param name="enabled"></param>
        private void EnableButton(bool enabled) 
        {
            this.BeginInvoke(new Action(() =>
            {
                btnFlowTest.Enabled = enabled;
            }));
        }

        private async void btnFlowTest_Click(object sender, EventArgs e)
        {
            string barcode = txtBarcode.Text.Trim();
            await Task.Run(()=> 
            {
                EnableButton(false);
                Tuple<int, string, string> tupleStart = WorkFlowEngineUtil.StartWorkFlow(barcode);
                DisplayContent($"【{barcode}】已启动工作流.错误号【{tupleStart.Item1}】,操作工序【{tupleStart.Item2}】,消息【{tupleStart.Item3}】");
                Thread.Sleep(2000);

                string operationName = tupleStart.Item2;
                do
                {
                    Tuple<int, string> tupleInbound = WorkFlowEngineUtil.Inbound(barcode, operationName);
                    DisplayContent($"【{barcode}】在工序【{operationName}】进站.错误号【{tupleInbound.Item1}】,操作工序【{operationName}】,消息【{tupleInbound.Item2}】");
                    if (tupleInbound.Item1 != 0) 
                    {
                        break;
                    }
                    Tuple<int, string, string> tupleNext = WorkFlowEngineUtil.SendNext(barcode, operationName);
                    DisplayContent($"【{barcode}】从工序【{operationName}】自动流转到工序【{tupleNext.Item2}】.错误号【{tupleNext.Item1}】,消息【{tupleNext.Item3}】");
                    if (tupleNext.Item1 == 0 && string.IsNullOrEmpty(tupleNext.Item2))
                    {
                        DisplayContent($"【{barcode}】已办结【已生产完成】.错误号【{tupleNext.Item1}】,消息【{tupleNext.Item3}】");
                        break;
                    }
                    else if (tupleNext.Item1 != 0) 
                    {
                        break;
                    }
                    //自动流转到下一工序
                    operationName = tupleNext.Item2;
                    Thread.Sleep(2000);
                } while (true);
                EnableButton(true);
            });
        }
    }
}

Sixth, the test operation is as shown in the figure:

 

 

Guess you like

Origin blog.csdn.net/ylq1045/article/details/127985987