吉特倉庫管理系統- 基本問題解答

賀臣發表於2016-08-31

 

  吉特倉儲管理系統簡單版開源也有一段時間了,得到了眾多的開發者和軟體開發企業的諮詢和青睞,在此期間也經歷了版權糾紛等問題,反而到現在好像也不是版權糾紛的問題了,軟體著作權這個東西本身就很難以區分, 經過上次這麼一鬧之後賣原始碼的網站反而越來越多了,實在是令人防不慎防,由於工作也就懶得去搭理這些東西了,就跟朋友說的我這是自找難受。由於個人工作時間的問題,有些技術方面的問題實在不好一一解答,今天寫一篇博文總結一下各位所問道的問題。

 

  一. 哪裡修改資料連線

    這個是所有開發者中問的最多的問題,基本上加我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]=@SPECIFIC_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   


作者:情緣
出處:http://www.cnblogs.com/qingyuan/
關於作者:從事倉庫,生產軟體方面的開發,在專案管理以及企業經營方面尋求發展之路
版權宣告:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。
聯絡方式: 個人QQ  821865130 ; 倉儲技術QQ群 88718955,142050808 ;
吉特倉儲管理系統 開源地址: https://github.com/hechenqingyuan/gitwms

 

相關文章