Crm-客户管理
客户管理表结构设计
客户信息管理模块表结构
这里主要涉及表:
t_customer 客户表、t_customer_contact 客户交往记录表、t_customer_linkman 客户联系人表、t_customer_order 客户订单表、t_order_details 订单详情表
t_customer | 客户信息表 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
khno | varchar(20) | 可空 | 客户编号 | |
name | varchar(20) | 可空 | 客户姓名 | |
area | varchar(20) | 可空 | 客户所属地区 | |
cus_manager | varchar(20) | 可空 | 客户经理 | |
level | varchar(30) | 可空 | 客户级别 | |
myd | varchar(30) | 可空 | 客户满意度 | |
xyd | varchar(30) | 可空 | 客户信用度 | |
address | varchar(500) | 可空 | 客户地址 | |
post_code | varchar(50) | 可空 | 邮编 | |
phone | varchar(20) | 可空 | 联系电话 | |
fax | varchar(20) | 可空 | 传真 | |
web_site | varchar(20) | 可空 | 网址 | |
yyzzzch | varchar(50) | 可空 | 营业执照注册号 | |
fr | varchar(20) | 可空 | 法人代表 | |
zczj | varchar(20) | 可空 | 注册资金 | |
nyye | varchar(20) | 可空 | 年营业额 | |
khyh | varchar(50) | 可空 | 开户银行 | |
khzh | varchar(50) | 可空 | 开户账号 | |
dsdjh | varchar(50) | 可空 | 地税登记号 | |
gsdjh | varchar(50) | 可空 | 国税登记号 | |
state | int(11) | 可空 | 流失状态 | |
is_valid | int(4) | 可空 | 有效状态 | |
create_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 |
t_customer_contact | 客户交往记录表 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
cus_id | int(11) | 可空 | 客户id | |
contact_time | datetime | 可空 | 交往时间 | |
address | varchar(500) | 可空 | 交往地址 | |
overview | varchar(100) | 可空 | 地址 | |
create_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 | |
is_valid | int(4) | 可空 | 有效状态 |
t_customer_linkman | 客户联系人表 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
cus_id | int(11) | 可空 | 客户id | |
link_name | varchar(20) | 可空 | 联系人姓名 | |
sex | varchar(20) | 可空 | 性别 | |
zhiwei | varchar(50) | 可空 | 职位 | |
office_phone | varchar(50) | 可空 | 办公电话 | |
phone | varchar(20) | 可空 | 手机号 | |
is_valid | int(4) | 可空 | 有效状态 | |
ceate_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 |
t_customer_order | 客户订单 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
cus_id | int(11) | 可空 | 客户id | |
order_no | varchar(40) | 可空 | 订单编号 | |
order_date | datetime | 可空 | 下单时间 | |
address | varchar(200) | 可空 | 地址 | |
state | int(11) | 可空 | 状态 | |
create_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 | |
is_valid | int(4) | 可空 | 有效状态 |
t_order_details | 订单详情表 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
order_id | int(11) | 可空 | 订单id | |
goods_name | varchar(100) | 可空 | 商品名称 | |
goods_num | int(11) | 可空 | 商品数量 | |
unit | varchar(20) | 可空 | 商品单位 | |
price | float | 可空 | 单价 | |
sum | float | 可空 | 总金额 | |
is_valid | int(4) | 可空 | 有效状态 | |
create_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 |
客户流失管理模块表结构
这里主要涉及表有
t_customer_loss 客户流失表
t_customer_reprieve 客户流失暂缓表
t_customer_loss | 客户流失表 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
cus_no | varchar(40) | 可空 | 客户编号 | |
cus_name | varchar(20) | 可空 | 客户姓名 | |
cus_manager | varchar(20) | 可空 | 客户经理 | |
last_order_time | date | 可空 | 最后下单时间 | |
confirm_loss_time | date | 可空 | 确认流失时间 | |
state | int(11) | 可空 | 流失状态 | |
loss_reason | varchar(1000) | 可空 | 流失原因 | |
is_valid | tinyint(4) | 可空 | 有效状态 | |
create_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 |
t_customer_reprieve | 客户流失暂缓表 | |||
---|---|---|---|---|
字段 | 字段类型 | 字段限制 | 字段描述 | |
主键 | id | int(11) | 自增 | id主键 |
loss_id | int(11) | 可空 | 流失id | |
measure | varchar(500) | 可空 | 措施 | |
is_valid | tinyint(4) | 可空 | 有效状态 | |
create_date | datetime | 可空 | 创建时间 | |
update_date | datetime | 可空 | 更新时间 |
客户信息查询后端代码实现
layui 框架通过表格展示后端表数据,数据格式见官网测试数据地址。
CustomerMapper 接口定义与Sql配置
- CustomerMapper .java
public interface CustomerMapper extends BaseMapper {
/*
由于考虑到多个模块均涉及多条件查询
这里对于多条件分页查询方法由父接口BaseMapper定义
*/
}
- CustomerMapper .xml
- CustomerQuery.java
在crm.query 包下创建CustomerQuery.java 查询类,设置查询条件
public class CustomerQuery extends BaseQuery {
private String cusName;
private String cusNo;
private String level;
}
CustomerService 定义
- CustomerService .java
@Service
public class CustomerService extends BaseService {
/*
由于考虑到多个模块均涉及多条件查询
这里对于多条件分页查询方法由父类BaseService定义并实现
*/
}
- BaseService.java 分页查询方法定义与实现
public Map queryByParamsForTable(BaseQuery baseQuery) {
Map result = new HashMap();
PageHelper.startPage(baseQuery.getPage(),baseQuery.getLimit());
PageInfo pageInfo =new PageInfo(selectByParams(baseQuery));
result.put("count",pageInfo.getTotal());
result.put("data",pageInfo.getList());
result.put("code",0);
result.put("msg","");
return result;
}
CustomerController.java
@Controller
@RequestMapping("customer")
public class CustomerController extends BaseController {
@Resource
private CustomerService customerService;
@Resource
private CustomerOrderService orderService;
@RequestMapping("index")
public String index(){
return "customer/customer";
}
@RequestMapping("list")
@ResponseBody
public Map queryCustomersByParams(CustomerQuery customerQuery){
return customerService.queryByParamsForTable(customerQuery);
}
客户信息管理前端核心代码
客户信息管理主页面模板
resources/views/customer目录创建customer.ftl 模块文件,模板内容如下(模板依赖的layui文件由common.ftl 文件提供),layui表格数据展示模板文件实现参考该地址
- customer.ftl
客户管理
<#include "../common.ftl">
客户信息管理主页面模板核心js
static/js/customer目录下创建customer.js 文件,初始化layui表格数据,layui表格数据展示模板文件实现参考该地址
- customer.js
layui.use(['table','layer',"form"],function(){
var layer = parent.layer === undefined ? layui.layer : top.layer,
$ = layui.jquery,
table = layui.table,
form = layui.form;
//客户列表展示
var tableIns = table.render({
elem: '#customerList',
url : ctx+'/customer/list',
cellMinWidth : 95,
page : true,
height : "full-125",
limits : [10,15,20,25],
limit : 10,
toolbar: "#toolbarDemo",
id : "customerListTable",
cols : [[
{type: "checkbox", fixed:"center"},
{field: "id", title:'编号',fixed:"true"},
{field: 'name', title: '客户名',align:"center"},
{field: 'fr', title: '法人', align:'center'},
{field: 'khno', title: '客户编号', align:'center'},
{field: 'area', title: '地区', align:'center'},
{field: 'cusManager', title: '客户经理', align:'center'},
{field: 'myd', title: '满意度', align:'center'},
{field: 'level', title: '客户级别', align:'center'},
{field: 'xyd', title: '信用度', align:'center'},
{field: 'address', title: '详细地址', align:'center'},
{field: 'postCode', title: '邮编', align:'center'},
{field: 'phone', title: '电话', align:'center'},
{field: 'webSite', title: '网站', align:'center'},
{field: 'fax', title: '传真', align:'center'},
{field: 'zczj', title: '注册资金', align:'center'},
{field: 'yyzzzch', title: '营业执照', align:'center'},
{field: 'khyh', title: '开户行', align:'center'},
{field: 'khzh', title: '开户账号', align:'center'},
{field: 'gsdjh', title: '国税', align:'center'},
{field: 'dsdjh', title: '地税', align:'center'},
{field: 'createDate', title: '创建时间', align:'center'},
{field: 'updateDate', title: '更新时间', align:'center'},
{title: '操作', templet:'#customerListBar',fixed:"right",align:"center", minWidth:150}
]]
});
});
客户信息多条件查询事件添加
客户信息数据表格数据展示成功后,接下来考虑添加多条件查询点击事件,这里使用layui表格reload重载基础方法实现,点击这里参考官网介绍。
- customer.js 添加搜索点击事件
// 多条件搜索
$(".search_btn").on("click",function(){
table.reload("customerListTable",{
page: {
curr: 1 //重新从第 1 页开始
},
where: {
cusName: $("input[name='name']").val(), //客户名
cusNo: $("input[name='khno']").val(), //客户编号
level: $("#level").val() //客户等级
}
})
});
机会数据添加实现思路
/**
* 1.参数校验
* 客户名称 name 非空 不可重复
* phone 联系电话 非空 格式符合规范
* 法人 非空
* 2.默认值设置
* isValid state cteaetDate updadteDate
* khno 系统生成 唯一 (uuid| 时间戳 | 年月日时分秒 雪花算法)
*3.执行添加 判断结果
*/
机会数据添加核心代码
@Transactional(propagation = Propagation.REQUIRED)
public void saveCustomer(Customer customer){
checkParams(customer.getName(),customer.getPhone(),customer.getFr());
AssertUtil.isTrue(null!=customerMapper.queryCustomerByName(customer.getName()),"该客户已存在!");
customer.setIsValid(1);
customer.setState(0);
customer.setCreateDate(new Date());
customer.setUpdateDate(new Date());
String khno = "KH_"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
customer.setKhno(khno);
AssertUtil.isTrue(insertSelective(customer)<1,"客户添加失败!");
}
private void checkParams(String name, String phone, String fr) {
AssertUtil.isTrue(StringUtils.isBlank(name),"请指定客户名称!");
AssertUtil.isTrue(!(PhoneUtil.isMobile(phone)),"手机号格式非法!");
AssertUtil.isTrue(StringUtils.isBlank(fr),"请指定公司法人!");
}
客户管理数据添加后端页面转发&添加方法调用
对于机会数据添加与更新表单页可以实现共享,这里在转发机会数据添加与更新页面时共用一套代码即可(考虑更新时涉及到机会数据显示操作,这里根据机会id查询机会记录并放入到请求域中)。
@RequestMapping("addOrUpdateSaleChancePage")
public String addOrUpdateSaleChancePage(Integer id,Model model){
model.addAttribute("customer",customerService.selectByPrimaryKey(id)) ;
return "customer/add_update";
}
@RequestMapping("save")
@ResponseBody
public ResultInfo saveCustomer(Customer customer){
customerService.saveCustomer(customer);
return success("客户添加成功");
}
客户管理添加前台模板与核心js
客户数据添加工具栏事件
这里对于对话框打开方法代码请参考官网页面
//头工具栏事件
table.on('toolbar(customers)', function(obj){
var checkStatus = table.checkStatus(obj.config.id);
switch(obj.event){
case "add":
openAddOrUpdateCustomerDialog();
break;
};
});
// 打开添加客户数据页面
function openAddOrUpdateCustomerDialog(id){
var url = ctx+"/customer/addOrUpdateSaleChancePage";
var title="客户管理-添加";
if(id){
url = url+"?id="+id;
title="客户管理-更新";
}
layui.layer.open({
title : title,
type : 2,
area:["700px","500px"],
maxmin:true,
content : url
});
}
add_update.ftl 表单模板文件
views/customer目录下添加add_update.ftl 表单模板
<#include "../common.ftl">
add.update.js 文件添加
js/customer目录下添加add.update.js 文件,完成机会数据添加与更新表单提交操作
layui.use(['form', 'layer'], function () {
var form = layui.form,
layer = parent.layer === undefined ? layui.layer : top.layer,
$ = layui.jquery;
form.on("submit(addOrUpdateCustomer)", function (data) {
var index = top.layer.msg('数据提交中,请稍候', {icon: 16, time: false, shade: 0.8});
//弹出loading
var url=ctx + "/customer/save";
if($("input[name='id']").val()){
url=ctx + "/customer/update";
}
$.post(url, data.field, function (res) {
if (res.code == 200) {
setTimeout(function () {
top.layer.close(index);
top.layer.msg("操作成功!");
layer.closeAll("iframe");
//刷新父页面
parent.location.reload();
}, 500);
} else {
layer.msg(
res.msg, {
icon: 5
}
);
}
});
return false;
});
});
客户信息数据更新
客户信息数据后端更新
客户信息后端更新实现思路
/**
* 1.参数校验
* 记录存在校验
* 客户名称 name 非空 不可重复
* phone 联系电话 非空 格式符合规范
* 法人 非空
* 2.默认值设置
* updadteDate
*3.执行更新 判断结果
*/
客户信息数据更新核心代码
@Transactional(propagation = Propagation.REQUIRED)
public void updateCustomer(Customer customer){ AssertUtil.isTrue(null==customer.getId()||null==selectByPrimaryKey(customer.getId()),"待更新记录不存在!");
checkParams(customer.getName(),customer.getPhone(),customer.getFr());
Customer temp =customerMapper.queryCustomerByName(customer.getName());
AssertUtil.isTrue(null !=temp && !(temp.getId().equals(customer.getId())),"该客户已存在!");
customer.setUpdateDate(new Date());
AssertUtil.isTrue(updateByPrimaryKeySelective(customer)<1,"客户更新失败!");
}
客户信息数据更新后端页面转发 & 更新方法调用
这里客户信息数据更新页面视图与添加操作实现视图代码共用。
@RequestMapping("update")
@ResponseBody
public ResultInfo updateCustomer(Customer customer){
customerService.updateCustomer(customer);
return success("客户更新成功");
}
客户信息数据前端模板与核心js
客户信息数据表格行监听事件添加
- sale.chance.js
表格添加行监听事件,行监听事件参考这里
/**
* 行监听
*/
table.on("tool(customers)", function(obj){
var layEvent = obj.event;
if(layEvent === "edit") {
openAddOrUpdateCustomerDialog(obj.data.id);
}
});
// 打开添加客户数据页面
function openAddOrUpdateCustomerDialog(id){
var url = ctx+"/customer/addOrUpdateSaleChancePage";
var title="客户管理-添加";
if(id){
url = url+"?id="+id;
title="客户管理-更新";
}
layui.layer.open({
title : title,
type : 2,
area:["700px","500px"],
maxmin:true,
content : url
});
}
客户信息管理数据删除
客户信息数据后端删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ErRpREW-1608794638358)(images\image-20200227221545509.png)]
客户信息后端删除核心代码
- CustomerService.java
@Transactional(propagation = Propagation.REQUIRED)
public void deleteCustomer(Integer cid){
Customer customer= selectByPrimaryKey(cid);
AssertUtil.isTrue(null==cid||null==cid,"待删除记录不存在!");
/**
* 如果客户被删除
* 级联 客户联系人 客户交往记录 客户订单 被删除
*
* 如果客户被删除
* 如果子表存在记录 不支持删除
*/
customer.setIsValid(0);
AssertUtil.isTrue(updateByPrimaryKeySelective(customer)<1,"客户删除失败!");
}
- CustomerController.java
@RequestMapping("delete")
@ResponseBody
public ResultInfo deleteCustomer(Integer id){
customerService.deleteCustomer(id);
return success("客户删除成功");
}