吉特仓储管理系统简单版开源也有一段时间了,得到了众多的开发者和软件开发企业的咨询和青睐,在此期间也经历了版权纠纷等问题,反而到现在好像也不是版权纠纷的问题了,软件著作权这个东西本身就很难以区分, 经过上次这么一闹之后卖源代码的网站反而越来越多了,实在是令人防不慎防,由于工作也就懒得去搭理这些东西了,就跟朋友说的我这是自找难受。由于个人工作时间的问题,有些技术方面的问题实在不好一一解答,今天写一篇博文总结一下各位所问道的问题。
一. 哪里修改数据连接
这个是所有开发者中问的最多的问题,基本上加我QQ问我问题的基本也就是这个了。数据库配置不是在web.config 中, 请各位不要被web.config中的连接误导了,这是由于新建项目自动生成的代码。 数据库配置文件路径:
\Git.Storage.Web\Configs\Data\Database.config 以下是数据库连接代码,其中database 节点中的name=“JooWMS” 不能随意修改, 这个对应映射到实体匹配关系,一般情况情况我设置为了与最初数据库名相同。
<?xml version="1.0" encoding="utf-8" ?> <databaseList> <database name="JooWMS"> <connectionString>Server=127.0.0.1;database=JooWMS;user id=sa;Password=000000</connectionString> </database> </databaseList>
二. 编译不通过
如果遇到编译不通过的可以先查看各个项目中dll引用是否有警告,如果遇到黄色dll引用警告则是dll文件丢失。 解决办法是找到相应的dll重新添加引用或使用nuget重新下载
三. 实体为什么使用partial关键字
[TableAttribute(DbName = "JooWMS", Name = "OutStoDetail", PrimaryKeyName = "ID", IsInternal = false)] public partial class OutStoDetailEntity : BaseEntity { public OutStoDetailEntity() { } [DataMapping(ColumnName = "ID", DbType = DbType.Int32, Length = 4, CanNull = false, DefaultValue = null, PrimaryKey = true, AutoIncrement = true, IsMap = true)] public Int32 ID { get; set; } public OutStoDetailEntity IncludeID(bool flag) { if (flag && !this.ColumnList.Contains("ID")) { this.ColumnList.Add("ID"); } return this; } [DataMapping(ColumnName = "SnNum", DbType = DbType.String, Length = 50, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string SnNum { get; set; } public OutStoDetailEntity IncludeSnNum(bool flag) { if (flag && !this.ColumnList.Contains("SnNum")) { this.ColumnList.Add("SnNum"); } return this; } [DataMapping(ColumnName = "OrderNum", DbType = DbType.String, Length = 50, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string OrderNum { get; set; } public OutStoDetailEntity IncludeOrderNum(bool flag) { if (flag && !this.ColumnList.Contains("OrderNum")) { this.ColumnList.Add("OrderNum"); } return this; } [DataMapping(ColumnName = "ProductName", DbType = DbType.String, Length = 200, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string ProductName { get; set; } public OutStoDetailEntity IncludeProductName(bool flag) { if (flag && !this.ColumnList.Contains("ProductName")) { this.ColumnList.Add("ProductName"); } return this; } [DataMapping(ColumnName = "BarCode", DbType = DbType.String, Length = 50, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string BarCode { get; set; } public OutStoDetailEntity IncludeBarCode(bool flag) { if (flag && !this.ColumnList.Contains("BarCode")) { this.ColumnList.Add("BarCode"); } return this; } [DataMapping(ColumnName = "ProductNum", DbType = DbType.String, Length = 50, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string ProductNum { get; set; } public OutStoDetailEntity IncludeProductNum(bool flag) { if (flag && !this.ColumnList.Contains("ProductNum")) { this.ColumnList.Add("ProductNum"); } return this; } [DataMapping(ColumnName = "BatchNum", DbType = DbType.String, Length = 100, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string BatchNum { get; set; } public OutStoDetailEntity IncludeBatchNum(bool flag) { if (flag && !this.ColumnList.Contains("BatchNum")) { this.ColumnList.Add("BatchNum"); } return this; } [DataMapping(ColumnName = "LocalNum", DbType = DbType.String, Length = 50, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string LocalNum { get; set; } public OutStoDetailEntity IncludeLocalNum(bool flag) { if (flag && !this.ColumnList.Contains("LocalNum")) { this.ColumnList.Add("LocalNum"); } return this; } [DataMapping(ColumnName = "StorageNum", DbType = DbType.String, Length = 50, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string StorageNum { get; set; } public OutStoDetailEntity IncludeStorageNum(bool flag) { if (flag && !this.ColumnList.Contains("StorageNum")) { this.ColumnList.Add("StorageNum"); } return this; } [DataMapping(ColumnName = "Num", DbType = DbType.Double, Length = 8, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public double Num { get; set; } public OutStoDetailEntity IncludeNum(bool flag) { if (flag && !this.ColumnList.Contains("Num")) { this.ColumnList.Add("Num"); } return this; } [DataMapping(ColumnName = "IsPick", DbType = DbType.Int32, Length = 4, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public Int32 IsPick { get; set; } public OutStoDetailEntity IncludeIsPick(bool flag) { if (flag && !this.ColumnList.Contains("IsPick")) { this.ColumnList.Add("IsPick"); } return this; } [DataMapping(ColumnName = "RealNum", DbType = DbType.Double, Length = 8, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public double RealNum { get; set; } public OutStoDetailEntity IncludeRealNum(bool flag) { if (flag && !this.ColumnList.Contains("RealNum")) { this.ColumnList.Add("RealNum"); } return this; } [DataMapping(ColumnName = "OutPrice", DbType = DbType.Double, Length = 8, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public double OutPrice { get; set; } public OutStoDetailEntity IncludeOutPrice(bool flag) { if (flag && !this.ColumnList.Contains("OutPrice")) { this.ColumnList.Add("OutPrice"); } return this; } [DataMapping(ColumnName = "Amount", DbType = DbType.Double, Length = 8, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public double Amount { get; set; } public OutStoDetailEntity IncludeAmount(bool flag) { if (flag && !this.ColumnList.Contains("Amount")) { this.ColumnList.Add("Amount"); } return this; } [DataMapping(ColumnName = "ContractOrder", DbType = DbType.String, Length = 50, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string ContractOrder { get; set; } public OutStoDetailEntity IncludeContractOrder(bool flag) { if (flag && !this.ColumnList.Contains("ContractOrder")) { this.ColumnList.Add("ContractOrder"); } return this; } [DataMapping(ColumnName = "ContractSn", DbType = DbType.String, Length = 50, CanNull = true, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public string ContractSn { get; set; } public OutStoDetailEntity IncludeContractSn(bool flag) { if (flag && !this.ColumnList.Contains("ContractSn")) { this.ColumnList.Add("ContractSn"); } return this; } [DataMapping(ColumnName = "CreateTime", DbType = DbType.DateTime, Length = 8, CanNull = false, DefaultValue = null, PrimaryKey = false, AutoIncrement = false, IsMap = true)] public DateTime CreateTime { get; set; } public OutStoDetailEntity IncludeCreateTime(bool flag) { if (flag && !this.ColumnList.Contains("CreateTime")) { this.ColumnList.Add("CreateTime"); } return this; } }
出库单实体类
以上是项目中截取的代码, 定义了出库单的实体对象,使用partial 关键字,以上代码是Git.Framework.ORM 中实体映射类,在这个项目中业务模型类与数据库模型类是公用的,所以在这个类上会扩展出来很多其他的属性出来。
public partial class OutStoDetailEntity { /// <summary> /// 产品规格 /// </summary> public string Size { get; set; } /// <summary> /// 库位名称 /// </summary> public string LocalName { get; set; } /// <summary> /// 用于退货临时数据变量,已经退货数量 /// </summary> public double BackNum { get; set; } /// <summary> /// 数量 临时变量 /// </summary> public double Qty { get; set; } }
出库单扩展字段
以上就是扩展出来的辅助字段,可以用于业务模型对象以及数据传输对象【我是偷懒了,业务模型,数据模型,数据传输模型我公用了一个类】。目前众多开发者受DDD领域驱动开发思想的影响,定义了众多的模型, 我承认我是为了偷懒减少代码量所以公用了。
四. 数据库操作好像不是EF
public override List<InStorageEntity> GetList(InStorageEntity entity, ref PageInfo pageInfo) { entity.IncludeAll(); entity.Where(a => a.IsDelete == (int)EIsDelete.NotDelete); entity.OrderBy(a => a.ID, EOrderBy.DESC); AdminEntity admin = new AdminEntity(); admin.Include(a => new { CreateUserName = a.UserName }); entity.Left<AdminEntity>(admin, new Params<string, string>() { Item1 = "CreateUser", Item2 = "UserCode" }); int rowCount = 0; List<InStorageEntity> listResult = this.InStorage.GetList(entity, pageInfo.PageSize, pageInfo.PageIndex, out rowCount); pageInfo.RowCount = rowCount; return listResult; }
数据库操作实例代码
上面一段代码是连接查询数据库,查询了两张表。并且有相应的查询条件,使用了表达式会让人误以为是EF,这个里面不是使用的EF操作数据库,本人对EF了解不够深,也不太喜欢使用EF,这是一个基于微软企业库的ORM框架,由本人个人开发,因为不够足够的优秀所以在网上也就不出名,基本也就我个人项目使用一下。既然不好为什么还要用, 原因很简单 顺手,开发项目快,而且基本趋于稳定。
关于这个ORM框架使用的相关文章: 《Git.Framework.Orm 框架使用文章汇总》 http://www.cnblogs.com/qingyuan/category/239086.html
五. 为什么不使用EF
1. EF 个人使用的太少,没有深入的去学习过EF, 有坑不能去解决
2. Git.Framework.Orm 是根据自己平时项目中遇到的问题总结下来编写的。比如指定修改某个字段,查询某些指定字段(数据权限控制),查询字段直接映射业务模型,支持最直接的SQL语句,底层是ADO.NET(基于微软企业库)
3. 自己写的东西用起来自然觉得舒服很多,自己的习惯来。
4. 除了使用对象映射还可以使用配置文件来配置SQL语句(用于复杂的SQL语句,ORM很难处理复杂的SQL语句)
5. 定义了一套完整的数据库操作方法, 支持存储过程对应映射,用法和ADO.NET一样
Proc_AuditeInStorageEntity auditeEntity = new Proc_AuditeInStorageEntity(); auditeEntity.OrderNum = entity.OrderNum; auditeEntity.Status = entity.Status; auditeEntity.AuditUser = entity.AuditUser; auditeEntity.Reason = entity.Reason; auditeEntity.OperateType = entity.OperateType; auditeEntity.EquipmentNum = entity.EquipmentNum; auditeEntity.EquipmentCode = entity.EquipmentCode; auditeEntity.Remark = entity.Remark; int line = this.Proc_AuditeInStorage.ExecuteNonQuery(auditeEntity);
存储过程调用示例
<dataCommand name="Common.GetProceParam" database="JooWMS" commandType="Text"> <commandText> <![CDATA[ SELECT [SPECIFIC_CATALOG],[SPECIFIC_NAME],[ORDINAL_POSITION],[PARAMETER_MODE],[PARAMETER_NAME],[DATA_TYPE],[CHARACTER_MAXIMUM_LENGTH] FROM [INFORMATION_SCHEMA].[PARAMETERS] WHERE [SPECIFIC_NAME][email protected]_NAME ]]> </commandText> <parameters> <param name="@SPECIFIC_NAME" dbType="String" direction="Input"/> </parameters> </dataCommand>
SQL语句配置执行
public List<ProceMetadata> GetMetadataList(string argProceName) { DataCommand command = DataCommandManager.GetDataCommand("Common.GetProceParam"); command.SetParameterValue("@SPECIFIC_NAME", argProceName); List<ProceMetadata> list = command.ExecuteEntityList<ProceMetadata>(); return list; }
六. 如何加载的CSS JS 文件
在加载CSS JS等文件的时候和传统的方式没有什么区别,只是在页面生成的时候做了一下处理。项目中的所有CSS 以及JS都是通过配置来加载的
配置路径:\gitwms\Git.Storage.Web\Configs\File\File.config
<?xml version="1.0" encoding="utf-8"?> <Configs> <file name="CSS.bootstrap"><![CDATA[/Theme/plugins/bootstrap/css/bootstrap.css]]></file> <file name="CSS.font-awesome"><![CDATA[/Theme/plugins/font-awesome/css/font-awesome.css]]></file> <file name="CSS.style"><![CDATA[/Theme/css/style.css]]></file> <file name="CSS.style-responsive"><![CDATA[/Theme/css/style-responsive.css]]></file> <file name="CSS.default"><![CDATA[/Theme/css/themes/default.css]]></file> <file name="CSS.jbox"><![CDATA[/Theme/plugins/jbox-v2.3/jBox/Skins/Gray/jbox.css]]></file> <file name="CSS.autocomplete"><![CDATA[/Theme/plugins/jquery-autocomplete3.2.2/jquery.autocomplete.css]]></file> <file name="CSS.Error"><![CDATA[/Theme/css/pages/error.css]]></file> <file name="CSS.metro"><![CDATA[/Theme/plugins/bootstrap/css/style-metro.css]]></file> <!--公用JS组件--> <file name="Js.Enum"><![CDATA[/Common/Js]]></file> <file name="Js.Jquery"><![CDATA[/Theme/plugins/jquery-1.8.3.min.js]]></file> <file name="Js.bootstrap"><![CDATA[/Theme/plugins/bootstrap/js/bootstrap.min.js]]></file> <file name="Js.jBox"><![CDATA[/Theme/plugins/jbox-v2.3/jBox/jquery.jBox-2.3.min.js]]></file> <file name="Js.autocomplete"><![CDATA[/Theme/plugins/jquery-autocomplete3.2.2/jquery.autocomplete.js]]></file> <file name="Js.WdatePicker"><![CDATA[/Theme/plugins/My97DatePicker/WdatePicker.js]]></file> <file name="Js.Common"><![CDATA[/Theme/customer/Git.Framework.Common.js]]></file> <file name="Js.UICommon"><![CDATA[/Theme/customer/Git.Framework.UICommon.js]]></file> <file name="Js.Uploader"><![CDATA[/Theme/customer/jquery.jUploader-1.01.min.js]]></file> <file name="Js.Git.Framework.Sequence"><![CDATA[/Theme/customer/Git.Framework.Sequence.js]]></file> <!--用户管理--> <file name="Js.Git.Storage.User"><![CDATA[/Theme/customer/User/Git.Storage.User.js]]></file> <!--角色管理--> <file name="Js.Git.Storage.Role"><![CDATA[/Theme/customer/User/Git.Storage.Role.js]]></file> <!--菜单管理--> <file name="Js.Git.Storage.Menu"><![CDATA[/Theme/customer/User/Git.Storage.Menu.js]]></file> <!--部门--> <file name="Js.Git.Storage.Depart"><![CDATA[/Theme/customer/Department/Git.Storage.Depart.js]]></file> <!--供应商--> <file name="Js.Git.Storage.Supplier"><![CDATA[/Theme/customer/Client/Git.Storage.Supplier.js]]></file> <!--客户管理--> <file name="Js.Git.Storage.Client"><![CDATA[/Theme/customer/Client/Git.Storage.Client.js]]></file> <!--设备管理--> <file name="Js.Git.Storage.Equipment"><![CDATA[/Theme/customer/Storage/Git.Storage.Equipment.js]]></file> <!--仓库管理--> <file name="Js.Git.Storage.Storage"><![CDATA[/Theme/customer/Storage/Git.Storage.Storage.js]]></file> <!--库位管理--> <file name="Js.Git.Storage.Location"><![CDATA[/Theme/customer/Storage/Git.Storage.Location.js]]></file> <!--初始化产品库存--> <file name="Js.Git.Storage.LocalProduct"><![CDATA[/Theme/customer/Storage/Git.Storage.LocalProduct.js]]></file> <!--计量单位--> <file name="Js.Git.Storage.Measure"><![CDATA[/Theme/customer/Storage/Git.Storage.Measure.js]]></file> <!--产品管理--> <file name="Js.Git.Storage.Goods"><![CDATA[/Theme/customer/Product/Git.Storage.Goods.js]]></file> <!--订单管理--> <file name="Js.Git.Storage.OrderManage"><![CDATA[/Theme/customer/OrderManage/Git.Storage.OrderManage.js]]></file> <!--产品入库管理列表--> <file name="Js.Git.Storage.ProductInOrder"><![CDATA[/Theme/customer/InStorage/Git.Storage.ProductInOrder.js]]></file> <!--产品出库管理列表--> <file name="Js.Git.Storage.ProductOutOrder"><![CDATA[/Theme/customer/OutStorage/Git.Storage.ProductOutOrder.js]]></file> <!--产品报损管理列表--> <file name="Js.Git.Storage.ProductBadOrder"><![CDATA[/Theme/customer/Bad/Git.Storage.ProductBadOrder.js]]></file> <!--产品移库管理列表--> <file name="Js.Git.Storage.MoveOrder"><![CDATA[/Theme/customer/Move/Git.Storage.MoveOrder.js]]></file> <!--产品盘点管理列表--> <file name="Js.Git.Storage.CheckOrder"><![CDATA[/Theme/customer/Check/Git.Storage.CheckOrder.js]]></file> <!--产品退货管理列表--> <file name="Js.Git.Storage.ReturnOrder"><![CDATA[/Theme/customer/Returns/Git.Storage.ReturnOrder.js]]></file> <!--*******************************************报表***************************************************************--> <!--产品在线库存报表--> <file name="Js.Git.Storage.ProductReport"><![CDATA[/Theme/customer/Report/Git.Storage.ProductReport.js]]></file> <!--产品出入库报表--> <file name="Js.Git.Storage.ProductInOutReport"><![CDATA[/Theme/customer/Report/Git.Storage.ProductInOutReport.js]]></file> <!--入库报表--> <file name="Js.Git.Storage.InStorageReport"><![CDATA[/Theme/customer/Report/Git.Storage.InStorageReport.js]]></file> <!--出库报表--> <file name="Js.Git.Storage.OutStorageReport"><![CDATA[/Theme/customer/Report/Git.Storage.OutStorageReport.js]]></file> <!--客户报表--> <file name="Js.Git.Storage.CustomerReport"><![CDATA[/Theme/customer/Report/Git.Storage.CustomerReport.js]]></file> <!--供应商报表--> <file name="Js.Git.Storage.SupplierReport"><![CDATA[/Theme/customer/Report/Git.Storage.SupplierReport.js]]></file> <!--库存清单报表--> <file name="Js.Git.Storage.StockBillReport"><![CDATA[/Theme/customer/Report/Git.Storage.StockBillReport.js]]></file> <!--报损报表--> <file name="Js.Git.Storage.BadReport"><![CDATA[/Theme/customer/Report/Git.Storage.BadReport.js]]></file> <!--退货报表--> <file name="Js.Git.Storage.ReturnReport"><![CDATA[/Theme/customer/Report/Git.Storage.ReturnReport.js]]></file> <!--台帐报表--> <file name="Js.Git.Storage.InventoryReport"><![CDATA[/Theme/customer/Report/Git.Storage.InventoryReport.js]]></file> <!--ampie报表组件--> <file name="Js.Swfobject"><![CDATA[/Theme/plugins/ampie/swfobject.js]]></file> <!--报表管理JS--> <file name="Js.Git.Storage.ManagerReport"><![CDATA[/Theme/customer/Report/Git.Storage.ManagerReport.js]]></file> </Configs>
CSS JS 文件的配置
<?xml version="1.0" encoding="utf-8"?> <Groups> <!--错误友好提示界面--> <group name="Home.Error"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.Error</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Uploader</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.User</file> </group> <!--用户用户列表--> <group name="Home.UserList"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Uploader</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.User</file> </group> <!--序号管理--> <group name="Home.Sequence"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.WdatePicker</file> <file>File.Js.Enum</file> <file>File.Js.Uploader</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Framework.Sequence</file> </group> <!--用于角色列表--> <group name="Home.RoleList"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Role</file> </group> <!--用于部门管理--> <group name="Home.DepartList"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Depart</file> </group> <!--菜单管理--> <group name="Home.Menu"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Menu</file> </group> <!--用于供应商管理--> <group name="Client.Supplier.Index"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Git.Storage.Supplier</file> </group> <!--用于客户管理--> <group name="Client.Customer.Index"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Git.Storage.Client</file> </group> <!--用于设备管理--> <group name="Storage.Equipment.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Equipment</file> </group> <!--用于仓库管理--> <group name="Storage.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Storage</file> </group> <!--用于库位管理--> <group name="Storage.Location.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Location</file> </group> <!--计量单位管理--> <group name="Storage.Measure.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.Measure</file> </group> <!--用于产品管理--> <group name="Product.Goods.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.autocomplete</file> <file>File.Js.Git.Storage.Goods</file> </group> <!--初始化产品库存--> <group name="Storage.LocalProduct.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.LocalProduct</file> </group> <!--用于订单管理--> <group name="Order.OrderManage.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Uploader</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.OrderManage</file> </group> <!--用于产品入库管理--> <group name="Product.ProductInOrder.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.ProductInOrder</file> </group> <!--用于产品出库管理--> <group name="Product.ProductOutOrder.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.ProductOutOrder</file> </group> <!--用于报损管理--> <group name="Product.ProductBad.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.ProductBadOrder</file> </group> <!--用于移库管理--> <group name="Product.ProductMove.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.MoveOrder</file> </group> <!--用于盘点管理--> <group name="Product.ProductCheck.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Uploader</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.CheckOrder</file> </group> <!--用于退货管理--> <group name="Product.ProductReturns.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.CSS.autocomplete</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.autocomplete</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Git.Storage.ReturnOrder</file> </group> <!--******************************************************报表***********************************************************--> <!--用于产品在线库存报表--> <group name="Product.Report.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Git.Storage.ProductReport</file> </group> <!--用于产品出入库报表--> <group name="Product.InOutReport.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.ProductInOutReport</file> </group> <!--用于入库报表--> <group name="Product.InStorageReport.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.InStorageReport</file> </group> <!--用于客户报表--> <group name="Product.CustomerReport.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.CustomerReport</file> </group> <!--用于供应商报表--> <group name="Product.SupplierReport.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.SupplierReport</file> </group> <!--用于出库报表--> <group name="Product.OutStorageReport.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.OutStorageReport</file> </group> <!--库存清单报表--> <group name="StockBill.Report.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Git.Storage.StockBillReport</file> </group> <!--报损报表--> <group name="BadReport.Report.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.BadReport</file> </group> <!--退货报表--> <group name="ReturnReport.Report.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Swfobject</file> <file>File.Js.Git.Storage.ReturnReport</file> </group> <!--台帐报表--> <group name="InventoryReport.Report.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Git.Storage.InventoryReport</file> </group> <!--报表管理--> <group name="Report.Manager.List"> <file>File.CSS.bootstrap</file> <file>File.CSS.font-awesome</file> <file>File.CSS.style</file> <file>File.CSS.style-responsive</file> <file>File.CSS.default</file> <file>File.CSS.jbox</file> <file>File.Js.Jquery</file> <file>File.Js.bootstrap</file> <file>File.Js.jBox</file> <file>File.Js.Enum</file> <file>File.Js.WdatePicker</file> <file>File.Js.Common</file> <file>File.Js.UICommon</file> <file>File.Js.Uploader</file> <file>File.Js.Git.Storage.ManagerReport</file> </group> </Groups>
文件组的配置
<?xml version="1.0" encoding="utf-8"?> <PageConfigs> <!--员工管理页面--> <page name="Home.UserList" path="/Home/UserList"> <group>FileGroup.Home.UserList</group> <seo>Seo.Index</seo> </page> <!--添加员工--> <page name="Home.AddUser" path="/Home/AddUser"> <group>FileGroup.Home.UserList</group> <seo>Seo.Index</seo> </page> <!--账户设置页面--> <page name="Home.AccountSetting" path="/Home/AccountSetting"> <group>FileGroup.Home.UserList</group> <seo>Seo.Index</seo> </page> <!--角色管理页面--> <page name="Home.RoleList" path="/Home/RoleList"> <group>FileGroup.Home.RoleList</group> <seo>Seo.Index</seo> </page> <!--部门管理页面--> <page name="Home.DepartList" path="/Home/DepartList"> <group>FileGroup.Home.DepartList</group> <seo>Seo.Index</seo> </page> <!--菜单管理--> <page name="Res.Index" path="/Res/Index"> <group>FileGroup.Home.Menu</group> <seo>Seo.Index</seo> </page> <!--权限分配--> <page name="Res.Power" path="/Res/Power"> <group>FileGroup.Home.Menu</group> <seo>Seo.Index</seo> </page> <!--系统日志--> <page name="Res.SysLog" path="/Res/SysLog"> <group>FileGroup.Home.Menu</group> <seo>Seo.Index</seo> </page> <!--错误友好提示界面--> <page name="Home.Error" path="/Home/Error"> <group>FileGroup.Home.Error</group> <seo>Seo.Index</seo> </page> <!--首页--> <page name="Home.Welcome" path="/Home/Welcome"> <group>FileGroup.Home.UserList</group> <seo>Seo.Index</seo> </page> <!--序号管理--> <page name="Home.Sequence" path="/Home/Sequence"> <group>FileGroup.Home.Sequence</group> <seo>Seo.Index</seo> </page> <!--标识符管理--> <page name="Home.SN" path="/Home/SN"> <group>FileGroup.Home.Sequence</group> <seo>Seo.Index</seo> </page> </PageConfigs>
页面组配置
看起来好复杂的样子,三级配置加载CSS JS 以及页面title等信息。页面中会有代码去解析这些配置文件。 会有人问这有毛线用,的确没有任何毛线用,然并卵。 这些配置文件都是依赖形式的,都缓存与系统中,当你文件有修改的时候会自动失效配置文件缓存然后重新读取新文件,目的就是为了不重启服务。 所以你认为他有用就有用,你认为多此一举就是多此一举。此举还带来了一个严重的问题,就是不熟悉此结构的人在开发过程中配置JS比较难以上手。
七. 用的什么方式打印
目前开源的代码中使用的FastReport作为报表设计工具以及打印工具, 之前也是用过lodop打印,所以项目中仍然存在lodop的残存文件。使用报表设计器看起来高大上,这在众多的开发者眼中是这样的,但是对于客户来说并不是这样的,客户其实相当比较难以上手设计一个报表打印,以为他要去了解这个系统的数据结构,这是一个非常痛苦的事情。 为什么使用报表设计器,是因为之前我在开发报表的时候一个报表就要去开发一个页面,使用报表设计器可以简化这个过程。 以上两个组件都是收费的,所以酌情考虑。
八. 数据库设计
认真看过代码的人都应该看过数据库结构,在此之前有人提出我的数据库设计非常烂,不适合初学者学习。这里我先不否认这个问题,我也不说这个项目有多么的优秀。 在此项目的设计过程中,数据库存在一个较大的问题,那就是表中重复的字段比较多。
if exists (select * from sysobjects where name=‘InStorDetail‘) drop table InStorDetail go create table InStorDetail ( ID int not null identity(1,1) primary key , --主键编号 SnNum varchar(50) not null , --唯一编号 OrderSnNum varchar(50) not null , --入库单唯一编号 ProductName nvarchar(100) , --产品名称 BarCode varchar(50) , --条码编号 ProductNum varchar(50) not null , --产品唯一编码 BatchNum nvarchar(50) , --生产批次 Num float not null , --入库数量 IsPick int not null , --是否审核 RealNum float not null , --实际数量 InPrice float not null , --入库单价 Amount float not null , --金额 ContractOrder varchar(50) , --关联单号 CreateTime datetime not null , --创建时间 LocalNum varchar(50) , --库位编号 StorageNum varchar(50) , --仓库编号 CompanyID varchar(50) not null , --公司唯一编码 ) go
就比如说上面这个表结构,其中产品的相关属性我们可以通过ProductNum 唯一值来关联查询出ProductName,BarCode 等信息, 数据库设计范式的问题。在众多的表中重复的字段非常之多,并非本人不懂数据库设计范式,具体情况具体来. 此次这样设计是为了减少关联查询的问题,避免查询的过程中关联多个表。 不要问我为什么,程序写多了你就明白真理并不是指明灯,理论有时候也很坑人。如果觉得此处学习是误导,那就请跳过此处问题
九. 单据的设计
在仓库系统中最多的也就是单据了, 在这个系统中单据基本分为主从关系。在前期的开发中,系统中涉及的单据非常之多,比如入库单就分为:采购入库单,销售退货入库单,生产入库单,退还入库单等等,因为考虑到要兼容各种业务场景,所以定义了非常之多的单据,数据库中的主从表也非常之多。在后期的改版中从支付宝的订单处理中得到一些启发,在整体上定义了单据的概念,单据操作的方法也固定在特定范围内。
public abstract partial class Bill<T, V> : DataFactory where T : BaseEntity where V : BaseEntity { /// <summary> /// 定义日志类 /// </summary> protected Log log = Log.Instance(typeof(T)); /// <summary> /// 创建单据 /// </summary> /// <param name="entity"></param> /// <param name="list"></param> /// <returns></returns> public abstract string Create(T entity, List<V> list); /// <summary> /// 取消单据 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract string Cancel(T entity); /// <summary> /// 删除单据 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract string Delete(T entity); /// <summary> /// 审核单据 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract string Audite(T entity); /// <summary> /// 打印单据 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract string Print(T entity); /// <summary> /// 查询单据 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract T GetOrder(T entity); /// <summary> /// 获得单据详细信息 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract List<V> GetOrderDetail(V entity); /// <summary> /// 查询单据分页 /// </summary> /// <param name="entity"></param> /// <param name="pageInfo"></param> /// <returns></returns> public abstract List<T> GetList(T entity, ref PageInfo pageInfo); /// <summary> /// 查询单据详细数据分页 /// </summary> /// <param name="entity"></param> /// <param name="pageInfo"></param> /// <returns></returns> public abstract List<V> GetDetailList(V entity, ref PageInfo pageInfo); /// <summary> /// 编辑单据信息 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract string EditOrder(T entity); /// <summary> /// 编辑单据详细信息 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract string EditDetail(V entity); /// <summary> /// 编辑入库单 /// </summary> /// <param name="entity"></param> /// <param name="list"></param> /// <returns></returns> public abstract string EditOrder(T entity, List<V> list); /// <summary> /// 获得订单数量 /// </summary> /// <param name="entity"></param> /// <returns></returns> public abstract int GetCount(T entity); /// <summary> /// 获得打印单据的数据源 /// </summary> /// <param name="argOrderNum"></param> /// <returns></returns> public abstract DataSet GetPrint(string argOrderNum); }
单据模型的抽象
以上是单据模型的抽象,所有实际的单据都要实现此抽象类,同时也合并了不同类型的入库为入库单. 入库单在总体上上是一个概念,如果要去扩展入库单到具体的业务可以再此基础上去修改。所以在仓库系统代码中定义了几个基本的单据:入库单,出库单,移库单,报损单,盘点单,因为仓储系统主要用于管理数量,而以上操作都是直接影响库存数据的。
十. 前端页面操作的颗粒性,一致性
自己曾在以往的软件开发过程中,很多动作都是连续进行的。 比如 列表中中删除一行数据然后重新刷新列表数据。 以往开发的时候做法一般是发送一个删除请求,然后同时返回删除之后的新数据,在目前现有的系统开发中这种操作都被分解,比如上述过程分解为两个动作:(1) 发送请求删除,返回删除状态 (2) 根据返回状态再重新请求后台列表数据, 也就是这个动作其实有两个请求,在以往的时候我开发直接使用了一个http请求就处理掉了【不是批判这个处理方式的问题,目前系统开发中也有很多人是这样处理的,很多人给出的理由多了一次请求】。 首先我这里不是什么特别高并发的系统, 多一次请求少一次请求也无所谓,其次这里为了保证任何操作动作的颗粒性,在处理权限上也是很不错的。
然而单据是一个整体,所以很多时候回设计到一个多表操作的动作,这个时候一定要使用到事务,这个在技术上自然不用多说。有很多人提出了一个疑问,在各种单据处理的时候,比如选择多个产品的时候,我选择了产品数据是保存在哪里的
在点击新增产品按钮的时候,然后选择产品之后表格中加载数据,很多人到数据库中去查找并没有发现新增数据。这里选择产品数据也是保存到了服务端的缓存中【注意是服务端缓存中,而不是客户端页面中】, 也有很多人将数据缓存到客户端的做法,有什么优缺点在这里不做过多的说明,业务型系统建议是保存到后台中。这里也有上面提到的颗粒操作, 表格中也有编辑以及删除操作,每一个动作都是拆分的,虽然看起来是连贯的。当产品确定之后提交整个表单,包括表单头部以及产品列表数据,使用事务一次性提交到数据库。
十一. 更多的Controller 控制器
本项目使用的asp.net mvc,细心的应该可以看出在Controller类上有点小小的不同, 一个模块(单据类型的模块)基本对应三个Controller,比如产品入库:ProductManagerAjaxController , ProductAjaxController, ProductController , 这三个控制器总体控制着入库单的所有操作,其中两个是带有Ajax的, 是的没有错。 ManagerAjaxController 基本是控制列表页面的操作, AjaxController 控制数据的编辑录入等,XController 基本就控制的试图的显示。
在整个系统中我将请求分为了四大类: 主页面控制(导航菜单出来的页面), 页面链接子页(导航菜单指向页面中的链接链出来的页面,和上面一个优点类似),对话框,Ajax 请求。 我不知道有没有人跟我一样做过类似的分类,就目前而且我觉得此种分类还是比较好的,基本囊括BS开发页面中的集中请求方式,虽然都是Http请求, 但是这个对于我在系统中的权限控制至关重要。
public class ProductAjaxController : AjaxPage { /// <summary> /// 新建入库单 /// 返回值说明: /// 1001 : 请选择要入库的产品以及数量 /// </summary> /// <returns></returns> [LoginAjaxFilter] public ActionResult Create() { int InType = WebUtil.GetFormValue<int>("InType", 0); int ProductType = WebUtil.GetFormValue<int>("ProductType", 0); string ContractOrder = WebUtil.GetFormValue<string>("ContractOrder", string.Empty); string SupNum = WebUtil.GetFormValue<string>("SupNum", string.Empty); string SupName = WebUtil.GetFormValue<string>("SupName", string.Empty); string ContactName = WebUtil.GetFormValue<string>("ContactName", string.Empty); string Phone = WebUtil.GetFormValue<string>("Phone", string.Empty); DateTime OrderTime = WebUtil.GetFormValue<DateTime>("OrderTime", DateTime.Now); string Remark = WebUtil.GetFormValue<string>("Remark", string.Empty); InStorageEntity entity = new InStorageEntity(); entity.OrderNum = SequenceProvider.GetSequence(typeof(InStorageEntity)); entity.InType = InType; entity.ProductType = ProductType; entity.SupNum = SupNum; entity.SupName = SupName; entity.ContactName = ContactName; entity.Phone = Phone; entity.Address = ""; entity.ContractOrder = ContractOrder; entity.Status = (int)EAudite.Wait; entity.IsDelete = (int)EIsDelete.NotDelete; entity.OrderTime = OrderTime; entity.CreateTime = DateTime.Now; entity.CreateUser = this.LoginUserCode; entity.AuditUser = string.Empty; entity.AuditeTime = DateTime.MinValue; entity.PrintUser = string.Empty; entity.PrintTime = DateTime.MinValue; entity.Reason = string.Empty; entity.OperateType = (int)EOpType.PC; entity.EquipmentNum = string.Empty; entity.EquipmentCode = string.Empty; entity.Remark = Remark; entity.StorageNum = this.DefaultStore; List<InStorDetailEntity> list = Session[CacheKey.TEMPDATA_CACHE_INSTORDETAIL] as List<InStorDetailEntity>; if (list.IsNullOrEmpty()) { this.ReturnJson.AddProperty("Key", "1001"); this.ReturnJson.AddProperty("Value", "请选择要入库的产品以及数量"); return Content(this.ReturnJson.ToString()); } entity.Num = list.Sum(a => a.Num); entity.Amount = list.Sum(a => a.Amount); Bill<InStorageEntity, InStorDetailEntity> bill = new InStorageOrder(); string returnValue = bill.Create(entity, list); if (returnValue == EnumHelper.GetEnumDesc<EReturnStatus>(EReturnStatus.Success)) { Session[CacheKey.TEMPDATA_CACHE_INSTORDETAIL] = null; this.ReturnJson.AddProperty("Key", "1000"); this.ReturnJson.AddProperty("Value", "入库单创建成功"); } return Content(this.ReturnJson.ToString()); } }
Ajax请求操作实例
public class ProductController : MasterPage { /// <summary> /// 入库单列表管理 /// </summary> /// <returns></returns> [LoginFilter] public ActionResult List() { ViewBag.InType = EnumHelper.GetOptions<EInType>(0, "请选择入库单类型"); ViewBag.ReportNum = ResourceManager.GetSettingEntity("InOrder_Template").Value; return View(); } }
页面请求实例
以上两个代码就区分了基本的Get页面请求以及Ajax请求, 在软件开发过程中我一直推崇的就是约定大于配置,说白了这全是他么的套路,套路,套路。 我为什么要这么定义,因为套路, 我熟悉套路所以我开发快。所以如果有心的同学可以参考一下此种做法
十二. 有没有更高级的版本
在这个项目上咨询的大部分都是软件开发者, 有时候提的一些问题令我是做不好怎么回答,技术问题,版权问题,让我技术支持问题,高级版本问题,为什么开源,为什么不全部开源
(1) 之前有人找我买源码,我问他的预算,他说要所有的源代码包括可以注册软件著作权的,预算几千块。 我的回答你自己找人去开发吧,还不用担心版权问题,想怎么来就怎么来
(2) "你写的代码太烂了,学习真的有难度,某个软件就比你的好,就是他的代码太贵了" , 一般这种问题也就技术人员提吧, 除非看自己的代码否则看别人的代码都是垃圾, 一句话我的代码中没有使用特别高深的技术,代码质量也有限,我自己能够看懂。
(3) "我可不可以跟你合作,你有产品我有客户", 这个当然没问题了,大家共同赚钱, 客户做成了你拿60%的费用都不是问题, 请问你现在有多少有意向的客户,回答:"我还没有取跑过客户"
(4) “我们公司想用你们的这套系统,要能够支持二次开发” , 毫不犹豫企业做仓库软件愿意提供较高质量的技术支持以及业务方面的指导
(5) “你这个好像不是完整代码” , 开源部分是从以往的项目中整理出来的,仓库作业基本是完整可以使用的,提供了数据结构 使用没有任何问题,但是不要奢望我去给你解释每个字段是什么含义,学习就得付出。
(6) “我在淘宝上花了10块钱买的你的源码,技术支持留的你的联系方式”, 我不再想回答这种问题
(7) "有没有更高版本的仓库系统",开源的版本定义为V3.0 ,现在已经开发出来V4.0版本了, 对多仓库,多企业,云服务,采购,销售,财务都有简单的支持,并且也已经应到几个企业中,后面不打算开源了,看着别人拿到淘宝上去卖源码有点心疼
题外话: 如果有企业想合作,可以授权源码开发,提供技术支持。 不要问我为什么,套路。
十三. 能不能带来收入
吉特仓储管理系统从我接触开始到现在已经差不多四年时间了,这个时间说长不长说短也不短了。 一个软件坚持做四年估计也是比较难的,也就今年才稍微好点。 能不能赚钱,我可以肯定的告诉各位是可以赚钱的, 8月份成交了两个企业单, 虽然比不来什么几千万的项目,也不可能几十万,但是在工作之余带来额外的收入这个数目还是比较客观的。
前不久给几个开发的好友讲解了一下吉特仓储管理系统的快速开发问题,以前就是自己一个人在房间里开发开发,这是第一次公开的给别人说仓库系统的开发。我希望仓库系统能够做的更好,功能更加的完善,在后续的过程中服务更多的客户。
打个小广告: 吉特仓储管理系统简单版开源地址: https://github.com/hechenqingyuan/gitwms 仓库系统交流群:88718955, 142050808 , 个人QQ: 821865130 如果有意愿合作和业务探讨的客户可以联系我 15800466429