程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Winform開發客戶關系管理系統(CRM)總結 2 基於框架的開發過程

Winform開發客戶關系管理系統(CRM)總結 2 基於框架的開發過程

編輯:關於.NET

在上篇隨筆《Winform開發框架之客戶關系管理系統(CRM)的開發總結系列1-界面功能展示》中介紹了 我的整個CRM系統的概貌,本篇繼續本系列的文章,介紹如何基於我的《winform開發框架》的基礎上進 行CRM系統模塊的開發工作,希望對大家在系統模塊開發有所啟示或者幫助。

在我整個開發框架的體系結構中,我都希望開發的業務模塊盡可能重用,因此遵循這個要求,所有的 模塊除了一些基礎模塊外,盡可能和其他業務模塊沒有任何耦合關系,同時也可以動態對模塊進行加載 使用,和我在《Winform開發框架之插件化應用框架實現》的思想一樣,各個模塊之間可以動態組合起來 ,實現更多的業務整合。

1、CRM系統的工程項目介紹

本客戶關系管理系統,也是基於這個目的和基礎上進行模塊開發,在整個項目模塊開發過程中,將會 利用到整個Winform開發框架的相關組件模塊,包括基礎界面模塊、程序啟動模塊、權限管理模塊、字典 管理模塊、分頁控件、公用類庫、附件管理等公用模塊。

整個CRM系統的界面效果如下所示。

首先我們來看看CRM系統主要項目工程的布局和說明。

設計好CRM的相關數據庫表後,利用C#代碼生成工具Database2Sharp生成框架各層的代碼,模塊開始 開發的時候,可以一次性把所有業務表的代碼一次性生成,然後在整個新的解決方案(.sln)上進行遞增 式完善即可,如果是後續模塊的開發,則需要增量把生成的代碼,復制到相關的框架目錄即可,整理後 的業務邏輯層代碼結構如下所示

這個時候,我們生成了界面層以下的所有分層代碼,整個代碼生成後,一次性即可編譯通過,界面層 我們另外建立一個Winform項目工程WHC.CRM.UIDx ,然後添加相關的界面引用程序集 (如DevExpress的相關界面程序集)。處理完這些後,我們又可以利用C#代碼生成工具Database2Sharp 來實現界面的快速開發工作了,代碼生成工具生成界面的操作界面如下所示,具體生成界面的操作可以 參考隨筆《利用代碼生成工具Database2Sharp設計數據編輯界面》進行了解。

最後得到類似項目目錄結構的CRM系統界面模塊工程。

由於整個CRM系統包含很多界面元素,因此以上模塊的界面部分只是其中一部分,如果內容較多,可 以建立目錄進行分類管理,這樣會更加清晰。

2、CRM系統的界面層代碼分析

利用C#代碼生成工具Database2Sharp,可以快速生成所需要的框架界面代碼,包括集成各種已有模塊 的界面基類、導入導出模塊支持、高級查詢能功能模塊,各種實體類對應關系等內容,這些如果利用手 工操作,效率非常低下,而且容易出錯。即使利用一些代碼生成工具,如果沒有和現成的界面模塊進行 很好的整合,也需要花費大量的時間進行整理,下面通過幾個界面代碼的展示進行大致的了解。

1)列表顯示界面的集成和分頁整合

2)字典模塊的整合處理(通過擴展類方法實現)

3)導入導出模塊的整合

