客户关系管理系统中对客户及相关数据的导入导出操作

在很多系统,我们都知道,Excel数据的导入导出操作是必不可少的一个功能,这种功能能够给使用者和外部进行数据交换,也能批量迅速的录入数据到系统中;但在一些系统中,为了方便,可能把很多个基础表或者相关的数据综合到一个Excel表格文件里面,然后希望通过接口进行导入,这种需求处理就显得比较复杂一点了。本文探讨在我的客户关系管理系统中,对于单个Excel表格中,集合了客户基础数据及相关数据的导入和导出操作的处理。

1、导入导出的需求分析

本随笔主要介绍如何在系统中,导入单一文件中的数据到系统中,这个文件包含了基础数据和相关数据的导入和导出操作,一般来说这样的操作对于导入数据已经足够简便了,但是,有时候数据很多的情况下,我们可能需要每次选定文件也是一个麻烦的事情。因此指定目录进行批量数据的导入操作也是一个好的需求,可以进一步简化用户的数据导入操作。

下面我们就来介绍,导入、批量导入和导出的三个重要的操作,如图所示。

导入的数据,是一个Excel,它要求包含几个不同表的数据,导入操作一次性完成数据的导入,Excel文件的格式如下所示。

2、数据导入操作的界面设计及处理

我们知道,要一次性导入几个表的数据,需要先读取Excel获取各个Sheet(工作表)的数据,然后把它转换为DataTable的数据对象,这样我们就可以根据它的字段赋值给对应的实体类,然后调用业务逻辑处理将数据写入数据库即可。

为了直观的给使用者查看将要导入的数据,我们把需要导入到数据库的数据,展现在界面上,供客户确认,如果没有问题,就可以进行导入操作。由于我们需要操作多个数据表,因此有效读取Excel里面的Sheet就是第一步工作。

查看Excel数据的操作代码如下所示,主要的逻辑就是调用Apose.Cell的封装类进行处理

AsposeExcelTools.ExcelFileToDataSet(this.txtFilePath.Text, out myDs, out error);

把Excel文件里面多个Sheet的数据转换为DataSet,然后每个进行依次的处理,展示代码如下所示。

        private void ViewData()
        {
            if (this.txtFilePath.Text == "")
            {
                MessageDxUtil.ShowTips("请选择指定的Excel文件");
                return;
            }

            try
            {

                myDs.Tables.Clear();
                myDs.Clear();
                this.gridCustomer.DataSource = null;

                string error = "";
                AsposeExcelTools.ExcelFileToDataSet(this.txtFilePath.Text, out myDs, out error);
                this.gridCustomer.DataSource = myDs.Tables[0];
                this.gridView1.PopulateColumns();

                this.gridFollow.DataSource = myDs.Tables[1];
                this.gridView2.PopulateColumns();

                this.gridContact.DataSource = myDs.Tables[2];
                this.gridView3.PopulateColumns();

                this.gridSupplier.DataSource = myDs.Tables[3];
                this.gridView4.PopulateColumns();
            }
            catch (Exception ex)
            {
                LogTextHelper.Error(ex);
                MessageDxUtil.ShowError(ex.Message);
            }
        }

由于导入过程中需要耗费一定的时间,因此我们可以通过后台线程结合进度条的方式提示用户,界面设计效果如下效果所示。

刚才说到,保存数据,我们把它放到后台线程BackgroudWorker进行处理即可,处理代码如下所示。

        private void btnSaveData_Click(object sender, EventArgs e)
        {
            if (worker.IsBusy)
                return;

            if (this.txtFilePath.Text == "")
            {
                MessageDxUtil.ShowTips("请选择指定的Excel文件");
                return;
            }

            if (MessageDxUtil.ShowYesNoAndWarning("该操作将把数据导入到系统数据库中,您确定是否继续?") == DialogResult.Yes)
            {
                if (myDs != null && myDs.Tables[0].Rows.Count > 0)
                {
                    this.progressBar1.Visible = true;
                    worker.RunWorkerAsync();
                }
            }
        }

