Winform开发框架之客户关系管理系统(CRM)的开发总结系列2-基于框架的开发过程

简介:

在上篇随笔《Winform开发框架之客户关系管理系统(CRM)的开发总结系列1-界面功能展示》中介绍了我的整个CRM系统的概貌,本篇继续本系列的文章,介绍如何基于我的《winform开发框架》的基础上进行CRM系统模块的开发工作,希望对大家在系统模块开发有所启示或者帮助。

在我整个开发框架的体系结构中,我都希望开发的业务模块尽可能重用,因此遵循这个要求,所有的模块除了一些基础模块外,尽可能和其他业务模块没有任何耦合关系,同时也可以动态对模块进行加载使用,和我在《Winform开发框架之插件化应用框架实现》的思想一样,各个模块之间可以动态组合起来,实现更多的业务整合。

 1、CRM系统的工程项目介绍

本客户关系管理系统,也是基于这个目的和基础上进行模块开发,在整个项目模块开发过程中,将会利用到整个Winform开发框架的相关组件模块,包括基础界面模块、程序启动模块、权限管理模块、字典管理模块、分页控件、公用类库、附件管理等公用模块。

整个CRM系统的界面效果如下所示。

首先我们来看看CRM系统主要项目工程的布局和说明。

解决方案项目工程介绍
WHC.Framework.BaseUIDx 重用模块。各模块的界面基类,包括通用窗体界面基类BaseUI;通用高级查询模块AdvanceSearch;通用Excel导入模块;插件化接口相关类PlugInInterface等。
WHC.Framework.StarterDx 重用模块。插件化应用程序启动界面。通过用户登录后,获取用户的菜单,动态创建菜单并加载插件,该模块集成权限管理系统模块、集成字典数据管理模块、集成多文档界面控件和布局控件、集成美观实用的登陆界面、闪屏展示界面、托盘缩小提示功能、全局运行一次实例限制模块代码等内容。
WHC.CRM.Core 新开发模块。客户关系管理系统的核心模块,包括业务处理、数据接口层、数据访问层、实体层等相关类。
WHC.CRM.UIDx 新开发模块。客户关系管理系统的界面层,包括所系统模块的各种界面、控件等内容。

设计好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,RelatedItems,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);
                }

通过在构造窗体的时候,传入相关的用户和权限对象属性即可实现这些信息的传递和使用。

另外,为了更加方便信息的传递,我们也可以在用户登陆的时候,把这些信息通过Cache对象把它缓存起来,类似Web开发里面的Session功能。

我的该CRM系统系列的几篇随笔链接如下,供阅读。

Winform开发框架之客户关系管理系统(CRM)的开发总结系列1-界面功能展示 

Winform开发框架之客户关系管理系统(CRM)的开发总结系列2-基于框架的开发过程 

Winform开发框架之客户关系管理系统(CRM)的开发总结系列3-客户分类和配置管理实现 

Winform开发框架之客户关系管理系统(CRM)的开发总结系列4-Tab控件页面的动态加载 

本文转自博客园伍华聪的博客,原文链接:Winform开发框架之客户关系管理系统(CRM)的开发总结系列2-基于框架的开发过程,如需转载请自行联系原博主。



