好用的客户管理系统软件(免费的客户关系管理系统)

本文为大家介绍好用的客户管理系统软件(免费的客户关系管理系统),下面和小编一起看看详细内容吧。
客户关系管理系统的服务介绍?
客户关系管理系统以客户为中心,帮助企业全面提升客户关系,围绕客户开展销售、营销、服务的信息化管理。 (以上内容仅适用于广东联通用户)
哪个客户管理系统好用
客户关系管理的作用可以归纳为营销中的客户关系管理、销售过程中的客户关系管理和客户服务过程中的客户关系管理三个方面,以下简称营销、销售、客户服务。
营销
在营销过程中,客户关系管理系统可以有效帮助市场人员分析现有的目标客户群,比如主要客户群集中在哪个行业、哪个职业、哪个年龄段、哪个地区等,从而以帮助市场人员准确的进行市场投放。客户关系管理还有效地分析了每项营销活动的投入产出比,并根据营销活动相关的收款记录和举办营销活动的报销单据,计算出所有营销活动的效果报告。
销售管理
销售是客户关系管理系统的主要组成部分,主要包括潜在客户、客户、联系人、商机、订单、付款回执、报表统计等模块。销售人员通过记录沟通内容、建立排班、查询预约提醒、快速浏览客户资料等功能,有效缩短工作时间,并具备大规模业务提醒、销售漏斗分析、绩效指标统计、业务统计等功能。阶段划分可以有效帮助管理者提高整个公司的订货率,缩短销售周期,从而实现利润最大化的业务增长。
客户服务
客户服务主要用于快速、及时地获取问题客户信息、客户历史问题记录等,从而有针对性、高效地为客户解决问题,提高客户满意度,提升企业形象。主要功能包括客户反馈、解决方案、满意度调查等功能。客户反馈应用中的自动升级功能,让管理者第一时间获取未解决的客户诉求。解决方案功能可以让公司所有员工第一时间提交给客户最满意的答复,满意度调查功能也可以让高层管理人员了解公司客户服务的真实水平。一些客户关系管理软件还集成了呼叫中心系统,可以缩短客服人员的响应时间,对提高客户服务水平起到很好的作用。
unix课程设计 基于linux内核的防火墙的分析与设计
1.什么是状态机
有限状态机是用于模拟对象行为的工具。它的主要功能是描述对象在其生命周期中所经历的状态序列,以及如何响应来自外界的各种事件。在面向对象的软件系统中,一个对象无论多么简单或复杂,都不可避免地要经历一个从创建到最终消亡的完整过程,通常称为对象的生命周期。一般来说,一个对象在其生命周期内是不可能完全孤立的。它必须通过发送消息来影响其他对象,或者通过接收消息来改变自己。在大多数情况下,这些消息只不过是简单的同步方法调用。例如,在银行客户管理系统中,客户类(customer)的实例可能会在需要时调用账户(account)类中定义的getbalance()方法。在这个简单的例子中,类customer 不需要有限状态机来描述它的行为,主要是因为它当前的行为不依赖于过去的某个状态。
不幸的是,并非所有情况都如此简单。事实上,很多实用的软件系统都必须维护一两个非常关键的对象。回复。例如,在voip 电话系统中,telephone 类的实例必须能够响应来自另一方的随机呼叫、来自用户的按键事件以及来自网络的信号。在处理这些消息时,telephone 类的行为完全取决于它当前的状态,因此此时使用状态机将是一个不错的选择。
游戏引擎是有限状态机最成功的应用领域之一。由于设计良好的状态机可以用来代替部分人工智能算法,因此游戏中的每个角色或设备都可能嵌入了状态机。考虑一个简单的对象,例如rpg 游戏中的城门,它有四种状态:opened、closed、locked 和unlocked,如图1 所示。当玩家到达状态为locked 的门时,如果他发现这个时候用钥匙开门,那么他就可以用它把门的当前状态变成unlocked,再转动门上的把手,把门的状态变成opened,就可以顺利进城了。
图1 控制城门的状态机
在描述有限状态机时,状态、事件、转移和动作是经常遇到的几个基本概念。
状态(state)是指对象在其生命周期中的一种状态。处于特定状态的对象必须满足特定条件、执行特定操作或等待特定事件。 '
事件(event)是指那些在时间和空间上占据一定位置,对状态机有意义的事物。事件通常会引起状态转换,促使状态机从一种状态切换到另一种状态。
transition是指两种状态之间的一种关系,表示对象在第一种状态下会执行某种动作,当事件发生并满足某种条件时会进入第二种状态。
动作(action)是指那些可以在状态机中执行的原子操作。所谓原子操作,就是在运行过程中不能被其他消息打断,必须连续执行。
2.手动写状态机
不同于其他常用的设计模式,编程
序员想要在自己的软件系统中加入状态机时,必须再额外编写一部分用于逻辑控制的代码,如果系统足够复杂的话,这部分代码实现和维护起来还是相当困难的。在实现有限状态机时,使用switch语句是最简单也是最直接的一种方式,其基本思路是为状态机中的每一种状态都设置一个case分支,专门用于对该状态进行控制。下面的代码示范了如何运用switch语句,来实现图1中所示的状态机:
switch (state) {
// 处理状态opened的分支
case (opened): {
// 执行动作open
open();
// 检查是否有closedoor事件
if (closedoor()) {
// 当前状态转换为closed
changestate(closed)
}
break;
}
// 处理状态closed的分支
case (closed): {
// 执行动作close
close();
// 检查是否有opendoor事件
if (opendoor()) {
// 当前状态转换为opened
changestate(opened);
}
// 检查是否有lockdoor事件
if (lockdoor()) {
// 当前状态转换为locked
changestate(locked);
}
break;
}
// 处理状态locked的分支
case (locked): {
// 执行动作lock
lock();
// 检查是否有unlockdoor事件
if (unlockdoor()) {
// 当前状态转换为unlocked
changestate(unlocked);
}
break;
}
// 处理状态unlocked的分支
case (unlocked): {
// 执行动作unlock
unlock();
// 检查是否有lockdoor事件
if (lockdoor()) {
// 当前状态转换为locked
changestate(locked)
}
// 检查是否有opendoor事件
if (opendoor()) {
// 当前状态转换为opened
changesate(opened);
}
break;
}
}
使用switch语句实现的有限状态机的确能够很好地工作,但代码的可读性并不十分理想,主要原因是在实现状态之间的转换时,检查转换条件和进行状态转换都是混杂在当前状态中来完成的。例如,当城门处于opened状态时,需要在相应的case中调用closedoor()函数来检查是否有必要进行状态转换,如果是的话则还需要调用changestate()函数将当前状态切换到closed。显然,如果在每种状态下都需要分别检查多个不同的转换条件,并且需要根据检查结果让状态机切换到不同的状态,那么这样的代码将是枯燥而难懂的。从代码重构的角度来讲,此时更好的做法是引入checkstatechange()和performstatechange()两个函数,专门用来对转换条件进行检查,以及激活转换时所需要执行的各种动作。这样一来,程序结构将变得更加清晰:
switch (state) {
// 处理状态opened的分支
case (opened): {
// 执行动作open
open();
// 检查是否有激发状态转换的事件产生
if (checkstatechange()) {
// 对状态机的状态进行转换
performstatechange();
}
break;
}
// 处理状态closed的分支
case (closed): {
// 执行动作close
close();
// 检查是否有激发状态转换的事件产生
if (checkstatechange()) {
// 对状态机的状态进行转换
performstatechange();
}
break;
}
// 处理状态locked的分支
case (locked): {
// 执行动作lock
lock();
// 检查是否有激发状态转换的事件产生
if (checkstatechange()) {
// 对状态机的状态进行转换
performstatechange();
}
break;
}
// 处理状态unlocked的分支
case (unlocked): {
// 执行动作lock
unlock();
// 检查是否有激发状态转换的事件产生
if (checkstatechange()) {
// 对状态机的状态进行转换
performstatechange();
}
break;
}
}
但checkstatechange()和performstatechange()这两个函数本身依然会在面对很复杂的状态机时,内部逻辑变得异常臃肿,甚至可能是难以实现。
在很长一段时期内,使用switch语句一直是实现有限状态机的唯一方法,甚至像编译器这样复杂的软件系统,大部分也都直接采用这种实现方式。但之后随着状态机应用的逐渐深入,构造出来的状态机越来越复杂,这种方法也开始面临各种严峻的考验,其中最令人头痛的是如果状态机中的状态非常多,或者状态之间的转换关系异常复杂,那么简单地使用switch语句构造出来的状态机将是不可维护的。
三、自动生成状态机
为实用的软件系统编写状态机并不是一件十分轻松的事情,特别是当状态机本身比较复杂的时候尤其如此,许多有过类似经历的程序员往往将其形容为毫无创意的过程,因为他们需要将大量的时间与精力倾注在如何管理好状态机中的各种状态上,而不是程序本身的运行逻辑。作为一种通用的软件设计模式,各种软件系统的状态机之间肯定会或多或少地存在着一些共性,因此人们开始尝试开发一些工具来自动生成有限状态机的框架代码,而在linux下就有一个挺不错的选择——fsme(finite state machine editor)。
图2 可视化的fsme
fsme是一个基于qt的有限状态机工具,它能够让用户通过图形化的方式来对程序中所需要的状态机进行建模,并且还能够自动生成用c 或者python实现的状态机框架代码。下面就以图1中城门的状态机为例,来介绍如何利用fsme来自动生成程序中所需要的状态机代码。
3.1状态机建模
首先运行fsme命令来启动状态机编辑器,然后单击工具栏上 new按钮来创建一个新的状态机。fsme中用于构建状态机的基本元素一共有五种:事件(event)、输入(input)、输出(output)、状态(state)和转换(transition),在界面左边的树形列表中可以找到其中的四种。
状态建模
在fsme界面左边的树形列表中选择states项,然后按下键盘上的insert键来插入一个新的状态,接着在右下方的name文本框中输入状态的名称,再在右上方的绘图区域单击该状态所要放置的位置,一个新的状态就创建好了。用同样的办法可以添加状态机所需要的所有状态,如图3所示。
图3 状态建模
事件建模
在fsme界面左边的树形列表中选 events项,然后按下键盘上的insert键来添加一个新的事件,接着在右下方的name文本框中输入事件的名称,再单击apply按钮,一个新的事件就创建好了。用同样的办法可以添加状态机所需要的所有事件,如图4所示。
图4 事件建模
转换建模
状态转换是整个建模过程中最重要的一个部分,它用来定义有限状态机中的一个状态是如何切换到另一个状态的。例如,当用来控制城门的状态机处于opened状态时,如果此时有close事件产生,那么状态机的当前状态将切换到closed状态,这样一个完整的过程在状态机模型中可以用closedoor这样一个转换来进行描述。
要在fsme中添加这样一个转换,首先需要在界面左边的树形列表中选 states下的opened项,然后按下键盘上的insert键来添加一个新的转换,接着在右下角的name文本框中输入转换的名字closedoor,在condition文本框中输入close表明触发该转换的条件是事件close的产生,在target下拉框中选择closed项表明该转换发生后状态机将被切换到closed状态,最后再单击apply按钮,一个新的状态转换关系就定义好了,如图5所示。用同样的办法可以添加状态机所需要的所有转换。
图5 转换建模
3.2 生成状态机框架
使用fsme不仅能够进行可视化的状态机建模,更重要的是它还可以根据得到的模型自动生成用c 或者python实现的状态机框架。首先在fsme界面左边的树形列表中选择root项,然后在右下角的name文本框中输入状态机的名字doorfsm,再从initial state下拉列表中选择状态opened作为状态机的初始化状态,如图6所示。
图6 设置初始属性
在将状态机模型保存为door.fsm文件之后,使用下面的命令可以生成包含有状态机定义的头文件:
$ fsmc door.fsm -d -o doorfsm.
进一步还可以生成包含有状态机实现的框架代码:
$ fsmc door.fsm -d -impl doorfsm.h -o doorfsm.cpp
如果想对生成的状态机进行验证,只需要再手工编写一段用于测试的代码就可以了:
/*
* testfsm.cpp
* 测试生成的状态机框架
*/
#include doorfsm.h
int main()
{
doorfsm door;
door.a(doorfsm::close);
door.a(doorfsm::lock);
door.a(doorfsm::unlock);
door.a(doorfsm::open);
}
有限状态机是由事件来进行驱动的,在fsme生成的状态机框架代码中,方法a()可以被用来向状态机发送相应的事件,从而提供状态机正常运转所需要的动力。状态机负责在其内部维护一个事件队列,所有到达的事件都会先被放到事件队列中进行等候,从而能够保证它们将按照到达的先后顺序被依次处理。在处理每一个到达的事件时,状态机都会根据自己当前所处的状态,检查与该状态对应的转换条件是否已经被满足,如果满足的话则激活相应的状态转换过程。
使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:
$ g doorfsm.cpp testfsm.cpp -o fsm
由于之前在用fsmc命令生成状态机代码时使用了-d选项,生成的状态机框架中会包含一定的调试信息,包括状态机中每次状态转换时的激活事件、转换前的状态、所经历的转换、转换后的状态等,如下所示:
$ ./fsm
doorfsm:event:'close'
doorfsm:state:'opened'
doorfsm:transition:'closedoor'
doorfsm:new state:'closed'
doorfsm:event:'lock'
doorfsm:state:'closed'
doorfsm:transition:'lockdoor'
doorfsm:new state:'locked'
doorfsm:event:'unlock'
doorfsm:state:'locked'
doorfsm:transition:'unlockdoor'
doorfsm:new state:'unlocked'
doorfsm:event:'open'
doorfsm:state:'unlocked'
doorfsm:transition:'opendoor'
doorfsm:new state:'opened'
3.3 定制状态机
目前得到的状态机已经能够响应来自外部的各种事件,并适当地调整自己当前所处的状态,也就是说已经实现了状态机引擎的功能,接下来要做的就是根据应用的具体需求来进行定制,为状态机加入与软件系统本身相关的那些处理逻辑。在fsme中,与具体应用相关的操作称为输出(output),它们实际上就是一些需要用户给出具体实现的虚函数,自动生成的状态机引擎负责在进入或者退出某个状态时调用它们。
仍然以控制城门的那个状态机为例,假设我们希望在进入每个状态时都添加一部分处理逻辑。首在fsme界面左边的树形列表选择outputs项,然后按下键盘上的insert键来添加一个新的输出,接着在右下方的name文本框中输入相应的名称,再单击apply按钮,一个新的输出就创建好了,如图7所示。用同样的办法可以添加状态机所需要的所有输出。
图7 添加输出
当所有的输出都定义好之后,接下来就可以为状态机中的每个状态绑定相应的输出。首先在fsme界面左侧的states项中选择相应的状态,然后从右下角的available列表框中选择与该状态对应的输出,再单击按钮将其添加到in列表中,如图8所示。用同样的办法可以为状态机中的所有状态设置相应的输出,同一个状态可以对应有多个输出,其中in列表中的输出会在进入该状态时被调用,而out列表中的输出则会在退出该状态时被调用,输出调用的顺序是与其在in或者out列表中的顺序相一致的。
图8 为状态设置输出
由于对状态机模型进行了修改,我们需要再次生成状态机的框架代码,不过这次不需要加上-d参数:
$ fsmc door.fsm -o doorfsm.h
$ fsmc door.fsm -d -impl doorfsm.h -o doorfsm.cpp
我们在新的状态机模型中添加了enteropend、enterclosed、enterlocked和enterunlocked四个输出,因此生成的类doorfsm中会包含如下几个纯虚函数
virtual void enteropened() = 0;
virtual void enterlocked() = 0;
virtual void enterunlocked() = 0;
virtual void enterclosed() = 0;
显然,此时生成的状态机框架不能够再被直接编译了,我们必须从类doorfsm派生出一个子类,并提供对这几个纯虚函数的具体实现:
/*
* doorfsmlogic.h
* 状态机控制逻辑的头文件
*/
#include doorfsm.h
class doorfsmlogic : public doorfsm
{
protected:
virtual void enteropened();
virtual void enterlocked();
virtual void enterunlocked();
virtual void enterclosed();
};
正如前面所提到过的,这几个函数实际上代表的正是应用系统的处理逻辑,作为例子我们只是简单地输出一些提示信息:
/*
* doorfsmlogic.cpp
* 状态机控制逻辑的实现文件
*/
#include doorfsmlogic.h
#include iostream
void doorfsmlogic::enteropened()
{
std::cout enter opened state. std::endl;
}
void doorfsmlogic::enterclosed()
{
std::cout enter closed state. std::endl;
}
void doorfsmlogic::enterlocked()
{
std::cout enter locked state. std::endl;
}
void doorfsmlogic::enterunlocked()
{
std::cout enter unlocked state. std::endl;
}
同样,为了对生成的状态机进行验证,我们还需要手工编写一段测试代码:
/*
* testfsm.cpp
* 测试状态机逻辑
*/
#include doorfsmlogic.h
int main()
{
doorfsmlogic door;
door.a(doorfsm::close);
door.a(doorfsm::lock);
door.a(doorfsm::unlock);
door.a(doorfsm::open);
}
使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:
$ g doorfsm.cpp doorfsmlogic.cpp testlogic.cpp -o logic
运行结果如下所示:
$ ./logic
enter closed state.
enter locked state.
enter unlocked state.
enter opened state.
四、小结
在面向对象的软件系统中,有些对象具有非常复杂的生命周期模型,使用有限状态机是描述这类对象最好的方法。作为一种软件设计模式,有限状态机的概念虽然不算复杂,实现起来也并不困难,但它的问题是当状态机的模型复杂到一定的程度之后,会带来实现和维护上的困难。linux下的fsme是一个可视化的有限状态机建模工具,而且支持状态机框架代码的自动生成,借助它可以更加轻松地构建基于有限状态机的应用系统。
192.168.2.1路由器设置密码? 路由器中有两个密码一个是无线密码一个是登录密码,分别介绍各自的设置或者更改方法:
一、设置路由器登录口令
1、路由器和电脑连接,打开浏览器,在地址栏输入192.168.1.1(一般路由器地址是这个或者查看路由器背面的登录信息)进路由-输入用户名,密码 ,(默认一般是admin)。
2、更改登录口令的选项一般在系统工具里面
3、在新的页面中,填入要更改的用户名和用户密码。前提是知道正确的原始用户名和原始用户密码。修改完毕后,保存即可。
二、设置或者修改无线连接密码
1、路由器和电脑连接,打开浏览器,在地址栏输入192.168.1.1(一般路由器地址是这个或者查看路由器背面的登录信息)进路由-输入用户名,密码 ,(默认一般是admin)。
2、进入后台后选择无线设置,然后选择无线安全设置,就可以设置或者更改无线密码了,如图:
好了,好用的客户管理系统软件(免费的客户关系管理系统)的介绍到这里就结束了,想知道更多相关资料可以收藏我们的网站。