后台线程操作的主要业务逻辑代码如下所示,就是依次把不同的数据进行解析,并保存即可。

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (myDs != null && myDs.Tables.Count >= 4 && myDs.Tables[0].Rows.Count > 0)
            {
                try
                {
                    ImportCustomerDataHelper helper = new ImportCustomerDataHelper();
                    helper.LoginUserInfo = LoginUserInfo;

                    //写入或更新客户信息
                    string customerID = helper.UpdateCustomer(myDs.Tables[0]);
                    if (!string.IsNullOrEmpty(customerID))
                    {
                        helper.AddFollow(customerID, myDs.Tables[1], worker);
                        helper.AddContact(customerID, myDs.Tables[2], worker);
                        helper.AddSupplier(customerID, myDs.Tables[3], worker);

                        e.Result = "操作完成";
                    }
                    else
                    {
                        e.Result = "操作失败";
                    }
                }
                catch (Exception ex)
                {
                    e.Result = ex.Message;
                    LogTextHelper.Error(ex);
                    MessageDxUtil.ShowError(ex.ToString());
                }
            }
            else
            {
                e.Result = "请检查数据记录是否存在";
            }
        }

3、数据批量导入操作

虽然上面可以一次性导入客户和其相关数据,但是还是一次性导入一个Excel,如果对于客户数据比较多的情况下,一次次导入操作也是很繁琐的事情,因此客户提出,需要按照目录把所有相关的Excel数据一次性导入,这种导入有个问题就是我们不能再中途干预导入操作,因此为了数据的安全性,我提供一个界面让客户选择目录,然后把目录里面的Excel文件列出来,然后在让客户确认是否进一步导入。

上面操作的实现代码我逐一介绍,首先第一步是需要递归列出目录下面的Excel文件,然后显示出来供用户确认导入的清单。

        private void btnSelectPath_Click(object sender, EventArgs e)
        {
            string mydocDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            string selectPath = FileDialogHelper.OpenDir(mydocDir);
            if (!string.IsNullOrEmpty(selectPath))
            {
                //清空就记录
                this.lstPath.Items.Clear();

                string[] fileArray = Directory.GetFiles(selectPath, "*.xls", SearchOption.AllDirectories);
                if (fileArray != null && fileArray.Length > 0)
                {
                    foreach (string file in fileArray)
                    {
                        string fileName = Path.GetFileName(file);
                        this.lstPath.Items.Add(new CListItem(fileName, file));
                    }
                }
            }
        }

当用户确认操作的时候,提示客户确认是否进行,确认后将统一批量导入列表里面的文件,这个地方也是为了方便,使用后台线程进行数据的导出操作,并在过程中提供进度条的指示。

        private void btnConfirm_Click(object sender, EventArgs e)
        {
            if (worker.IsBusy)
                return;

            if (this.lstPath.Items.Count > 0)
            {
                if (MessageDxUtil.ShowYesNoAndTips("您确认导入列表的Excel文件吗?") == System.Windows.Forms.DialogResult.Yes)
                {
                    List<string> fileList = new List<string>();
                    foreach (object item in this.lstPath.Items)
                    {
                        CListItem fileItem = item as CListItem;
                        if (fileItem != null)
                        {
                            fileList.Add(fileItem.Value);
                        }
                    }

                    this.progressBar1.Visible = true;
                    worker.RunWorkerAsync(fileList);
                }
            }
        }

这个后台线程的处理逻辑和单个文件导入的操作差不多,只不过这里需要增加一个文件列表的遍历处理而已,具体代码如下所示。

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            List<string> fileList = e.Argument as List<string>;
            if (fileList == null || fileList.Count == 0) return;

            bool hasError = false;
            ImportCustomerDataHelper helper = new ImportCustomerDataHelper();
            helper.LoginUserInfo = LoginUserInfo;

            foreach (string file in fileList)
            {
                DataSet myDs = new DataSet();
                string error = "";
                AsposeExcelTools.ExcelFileToDataSet(file, out myDs, out error);

                if (myDs != null && myDs.Tables.Count >= 4 && myDs.Tables[0].Rows.Count > 0)
                {
                    try
                    {
                        //写入或更新客户信息
                        string customerID = helper.UpdateCustomer(myDs.Tables[0]);
                        if (!string.IsNullOrEmpty(customerID))
                        {
                            helper.AddFollow(customerID, myDs.Tables[1], worker);
                            helper.AddContact(customerID, myDs.Tables[2], worker);
                            helper.AddSupplier(customerID, myDs.Tables[3], worker);
                        }
                    }
                    catch (Exception ex)
                    {
                        hasError = true;
                        LogTextHelper.Error(ex);
                    }
                }
            }

            string msg = "操作完成";
            if (hasError)
            {
                msg += ",导入出现错误。具体可以查看log.txt日志记录。";
            }
            e.Result = msg;
        }

