在Winform应用中增加通用的业务编码规则生成
在我们很多应用系统中,往往都需要根据实际情况生成一些编码规则,如订单号、入库单号、出库单号、退货单号等等,我们有时候根据规则自行增加一个函数来生成处理,不过我们仔细观察后,发现它们的编码规则有很大的共通性,因此可以考虑使用一些通用的业务编码规则生成,从而在系统中统一维护即可,本篇随笔介绍如何在WInform界面中实现通用的业务编码规则生成。
1、常见单号的业务编码规则
刚才我们提到一些编码规则,如订单号、入库单号、出库单号、退货单号等等,它们都是有大同小异的规则,有前缀、有日期的编码、有一些流水号,还有一些特殊的规则处理,往往就是这些,需要协调好流水号的增加处理即可。
例如,原来在我的CRM业务模块中,增加了一个函数,用来生成订单号的,如下所示。
/// <summary>
/// 生成单据号码,编码为XS-{userId}-{yyyyMMdd}-流水号
/// </summary>
/// <returns></returns>
public async Task<string> GetOrderNo()
{
string prefix = string.Format("XS-{0}-{1}", CurrentApiUser.Id, DateTime.Now.ToString("yyyyMMdd")); //获取当天的记录数量+1
DateTime currentDate = DateTime.Now.ToString("yyyy-MM-dd").ToDateTime(); //当前日期
//计算条件数量+1
int count = this.EntityDb.Count(s => s.OrderDate >= currentDate && s.OrderDate <= currentDate.AddDays(1)) + 1; //循环检索,直到不重复的编号
string number = string.Format("{0}-{1}", prefix, count);
while (true)
{
var result = await CheckNumberExist(number);
if (result)
{
//存在增加1再判断
number = string.Format("{0}-{1}", prefix, count++);
}
else
{
break;
}
} return number;
}
这里为了增加对流水号的循环判断,直到没有重复的即可输出来作为订单号。
大多数的编码规则大同小异,因此我们可以考虑使用共同的规则进行处理,类似我们通用字典的模块处理。订单编码,可以在新建订单的时候生成,也可以提供用户手动生成【生成编号】的操作,如下界面所示。

2、设计通用的业务编码规则
我们归纳了一些编码规则,基本上也就是前缀,日期分隔,分隔符,后缀,流水号这些元素的组合,如果需要更加复杂的也可以自行调整接口,我们这里设计一个通用的编码规则,对这些元素进行组合配置,数据库设计如下所示。

根据这些内容,我们使用手工编码或者代码生成工具生成相关的基础代码 (可以基于EnterpriseLibrary的框架代码或者基于SqlSugar开发框架的代码),最终我们都用于WInform的界面调用。
这里以我们基于SqlSugar开发框架的代码生成为例。

