Crm-客户管理

173 阅读7分钟

Crm-客户管理

客户管理表结构设计

客户信息管理模块表结构

这里主要涉及表:

​ t_customer 客户表、t_customer_contact 客户交往记录表、t_customer_linkman 客户联系人表、t_customer_order 客户订单表、t_order_details 订单详情表

t_customer客户信息表
字段字段类型字段限制字段描述
主键idint(11)自增id主键
khnovarchar(20)可空客户编号
namevarchar(20)可空客户姓名
areavarchar(20)可空客户所属地区
cus_managervarchar(20)可空客户经理
levelvarchar(30)可空客户级别
mydvarchar(30)可空客户满意度
xydvarchar(30)可空客户信用度
addressvarchar(500)可空客户地址
post_codevarchar(50)可空邮编
phonevarchar(20)可空联系电话
faxvarchar(20)可空传真
web_sitevarchar(20)可空网址
yyzzzchvarchar(50)可空营业执照注册号
frvarchar(20)可空法人代表
zczjvarchar(20)可空注册资金
nyyevarchar(20)可空年营业额
khyhvarchar(50)可空开户银行
khzhvarchar(50)可空开户账号
dsdjhvarchar(50)可空地税登记号
gsdjhvarchar(50)可空国税登记号
stateint(11)可空流失状态
is_validint(4)可空有效状态
create_datedatetime可空创建时间
update_datedatetime可空更新时间
t_customer_contact客户交往记录表
字段字段类型字段限制字段描述
主键idint(11)自增id主键
cus_idint(11)可空客户id
contact_timedatetime可空交往时间
addressvarchar(500)可空交往地址
overviewvarchar(100)可空地址
create_datedatetime可空创建时间
update_datedatetime可空更新时间
is_validint(4)可空有效状态
t_customer_linkman客户联系人表
字段字段类型字段限制字段描述
主键idint(11)自增id主键
cus_idint(11)可空客户id
link_namevarchar(20)可空联系人姓名
sexvarchar(20)可空性别
zhiweivarchar(50)可空职位
office_phonevarchar(50)可空办公电话
phonevarchar(20)可空手机号
is_validint(4)可空有效状态
ceate_datedatetime可空创建时间
update_datedatetime可空更新时间
t_customer_order客户订单
字段字段类型字段限制字段描述
主键idint(11)自增id主键
cus_idint(11)可空客户id
order_novarchar(40)可空订单编号
order_datedatetime可空下单时间
addressvarchar(200)可空地址
stateint(11)可空状态
create_datedatetime可空创建时间
update_datedatetime可空更新时间
is_validint(4)可空有效状态
t_order_details订单详情表
字段字段类型字段限制字段描述
主键idint(11)自增id主键
order_idint(11)可空订单id
goods_namevarchar(100)可空商品名称
goods_numint(11)可空商品数量
unitvarchar(20)可空商品单位
pricefloat可空单价
sumfloat可空总金额
is_validint(4)可空有效状态
create_datedatetime可空创建时间
update_datedatetime可空更新时间

客户流失管理模块表结构

在这里插入图片描述

这里主要涉及表有

​ t_customer_loss 客户流失表

​ t_customer_reprieve 客户流失暂缓表

t_customer_loss客户流失表
字段字段类型字段限制字段描述
主键idint(11)自增id主键
cus_novarchar(40)可空客户编号
cus_namevarchar(20)可空客户姓名
cus_managervarchar(20)可空客户经理
last_order_timedate可空最后下单时间
confirm_loss_timedate可空确认流失时间
stateint(11)可空流失状态
loss_reasonvarchar(1000)可空流失原因
is_validtinyint(4)可空有效状态
create_datedatetime可空创建时间
update_datedatetime可空更新时间
t_customer_reprieve客户流失暂缓表
字段字段类型字段限制字段描述
主键idint(11)自增id主键
loss_idint(11)可空流失id
measurevarchar(500)可空措施
is_validtinyint(4)可空有效状态
create_datedatetime可空创建时间
update_datedatetime可空更新时间

