基於Extjs的web表單設計器 第七節——取數公式設計之取數公式定義
基於Extjs的web表單設計器 第七節——取數公式設計之取數公式的使用
基於Extjs的web表單設計器 第八節——表單引擎設計
在上一節中給大家介紹了如何定義一套取數公式,以及取數公式的參數設計。有了這些知識基礎,我們本節主要介紹取數公式的使用。
一個具體業務范疇的系統中,我們首先會根據業務知識的積累,定義出業務范圍之內通用的取數公式。比如單據的日期、單據編號、制單人、制單部門、部門職員、職員職責等等信息。這些取數方法基本上每個業務單據都會涉及到。當我們抽象並定義出了這些取數公式之后,后面在表單設計器中設計業務單據的時候直接使用它們就行了。
首先我們定義一個取數公式的實體類型:

1 public class Formula 2 { 3 /// <summary> 4 /// 取數公式名稱 5 /// </summary> 6 public string Name { get; set; } 7 8 /// <summary> 9 /// 取數地址 10 /// </summary> 11 public string Url { get; set; } 12 13 /// <summary> 14 /// 取數參數列表 15 /// </summary> 16 public Dictionary<string, string> Parameters { get; set; } 17 18 /// <summary> 19 /// 計算公式 20 /// </summary> 21 public string Expression { get; set; } 22 23 /// <summary> 24 /// 授權的控件類型 25 /// </summary> 26 public string ControlType { get; set; } 27 28 /// <summary> 29 /// 取數公式對應的資源參照 30 /// </summary> 31 public string ResourceTypeID { get; set; } 32 33 public Formula() 34 { 35 this.Parameters = new Dictionary<string, string>(); 36 } 37 }
該實體類型的屬性和我們上一節講的取數公式的XML定義的屬性基本一致的,只是少了一個公式的描述,多了一個Expression的屬性。該屬性是我們用來存儲一些特殊的取數公式的表達式用的。那些特殊的取數公式會有表達式呢?這里我給大家列舉兩類特殊的取數公式會有表達式,然后就是控件的條件隱藏功能會用到表達式。這里請注意,我們沒有把條件隱藏作為取數公式,而是一個控件的功能屬性。為什么?請大家思考。
因為取數公式是每個控件的數據源的抽象表示,一個控件的數據來源不會有兩個公式吧?而每個控件也都有可能會根據其他控件的取值進行隱藏、顯示的(條件隱藏)需求吧。因此兩者是不同的東西,是並行存在的。那這里可能會有人會問,既然是兩個並行存在的不同的東西,那為什么會把條件隱藏的表達式存放到公式的實體中去呢?(如果有人想到這個問題,我很想贊美你一句“很好,說明你已經具備很強的軟件設計能力。懂得職責單一的道理。”)既然把它們兩個東西搞到一坨,肯定還是有點道理的,職責單一也不是說非得什么東西都得單一設計,具體情況具體分析。這兒因為這兩個表達式的保存前的校驗,數據庫中的保存方式,前台JS引擎解析等過程都是一樣的流程,因此我們沒有必要單一設計。把它們統一到一個Json對象中統一處理也不為一種好的處理方式。
好啦,掰扯了半天還沒說“兩類特殊的取數公式”是啥?這里所說的兩類特殊的取數公式是下圖一中的描述的東東。我現在喜歡用一些圖來表述一些東西,很簡潔,很明了,很爽。深切體會到“文不如表,表不如圖”。相信大家一看就明白了。
為了在表單設計器中使用這些取數公式,那么我們首先得取到這些取數公式。我們定義一個接口專門把取數公式的XML文件中的所有的XML描述的取數公式全部解析到對應的Formula實體對象的集合。

public IEnumerable<Formula> GetFormulaList() { XElement xRoot = XElement.Load(path); foreach (var xel in xRoot.Elements()) { var url = xel.Attribute("Url"); var controlType = xel.Attribute("ControlType"); var resourceTypeId = xel.Attribute("ResourceTypeID"); Dictionary<string, string> dict = null; if (xel.HasElements) { dict = new Dictionary<string, string>(); foreach (var p in xel.Element("Parameters").Elements()) { var pName = p.Attribute("Name"); var name = pName == null ? null : pName.Value; dict.Add(p.Value, name); } } yield return new Formula { Name = xel.Attribute("Name").Value, Url = url == null ? null : url.Value, ControlType = controlType == null ? null : controlType.Value, ResourceTypeID = resourceTypeId == null ? null : resourceTypeId.Value, Parameters = dict }; } }
那么至此我們准備好了取數公式的數據源,剩下的事兒就是在表單設計器中根據不同類型的控件來選擇這些不同的取數公式並設定相關的公式參數。文不如圖,那么就直接上圖,下面圖二是表單設計器中我們對兩類不同類型控件的取數公式界面的截圖展示。一個是金額控件,一個是下拉樹控件,請大家對比其中的一些區別地方。
圖二
區別有三:
1.下拉樹控件的取數公式的類型比金額控件多了一個選項“資源取數”;
2.下拉樹控件的取數公式選擇類型為“資源取數”后,設置的界面多了一個“設置取值范圍”的功能,見上圖;
3.兩種控件的公式取數,取數公式內容不一樣;(PS:上圖是看不出來的,不用找了)
這里對這三個區別一一做出解釋:
1.下拉樹控件的取數方法多了一個資源取數,這兒請大家聯想我們在上一節中介紹的知識去理解。因為下拉樹的數據源就是我們系統中的資源類型,這里的資源取數其實就是對應我們在上一節中介紹的靜態資源。我們可以為下拉樹控件直接設定它的數據源是某種靜態的資源,而不需要根據其他參數進行組合篩選,因此這里的資源取數是必要的的。
2.因為有了上面的1的存在,因此2 的存在也是必要的。既然我們可以為下拉樹控件設置靜態的資源,那么我們就可以設定一個靜態的資源作為下拉樹控件的默認值。有些同學可能會問,難道根據公式取數的動態資源就不能設定默認值么???答案是可以設定的,但是設定了是沒有意義的,既然沒有意義,那么就不需提供這個功能!!!為什么沒有意義?我的解釋是——既然是公式取數,那么公式就是在運行時解析的一個東西,我們事先是不能明確該公式的參數值的,既然參數值都不能確定,那么結果值就更不能確定了,也許結果集里面根本就不包含這個默認值,那么你設置一個默認值還有意義么?所以公式取數我們是沒有默認值范圍的。
3.在上一節中已經介紹了,每個取數公式都有一個支持的控件的類型,不同類型的控件能夠使用的取數公式也自然是不一樣的。因此我們在表單設計器中使用的時候肯定會根據選擇的控件類型不同來對取數公式的數據源進行過濾,只提供該類型控件能夠使用的取數公式列表即可。
下面我們來通過一個例子介紹一下取數公式在表單設計器中的使用。比如有一個叫取數公式“部門下的職員”——意思就是根據選擇的部門key來動態獲取該部門下的所有職員的列表。那么在我們的表單模板設計中,比如有兩個控件:一個是“借款部門”,另一個是“借款人” 如圖三所示。
圖三
然后借款人就需要根據“部門下的職員”這個取數公式來動態的傳入“借款部門”這個控件所選取的值作為參數來獲取該部門下的職員列表。那么我們在設置借款人這個控件的取數公式的時候就需要選擇公式列表中的“部門下的職員”這個公式。然后設定它的公式參數“部門”的值為"借款部門"這個控件。這里我們也提供了兩種特殊的取數公式“摘要生成”和“公式計算”的使用截圖,如圖四所示。請大家注意圖四中幾幅圖的區別和聯系。
圖四
然后設置好這些屬性之后,我們點擊控件屬性面板的“確定”按鈕表單設計器就會自動的為控件生成一個取數公式的JSON對象,並且會去校驗取數公式設置的正確與否,如果正確就存放到控件的Formula屬性中去,最后保存表單模板的就會直接存入數據庫中。至此,我們介紹了取數公式在表單設計器中的使用,到這里我們表單設計器這個部分的主要功能和設計都已經作了介紹。余下的就是另一個重要的組成部分——表單引擎的介紹了。表單引擎主要負責了我們表單模板的加載、控件層級關系嵌套及渲染,控件各個屬性的生成及應用,控件取數公式的生成及解析,控件聯動關系的生成及解析,權限值的控制及應用等等核心內容。這些內容我們會在后面的章節娓娓道來,請看下一節“基於Extjs的web表單設計器 第八節——表單引擎設計 “。