生成后,会生成一个相关的业务类,实现相关的CRUD接口,如下代码定义所示,如果你有自己的基础框架实现,那么也可以忽略具体的代码生成,关注业务编码的生成的的规则即可。
/// <summary>
/// 业务表编码规则 应用层服务接口实现
/// </summary>
public class TableNumberService : MyCrudService<TableNumberInfo, string, TableNumberPagedDto>, ITableNumberService
为了控制编码的规则生成,我们增加一个同步锁来实现冲突处理。
/// <summary>
/// 同步锁
/// </summary>
private static SemaphoreSlim syncRoot = new SemaphoreSlim(1);
最终我们的实现代码如下所示。
/// <summary>
/// 根据定义表名、单据头、分割符1、分割符2,生成业务编码。如果生成错误,返回空字符串
/// </summary>
/// <param name="tableNameOrCode">表名或代码</param>
/// <returns></returns>
public async Task<string> GenerateNumber(string tableNameOrCode)
{
string businessNumber = "";
await syncRoot.WaitAsync(); //等待锁
try
{
var info = await base.GetFirstAsync(s => s.TableName == tableNameOrCode || s.Code == tableNameOrCode);
if (info != null)
{
string currentDate = "";
string lastDate = "";
int currentNumber = 1; //流水号起始值
int serialLength = 3; //流水号长度 if(!info.LastGenerateTime.HasValue)
{
info.LastGenerateTime = DateTime.Now;
} if (info.RuleFormat == "年月日")
{
currentDate = DateTime.Now.ToString("yyyyMMdd");
lastDate = info.LastGenerateTime.Value.ToString("yyyyMMdd");
}
else if (info.RuleFormat == "年月")
{
currentDate = DateTime.Now.ToString("yyyyMM");
lastDate = info.LastGenerateTime.Value.ToString("yyyyMM");
} //如果当前日期和最后日期不一致,流水号重置为0
if(!currentDate.Equals(lastDate))
{
info.CurrentValue = 0;
} //如果流水号非起始值,那么累计计算
if(info.CurrentValue.HasValue && info.CurrentValue >= 0)
{
currentNumber = (int)info.CurrentValue + 1;//流水号当前值
} //流水号长度
if(info.ValueLength.HasValue && info.ValueLength > 3)
{
serialLength = (int)info.ValueLength;//流水号长度
}
var SplitString1 = string.IsNullOrEmpty(info.SplitString1) ? "-" : info.SplitString1;
var SplitString2 = string.IsNullOrEmpty(info.SplitString2) ? "-" : info.SplitString2; //生成业务编码
businessNumber = $"{info.Prex}{SplitString1}{currentDate}{SplitString2}{currentNumber.ToString().PadLeft(serialLength, '0')}{info.Suffix}"; //更新记录
info.CurrentValue = currentNumber;
info.SplitString1 = SplitString1;
info.SplitString2 = SplitString2;
info.CurrentNumberString = businessNumber;
info.LastGenerateTime = DateTime.Now;//更新最后生成编码日期 await base.UpdateAsync(info);
}
}
catch (Exception ex)
{
var errorText = $"生成单号时出现错误:{ex.Message}";
LogTextHelper.Error(errorText, ex);
}
finally
{
syncRoot.Release();//释放锁
} return businessNumber;
}
上面主要注意的就是流水号的生成,这个稍微特殊处理一下,如果定义的规则是年月日,那么和最后的生成日期和当前日期不一致的话(转换为年月日对比),就认为流水号重新重置为1,否则是同一天的,流水号递增即可。如果是年月的,也是判断最后日期和当前日期的年月是否一致,不一致则重置为1,否则递增。注意流水号的编码长度,一般为4位,如果不满足的可以增加到6位等。
最终我们实际的业务编码的管理界面和查看的对应编码的界面如下所示,供参考设计界面处理。

编辑单个业务编码规则的界面如下所示。

为了方便,我们这里提供一个【测试生成】的按钮,用于测试具体的编码生成,我们具体的业务调用,就是类似这个调用即可。
var handNo = await BLLFactory<ITableNumberService>.Instance.GenerateNumber(tableNameOrCode);
同样,我们也可以把这个界面搬到WPF框架界面上去,可以重用具体的业务编码规则处理,如上类似的界面处理。

单个通用的业务编码规则的编辑界面如下所示。