和上面的单个文件导入一样,我们这里使用了一个封装类ImportCustomerDataHelper,用来对数据进行转换实体类,然后保存到数据库的操作过程,下面我们来简单看看里面的处理代码

    /// <summary>
    /// 客户数据的批量导入和普通导入的操作逻辑代码
    /// </summary>
    public class ImportCustomerDataHelper
    {
        /// <summary>
        /// 登陆用户信息
        /// </summary>
        public LoginUserInfo LoginUserInfo { get; set; }

        /// <summary>
        /// 写入或更新客户数据,如果成功更新返回ID值
        /// </summary>
        /// <param name="dataTable">客户数据表</param>
        /// <returns></returns>
        public string UpdateCustomer(DataTable dataTable)
        {
            bool success = false;
            bool converted = false;
            DateTime dtDefault = Convert.ToDateTime("1900-01-01");
            DateTime dt;
            string result = "";

            DataRow dr = dataTable.Rows[0];
            if (dr != null)
            {
                string customerName = dr["客户名称"].ToString();
                CustomerInfo info = CallerFactory<ICustomerService>.Instance.FindByName(customerName);
                bool isNew = false;
                if (info == null)
                {
                    info = new CustomerInfo();
                    isNew = true;
                }

                info.Name = customerName;
                info.HandNo = dr["客户编号"].ToString();
                info.SimpleName = dr["客户简称"].ToString();
                ..........................
                info.IsPublic = dr["公开与否"].ToString().ToBoolean();
                info.Satisfaction = dr["客户满意度"].ToString().ToInt32();
                info.TransactionCount = dr["交易次数"].ToString().ToInt32();
                info.TransactionTotal = dr["交易金额"].ToString().ToDecimal();
                info.Creator = dr["客户所属人员"].ToString();
                converted = DateTime.TryParse(dr["创建时间"].ToString(), out dt);
                if (converted && dt > dtDefault)
                {
                    info.CreateTime = dt;
                }
                info.Editor = LoginUserInfo.ID.ToString();
                info.EditTime = DateTime.Now;

                if (isNew)
                {
                    info.Dept_ID = LoginUserInfo.DeptId;
                    info.Company_ID = LoginUserInfo.CompanyId;
                    success = CallerFactory<ICustomerService>.Instance.Insert(info);
                }
                else
                {
                    success = CallerFactory<ICustomerService>.Instance.Update(info, info.ID);
                }

                if (success)
                {
                    result = info.ID;
                }
            }

            return result;
        }

...........................

4、数据的导出操作

导出操作,我们根据用户的选择,可以一次性导出多个Excel文件,每个Excel文件包含客户的基础信息,也包含相关数据,它们的格式和导入的格式保持一致即可,这样方便数据的交换处理。

导出操作,我们需要把客户的选择信息转换为需要导出的对象列表数据,然后绑定到Excel里面即可,因此我们的Excel里面,可以通过自定义模板,指定列的数据属性就可以绑定好数据了。

获取选择的客户信息的代码如下所示。

                List<CustomerInfo> list = new List<CustomerInfo>();
                foreach (int iRow in rowSelected)
                {
                    string ID = this.winGridViewPager1.GridView1.GetRowCellDisplayText(iRow, "ID");
                    CustomerInfo info = CallerFactory<ICustomerService>.Instance.FindByID(ID);
                    if (info != null)
                    {
                        list.Add(info);
                    }
                }

前面介绍了,我们将使用自定义模板,在模板文件里面的对应字段下面,绑定一个参数属性就可以了,通过Aspose.Cell的操作处理,我们就很方便把数据导出到Excel里面了,而里面的字段还可以很方便实现自由的裁剪操作。

自定义模板文件效果如下所示。

导出客户以及相关信息的主要核心代码如下所示。

                            #region 导出操作
                            //依次每个客户数据导出一个文件
                            string ownerUserName = CallerFactory<IUserService>.Instance.GetFullNameByID(customerInfo.Creator.ToInt32());
                            string filePath = Path.Combine(selectPath, ownerUserName);
                            DirectoryUtil.AssertDirExist(filePath);

                            Dictionary<string, object> dict = new Dictionary<string, object>();
                            dict.Add("Customer", new List<CustomerInfo>() { customerInfo });//需要构造一个列表绑定

                            List<FollowInfo> followList = CallerFactory<IFollowService>.Instance.Find(string.Format("Customer_ID =‘{0}‘ ", customerInfo.ID));
                            dict.Add("Follow", followList);

                            List<ContactInfo> contactList = CallerFactory<IContactService>.Instance.FindByCustomer(customerInfo.ID);
                            dict.Add("Contact", contactList);

                            PagerInfo pagerInfo = null;
                            List<SupplierInfo> supplierList = CallerFactory<ISupplierService>.Instance.FindByCustomer(customerInfo.ID, "", ref pagerInfo);
                            dict.Add("Supplier", supplierList);

                            string templateFile = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "客户综合资料-导出模板.xls");
                            if (!File.Exists(templateFile))
                            {
                                throw new ArgumentException(templateFile, string.Format("{0} 文件不存在,", Path.GetFileName(templateFile)));
                            }

                            string saveFileName = string.Format("{0}.xls", customerInfo.Name);
                            string saveFilePath = Path.Combine(filePath, saveFileName);

                            WorkbookDesigner designer = new WorkbookDesigner();
                            designer.Workbook = new Workbook(templateFile);
                            foreach (string key in dict.Keys)
                            {
                                designer.SetDataSource(key, dict[key]);
                            }
                            designer.Process();
                            designer.Workbook.Save(saveFilePath, SaveFormat.Excel97To2003);
                            #endregion

