系列文章
【C#】最全业务单据号生成(支持定义规则、流水号、传参数)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129129787
【C#】日期范围生成器(开始日期、结束日期)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129040663
【C#】组件化开发,调用dll组件方法
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129492112
【C#】数据实体类使用
本文链接:https://blog.csdn.net/youcheng_ge/article/details/128816638
【C#】单据审批流方案
本文链接:https://blog.csdn.net/youcheng_ge/article/details/128972545
【C#】条码管理操作手册
本文链接:https://blog.csdn.net/youcheng_ge/article/details/126589496
【C#】IIS平台下,WebAPI发布及异常处理
本文链接:https://blog.csdn.net/youcheng_ge/article/details/126539836
【C#】代码模板生成工具
本文链接:https://blog.csdn.net/youcheng_ge/article/details/126890673
【C#】MySQL数据库导入工具(批量Excel插入)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/126427323
【C#】简单二维码制作和打印工具
本文链接:https://blog.csdn.net/youcheng_ge/article/details/126884228
【C#】最全单据打印(打印模板、条形码&二维码、字体样式、项目源码)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129415723
【C#】Windows服务(Service)安装及启停方案
本文链接:https://blog.csdn.net/youcheng_ge/article/details/124053794
【C#】穿透Session隔离,服务调用外部程序(无窗体界面解决)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/124053033
【C#】任务计划实现,使用Quartz类
本文链接:https://blog.csdn.net/youcheng_ge/article/details/123667723
【C#】源码解析正则表达式
本文链接:https://blog.csdn.net/youcheng_ge/article/details/118337074
【C#】软件版本和文件MD5记录(XML操作)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/112513871
【C#】测试网络是否连通
本文链接:https://blog.csdn.net/youcheng_ge/article/details/110137288
【C#】根据名称获取编码(Dictionary获取key方法)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129816701
【C#】数据建模,你是使用DataTable还是List?
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129792726
【C#】GridControl控件和数据集双向绑定
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129423755
【C#】GridControl动态更换DataSource,数据查询异常处理
本文链接:https://blog.csdn.net/youcheng_ge/article/details/130305424
【C#】GridControl日期字段显示时分秒
本文链接:https://blog.csdn.net/youcheng_ge/article/details/130718303
【C#】GridControl增加选择列(不用二次点击)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/130763713
【C#】数据库检查工具(可跨库访问)
本文链接:https://blog.csdn.net/youcheng_ge/article/details/97172329
【C#】代码解析–打印数据集
本文链接:https://blog.csdn.net/youcheng_ge/article/details/131431829
【C#】代码解析–截取整个方法函数
本文链接:https://blog.csdn.net/youcheng_ge/article/details/109817809
【C#】反射机制,动态加载类文件
本文链接:https://blog.csdn.net/youcheng_ge/article/details/131435110
更新日志
版本 | 更新日期 | 更新说明 |
---|---|---|
V1.0 | 2023-02-20 | 首次发布自动编号生成器 |
V1.1 | 2023-03-15 | 代码未变更,仅仅调整文章章节,使之结构更清晰 |
V2.0 | 2023-03-21 | 原编号规则–流水号位数,采用分号分割。因新业务需求,我需要在编码中传入【参数】,我没有特殊字符识别这类,改造流水号位数为阿拉伯数字 。见3.4 创建自动编号客户端(V2.0) |
V3.0 | 2023-11-15 | 规则中,传入参数个数可以根据参数表自动定义,使用public static String Format(String format, params object[] args) |
V4.0 | 2023-12-25 | 代码简化,增加注释,【流水号】不是必传参数` |
前言
我能抽象出整个世界,但是我不能抽象你。 想让你成为私有常量,这样外部函数就无法访问你。 又想让你成为全局常量,这样在我的整个生命周期都可以调用你。 可惜世上没有这样的常量,我也无法定义你,因为你在我心中是那么的具体。
哈喽大家好,本专栏为【项目实战】,有别于【底层库】专栏,我们可以发现增加 了『问题描述』、『项目展示』章节,十分贴合项目开发流程,让读者更加清楚本文能够解决的问题、以及产品能够达到的效果。本专栏收纳项目开发过程中的解决方案,是我项目开发相对成熟、可靠方法的总结,在不涉及职务作品
、保密协议
的前提下,我将问题的解决方案重新梳理,撰写本文分享给大家,大家遇到类似问题,可按本文方案处理。
本专栏会持续更新,不断完善,专栏文章关联性较弱(文章之间依赖性较弱,没有阅读顺序)。大家有任何问题,可以私信我。如果您对本专栏感兴趣,欢迎关注吧,我将带你用最简洁的代码,实现复杂的功能。
·提示:本专栏为项目实战篇,未接触项目开发的同学可能理解困难,不推荐阅读。
一、问题描述
1.1 原业务需求
我在生产型公司担任 软件工程师。问题起因,各部门日常运营会产生各种各样的单据,而这些单据标识需要用到 编号
。比如:销售订单–销售订单号、采购订单–采购订单号、材料入库单–入库单号、原材料出库单–出库单号、财务凭证单–凭证单号、成品发货单–物流单号等。
大部分人员会使用随机数Guid、自增列,作为标识。但是,业务部门未必认可这样的编号。有意义的业务单据号设计,业务员看到就能够对业务进行分类,知道这个单据应该走哪类处理流程。
显然,单纯的随机数、自增id,无法实现这样的效果。
提示:这是业务部门给出的部分编号规则,,只是物料部分。
1.2 新业务需求
公司实验室需要对物料进行质检,“样品编号”,需要能够明显关联“原物料”(不查系统,人工看编号)。我们的“样品编号”,要包含“物料编号”,这样就解决这个问题。
故而,我们的业务单据号生成器
还需要支持 传参数
,直接把原物料的编号传入,编号规则中。
二、解决方案
2.1 可行性分析
如上图所示,业务部门给出的“编号规则”,基本是 固定字符+流水号 的形式。这是最简单的版本,如果再复杂一点,可以细分为 固定字符+日期缩写+流水号。再进行复杂一点,又可以分为 固定字符+类型(获取系统参数)+日期缩写+员工代号+流水号等等。
那么我们的处理必然要区分“编号组成”,分开处理,采用字符串拼接的方式。固定字符,保留;流水号是数值类型(1,2,3,4,5…),需要先取得上一次的数值,执行+1操作;类型,获取系统参数,解决思路从用户登录信息、功能模块操作记录、点击事件中抓取数据。
所以,我们要解决的核心问题:要先获取上一次单据号,看流水号排到多少了,然后才能进行+1操作。我们就要查询数据库业务表,获得最大的流水号是多少。
2.2 采用方案
在代码里写大量取数,拼接字符串,这工作量太大了,而且很容易出错。就算他们不出错,如果对于业务部门,哪天业务调整了,编号要变化,又要改程序太麻烦了。
所以我为了解决这个问题,我想开发一个专门的服务,统一生成这么个编号。
我将这服务通用化,对平台、开发语言的依赖要尽可能低,就是说,无论你用 电脑、平板、手机、浏览器还是以后的什么设备,都可以获取我的“自动编号”。
解决方案:①创建API应用接口 ②编写自动编号生成器 ③部署服务 ④客户端调用,获取自动编号。
2.3 方案增补(V2.0)
解决编号【传参】问题,使用string.Format()
。
public const string 钨条样编号规则 = “WT-{0}-[2位流水号]”;
string.Format(编号规则.钨条样编号规则,item.钨条编号)
2.4 方案增补(V3.0)
解决编号【传参】参数个数不确定问题,为了通用化,规则表不再使用 字符串拼接
。
开发时遇到string.Format 需要传递任意个参数的情况(一般是配置中不确定参数个数)
string.Format有以下重载,最适合的是public static String Format(String format, params object[] args);
2.5 方案增补(V4.0)
简化代码,【流水号】不作为必须参数。
三、软件开发(项目源码)
3.1 引入底层库
Visual Studio创建WebAPI项目,使用本文内容,还需要两个底层库支持,在 底层库
专栏你可以找到它。
1、C#底层库–MySQL数据库访问操作辅助类(推荐阅读)
2、C#底层库–StringExtension字符串扩展类
3、C#底层库–SQLSuger数据库访问操作类(推荐阅读),如果想支持多数据库产品,使用Sqlsuger
。
提示:C#底层库专栏,包含开发中最基础的库,
3.2 创建数据模型
创建类AutoCodeRuleModel.cs,作为 传入的参数实体,复制以下代码:
using System;
namespace DLMESWebAPI
{
public class AutoCodeRuleModel
{
public string 编号规则 { get; set; } //自动编号规则
public string 表 { get; set; } //数据库表
public string 字段 { get; set; } //表字段
}
}
3.3 创建自动编号客户端(V1.0)
创建类 AutoCodeClient.cs,用于自动编号生成,是核心方法,复制以下代码:
using BaseClass_NameSpace;
using System;
using System.Data;
namespace DLMESWebAPI.BLL
{
public class AutoCodeClient
{
/// <summary>
/// 获取自动编号
/// </summary>
/// <param name="a_strAutoRule">编号规则</param>
/// <param name="a_strCodeTable">表名</param>
/// <param name="a_strCodeField">字段名</param>
/// <returns></returns>
public static string GetAutoCode(string a_strAutoRule, string a_strCodeTable, string a_strCodeField)
{
int a_CodeLength = 4;
string[] array = a_strAutoRule.Split(new char[]
{
',',
';'
});
if (array.Length > 1) //编号规则是否定义了流水号位数。
{
int.TryParse(array[1], out a_CodeLength);
return AutoCodeClient.GetAutoCode(array[0], a_CodeLength, a_strCodeTable, a_strCodeField);
}
return AutoCodeClient.GetAutoCode(a_strAutoRule, a_CodeLength, a_strCodeTable, a_strCodeField);
}
public static string GetAutoCode(string a_strAutoRule, int a_CodeLength, string a_strCodeTable, string a_strCodeField)
{
string text = "";
string text2 = "";
checked
{
for (int i = 0; i < a_CodeLength; i++)
{
text += "_";
text2 += "0";
}
string text3 = AutoCodeClient.ParseCodeRule(a_strAutoRule, a_CodeLength);
string s = AutoCodeClient.ParseQueryRule(a_strAutoRule, a_CodeLength);
int num = text3.IndexOf(text);
MySQLHelper fetchData = new MySQLHelper();
string text4 = "select {0} from {1} where {2} like {3} order by 1 desc LIMIT 0,1";
text4 = string.Format(text4, new object[]
{
string.Format("SUBSTRING({0}, {1}, {2})", a_strCodeField, num + 1, a_CodeLength),
a_strCodeTable,
a_strCodeField,
s.QuotedStr()
});
DataTable l_dt = fetchData.Query(text4).Tables[0];
if (l_dt!=null)
{
string newValue;
if (l_dt.Rows.Count<=0)
{
newValue = 1.ToString(text2);
}
else
{
text3.Substring(0, num);
if (text3.Length > num + 4)
{
text3.Substring(num + 4);
}
string s2 = l_dt.Rows[0][0].ToString();
int num2 = 0;
int.TryParse(s2, out num2);
num2++;
newValue = num2.ToString(text2);
}
text3 = text3.Replace(text, newValue);
}
return text3;
}
}
public static string GetAutoCodeAlpha(string a_strAutoRule, string a_strCodeTable, string a_strCodeField)
{
int num = 1;
string text = "";
string str = "";
checked
{
for (int i = 0; i < num; i++)
{
text += "_";
str += "0";
}
string text2 = AutoCodeClient.ParseCodeRule(a_strAutoRule, num);
string s = AutoCodeClient.ParseQueryRule(a_strAutoRule, num);
int num2 = text2.IndexOf(text);
//BaseMySQL fetchData = new BaseMySQL();
MySQLHelper fetchData = new MySQLHelper();
string text3 = "select top 1 {0} from {1} where {2} like {3} order by 1 desc";
text3 = string.Format(text3, new object[]
{
string.Format("SUBSTRING({0}, {1}, {2})", a_strCodeField, num2 + 1, num),
a_strCodeTable,
a_strCodeField,
s.QuotedStr()
});
DataTable l_dt = fetchData.Query(text3).Tables[0];
if (l_dt!=null)
{
string newValue;
if (l_dt.Rows.Count<=0)
{
newValue = "A";
}
else
{
text2.Substring(0, num2);
if (text2.Length > num2 + 4)
{
text2.Substring(num2 + 4);
}
string text4 = l_dt.Rows[0][0].ToString();
int num3 = 65;
if (text4.Length > 0)
{
num3 = (int)text4[0];
}
num3++;
if (num3 > 90)
{
return AutoCodeClient.GetAutoCodeAlpha2(a_strAutoRule, a_strCodeTable, a_strCodeField);
}
newValue = Convert.ToString((char)num3);
}
text2 = text2.Replace(text, newValue);
}
return text2;
}
}
private static string GetAutoCodeAlpha2(string a_strAutoRule, string a_strCodeTable, string a_strCodeField)
{
int num = 2;
string text = "";
string str = "";
checked
{
for (int i = 0; i < num; i++)
{
text += "_";
str += "0";
}
string text2 = AutoCodeClient.ParseCodeRule(a_strAutoRule, num);
string s = AutoCodeClient.ParseQueryRule(a_strAutoRule, num);
int num2 = text2.IndexOf(text);
//BaseMySQL fetchData = new BaseMySQL();
MySQLHelper fetchData = new MySQLHelper();
string text3 = "select top 1 {0} from {1} where {2} like {3} order by 1 desc";
text3 = string.Format(text3, new object[]
{
string.Format("SUBSTRING({0}, {1}, {2})", a_strCodeField, num2 + 1, num),
a_strCodeTable,
a_strCodeField,
s.QuotedStr()
});
DataTable l_dt = fetchData.Query(text3).Tables[0];
if (l_dt!=null)
{
string newValue;
if (l_dt.Rows.Count<=0)
{
newValue = "AA";
}
else
{
string input = l_dt.Rows[0][0].ToString();
newValue = AutoCodeClient.IncAlphaCode(input);
}
text2 = text2.Replace(text, newValue);
}
return text2;
}
}
private static string IncAlphaCode(string input)
{
char c = input[0];
char c2 = input[1];
int num = (int)c;
int num2 = (int)c2;
checked
{
if (num2 < 90)
{
return Convert.ToString((char)num) + Convert.ToString((char)(num2 + 1));
}
return Convert.ToString((char)(num + 1)) + "A";
}
}
private static string ParseCodeRule(string a_strAutoRule, int a_CodeLength)
{
DateTime date = DateTime.Now.Date;
if (a_strAutoRule.Contains("[紧缩天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[紧缩天数]", date.Day.ToString());
}
if (a_strAutoRule.Contains("[两位天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", date.Day.ToString("00"));
}
if (a_strAutoRule.Contains("[紧缩月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString());
}
if (a_strAutoRule.Contains("[两位月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString("00"));
}
checked
{
if (a_strAutoRule.Contains("[一位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[一位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 1, 1));
}
if (a_strAutoRule.Contains("[两位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 2, 2));
}
if (a_strAutoRule.Contains("[四位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[四位年份]", date.Year.ToString("0000"));
}
string text2 = "";
for (int i = 0; i < a_CodeLength; i++)
{
text2 += "_";
}
a_strAutoRule = a_strAutoRule.Replace("[流水编号]", text2);
a_strAutoRule = a_strAutoRule.Replace("[按月编号]", text2);
a_strAutoRule = a_strAutoRule.Replace("[按年编号]", text2);
return a_strAutoRule;
}
}
private static string ParseQueryRule(string a_strAutoRule, int a_CodeLength)
{
DateTime date = DateTime.Now.Date;
if (a_strAutoRule.Contains("[紧缩天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[紧缩天数]", date.Day.ToString());
}
if (a_strAutoRule.Contains("[两位天数]"))
{
if (a_strAutoRule.Contains("[按月编号]") || a_strAutoRule.Contains("[按年编号]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", "__");
}
else
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", date.Day.ToString("00"));
}
}
if (a_strAutoRule.Contains("[紧缩月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString());
}
if (a_strAutoRule.Contains("[两位月份]"))
{
if (a_strAutoRule.Contains("[按年编号]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", "__");
}
else
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString("00"));
}
}
checked
{
if (a_strAutoRule.Contains("[一位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[一位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 1, 1));
}
if (a_strAutoRule.Contains("[两位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 2, 2));
}
if (a_strAutoRule.Contains("[四位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[四位年份]", date.Year.ToString("0000"));
}
string text2 = "";
for (int i = 0; i < a_CodeLength; i++)
{
text2 += "_";
}
a_strAutoRule = a_strAutoRule.Replace("[流水编号]", text2);
a_strAutoRule = a_strAutoRule.Replace("[按月编号]", text2);
a_strAutoRule = a_strAutoRule.Replace("[按年编号]", text2);
return a_strAutoRule;
}
}
}
}
3.4 创建自动编号客户端(V2.0)
AutoCodeClient.cs,代码进行了修改,引入了正则表达式,增加【参数】支持。
以下是修改后的代码:
using BaseClass_NameSpace;
using System;
using System.Data;
using System.Text.RegularExpressions;
namespace WBF.Utils
{
/// <summary>
/// 自动编号客户端
/// 创建人:gyc
/// 创建时间:2022-11-16
/// 备注:流水号经过压力测试,位数可以任意
/// </summary>
public class AutoCodeClient
{
//实在不适合字符串分割,所以我引入了强大的正则
public const string 流水号正则 = @"(\[[0-9]+位流水号])";
public const string 流水号位数正则 = "[0-9]+";
/// <summary>
/// 获取自动编号
/// </summary>
/// <param name="a_strAutoRule">编号规则</param>
/// <param name="a_strCodeTable">表名</param>
/// <param name="a_strCodeField">数据库表字段,存储编号的字段</param>
/// <returns></returns>
public static string AutoCode(string a_strAutoRule, string a_strCodeTable, string a_strCodeField)
{
string l_strSNText = RegexForString(流水号正则, a_strAutoRule);//流水号文本
int l_intSNLength = 4;//流水号长度
string l_strSN = RegexForString(流水号位数正则, l_strSNText);
int.TryParse(l_strSN, out l_intSNLength);
//string[] array = a_strAutoRule.Split(new char[]
//{
// ';'
//});
//if (array.Length > 1) //编号规则是否定义了流水号位数。
//{
// int.TryParse(array[1], out l_intSNLength);
// return AutoCodeClient.GetAutoCode(array[0], l_intSNLength, a_strCodeTable, a_strCodeField);
//}
return AutoCodeClient.GetAutoCode(a_strAutoRule, l_strSNText, l_intSNLength, a_strCodeTable, a_strCodeField);
}
/// <summary>
/// 获取自动编号
/// </summary>
/// <param name="a_strAutoRule">编号规则</param>
/// <param name="a_strSNText">d位流水号</param>
/// <param name="a_intSNLength">d</param>
/// <param name="a_strCodeTable">数据库表</param>
/// <param name="a_strCodeField">数据库表字段,存储编号的字段</param>
/// <returns></returns>
public static string GetAutoCode(string a_strAutoRule,string a_strSNText, int a_intSNLength, string a_strCodeTable, string a_strCodeField)
{
string text = "";
string text2 = "";
checked
{
for (int i = 0; i < a_intSNLength; i++)
{
text += "_";
text2 += "0";
}
string text3 = AutoCodeClient.ParseCodeRule(a_strAutoRule, a_strSNText, a_intSNLength);
string s = AutoCodeClient.ParseQueryRule(a_strAutoRule, a_strSNText, a_intSNLength);
int num = text3.IndexOf(text);
//使用 BaseMySQL取数,需要指定 数据库名
//MySQLHelper fetchData = new MySQLHelper();
BaseMySQL fetchData = new BaseMySQL();
string text4 = "select {0} from {1} where {2} like {3} order by 1 desc LIMIT 0,1";
text4 = string.Format(text4, new object[]
{
string.Format("SUBSTRING({0}, {1}, {2})", a_strCodeField, num + 1, a_intSNLength),
a_strCodeTable,
a_strCodeField,
s.QuotedStr()
});
//DataTable l_dt = fetchData.Query(text4).Tables[0];
DataTable l_dt = fetchData.Query(text4);
if (l_dt!=null)
{
string newValue;
if (l_dt.Rows.Count<=0)
{
newValue = 1.ToString(text2);
}
else
{
text3.Substring(0, num);
if (text3.Length > num + 4)
{
text3.Substring(num + 4);
}
string s2 = l_dt.Rows[0][0].ToString();
int num2 = 0;
int.TryParse(s2, out num2);
num2++;
newValue = num2.ToString(text2);
}
text3 = text3.Replace(text, newValue);
}
return text3;
}
}
private static string ParseCodeRule(string a_strAutoRule, string a_strSNText, int a_CodeLength)
{
DateTime date = DateTime.Now.Date;
if (a_strAutoRule.Contains("[紧缩天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[紧缩天数]", date.Day.ToString());
}
if (a_strAutoRule.Contains("[两位天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", date.Day.ToString("00"));
}
if (a_strAutoRule.Contains("[紧缩月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString());
}
if (a_strAutoRule.Contains("[两位月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString("00"));
}
checked
{
if (a_strAutoRule.Contains("[一位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[一位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 1, 1));
}
if (a_strAutoRule.Contains("[两位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 2, 2));
}
if (a_strAutoRule.Contains("[四位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[四位年份]", date.Year.ToString("0000"));
}
string text2 = "";
for (int i = 0; i < a_CodeLength; i++)
{
text2 += "_";
}
a_strAutoRule = a_strAutoRule.Replace(a_strSNText, text2);
a_strAutoRule = a_strAutoRule.Replace("[按月编号]", text2);
a_strAutoRule = a_strAutoRule.Replace("[按年编号]", text2);
return a_strAutoRule;
}
}
private static string ParseQueryRule(string a_strAutoRule, string a_strSNText, int a_CodeLength)
{
DateTime date = DateTime.Now.Date;
if (a_strAutoRule.Contains("[紧缩天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[紧缩天数]", date.Day.ToString());
}
if (a_strAutoRule.Contains("[两位天数]"))
{
if (a_strAutoRule.Contains("[按月编号]") || a_strAutoRule.Contains("[按年编号]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", "__");
}
else
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", date.Day.ToString("00"));
}
}
if (a_strAutoRule.Contains("[紧缩月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString());
}
if (a_strAutoRule.Contains("[两位月份]"))
{
if (a_strAutoRule.Contains("[按年编号]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", "__");
}
else
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString("00"));
}
}
checked
{
if (a_strAutoRule.Contains("[一位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[一位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 1, 1));
}
if (a_strAutoRule.Contains("[两位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 2, 2));
}
if (a_strAutoRule.Contains("[四位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[四位年份]", date.Year.ToString("0000"));
}
string text2 = "";
for (int i = 0; i < a_CodeLength; i++)
{
text2 += "_";
}
a_strAutoRule = a_strAutoRule.Replace(a_strSNText, text2);
a_strAutoRule = a_strAutoRule.Replace("[按月编号]", text2);
a_strAutoRule = a_strAutoRule.Replace("[按年编号]", text2);
return a_strAutoRule;
}
}
/// <summary>
/// 匹配返回string
/// </summary>
/// <param name="a_strPattern">正则表达式</param>
/// <param name="a_txtContext">匹配文本</param>
/// <returns></returns>
private static string RegexForString(string a_strPattern, string a_txtContext)
{
Regex l_reg = new Regex(@a_strPattern, RegexOptions.IgnoreCase);
MatchCollection matches_Type = l_reg.Matches(a_txtContext);
foreach (Match item in matches_Type)
{
return item.Value;
}
return "";
}
}
}
3.5 创建自动编号客户端(V4.0)
推荐使用该版本,代码简化了,更容易理解。
//函数内容: 自动编号处理
//函数版本: 0.0.0.1
//修改时间: 2023.03.26
//============================================================================================
//注意事项
// 1. a_strAutoRule保存规则
// 2. a_strCodeTable编码表
// 3. a_strCodeField编码字段
//============================================================================================
public string AutoCode(string a_strAutoRule, string a_strCodeTable, string a_strCodeField)
{
DateTime date = DateTime.Now.Date;
//年份
if (a_strAutoRule.Contains("[四位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[四位年份]", date.Year.ToString("0000"));
}
if (a_strAutoRule.Contains("[两位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 2, 2));
}
if (a_strAutoRule.Contains("[一位年份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[一位年份]", date.Year.ToString().Substring(date.Year.ToString().Length - 1, 1));
}
//月份
if (a_strAutoRule.Contains("[紧缩月份]")) //0-9月一位,10-12月两位
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString());
}
if (a_strAutoRule.Contains("[两位月份]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位月份]", date.Month.ToString("00"));
}
//天数
if (a_strAutoRule.Contains("[紧缩天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[紧缩天数]", date.Day.ToString());
}
if (a_strAutoRule.Contains("[两位天数]"))
{
a_strAutoRule = a_strAutoRule.Replace("[两位天数]", date.Day.ToString("00"));
}
//流水号(没有流水号,不执行)
string 流水号正则 = @"(\[[0-9]+位流水号])";
if (!string.IsNullOrEmpty(RegexForString(流水号正则, a_strAutoRule)))
{
a_strAutoRule = BuildSerialNum(a_strAutoRule, a_strCodeTable, a_strCodeField);
}
return a_strAutoRule;
}
//函数内容: 构造流水号
//函数版本: 0.0.0.1
//修改时间: 2023.03.26
//============================================================================================
//注意事项
// 1.
// 2.
//============================================================================================
private string BuildSerialNum(string a_strAutoRule, string a_strCodeTable, string a_strCodeField)
{
string text1 = "";//通配符
string text2 = "";//补位格式
string 流水号正则 = @"(\[[0-9]+位流水号])";
string 流水号位数正则 = "[0-9]+";
string str_SNText = RegexForString(流水号正则, a_strAutoRule);//流水号文本
int int_SNLength = 0; //流水号长度
if (!int.TryParse(RegexForString(流水号位数正则, str_SNText), out int_SNLength)) //格式不符合,不处理
{
return string.Empty;
}
for (int i = 0; i < int_SNLength; i++)
{
text1 += "_";
text2 += "0";
}
a_strAutoRule = a_strAutoRule.Replace(str_SNText, text1);//转码
int int_StartIndex = a_strAutoRule.IndexOf(text1);//起始位置
//使用 BaseMySQL取数
string str_Sql = "SELECT {0} FROM {1} WHERE {2} LIKE {3} ORDER BY 1 DESC LIMIT 0,1;";
str_Sql = string.Format(str_Sql, new object[]
{
string.Format("SUBSTRING({0}, {1}, {2})", a_strCodeField, int_StartIndex + 1, int_SNLength),
a_strCodeTable,
a_strCodeField,
"'"+a_strAutoRule+"'"
});
DataTable dt_Result = AdoGetDataTable(str_Sql);
if (dt_Result != null)
{
string newValue;
if (dt_Result.Rows.Count <= 0)
{
newValue = 1.ToString(text2);
}
else
{
string s2 = dt_Result.Rows[0][0].ToString();
int num2 = 0;
int.TryParse(s2, out num2);
num2++;
newValue = num2.ToString(text2);
}
a_strAutoRule = a_strAutoRule.Replace(text1, newValue);
return a_strAutoRule;
}
return string.Empty;
}
//函数内容: 正则表达式判断
//函数版本: 0.0.0.1
//修改时间: 2023.03.26
//============================================================================================
//注意事项
// 1.
// 2.
//============================================================================================
private string RegexForString(string a_strPattern, string a_txtContext)
{
Regex l_reg = new Regex(@a_strPattern, RegexOptions.IgnoreCase);
MatchCollection matches_Type = l_reg.Matches(a_txtContext);
foreach (Match item in matches_Type)
{
return item.Value;
}
return "";
}
3.6 创建数据库操作类
创建数据库操作类 MySQLHelper.cs,代码收纳在《C#底层库》专栏。使用MySQL数据,用MySQLHelper.cs;SQL server,用SQLHelper.cs;使用Sqlsuger,用 SqlsugerHelper.cs。
3.7 创建字符串操作类
C#底层库–StringExtension字符串扩展类
本文链接:https://blog.csdn.net/youcheng_ge/article/details/129520428
3.8 编写API控制器
Controllers文件夹下,创建类QRController.cs,当然如果你也可以不采用这种方式,直接C/S架构,客户端直接调用【核心类】获取自动编号,本章节可以跳过。
注意:非必要内容,不采用WebAPI调用方式,可以不看本章节。
位置:ApiController.cs
/// <summary>
/// 自动编号
/// </summary>
/// <param name="parm">参数</param>
/// <returns></returns>
[HttpPost]
public IActionResult AutoCode([FromBody] AutoCodeDto parm)
{
try
{
return toResponse(GetAutoCode(parm));
}
catch (Exception ex)
{
return toResponse(StatusCodeType.Error, ex.Message);
}
}
位置:BaseController.cs,WebAPI统一返回数据格式。
/// <summary>
/// 获得自动编号
/// </summary>
/// <param name="rule">规则</param>
/// <param name="parm"></param>
/// <returns></returns>
public static string GetAutoCode(AutoCodeDto param)
{
//TODO:待确认出入库编码格式,业务部门他想自己定,不用开发编号
BaseService<裸砂原料信息表> sqlSugar = new BaseService<裸砂原料信息表>();
string strAutoCode = sqlSugar.AutoCode(string.Format(param.rule, param.paramValue),
param.tableName, param.fieldName);
return strAutoCode;
}
数据实体 AutoCodeDto,前端传来的参数。
public class AutoCodeDto
{
/// <summary>
/// 描述 : 编号规则
/// 空值 : False
/// 默认 :
/// </summary>
[Display(Name = "编号规则")]
public string rule { get; set; }
/// <summary>
/// 描述 : 参数值
/// 空值 : False
/// 默认 :
/// </summary>
[Display(Name = "参数值")]
public List<string> paramValue { get; set; }
/// <summary>
/// 描述 : 表名
/// 空值 : False
/// 默认 :
/// </summary>
[Display(Name = "表名")]
public string tableName { get; set; }
/// <summary>
/// 描述 : 字段名
/// 空值 : False
/// 默认 :
/// </summary>
[Display(Name = "字段名")]
public string fieldName { get; set; }
四、运行效果
4.1 调用方式
【业务编号】获取方式,已部署API服务,支持多端(pad、PC)获取业务编号。
URL: http://172.16.**.*:8888/API/QR/GetAutoCode
http请求方式:POST
数据类型:json
调用样例:
{
“编号规则”: “[一位年份]A0N[流水编号];6”,
“表”: “t_codenumbertest”,
“字段”: “编号”
}
4.2 参数说明
“编号规则”:自动编号的规则定义,系统参数带中括号
。
“表”:业务编号存储的数据库表
。
“字段”:业务编号存储的表字段
。如“钨条标签打印纪录表”字段“钨条编号”是单据号,那么 表=“钨条标签打印纪录表”、字段=“钨条编号”
其它问题:
①编号规则,系统预留:
[四位年份]
[两位年份]
[一位年份]
[紧缩月份] --10以内,不补位
[两位月份]
[紧缩天数] --10以内,不补位
[两位天数]
[[0-9]+位流水号]–正则,位数阿拉伯数字
②规则中,“固定值”如何设置?
不加中括号 []为固定值,编码保留。
③规则中,流水号位数如何设置?
1(阿拉伯数字)位流水号,例如:1位流水号,3位流水号.
4.3 项目展示
4.3.1 Postman测试效果
① “编号规则”: “[一位年份]A0N[流水编号];6”,
② “编号规则”: “SO[四位年份][两位月份][流水编号];4”,
③ “编号规则”: “[两位年份][两位月份][流水编号]PZ;10”,
你想怎么定义规则,编号就怎么生成。
4.3.2 vue测试效果
五、资源链接
5.1 数据库脚本
业务编号查询的SQL语句参考
SELECT SUBSTRING(出入库单据编号, 10, 3) FROM 裸砂原料出入库表 WHERE 出入库单据编号 LIKE 'YLY202312___' ORDER BY 1 DESC LIMIT 0,1;
注意:_为通配符,占用1位
。