因此,不管对于Winform还是WPF的界面,他们的展示方式都是类似的,我们可以重用业务层对通用编码规则的定义。
在Winform应用中增加通用的业务编码规则生成的更多相关文章
- 通用的业务编码规则设计实现[转:http://www.cnblogs.com/xqin/p/3708367.html]
一.背景 每一个企业应用中不可避免的都会涉及到业务编码规则的问题,比如订单管理系统中的订单编号,比如商品管理系统中的商品编码,比如项目管理系统中的项目编码等等,这一系列的编码都需要管理起来,那么它们的 ...
- Winform开发框架中工作流模块的业务表单开发
在我们开发工作流的时候,往往需要设计到具体业务表单信息的编辑,有些是采用动态编辑的,有些则是在开发过程中处理的,各有各的优点,动态编辑的则方便维护各种各样的表单,但是数据的绑定及处理则比较麻烦,而自定 ...
- Winform界面中实现通用工具栏按钮的事件处理
在一个给客户做的项目中,界面要求修改增加通用工具栏按钮的事件处理,也就是在主界面中放置几个固定的功能操作按钮,打开不同的页面的时候,实现对应页面的功能处理,这种和我标准的界面处理方式有所不同,标准的列 ...
- 参照企业微信审批业务,在Winform开发框架中工作流模块的实现业务审批
目前微信的企业号已经切换到企业微信里面,这个是一个APP程序,提供了很丰富的企业应用,其中包括了业务审批处理,审批业务包括请假.报销.费用.出差等很多个审批场景,在Winform开发框架中工作流模块这 ...
- Winform开发框架中工作流模块之申请单草稿处理
在我们开发工作流模块的时候,有时候填写申请单过程中,暂时不想提交审批,那么可以暂存为草稿,以供下次继续填写或者提交处理,那么这个草稿的功能是比较实用的,否则对于一些填写内容比较多的申请单,每次要重填写 ...
- Winform开发框架中工作流模块之审批会签操作(2)
前面随笔介绍了请假申请单和报销申请单两个不同的业务表单的流程处理,一个是单表信息,一个包含明细的主从表信息,后者包含了条件流程的处理,在流程审批中,一般还有一种流程处理就是会签的操作,会签处理是几个审 ...
- Winform开发框架中工作流模块之审批会签操作
在前面介绍了框架中工作流的几个开发过程,本篇随笔重点介绍一下日常审批环节中的具体处理过程,从开始创建表单,以及各个审批.会签过程的流转过程,希望大家对其中流程的处理有一个大概的印象. 1.请假申请表单 ...
- Winform开发框架中工作流模块的表设计分析
在较早博客随笔里面写过文章<Winform开发框架之简易工作流设计>之后,很久没有对工作流部分进行详细的介绍了,本篇继续这个主题,详细介绍其中的设计.实现及效果给大家,这个工作流在好几年前 ...
- RDIFramework.NET开发框架编码管理助力业务编码的自动处理
1.概述 几乎每一个企业应用中不可避免的都会涉及到业务编码规则的问题,比如订单管理中的订单编号,商品管理中的商品编码,项目管理中的项目编码等等,针对这一系列的编码如果直接写在程序中,不仅复杂,代码重复 ...
- WinForm开发中通用附件管理控件设计开发参考
1.引言 在WinForm开发中,文件附件的管理几乎在任何一个应用上都会存在,是一个非常通用集中的公共模块.我们日常记录会伴随着有图片.文档等附件形式来展现,如果为每个业务对象都做一个附件管理,或者每 ...
随机推荐
- C#性能优化-树形结构递归优化
前言 大家好,我是wacky,最近在工作中遇到一个有趣的问题,同事反馈说WPF中有一个树形结构的集合,在加载时会直接报堆栈溢出,一直没时间(懒得)看,导致很久了也没人解决掉.于是,组长就把这个&quo ...
- Redhat 8.2 系统语言切换(英文转中文)
前提条件 确保已连上网,并且配好 yum 源 若未配好 yum 源 可参考我上一篇文章 部分 Linux 换国内源 操作步骤 安装中文语言包 dnf install glibc-langpack-zh ...
- API接口的研发与应用
API(Application Programming Interface,应用程序编程接口)指的是为不同的软件应用程序提供编程接口的一组协议.规则以及工具的集合,以便它们能够互相交互,实现数据通 ...
- Unity UGUI的ScrollRect(滚动视图)组件的介绍及使用
Unity UGUI的ScrollRect(滚动视图)组件的介绍及使用 1. 什么是ScrollRect组件? ScrollRect(滚动视图)是Unity UGUI中的一个常用组件,用于在UI界面中 ...
- 解密网络通信的关键技术(下):DNS、ARP、DHCP和NAT,你了解多少?
引言 在上一章中,我们详细介绍了域名系统(DNS)和地址解析协议(ARP)的工作原理,从而对域名解析和介质访问控制(MAC)地址寻址有了更深入的了解.在今天的章节中,我们将继续探讨动态主机配置协议(D ...
- java实现 微信公众号推送消息 ,cv 就可运行!!!
一,注册公众号 1,官网地址:申请测试公众号 地址: 微信公众平台 (qq.com) 文档地址:微信开放文档 (qq.com) 2,注册后可以查看自己的appId 和 appsecret 3,创建模板 ...
- 【Mac2021版Intel芯片下载】 - Intel芯片推荐安装
[Mac2021版Intel芯片下载] - Intel芯片推荐安装 往下拉有安装图文教程一.下载提示1请点击图标进行下载 ●每个软件下方均标注了该软件的用途,请注意查看: ●如果点击无反应,请换一个浏 ...
- 推荐免费的svn空间(SVN代码托管)
推荐免费的svn空间(SVN代码托管) 最近研究了国内和国外的免费svn空间,SVN代码托管,SVN在线,代码托管中心,有所心得. 1.http://www.svn999.com/ [推荐]国内的,免 ...
- vue 基于原生动画的自动滚动表格
前言 公司展示大屏需要写滚动表格,通过滚动播放数据,自己随便摸了一个基于动画的自动滚动表格 原理 根据每行的大小和设置的每行滚动时间设置滚动位置,动态添加动画,并把数组第一项移动到最后一项,并订阅该动 ...
- 轻松掌握组件启动之Redis单机、主从、哨兵、集群配置
单机配置启动 Redis安装 下载地址:http://redis.io/download 安装步骤: 1: 安装gcc编译器:yum install gcc 2: 将下载好的redis‐5.0.3.t ...