这样利用Aspose.Cell的处理操作,通过绑定相关的数据对象,我们就很容易实现数据导出到符合我们预期格式的Excel里面去了,这样操作高效、代码干净,Excel格式也非常符合我们的要求。

以上就是在客户关系管理系统里面碰到特殊的数据导入导出需求的介绍和实现,希望大家相互交流,共同把软件开发过程中,数据导入导出操作的使用体验做到最好,更符合我们客户使用的习惯和需求。

时间: 2024-10-07 06:47:05

客户关系管理系统中对客户及相关数据的导入导出操作的相关文章

MATLAB中文件的读写和数据的导入导出

http://blog.163.com/tawney_daylily/blog/static/13614643620111117853933/ 在编写一个程序时,经常需要从外部读入数据,或者将程序运行的结果保存为文件.MATLAB使用多种格式打开和保存数据.本章将要介绍 MATLAB中文件的读写和数据的导入导出. 13.1 数据基本操作 本节介绍基本的数据操作,包括工作区的保存.导入和文件打开.13.1.1 文件的存储 MATLAB支持工作区的保存.用户可以将工作区或工作区中的变量以文件的形式保

CRM客户关系管理系统如何分析客户的动态需求

由于激烈的市场竞争,对于怎样掌握客户的动态需求,怎样保持客户市场的稳定增长,对于企业来说已经成为普遍的关注点.CRM客户关系管理系统经过了10年的发展历程,怎样管理客户.了解客户成就了CRM客户关系管理系统的大市场. CRM供货商一般侧重于宣扬软件的特性及功用,而对其全体价值则没有做出了解的表述. 用户高档处理层一般从基础设施安顿而非运营和战略视点对待CRM客户关系管理系统施行. 由于无法从运营和战略视点安顿CRM客户关系管理系统,用户对CRM的价值认知只停留在技术功率层面上. 只需跨过技术和流

基于JAVA技术的客户关系管理系统

获取项目源文件,技术交流与指导联系Q:1225467431 摘要:该客户关系管理系统是基于J2EE技术进行开发,主要采用JAVA语言作为开发语言,基于MVC的设计思想,利用J2EE网页制作技术完成前台静态页面和动态页面的设计,同时利用JDBC技术完成前台页面和后台MySQL数据库的连接操作,最终完成一个客户关系管理系统.该系统共分为营销管理.客户管理.服务管理和统计报表四个功能模块,系统可以帮助企业发掘并创建客户信息记录,对所有的客户进行有效的管理:按照客户的一些基本信息和业务信息进行分类,掌握