目录
相关文章
|
11天前
|
机器学习/深度学习 安全 搜索推荐
中国CRM市场深度解析:本土化定制开发的领军厂商与未来趋势
国内CRM软件企业正面临日益增长的本土定制需求,这不仅考验服务商的综合水平,也推动了市场的快速发展。本文将深入解析中国CRM市场的现状,探讨领军厂商的优势,并预测未来趋势,包括智能化、集成化、本土化与国际化并行及云服务模式的普及。
|
5天前
|
机器学习/深度学习 人工智能 安全
精选CRM软件:顶级客户关系管理工具深度剖析
本文综合评测2024年顶级CRM工具,依据功能性、用户体验、集成能力、数据安全、客户支持及成本效益六大标准,深度剖析纷享销客、Salesforce、Microsoft Dynamics 365、用友CRM和SAP CRM等软件,为企业选型提供参考。
|
3月前
|
开发框架 人工智能 数据挖掘
2024年国产CRM软件排行榜:客户关系管理工具
CRM软件是企业数字化战略的核心,通过全渠道互动、客户细分和销售赋能提升竞争力。2024年,国产CRM软件凭借本土化优势、成本效益、政策支持和市场机会展现出强劲竞争力。销售易、白码CRM、悟空CRM、用友CRM、金蝶CRM、珍客CRM、八百客CRM和销帮帮CRM等名列前茅。选择CRM时需考虑本土化服务、技术兼容性和长期合作潜力等因素。随着国产CRM软件的崛起,企业应根据需求选择最适合的解决方案,实现客户关系管理和业务增长的优化。
|
3月前
|
人工智能 搜索推荐 数据挖掘
中国CRM市场深度解析:本土化定制开发的领军厂商与未来趋势
在数字化转型的大潮中,客户关系管理系统(CRM)已成为企业增强竞争力和服务质量的关键工具。鉴于中国市场独特的文化背景和商业环境,高度定制化的CRM解决方案显得尤为重要。本文深入剖析了中国CRM市场的现状及其未来发展走向,同时重点介绍了销售易CRM、纷享销客等领军厂商如何通过深入理解本土需求、提供贴合国情的产品和服务来助力企业成长。这些解决方案不仅强化了客户互动的亲切感和有效性,还确保了数据的安全与合规,为企业提供了强大的竞争优势。随着人工智能、大数据等前沿技术的应用,未来的CRM系统将更加智能、高效,为企业创造更多价值。
|
3月前
|
搜索推荐
实现CRM与ERP系统无缝集成,优化客户关系管理
在当今竞争激烈的市场环境中,企业要想保持领先地位,必须高效地管理客户关系并优化内部资源。CRM(客户关系管理)系统与ERP(企业资源规划)系统的无缝集成,为企业提供了一种强大的工具,以实现这一目标
62 2
|
3月前
|
监控 搜索推荐 数据管理
crm客户管理系统来帮助企业管理和提高运营效率
crm系统帮助企业简化销售流程,提高工作效率。CRM 客户管理系统确实能够在多个方面帮助企业管理和提高运营效率,具体表现如下:
33 3
|
4月前
|
监控 数据挖掘 数据安全/隐私保护
ERP系统中的客户关系管理(CRM)
【7月更文挑战第25天】 ERP系统中的客户关系管理(CRM)
316 3
|
3月前
|
数据挖掘 BI API
简单了解CRM与SaaS系统
本文介绍了CRM(客户关系管理系统)和SaaS(软件即服务)的概念、应用场景、两者之间的关系以及CRM接口的作用和设置流程,强调了SaaS模式为CRM系统提供了灵活、便捷、经济高效的使用方式,以及CRM接口在数据集成、自动化流程、功能扩展和数据分析方面的重要性。
92 0
|
4月前
|
存储 Python
在计算机管理系统工程中,我们利用计算机技术来构建、优化和管理各种系统,如企业资源规划(ERP)、客户关系管理(CRM)等。
。在计算机管理系统工程中,我们利用计算机技术来构建、优化和管理各种系统,如企业资源规划(ERP)、客户关系管理(CRM)等。
|
4月前
|
数据采集 存储 搜索推荐
CRM客户系统全解析:定义与企业应用
Zoho CRM是一个集成客户数据、销售流程、市场活动和客户服务的平台,助力企业提升效率和竞争力。它支持销售管理、客户细分及个性化营销,改善客户体验。系统在销售预测、客户档案管理和市场营销策略制定上发挥作用。然而,挑战包括系统集成、数据质量、员工培训和用户接纳。企业需克服这些挑战以确保CRM的有效运营。
65 2