1.需求分析
客户是公司最宝贵的资源,为了更好的发掘老客户的价值,并开发更多新客户,公司实施客户关系管理系统。系统的功能是:通过这个系统完成对员工基本信息、客户基本信息、交往信息、客户服务信息的充分共享和规范化管理;通过对销售机会、客户开发过程的追踪和记录,提高新客户的开发能力;在客户将要流失时系统及时预警,以便销售人员及时采取措施,降低损失。
客户服务水平的高低决定着公司的核心竞争力。该客户关系管理系统提供一个客户服务在线平台,使客户服务处理过程中的相关人员可以在线完成服务的处理和记录工作。
1.1 功能需求分析
功能需求分析目的是为了对每一个模块和模块内每一个小的功能点进行规划和设计,为之后的开发打好信息基础做好准备。根据对收集的用户问询馈意见,需要对系统的前端和后台进行总体布局设计。
本客户关系管理系统,旨在为所有用户提供如下功能:
(1)需要对企业信息进行统一管理,以提升公司的管理规范,对人员信息管理更加规范;
(2)当企业用户发掘下新客户时,需要将客户录入系统并将客户联系人进行管理,方便后续跟踪拜访客户;
(3)当企业员工对客户进行拜访后,需将拜访信息录入系统,方便管理自己对客户的跟踪情况;也方便系统提示自己下次拜访客户时间,根据每次拜访记录可分析客户的目前状态等;
(4)根据系统现有数据呈现可视化统计图,图文并茂呈现出结果,使管理者可清晰看到自己感兴趣的数据。
1.2 用户需求分析
CRM系统是指利用信息化手段将客户、拜访记录等做一个管理,从而提升工作效率、业绩及其公司管理水平。因此,开发客户关系管理系统,首先需要明确现阶段整个系统需要实现的功能。本系统主要是企业用户进行使用。
用户登录后,可以进行客户管理、联系人管理、拜访客户、统计查看操作。
(1)用户登录
用户输入正确的用户名、密码的用户才能登陆成功并自动取得获得授予的对应访问权限,退出登录应移出用户状态。
(2)用户功能
·客户管理
对客户信息进行进行增、删、改、查操作。
·联系人管理
对联系人进行增、删、改、查操作。
·拜访跟踪
对已录入客户进行拜访跟踪信息记录、查询。
·统计
按照来源、行业等对信息进行可视化统计展示。
2.E-R图与关系模式设计
2.1 E-R图
2.1.1 实体分析描述
从用户角度来说,数据库的需求主要体现在对数据库表的增删改查。因此,数据库结构需同时满足两个要素:输入、输出。在进行数据设计时,首先需收集数据,然后分析数据结构,最后处理数据。根据本系统的需求,设计以下主要的数据项和数据结构:
(1)用户实体:用户id、用户账号、用户名称、用户密码、用户状态。
(2)联系人实体:联系人编号、联系人姓名、客户id、联系人性别、联系人办公电话、联系人手机、联系人邮箱、联系人qq、联系人职位、联系人备注。
(3)客户实体:客户编号、客户名称(公司名称)、客户信息来源、客户所属行业、客户级别、固定电话、移动电话。
(4)客户详情实体:客户编号、客户地区、客户邮政编码、客户联系地址、客户传真、客户网址、客户营业执照注册号、企业法人、客户注册资金、开户银行及账号、客户资质图片、客户简介。
(5)数据字典实体:数据字典id、数据字典类别代码、数据字典类别名称、数据字典项目名称、数据字典项目、排序字段、状态、备注。
2.1.2 实体E-R图
用户实体如图1.1所示。
图1.1 用户实体
联系人实体如图1.2所示。
图1.2 联系人实体
客户实体如图1.3所示。
图1.3 客户实体
客户详情实体如图1.4所示。
图1.4 客户详情实体
2.1.3 整体E-R图
图1.5 整体E-R图
2.2关系模式
关系模式:用户信息(用户id、用户账号、用户名称、用户密码、用户状态)
模式判定:用户信息∈2NF,且每个非主属性都不传递函数依赖于员工信息的主关系键,所以用户信息∈3NF
关系模式:联系人信息(联系人编号、联系人姓名、客户id、联系人性别、联系人办公电话、联系人手机、联系人邮箱、联系人qq、联系人职位、联系人备注)
模式判定:联系人信息∈2NF,且每个非主属性都不传递函数依赖于部门信息的主关系键,所以联系人信息∈3NF
关系模式:客户信息(客户编号、客户名称(公司名称)、客户信息来源、客户所属行业、客户级别、固定电话、移动电话)
模式判定:客户信息∈2NF,且每个非主属性都不传递函数依赖于工资信息的主关系键,所以客户信息∈3NF
关系模式:客户详情信息(客户编号、客户地区、客户邮政编码、客户联系地址、客户传真、客户网址、客户营业执照注册号、企业法人、客户注册资金、开户银行及账号、客户资质图片、客户简介)
模式判定:客户详情信息∈2NF,且每个非主属性都不传递函数依赖于考勤信息的主关系键,所以客户详情信息∈3NF
关系模式:数据字典信息(数据字典id、数据字典类别代码、数据字典类别名称、数据字典项目名称、数据字典项目、排序字段、状态、备注)
模式判定:数据字典信息∈2NF,且每个非主属性都不传递函数依赖于津贴信息的主关系键,所以数据字典信息∈3NF
关系模式:客户拜访信息(客户拜访id、客户id、用户id、拜访时间、拜访地址、拜访详情、下次拜访时间)
模式判定:客户拜访信息∈2NF,且每个非主属性都不传递函数依赖于津贴信息的主关系键,所以数据字典信息∈3NF
2.3 数据库表结构
表2.1 用户表sys_user
属性名 | 字段名 | 数据类型 | 长度 | 是否允许为空 | 是否主键 |
用户id | user_id | bigint | 0 | 不允许 | 是 |
用户账号 | user_code | varchar | 32 | 允许 | 否 |
用户名称 | user_name | varchar | 64 | 允许 | 否 |
用户密码 | user_password | varchar | 32 | 允许 | 否 |
用户状态 | user_state | varchar | 2 | 允许 | 否 |
表2.2 联系人表cst_linkman
属性名 | 字段名 | 数据类型 | 长度 | 是否允许为空 | 是否主键 |
联系人编号 | lkm_id | int | 0 | 不允许 | 是 |
联系人姓名 | lkm_name | varchar | 16 | 允许 | 否 |
客户id | lkm_cust_id | bigint | 16 | 允许 | 否 |
联系人性别 | lkm_gender | varchar | 0 | 允许 | 否 |
联系人办公电话 | lkm_phone | varchar | 16 | 允许 | 否 |
联系人手机 | lkm_mobile | varchar | 16 | 允许 | 否 |
联系人邮箱 | lkm_email | varchar | 16 | 允许 | 否 |
联系人qq | lkm_qq | varchar | 16 | 允许 | 否 |
联系人职位 | lkm_position | varchar | 16 | 允许 | 否 |
联系人备注 | lkm_memo | varchar | 512 | 允许 | 否 |
表2.3 客户表cst_customer
属性名 | 字段名 | 数据类型 | 长度 | 是否允许为空 | 是否主键 |
客户编号 | cust_id | int | 0 | 不允许 | 是 |
客户名称(公司名称) | cust_name | varchar | 32 | 允许 | 否 |
客户信息来源 | cust_source | varchar | 32 | 允许 | 否 |
客户所属行业 | cust_industry | varchar | 32 | 允许 | 否 |
客户级别 | cust_level | varchar | 32 | 允许 | 否 |
固定电话 | cust_phone | varchar | 32 | 允许 | 否 |
移动电话 | cust_mobile | varchar | 32 | 允许 | 否 |
表2.4 客户详情表cst_customer_detail
属性名 | 字段名 | 数据类型 | 长度 | 是否允许为空 | 是否主键 |
客户编号 | cust_id | int | 0 | 不允许 | 是 |
客户地区 | cust_region | varchar | 64 | 允许 | 否 |
客户邮政编码 | cust_zip | varchar | 16 | 允许 | 否 |
客户联系地址 | cust_address | varchar | 128 | 允许 | 否 |
客户传真 | cust_fax | varchar | 64 | 允许 | 否 |
客户网址 | cust_website | varchar | 128 | 允许 | 否 |
客户营业执照注册号 | cust_licence | varchar | 64 | 允许 | 否 |
企业法人 | cust_corporation | varchar | 64 | 允许 | 否 |
客户注册资金 | cust_capital | bigint | 0 | 允许 | 否 |
开户银行及账号 | cust_bank | varchar | 20 | 允许 | 否 |
客户资质图片 | cust_pic | varchar | 64 | 允许 | 否 |
客户简介 | cust_memo | longtext | 0 | 允许 | 否 |
表2.5 基础数据字典表base_dict
属性名 | 字段名 | 数据类型 | 长度 | 是否允许为空 | 是否主键 |
数据字典id | dict_id | int | 0 | 不允许 | 是 |
数据字典类别代码 | dict_type_code | varchar | 32 | 允许 | 否 |
数据字典类别名称 | dict_type_name | varchar | 10 | 允许 | 否 |
数据字典项目名称 | dict_item_name | varchar | 64 | 允许 | 否 |
数据字典项目 | dict_item_code | varchar | 64 | 允许 | 否 |
排序字段 | dict_sort | varchar | 10 | 允许 | 否 |
状态 | dict_enable | varchar | 1 | 允许 | 否 |
备注 | dict_memo | varchar | 64 | 允许 | 否 |
表2.6 客户拜访表sale_visit
属性名 | 字段名 | 数据类型 | 长度 | 是否允许为空 | 是否主键 |
客户拜访id | visit_id | int | 0 | 不允许 | 是 |
客户id | visit_cust_id | bigint | 0 | 允许 | 否 |
用户id | visit_user_id | bigint | 0 | 允许 | 否 |
拜访时间 | visit_time | date | 0 | 允许 | 否 |
拜访地址 | visit_addr | varchar | 128 | 允许 | 否 |
拜访详情 | visit_detail | varchar | 256 | 允许 | 否 |
下次拜访时间 | visit_nexttime | date | 0 | 允许 | 否 |
3.实现效果
(1)登录
(2) 系统主界面
(3)新增客户
(4)客户列表
(5)新增联系人
(6)联系人列表
(7) 新增客户拜访
(8)客户拜访列表
4.数据库核心
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for base_dict
-- ----------------------------
DROP TABLE IF EXISTS `base_dict`;
CREATE TABLE `base_dict` (
`dict_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '数据字典id(主键)',
`dict_type_code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '数据字典类别代码',
`dict_type_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '数据字典类别名称',
`dict_item_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '数据字典项目名称',
`dict_item_code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据字典项目(可为空)',
`dict_sort` int(10) NULL DEFAULT NULL COMMENT '排序字段',
`dict_enable` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '1:使用 0:停用',
`dict_memo` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`dict_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of base_dict
-- ----------------------------
INSERT INTO `base_dict` VALUES ('1', '001', '客户行业', '教育培训 ', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('10', '003', '公司性质', '民企', NULL, 3, '1', NULL);
INSERT INTO `base_dict` VALUES ('12', '004', '年营业额', '1-10万', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('13', '004', '年营业额', '10-20万', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('14', '004', '年营业额', '20-50万', NULL, 3, '1', NULL);
INSERT INTO `base_dict` VALUES ('15', '004', '年营业额', '50-100万', NULL, 4, '1', NULL);
INSERT INTO `base_dict` VALUES ('16', '004', '年营业额', '100-500万', NULL, 5, '1', NULL);
INSERT INTO `base_dict` VALUES ('17', '004', '年营业额', '500-1000万', NULL, 6, '1', NULL);
INSERT INTO `base_dict` VALUES ('18', '005', '客户状态', '基础客户', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('19', '005', '客户状态', '潜在客户', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('2', '001', '客户行业', '电子商务', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('20', '005', '客户状态', '成功客户', NULL, 3, '1', NULL);
INSERT INTO `base_dict` VALUES ('21', '005', '客户状态', '无效客户', NULL, 4, '1', NULL);
INSERT INTO `base_dict` VALUES ('22', '006', '客户级别', '普通客户', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('23', '006', '客户级别', 'VIP客户', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('24', '007', '商机状态', '意向客户', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('25', '007', '商机状态', '初步沟通', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('26', '007', '商机状态', '深度沟通', NULL, 3, '1', NULL);
INSERT INTO `base_dict` VALUES ('27', '007', '商机状态', '签订合同', NULL, 4, '1', NULL);
INSERT INTO `base_dict` VALUES ('3', '001', '客户行业', '对外贸易', NULL, 3, '1', NULL);
INSERT INTO `base_dict` VALUES ('30', '008', '商机类型', '新业务', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('31', '008', '商机类型', '现有业务', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('32', '009', '商机来源', '电话营销', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('33', '009', '商机来源', '网络营销', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('34', '009', '商机来源', '推广活动', NULL, 3, '1', NULL);
INSERT INTO `base_dict` VALUES ('4', '001', '客户行业', '酒店旅游', NULL, 4, '1', NULL);
INSERT INTO `base_dict` VALUES ('5', '001', '客户行业', '房地产', NULL, 5, '1', NULL);
INSERT INTO `base_dict` VALUES ('6', '002', '客户信息来源', '电话营销', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('7', '002', '客户信息来源', '网络营销', NULL, 2, '1', NULL);
INSERT INTO `base_dict` VALUES ('8', '003', '公司性质', '合资', NULL, 1, '1', NULL);
INSERT INTO `base_dict` VALUES ('9', '003', '公司性质', '国企', NULL, 2, '1', NULL);
SET FOREIGN_KEY_CHECKS = 1;
5.核心代码
public class BaseDao {
//驱动
private static String driver = "com.mysql.jdbc.Driver";
//url
private static String url = "jdbc:mysql://localhost:3306/crm?characterEncoding=utf-8";
//用户名
private static String username = "root";
//密码
private static String pwd = "root";
/**
* 创建连接
* @return
*/
public static Connection getConnection(){
Connection connection=null;
//加载驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//建立连接获取Connection对象
try {
connection= DriverManager.getConnection(url,username,pwd);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* 关闭链接
* @param connection
* @param statement
* @param resultSet
*/
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){
try {
if(resultSet!=null){
resultSet.close();
}
if(statement!=null){
statement.close();
}
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 执行增、删、改的方法
* @param sql
* @return
*/
public static int execute(String sql){
//获取链接
Connection connection=getConnection();
int flag=0;
try {
//创建Statement对象
Statement statement=connection.createStatement();
//执行sql语句
flag=statement.executeUpdate(sql);
//关闭链接
closeAll(connection,statement,null);
} catch (SQLException e) {
e.printStackTrace();
}
return flag;
}
/*
测试
*/
public static void main(String[] args) {
String sql = "SELECT * FROM `cm_cst`.`base_dict` WHERE dict_id = 1";
Connection connection = getConnection();
Statement statement = null;
try {
statement= connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
String typename = resultSet.getString(3);
System.out.println("类别名称"+typename);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}