JDBC实现客户关系管理系统模块

这是一个使用JDBC技术来实现客户关系管理系统的案例. 创建MVC架构的Web项目 在Eclipse中新创建一个day14_customer项目,导入项目所需要的开发包(jar包),创建项目所需要的包,在java开发中,架构的层次是以包的形式体现出来的. 项目所需要的开发包(jar包): 序号 开发包名称 描述 1 stl-1.2.jar jstl标签库和EL表达式依赖包 2 mysql-connector-java-5.1.38-bin.jar MySQL数据库驱动包 3 commons-be

loadrunner实战篇 - 客户关系管理系统性能测试

系统介绍                                                             图1(客户关系管理系统模块关系图) 需求分析 一.性能指标 性能指标分析,根据客户需求与本系统相结合,用户希望模块能满足下表所列的性能指标. 图2(性能指标) 很明显,上面的需求是不具可操作性的,这就像和客户谈需求一样,客户只是很简单地描述了需求,而如果仅仅从上面这个简单的表格来进行性能测试,是很难的一件事情,并且很可能测试出来的结果与实际结果存在很大的差距,这样就需

基于SSM框架下的JAVA客户关系管理系统

每天记录学习,每天会有好心情.*^_^* 今天和一个朋友共同完成了一个客户关系管理系统项目,我们在开发时选用的框架是SSM(MYECLIPSE)框架.我这个朋友知识有限,只会这个框架,哈哈,都是为了方便他.和往常一样选用简单又便捷的MYECLIPSE作为开发工具,这是一个 后台项目.这个系统的介绍是这样的:进行客户关系管理能充分利用顾客资源,通过客户交流.建立客户档案和与客户合作等,可以从中获得大量针对性强.内容具体.有价值的市场信息,包括有关产品特性和性能.销售渠道.需求变动.潜在用户等,可以

crm客户关系管理系统大约多少钱?

随着CRM在企业中的应用普遍化,不少人相信对CRM系统并不陌生,但是更多人关注的还是CRM客户关系管理系统价格如何. 其实CRM价格并不是固定的,毕竟市面上CRM系统种类众多,种类不同,价格不一样,功能不同,价格也不一样,所以CRM客户关系管理系统价格是由多方面因素影响的. 其实不同的CRM都有不同的价格,况且现在很多CRM都分模块或分版本销售,所以会出现不同的需求不同的价格.当然了选择CRM不仅仅要看价格,而且要看这套CRM是否符合自己公司的具体需求.可以尝试多去试用,多去对比,找出适合自己企

最好用的CRM客户关系管理系统

佳网CRM客户关系管理系统我们致力于解决企业客户管理,提高企业的办事效率,为企业提供一站式服务化繁为简: 统一管理,不再分散 解决客户资料分散于业务员个人的问题,现在每个人一个帐号,客户资料统一管理 权限设置细化明确 不同部门设置不同的菜单权限,不同的员工级别设置不同的操作权限 精准定位,多条件查找 根据级别.合同状态.所属业务员.跟单状态等不同条件快速查找客户资料 客户资料随身而行 移动端全功能支持,随时随地看客户.跟单.订单.合同资料 实时消息提醒 第一时间通知与您相关的新消息,即刻加入企业

CRM客户关系管理系统-需求概设和详设

大概设计 大概设计就是对需求进行一个整体性分析,把需要实现的功能都列出来,对于客户关系管理系统,我们需要从角色出发,从而确定有哪些需求,最好是画个思维导图 首先我们是为培训学校这么一个场景来开发的,所以有:学生,讲师,销售,老板这么四个角色,那接下来,我们就要对这几个角色需要实现哪些功能逐一分析了 第一个,学生,1.交作业 2.查成绩 3.请假 4.合同 5.我的推荐 6.投诉建议 第二个,讲师, 1.上课点名 2.批作业 3.创建上课记录 4.查看班级成绩 5.课时申报 6.问卷调查 第三个,