private string moduleName = "客戶合同信息";
        /// <summary>
        /// 導入Excel的操作
        /// </summary>          
        private void btnImport_Click(object sender, EventArgs e)
        {
            string templateFile = string.Format("{0}-模板.xls", moduleName);
            FrmImportExcelData dlg = new FrmImportExcelData();
            dlg.SetTemplate(templateFile, System.IO.Path.Combine(Application.StartupPath, templateFile));
            dlg.OnDataSave += new FrmImportExcelData.SaveDataHandler(ExcelData_OnDataSave);
            dlg.OnRefreshData += new EventHandler(ExcelData_OnRefreshData);
            dlg.ShowDialog();
        }
    
        void ExcelData_OnRefreshData(object sender, EventArgs e)
        {
            BindData();
        }
    
        bool ExcelData_OnDataSave(DataRow dr)
        {
            string customerName = dr["客戶名稱"].ToString();
            if (string.IsNullOrEmpty(customerName))
                return false;
    
            CustomerInfo customerInfo = BLLFactory<Customer>.Instance.FindByName(customerName);
            if (customerInfo == null)
            {
                throw new ArgumentException(string.Format("客戶名稱【{0}】不存在,記錄已跳過", customerName));
            }
    
            bool success = false;
            bool converted = false;
            DateTime dtDefault = Convert.ToDateTime("1900-01-01");
            DateTime dt;
            ContractInfo info = new ContractInfo();
            info.Customer_ID = customerInfo.ID;//客戶ID
            info.HandNo = dr["合同編號"].ToString();
            info.ExpenditureType = dr["收支類型"].ToString();
            info.ContractType = dr["合同類型"].ToString();
            info.ContractName = dr["合同名稱"].ToString();
            info.ContractMoney = dr["合同金額"].ToString().ToDecimal();
            converted = DateTime.TryParse(dr["簽約日期"].ToString(), out dt);
            if (converted && dt > dtDefault)
            {
                info.SignDate = dt;
            }
........................................
    
            success = BLLFactory<Contract>.Instance.Insert(info);
            return success;
        }
    
        /// <summary>
        /// 導出Excel的操作
        /// </summary>
        private void btnExport_Click(object sender, EventArgs e)
        {
            string file = FileDialogHelper.SaveExcel(string.Format("{0}.xls", moduleName));
            if (!string.IsNullOrEmpty(file))
            {
                string where = GetConditionSql();
                List<ContractInfo> list = BLLFactory<Contract>.Instance.Find(where);
                DataTable dtNew = DataTableHelper.CreateTable("序號|int,客戶名稱,合同編號,收支類型,合同類型,合同名稱,合同金額,公司簽約人,客戶簽約人,簽約日期,簽約地點,乙方名稱,合同開始日期,合同結束日期,結算情況,合同狀態,關聯項目,聯系人,聯系人電話,聯系人手機,合同內容,

備注說明,經辦人");
                DataRow dr;
                int j = 1;
                for (int i = 0; i < list.Count; i++)
                {
                    dr = dtNew.NewRow();
                    dr["序號"] = j++;
                    dr["客戶名稱"] = BLLFactory<Customer>.Instance.GetCustomerName(list[i].Customer_ID);//轉義為客戶名稱
                    dr["合同編號"] = list[i].HandNo;
                    dr["收支類型"] = list[i].ExpenditureType;
                    dr["合同類型"] = list[i].ContractType;
......................................
                    dr["經辦人"] = list[i].Operator;
                    dtNew.Rows.Add(dr);
                }
    
                try
                {
                    string error = "";
                    AsposeExcelTools.DataTableToExcel2(dtNew, file, out error);
                    if (!string.IsNullOrEmpty(error))
                    {
                        MessageDxUtil.ShowError(string.Format("導出Excel出現錯誤:{0}", error));
                    }
                    else
                    {
                        if (MessageDxUtil.ShowYesNoAndTips("導出成功,是否打開文件?") == System.Windows.Forms.DialogResult.Yes)
                        {
                            System.Diagnostics.Process.Start(file);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogTextHelper.Error(ex);
                    MessageDxUtil.ShowError(ex.Message);
                }
            }
        }

4)高級查詢模塊的整合

private FrmAdvanceSearch dlg;
        private void btnAdvanceSearch_Click(object sender, EventArgs e)
        {
            if (dlg == null)
            {
                dlg = new FrmAdvanceSearch();
                dlg.FieldTypeTable = BLLFactory<Contract>.Instance.GetFieldTypeList();
                dlg.ColumnNameAlias = BLLFactory<Contract>.Instance.GetColumnNameAlias();
                dlg.DisplayColumns = "Customer_ID,HandNo,ExpenditureType,ContractType,ContractName,ContractMoney,CompanySigner,CustomerSigner,SignDate,SignLocation,PartyBName,StartDate,EndDate,Settlement,Status,Rel

atedItems,Contact,ContactPhone,ContactMobile,Content,Note,Operator";
    
                #region 下拉列表數據
    
                //dlg.AddColumnListItem("UserType", Portal.gc.GetDictData("人員類型"));//字典列表
                //dlg.AddColumnListItem("Sex", "男,女");//固定列表
                //dlg.AddColumnListItem("Credit", BLLFactory<Contract>.Instance.GetFieldList("Credit"));//動態列表
    
                #endregion
    
                dlg.ConditionChanged += new FrmAdvanceSearch.ConditionChangedEventHandler(dlg_ConditionChanged);
            }
            dlg.ShowDialog();
        }
    
        void dlg_ConditionChanged(SearchCondition condition)
        {
            advanceCondition = condition;
            BindData();
        }

5)編輯界面的基類繼承

3、CRM系統的界面層的用戶及權限信息傳遞

我們知道,每個業務模塊都可能需要獲取當前登錄的一些用戶信息和權限信息,以便達到更好的控制 和數據的顯示,如某些模塊,可能只需要顯示當前用戶的數據,由於CRM系統的界面是獨立開發,不整合 在啟動界面模塊裡面,那麼如何獲得用戶和權限控制信息呢?例如下面的CRM模塊裡面的界面,需要根據 當前用戶獲取到客戶的分組列表的。

首先我們可以在界面基類中實現一個接口,以便傳遞相關的用戶和權限信息。

namespace WHC.Framework.BaseUI
{
    public partial class BaseForm : DevExpress.XtraEditors.XtraForm, IFunction
    {

其中IFunction的定義如下所示。

namespace WHC.Framework.BaseUI
{
    /// <summary>
    /// 父窗體實現的權限控制接口
    /// </summary>
    public interface IFunction
    {
        /// <summary>
        /// 初始化權限控制信息
        /// </summary>
        void InitFunction(LoginUserInfo userInfo, Dictionary<string, string> functionDict);
    
        /// <summary>
        /// 是否具有訪問指定控制ID的權限
        /// </summary>
        /// <param name="controlId">功能控制ID</param>
        /// <returns></returns>
        bool HasFunction(string controlId);
    
        /// <summary>
        /// 登陸用戶基礎信息
        /// </summary>
        LoginUserInfo LoginUserInfo { get; set; }
    
        /// <summary>
        /// 登錄用戶具有的功能字典集合
        /// </summary>
        Dictionary<string, string> FunctionDict { get; set; }
    
        /// <summary>
        /// 應用程序基礎信息
        /// </summary>
        AppInfo AppInfo { get; set; }
    
    }
}

其中就定義了接口進行用戶和權限信息的賦值。在界面按鈕構建相關模塊的功能界面窗體的時候,我 們可以為這些傳遞傳遞相關的對象信息。

private void barCRMContact_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs 

e)
        {
            ChildWinManagement.LoadMdiForm(this, typeof(FrmCustomerContact));
        }
    
        private void barCRMCustomer_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            ChildWinManagement.LoadMdiForm(this, typeof(FrmCustomerManage));
        }
tableForm = (Form) Activator.CreateInstance(formType);
                tableForm.MdiParent = mainDialog;
    
                //如果窗體集成了IFunction接口(第一次創建需要設置)
                IFunction function = tableForm as IFunction;
                if (function != null)
                {
                    //初始化權限控制信息
                    function.InitFunction(Portal.gc.LoginUserInfo, Portal.gc.FunctionDict);
    
                    //記錄程序的相關信息
                    function.AppInfo = new AppInfo(Portal.gc.AppUnit, Portal.gc.AppName, 

Portal.gc.AppWholeName, Portal.gc.SystemType);
                }

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved