提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
转帖|使用教程|编辑:龚雪|2024-02-23 11:05:44.337|阅读 21 次
概述:本文主要介绍如何在WinForms应用界面中实现通用的业务编码规则生成,希望帮助到大家~
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
相关链接:
在我们很多应用系统中,往往都需要根据实际情况生成一些编码规则,如订单号、入库单号、出库单号、退货单号等。有时候根据规则自行增加一个函数来生成处理,不过仔细观察后,发现它们的编码规则有很大的共通性,因此可以考虑使用一些通用的业务编码规则生成,从而在系统中统一维护即可,本文将介绍如何在WinForm界面中实现通用的业务编码规则生成。
PS:给大家推荐一个C#开发可以用到的界面组件——DevExpress WinForms,它能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!
DevExpress技术交流群9:909157416 欢迎一起进群讨论
刚才我们提到一些编码规则,如订单号、入库单号、出库单号、退货单号等等,它们都是有大同小异的规则,有前缀、有日期的编码、有一些流水号,还有一些特殊的规则处理,往往就是这些,需要协调好流水号的增加处理即可。
例如,原来在我的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; }
这里为了增加对流水号的循环判断,直到没有重复的即可输出来作为订单号。
大多数的编码规则大同小异,因此我们可以考虑使用共同的规则进行处理,类似通用字典的模块处理。订单编码,可以在新建订单的时候生成,也可以提供用户手动生成【生成编号】的操作,如下界面所示。
我们归纳了一些编码规则,基本上也就是前缀,日期分隔,分隔符,后缀,流水号这些元素的组合,如果需要更加复杂的也可以自行调整接口,这里设计一个通用的编码规则,对这些元素进行组合配置,数据库设计如下所示。
根据这些内容,使用手工编码或者代码生成工具生成相关的基础代码 (可以基于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的界面,他们的展示方式都是类似的,我们可以重用业务层对通用编码规则的定义。
本文转载自:
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn
文章转载自:本文探讨 SQL Server 中 NULL 和空值之间的区别,并讨论如何有效地处理它们。
Unity 是一款功能极其丰富的游戏引擎,允许开发人员将各种媒体集成到他们的项目中。但是,它缺少最令人兴奋的功能之一 - 将 Web 内容(例如 HTML、CSS 和 JavaScript)直接渲染到 3D 场景中的纹理上的能力。在本文中,我们将介绍如何使用 DotNetBrowser 在 Unity3D 中将 Web 内容渲染为纹理。
DevExpress v24.2帮助文档正式发布上线了,请按版本按需下载~
本教程将向您展示如何用MyEclipse构建一个Web项目,欢迎下载最新版IDE体验!
行业领先的界面控件开发包,帮助企业构建卓越应用!
DevExpress DXperience Subscription高性价比的企业级.NET用户界面套包,助力企业创建卓越应用!
DevExpress WinForms Subscription为Windows Forms平台创建具有影响力的业务解决方案,高性价比WinForms界面控件套包。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@pclwef.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