客户信息查询后端代码实现

layui 框架通过表格展示后端表数据,数据格式见官网测试数据地址。

CustomerMapper 接口定义与Sql配置
  • CustomerMapper .java
public interface CustomerMapper  extends BaseMapper<Customer,Integer> {
	/*
	  由于考虑到多个模块均涉及多条件查询
	  这里对于多条件分页查询方法由父接口BaseMapper定义
	*/
}
  • CustomerMapper .xml
    <select id="selectByParams" parameterType="com.xxxx.crm.query.CustomerQuery" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from t_customer
        <where>
            is_valid=1
            <!--
               state  流失状态
                  0  未流失
                  1  已流失
            -->
            and state =0
            <if test="null !=cusName and cusName !=''">
                and name like concat('%',#{cusName},'%')
            </if>
            <if test="null !=cusNo and cusNo !=''">
                and khno =#{cusNo}
            </if>
            <if test="null !=level and level !=''">
                and level =#{level}
            </if>
            <if test="null !=myd and myd !=''">
                and myd =#{myd}
            </if>


        </where>
    </select>
  • 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<Customer, Integer> {
	/*
	  由于考虑到多个模块均涉及多条件查询
	  这里对于多条件分页查询方法由父类BaseService定义并实现
	*/
}
  • BaseService.java 分页查询方法定义与实现
    public Map<String, Object> queryByParamsForTable(BaseQuery baseQuery) {
        Map<String,Object> result = new HashMap<String,Object>();
        PageHelper.startPage(baseQuery.getPage(),baseQuery.getLimit());
        PageInfo<T> pageInfo =new PageInfo<T>(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<String,Object> queryCustomersByParams(CustomerQuery customerQuery){
        return customerService.queryByParamsForTable(customerQuery);
    }

客户信息管理前端核心代码

客户信息管理主页面模板

resources/views/customer目录创建customer.ftl 模块文件,模板内容如下(模板依赖的layui文件由common.ftl 文件提供),layui表格数据展示模板文件实现参考该地址

  • customer.ftl
<!DOCTYPE html>
<html>
<head>
	<title>客户管理</title>
	<#include "../common.ftl">
</head>
<body class="childrenBody">

<form class="layui-form" >
	<blockquote class="layui-elem-quote quoteBox">
		<form class="layui-form">
			<div class="layui-inline">
				<div class="layui-input-inline">
					<input type="text" name="name"
						   class="layui-input
					searchVal" placeholder="客户名" />
				</div>
				<div class="layui-input-inline">
					<input type="text" name="khno" class="layui-input
					searchVal" placeholder="客户编号" />
				</div>
				<div class="layui-input-inline">
                    <select name="level"  id="level">
						<option value="">请选择...</option>
						<option value="战略合作伙伴">战略合作伙伴</option>
						<option value="大客户">大客户</option>
						<option value="重点开发客户">重点开发客户</option>
                    </select>
				</div>
				<a class="layui-btn search_btn" data-type="reload"><i
							class="layui-icon">&#xe615;</i> 搜索</a>
			</div>
		</form>
	</blockquote>
	<table id="customerList" class="layui-table"  lay-filter="customers"></table>


	
	<!--操作-->
	<script id="customerListBar" type="text/html">
		<a class="layui-btn layui-btn-xs" id="edit" lay-event="edit">编辑</a>
		<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
	</script>


</form>
<script type="text/javascript" src="${ctx}/static/js/customer/customer.js"></script>

</body>
</html>
客户信息管理主页面模板核心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重载基础方法实现,点击这里参考官网介绍

<script type="text/html" id="toolbarDemo">
		<div class="layui-btn-container">
			<a class="layui-btn layui-btn-normal addNews_btn" lay-event="add">
				<i class="layui-icon">&#xe608;</i>
				添加
			</a>
			<a class="layui-btn layui-btn-normal  " lay-event="link">
				<i class="layui-icon">&#xe608;</i>
				联系人管理
			</a>
			<a class="layui-btn layui-btn-normal addNews_btn" lay-event="recode">
				<i class="layui-icon">&#xe608;</i>
				交往记录
			</a>
			<a class="layui-btn layui-btn-normal addNews_btn" lay-event="order">
				<i class="layui-icon">&#xe608;</i>
				订单查看
			</a>
		</div>
	</script>
  • 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 表单模板

<!DOCTYPE html>
<html>
<head>
    <#include "../common.ftl">
</head>
<body class="childrenBody">
<form class="layui-form" style="width:80%;">
    <input name="id" type="hidden" value="${(customer.id)!}"/>


    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">客户名称</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="name" id="name"  lay-verify="required" value="${(customer.name)!}" placeholder="请输入客户名">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">法人</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="fr" id="fr" lay-verify="required" value="${(customer.fr)!}" placeholder="请输入法人">
            </div>
        </div>
    </div>

    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">区域</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="area"  lay-verify="required"  value="${(customer.area)!}" placeholder="请输入区域">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">客户经理</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="cusManager" value="${(customer.cusManager)!}" placeholder="请输入客户经理">
            </div>
        </div>
    </div>

    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">客户级别</label>
            <div class="layui-input-block">
                <select name="level"  id="level">
                    <option value="" >请选择</option>
                    <option value="普通客户">普通客户</option>
                    <option value="重点开发客户" >重点开发客户</option>
                    <option value="大客户" >大客户</option>
                    <option value="合作伙伴" >合作伙伴</option>
                </select>
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">信用度</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="xyd" value="${(customer.xyd)!}"  placeholder="请输入客户信用级别">
            </div>
        </div>
    </div>


    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">邮编</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="postCode" value="${(customer.postCode)!}"  placeholder="请输入客户邮编">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">联系电话</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="phone" value="${(customer.phone)!}"  placeholder="请输入客户联系电话">
            </div>
        </div>
    </div>

    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">客户地址</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="address" value="${(customer.address)!}"  placeholder="请输入客户地址">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">传真</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="fax" value="${(customer.fax)!}"  placeholder="请输入客户传真">
            </div>
        </div>
    </div>

    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">网站</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="webSite" value="${(customer.webSite)!}"  placeholder="请输入客户网站地址">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">注册资金</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="zczj" value="${(customer.zczj)!}"  placeholder="请输入注册资金">
            </div>
        </div>
    </div>



    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">开户行</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="khyh" value="${(customer.khyh)!}"  placeholder="请输入客户开户行">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">开户账号</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="khzh" value="${(customer.khzh)!}"  placeholder="请输入开户账号">
            </div>
        </div>
    </div>

    <div class="layui-form-item layui-row">
        <div class="layui-col-xs6">
            <label class="layui-form-label">国税</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="gsdjh" value="${(customer.gsdjh)!}"  placeholder="请输入国税">
            </div>
        </div>
        <div class="layui-col-xs6">
            <label class="layui-form-label">地税</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="dsdjh" value="${(customer.dsdjh)!}"  placeholder="请输入地税">
            </div>
        </div>
    </div>

    <div class="layui-form-item layui-row">

        <div class="layui-col-xs6">
            <label class="layui-form-label">年营业额</label>
            <div class="layui-input-block">
                <input type="text" class="layui-input"
                       name="nyye" value="${(customer.nyye)!}"  placeholder="请输入客户年营业额">
            </div>
        </div>
    </div>


    <br/>
    <div class="layui-form-item layui-row layui-col-xs12">
        <div class="layui-input-block">
            <button class="layui-btn layui-btn-lg" lay-submit=""
                    lay-filter="addOrUpdateCustomer">确认
            </button>
            <button class="layui-btn layui-btn-lg layui-btn-normal">取消</button>
        </div>
    </div>
</form>
<script type="text/javascript" src="${ctx}/static/js/customer/add.update.js"></script>
</body>
</html>
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("客户删除成功");
}