Crm系统营销管理模块——营销机会管理与客户开发计划

本小节对 营销机会管理 功能块 进行系统的实现

 一、营销机会管理模块实现

(一)准备工作

        1、表格准备:

              Navicat里准备好营销机会管理表:t_sale_chance

表中字段及一条记录示例

         

         2、启动逆向工程

            2.1、 更改resources目录下generatorConfig.xml里<table>标签第一行tableName和domainObjectName属性

                      值的信息 ,具体代码如下:

<!--逆向工程配置-->
        <!--执行后自动生成与数据库中x_xx表所对应Java三件套,分别是
            vo包下xx实体类、dao包下xx_mapper接口、resources目录下mappers包下xx_mapper.xml文件
            table标签里第一行是可变动的:属性值是填表的名字和对应的实体类名(大驼峰),下面两行不用动
        -->
        <!--这下面是生成t_sale_chance表对应的的Java三件套时用的配置-->
        <table tableName="t_sale_chance" domainObjectName="SaleChance"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
       
        <!--下面注释掉的是之前生成t_user表对应的Java三件套时用的配置-->
        <!--<table tableName="t_user" domainObjectName="User"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->

            2.2、执行命令:mybatis-generator:generate -e

            2.3、查看生成的Java三件套,分别是
            vo包下xx实体类、dao包下xx_mapper接口、resources目录下mappers包下xx_mapper.xml文件

            2.4、修改上图圈1的SaleChanceMapper接口文件

package com.msb.crm.dao;

import com.msb.crm.base.BaseMapper;
import com.msb.crm.vo.SaleChance;

public interface SaleChanceMapper extends BaseMapper<SaleChance,Integer> {
}

            2.5、Service层代码

package com.msb.crm.service;

import com.msb.crm.base.BaseService;
import com.msb.crm.dao.SaleChanceMapper;
import com.msb.crm.vo.SaleChance;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
/**
 * 业务层三件套:继承、注解、注入该类mapper层对象
 */
@Service
public class SaleChanceService extends BaseService<SaleChance,Integer> {
    @Resource
    private SaleChanceMapper saleChanceMapper;
}

            2.6、Controller层代码

package com.msb.crm.controller;

import com.msb.crm.base.BaseController;
import com.msb.crm.service.SaleChanceService;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

/**
 * 控制层三件套:继承、注解、注入该类的Service层对象
 */
@Controller
public class SaleChanceController extends BaseController {
    @Resource
    private SaleChanceService saleChanceService;
}
 3、IDEA创建MySql连接

        将数据库表连接到IDEA的好处:

                使我们在xx_mapper.xml文件里写增删改查语句很便捷,并且也不用打开 Navicat就能在IDEA里直接写SQL语句,接下来是具体连接步骤: 

            3.1、 复制application.yml文件里的url后面的路径,一会儿要用

            3.2、

            3.3、弹出框里填写的7个步骤

                将刚刚复制的路径粘贴在圈①,圈2就会自动填好,圈3根据自己本地数据库账号密码填写,圈4可以自定义修改,然后执行圈5、6、7,如果点完圈5按钮有弹出框,看下面的解决办法。

                 以上步骤点击了圈5如果出现这个界面:选择DownLoad Driver Files选项

                等他下载好就连接成功了,然后接着完成6、7,步骤 

                 然后刷新一下,就可以看到我们数据库里的表被连接到IDEA里了。

                 点一下“QL”按钮 就可以在IDEA里直接写SQL语句了

(二)针对_营销机会管理页面数据的操作

        操作包括:增/删/改 /多条件查询/分页查询
        后端、前端代码存放目录概览

        1、后端代码实现: 
            1.1、 crm包下创建query包,包下创建SaleChanceQuery.java类,设置对应的查询条件。
package com.msb.crm.query;

import com.msb.crm.base.BaseQuery;

/**
 * 营销机会查询类:设置对应的查询条件
 * 实现功能:
 *  1、为用户在页面进行条件查询提供后台支持
 *  2、为用户在页面进行分页查询提供后台支持
 */
public class SaleChanceQuery extends BaseQuery {


    //条件查询
    private String customerName; //客户姓名
    private String createMan;  //创建人
    private Integer state;  //分配状态  0=未分配  1=已分配

    //提供对应的set/get方法
    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public String getCreateMan() {
        return createMan;
    }

    public void setCreateMan(String createMan) {
        this.createMan = createMan;
    }

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }
}
            1.2、分别在SaleChanceMapper.xml和UserMapper.xml两个映射文件中添加代码段
                (1) SaleChanceMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.msb.crm.dao.SaleChanceMapper" >
  <resultMap id="BaseResultMap" type="com.msb.crm.vo.SaleChance" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="chance_source" property="chanceSource" jdbcType="VARCHAR" />
    <result column="customer_name" property="customerName" jdbcType="VARCHAR" />
    <result column="cgjl" property="cgjl" jdbcType="INTEGER" />
    <result column="overview" property="overview" jdbcType="VARCHAR" />
    <result column="link_man" property="linkMan" jdbcType="VARCHAR" />
    <result column="link_phone" property="linkPhone" jdbcType="VARCHAR" />
    <result column="description" property="description" jdbcType="VARCHAR" />
    <result column="create_man" property="createMan" jdbcType="VARCHAR" />
    <result column="assign_man" property="assignMan" jdbcType="VARCHAR" />
    <result column="assign_time" property="assignTime" jdbcType="TIMESTAMP" />
    <result column="state" property="state" jdbcType="INTEGER" />
    <result column="dev_result" property="devResult" jdbcType="INTEGER" />
    <result column="is_valid" property="isValid" jdbcType="INTEGER" />
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
    <result column="update_date" property="updateDate" jdbcType="TIMESTAMP" />
  </resultMap>
  <sql id="Base_Column_List" >
    <if test="true">
      id, chance_source, customer_name, cgjl, overview, link_man, link_phone, description,
      create_man, assign_man, assign_time, state, dev_result, is_valid, create_date, update_date
    </if>
  </sql>
  <!--对表格中单行记录进行:增、删、改、查-->
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from t_sale_chance
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from t_sale_chance
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.msb.crm.vo.SaleChance" >
    insert into t_sale_chance (id, chance_source, customer_name, 
      cgjl, overview, link_man, 
      link_phone, description, create_man, 
      assign_man, assign_time, state, 
      dev_result, is_valid, create_date, 
      update_date)
    values (#{id,jdbcType=INTEGER}, #{chanceSource,jdbcType=VARCHAR}, #{customerName,jdbcType=VARCHAR}, 
      #{cgjl,jdbcType=INTEGER}, #{overview,jdbcType=VARCHAR}, #{linkMan,jdbcType=VARCHAR}, 
      #{linkPhone,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{createMan,jdbcType=VARCHAR}, 
      #{assignMan,jdbcType=VARCHAR}, #{assignTime,jdbcType=TIMESTAMP}, #{state,jdbcType=INTEGER}, 
      #{devResult,jdbcType=INTEGER}, #{isValid,jdbcType=INTEGER}, #{createDate,jdbcType=TIMESTAMP}, 
      #{updateDate,jdbcType=TIMESTAMP})
  </insert>
  <insert id="insertSelective" parameterType="com.msb.crm.vo.SaleChance" >
    insert into t_sale_chance
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="chanceSource != null" >
        chance_source,
      </if>
      <if test="customerName != null" >
        customer_name,
      </if>
      <if test="cgjl != null" >
        cgjl,
      </if>
      <if test="overview != null" >
        overview,
      </if>
      <if test="linkMan != null" >
        link_man,
      </if>
      <if test="linkPhone != null" >
        link_phone,
      </if>
      <if test="description != null" >
        description,
      </if>
      <if test="createMan != null" >
        create_man,
      </if>
      <if test="assignMan != null" >
        assign_man,
      </if>
      <if test="assignTime != null" >
        assign_time,
      </if>
      <if test="state != null" >
        state,
      </if>
      <if test="devResult != null" >
        dev_result,
      </if>
      <if test="isValid != null" >
        is_valid,
      </if>
      <if test="createDate != null" >
        create_date,
      </if>
      <if test="updateDate != null" >
        update_date,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="chanceSource != null" >
        #{chanceSource,jdbcType=VARCHAR},
      </if>
      <if test="customerName != null" >
        #{customerName,jdbcType=VARCHAR},
      </if>
      <if test="cgjl != null" >
        #{cgjl,jdbcType=INTEGER},
      </if>
      <if test="overview != null" >
        #{overview,jdbcType=VARCHAR},
      </if>
      <if test="linkMan != null" >
        #{linkMan,jdbcType=VARCHAR},
      </if>
      <if test="linkPhone != null" >
        #{linkPhone,jdbcType=VARCHAR},
      </if>
      <if test="description != null" >
        #{description,jdbcType=VARCHAR},
      </if>
      <if test="createMan != null" >
        #{createMan,jdbcType=VARCHAR},
      </if>
      <if test="assignMan != null" >
        #{assignMan,jdbcType=VARCHAR},
      </if>
      <if test="assignTime != null" >
        #{assignTime,jdbcType=TIMESTAMP},
      </if>
      <if test="state != null" >
        #{state,jdbcType=INTEGER},
      </if>
      <if test="devResult != null" >
        #{devResult,jdbcType=INTEGER},
      </if>
      <if test="isValid != null" >
        #{isValid,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        #{createDate,jdbcType=TIMESTAMP},
      </if>
      <if test="updateDate != null" >
        #{updateDate,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.msb.crm.vo.SaleChance" >
    update t_sale_chance
    <set >
      <if test="chanceSource != null" >
        chance_source = #{chanceSource,jdbcType=VARCHAR},
      </if>
      <if test="customerName != null" >
        customer_name = #{customerName,jdbcType=VARCHAR},
      </if>
      <if test="cgjl != null" >
        cgjl = #{cgjl,jdbcType=INTEGER},
      </if>
      <if test="overview != null" >
        overview = #{overview,jdbcType=VARCHAR},
      </if>
      <if test="linkMan != null" >
        link_man = #{linkMan,jdbcType=VARCHAR},
      </if>
      <if test="linkPhone != null" >
        link_phone = #{linkPhone,jdbcType=VARCHAR},
      </if>
      <if test="description != null" >
        description = #{description,jdbcType=VARCHAR},
      </if>
      <if test="createMan != null" >
        create_man = #{createMan,jdbcType=VARCHAR},
      </if>
      <if test="state != null" >
        state = #{state,jdbcType=INTEGER},
      </if>
      <if test="devResult != null" >
        dev_result = #{devResult,jdbcType=INTEGER},
      </if>
      <if test="isValid != null" >
        is_valid = #{isValid,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        create_date = #{createDate,jdbcType=TIMESTAMP},
      </if>
      <if test="updateDate != null" >
        update_date = #{updateDate,jdbcType=TIMESTAMP},
      </if>

    <!--这两项不判断为空,否则进行更新操作时不能通过,即更新前他们的值可以空-->
      assign_man = #{assignMan,jdbcType=VARCHAR},
      assign_time = #{assignTime,jdbcType=TIMESTAMP},
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.msb.crm.vo.SaleChance" >
    update t_sale_chance
    set chance_source = #{chanceSource,jdbcType=VARCHAR},
      customer_name = #{customerName,jdbcType=VARCHAR},
      cgjl = #{cgjl,jdbcType=INTEGER},
      overview = #{overview,jdbcType=VARCHAR},
      link_man = #{linkMan,jdbcType=VARCHAR},
      link_phone = #{linkPhone,jdbcType=VARCHAR},
      description = #{description,jdbcType=VARCHAR},
      create_man = #{createMan,jdbcType=VARCHAR},
      assign_man = #{assignMan,jdbcType=VARCHAR},
      assign_time = #{assignTime,jdbcType=TIMESTAMP},
      state = #{state,jdbcType=INTEGER},
      dev_result = #{devResult,jdbcType=INTEGER},
      is_valid = #{isValid,jdbcType=INTEGER},
      create_date = #{createDate,jdbcType=TIMESTAMP},
      update_date = #{updateDate,jdbcType=TIMESTAMP}
    where id = #{id,jdbcType=INTEGER}
  </update>

  <!--该sql实现从数据库进行:多条件查询-查询符合筛选条件的所有行记录-->
  <select id="selectByParams" parameterType="com.msb.crm.dao.SaleChanceMapper" resultType="com.msb.crm.vo.SaleChance">
    select
        s.id, chance_source, customer_name, cgjl, overview, link_man, link_phone, description,
        create_man, assign_man, assign_time, state, dev_result, s.is_valid, s.create_date, s.update_date, u.user_name as uname
    from
        t_sale_chance s
    left join
        t_user u
    on
        s.assign_man = u.id
    <where>
        s.is_valid = 1
        <if test="customerName!=null and customerName!=''">
          and s.customer_name like concat('%',#{customerName},'%')
        </if>
        <if test="createMan !=null and createMan !=''">
          and s.create_man = #{creatman}
        </if>
          <if test="state != null">
          and s.state = #{state}
          </if>
    </where>
  </select>

  <!--批量删除操作:这里采取假删除,真隐藏(即进行更新操作:把有效字段修改为无效即可)
      该操作针对营销管理主页面中表格的头部工具栏按钮:删除按钮-->
  <update id="deleteBatch">
    update
        t_sale_chance
    set
        is_valid = 0
    where
        id
    in
        <foreach collection="array" separator="," open="(" close=")" item="id">
            #{id}
        </foreach>
  </update>
  
</mapper>
                    (2) UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.msb.crm.dao.UserMapper" >
  <resultMap id="BaseResultMap" type="com.msb.crm.vo.User" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="user_name" property="userName" jdbcType="VARCHAR" />
    <result column="user_pwd" property="userPwd" jdbcType="VARCHAR" />
    <result column="true_name" property="trueName" jdbcType="VARCHAR" />
    <result column="email" property="email" jdbcType="VARCHAR" />
    <result column="phone" property="phone" jdbcType="VARCHAR" />
    <result column="is_valid" property="isValid" jdbcType="INTEGER" />
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
    <result column="update_date" property="updateDate" jdbcType="TIMESTAMP" />
  </resultMap>
  <sql id="Base_Column_List" >
    <if test="true">
      id, user_name, user_pwd, true_name, email, phone, is_valid, create_date, update_date
    </if>
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from t_user
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from t_user
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.msb.crm.vo.User" >
    insert into t_user (id, user_name, user_pwd, 
      true_name, email, phone, 
      is_valid, create_date, update_date
      )
    values (#{id,jdbcType=INTEGER}, #{userName,jdbcType=VARCHAR}, #{userPwd,jdbcType=VARCHAR}, 
      #{trueName,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, 
      #{isValid,jdbcType=INTEGER}, #{createDate,jdbcType=TIMESTAMP}, #{updateDate,jdbcType=TIMESTAMP}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.msb.crm.vo.User" >
    insert into t_user
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="userName != null" >
        user_name,
      </if>
      <if test="userPwd != null" >
        user_pwd,
      </if>
      <if test="trueName != null" >
        true_name,
      </if>
      <if test="email != null" >
        email,
      </if>
      <if test="phone != null" >
        phone,
      </if>
      <if test="isValid != null" >
        is_valid,
      </if>
      <if test="createDate != null" >
        create_date,
      </if>
      <if test="updateDate != null" >
        update_date,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="userName != null" >
        #{userName,jdbcType=VARCHAR},
      </if>
      <if test="userPwd != null" >
        #{userPwd,jdbcType=VARCHAR},
      </if>
      <if test="trueName != null" >
        #{trueName,jdbcType=VARCHAR},
      </if>
      <if test="email != null" >
        #{email,jdbcType=VARCHAR},
      </if>
      <if test="phone != null" >
        #{phone,jdbcType=VARCHAR},
      </if>
      <if test="isValid != null" >
        #{isValid,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        #{createDate,jdbcType=TIMESTAMP},
      </if>
      <if test="updateDate != null" >
        #{updateDate,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.msb.crm.vo.User" >
    update t_user
    <set >
      <if test="userName != null" >
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="userPwd != null" >
        user_pwd = #{userPwd,jdbcType=VARCHAR},
      </if>
      <if test="trueName != null" >
        true_name = #{trueName,jdbcType=VARCHAR},
      </if>
      <if test="email != null" >
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="phone != null" >
        phone = #{phone,jdbcType=VARCHAR},
      </if>
      <if test="isValid != null" >
        is_valid = #{isValid,jdbcType=INTEGER},
      </if>
      <if test="createDate != null" >
        create_date = #{createDate,jdbcType=TIMESTAMP},
      </if>
      <if test="updateDate != null" >
        update_date = #{updateDate,jdbcType=TIMESTAMP},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <!--通过名字查询用户信息:这里的数据是进入主页后在用户基本资料按钮被点击时要提供给前台展示的信息-->
  <select id="queryUserByName" parameterType="String" resultType="com.msb.crm.vo.User">
  select
  <include refid="Base_Column_List" />
  from
  t_user
  where
  user_name = #{userName}
  </select>
  <!--查询所有销售人员:这里的数据是在营销机会管理页
    按下”添加/编辑“按钮时弹出层的指派人那一个下拉框需要的全部选项信息-->
  <select id="queryAllSales" resultType="java.util.Map">
    SELECT
      u.id,u.user_name uname
    FROM
      t_user u
    left join
      t_user_role ur
    on
      u.id = ur.user_id
    left join
      t_role r
    on
      ur.role_id = r.id
    where
      u.is_valid = 1
      and
      r.is_valid = 1
      and
      r.role_name = '销售'
  </select>
</mapper>
            1.3、dao层代码
                 (1) UserMapper.java
package com.msb.crm.dao;

import com.msb.crm.base.BaseMapper;
import com.msb.crm.vo.User;

import java.util.List;
import java.util.Map;

/**
 * 定义UserMapper类dao层接口:接收service层传来的参数
 * 具体实现本层CRUD操作的是该类对应的mapper.xml里的sql语句
 */
public interface UserMapper extends BaseMapper<User,Integer> {
    //通过用户名查询用户记录,返回用户对象
    public User queryUserByName(String userName);

    //查询所有销售人员(得到用户Id与姓名)
    List<Map<String,Object>> queryAllSales();

}
                (2) SaleChanceMapper.java
package com.msb.crm.dao;

import com.msb.crm.base.BaseMapper;
import com.msb.crm.vo.SaleChance;
/**
 * 定义SaleChanceMapper类dao层接口:接收service层传来的参数
 * 具体实现本层CRUD操作的是该类对应的mapper.xml里的sql语句
 */
public interface SaleChanceMapper extends BaseMapper<SaleChance,Integer> {
    /**
     * 由于多个模块有分页查询需求
     * 分页查询的接口在继承的BaseQuery里已经定义好了,不用单独写
     */
    /**
     * 更新单条记录已经在继承的类里有了,不用单独写
     */
}
                 (3) BaseMapper.java
package com.msb.crm.base;


import org.springframework.dao.DataAccessException;

import java.util.List;

/**
 * BaseMapper  基本方法定义
 *  增、添、改、查
 */
public interface BaseMapper<T,ID> {
    /**
     * 添加记录返回行数
     * @param entity
     * @return
     */
    public Integer insertSelective(T entity) throws DataAccessException;

    /**
     * 添加记录返回主键
     * @param entity
     * @return
     */
    public Integer insertHasKey(T entity) throws DataAccessException;

    /**
     * 批量添加
     * @param entities
     * @return
     */
    public Integer insertBatch(List<T> entities) throws DataAccessException;


    /**
     * 根据id 查询详情
     * @param id
     * @return
     */
    public T selectByPrimaryKey(ID id) throws DataAccessException;


    /**
     * 多条件查询
     * @param baseQuery
     * @return
     */
    public List<T> selectByParams(BaseQuery baseQuery) throws DataAccessException;


    /**
     * 更新单条记录
     * @param entity
     * @return
     */
    public Integer updateByPrimaryKeySelective(T entity) throws DataAccessException;


    /**
     * 批量更新
     * @param entities
     * @return
     */
    public Integer updateBatch(List<T> entities) throws DataAccessException;

    /**
     * 删除单条记录
     * @param id
     * @return
     */
    public Integer deleteByPrimaryKey(ID id) throws DataAccessException;

    /**
     * 批量删除
     * @param ids
     * @return
     */
    public Integer deleteBatch(ID[] ids) throws DataAccessException;

}
            1.4、Service层
                (1) SaleChanceService.java方法概览
               SaleChanceService.java具体代码
package com.msb.crm.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.msb.crm.base.BaseService;
import com.msb.crm.dao.SaleChanceMapper;
import com.msb.crm.enums.DevResult;
import com.msb.crm.enums.StateStatus;
import com.msb.crm.query.SaleChanceQuery;
import com.msb.crm.utils.AssertUtil;
import com.msb.crm.utils.PhoneUtil;
import com.msb.crm.vo.SaleChance;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 业务(Service)层
 * 注入该类mapper层对象
 */
@Service
public class SaleChanceService extends BaseService<SaleChance,Integer> {
    @Resource
    private SaleChanceMapper saleChanceMapper;

    /**
     * 多条件分页查询营销机会数据
     *  返回的数据格式要求满足LayUi要求的表格数据格式
     * @param saleChanceQuery
     * @return Java.Util.Map<Java.Long.String,Java.Long.Object>
     */
    public Map<String,Object> querySaleChanceByParams(SaleChanceQuery saleChanceQuery){
        Map<String,Object> map = new HashMap<>();
        // 开启分页
        PageHelper.startPage(saleChanceQuery.getPage(),saleChanceQuery.getLimit());
        //调用mapper层方法:得到对应分页对象
        PageInfo<SaleChance> pageInfo = new PageInfo<>(saleChanceMapper.selectByParams(saleChanceQuery));
        //设置map
        map.put("code",0);
        map.put("msg","success");
        map.put("count",pageInfo.getTotal());
        map.put("data",pageInfo.getList());
        return map;
    }

    /**
     * 添加:营销机会数据
     * 1、参数校验:设置值不能为空的字段(customerName,linkMan,linkPhone(格式要正确))
     * 2、设置相关参数默认值
     * 3、执行添加操作,判断受影响的行数
     * @param saleChance
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void addSaleChance(SaleChance saleChance){
        //1、调用<参数校验>函数
        checkSaleChanceParams(saleChance.getCustomerName(),saleChance.getLinkMan(),saleChance.getLinkPhone());
        //2、设置默认值
        //2.1、isValid是否有效,设置为有效1=有效
        saleChance.setIsValid(1);
        //2.2、createDate创建时间:默认是系统当前时间
        saleChance.setCreateDate(new Date());
        //2.3、updateDate:默认是系统当前时间
        saleChance.setUpdateDate(new Date());
        //2.4、assignMan指派人
        if (StringUtils.isBlank(saleChance.getAssignMan())){
            //未设置指派人
            //state分配状态:0=未分配
            saleChance.setState(StateStatus.STATED.getType());
            //assignTime指派时间:设置为null
            saleChance.setAssignTime(null);
            //devResult开发状态:0=未开发
            saleChance.setDevResult(DevResult.UNDEV.getStatus());
        }else{
            //设置了指派人
            //state分配状态:分配
            saleChance.setState(StateStatus.STATED.getType());
            //assignTime指派时间:设置为系统当前时间
            saleChance.setAssignTime(new Date());
            //devResult开发状态:开发中
            saleChance.setDevResult(DevResult.DEVING.getStatus());
        }
        //3、执行添加操作,判断受影响的行数
        AssertUtil.isTrue(saleChanceMapper.insertSelective(saleChance)!=1,"添加营销机会操作失败");

    }

    /**
     * 1.1、<参数校验>函数
     * @param customerName 客户名
     * @param linkMan 联系人
     * @param linkPhone 联系电话
     */
    private void checkSaleChanceParams(String customerName, String linkMan, String linkPhone) {
        //customerName 客户名  非空,并给出提示
        AssertUtil.isTrue(StringUtils.isBlank(customerName),"客户名不能为空");
        //linkMan 联系人  非空,并给出提示
        AssertUtil.isTrue(StringUtils.isBlank(linkMan),"联系人不能为空");
        //linkPhone 联系电话  非空,并给出提示
        AssertUtil.isTrue(StringUtils.isBlank(linkPhone),"联系人电话不能为空");
        //linkPhone 联系电话   格式正确
        AssertUtil.isTrue(!PhoneUtil.isMobile(linkPhone),"电话号码不正确");
    }

    /**
     * 更新:营销机会数据
     * @param saleChance
     */
    public void updateSaleChance(SaleChance saleChance){
        /*1、参数校验*/
        //营销机会ID 非空,数据库中对应记录存在
        AssertUtil.isTrue(null == saleChance.getId(),"待更新记录不存在");
        //通过主键查询对象
        SaleChance temp = saleChanceMapper.selectByPrimaryKey(saleChance.getId());
        //判断该对象是否存在
        AssertUtil.isTrue(temp == null,"待更新记录不存在!");
        //参数校验方法调用
        checkSaleChanceParams(saleChance.getCustomerName(),saleChance.getLinkMan(),saleChance.getLinkPhone());
        /*2、设置相关参数默认值*/
        //2.1、updateDate更新时间:设置为系统当前时间
        saleChance.setUpdateDate(new Date());
        //2.2、assignMan指派人
        //2.2.1、原始数据存在状态判断
        if (StringUtils.isBlank(temp.getAssignMan())){
            //原始空:原来没指派人
            //修改后的值存在状态判断
            if (!StringUtils.isBlank(saleChance.getAssignMan())){
                //更新有值
                //assignTime指派时间:设置为系统当前时间
                saleChance.setAssignTime(new Date());
                //分配状态1=已分配
                saleChance.setState(StateStatus.STATED.getType());
                //开发状态1=开发中
                saleChance.setDevResult(DevResult.DEVING.getStatus());
            }
        }else {//原始有值,表示原来有指派人
            //更新值存在状态判断
            if (StringUtils.isBlank(saleChance.getAssignMan())){
                //更新为空
                //assignTime指派时间设置为null
                saleChance.setAssignTime(null);
                //分配状态0=未分配
                saleChance.setState(StateStatus.UNSTATE.getType());
                //开发状态0=未开发
                saleChance.setDevResult(DevResult.UNDEV.getStatus());
            }else {//更新不空
                //判断修改前后是否为同一指派人
                if (!saleChance.getAssignMan().equals(temp.getAssignMan())){
                    //如果是,则不需要操作
                    //如果不是,则需要更新assignTime指派时间设置为系统当前时间
                    saleChance.setAssignTime(new Date());
                }else {
                    //设置指派时间为修改前的时间
                    saleChance.setAssignTime(temp.getAssignTime());

                }
            }

        }

        /*3、执行更新操作,判断受影响的行数*/
        AssertUtil.isTrue(saleChanceMapper.updateByPrimaryKeySelective(saleChance) !=1,"更新营销机会失败");

    }

    /**
     * 删除:营销机会数据
     * @param ids
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteSaleChance (Integer[] ids){
        //判断id是否为空
        AssertUtil.isTrue(null == ids || ids.length==0,"待删除记录不存在!");
        //执行删除操作,判断受影响行数
        AssertUtil.isTrue(saleChanceMapper.deleteBatch(ids) !=ids.length,"营销机会数据删除失败");
    }

}
                (2) UserService.java
package com.msb.crm.service;

import com.msb.crm.base.BaseService;
import com.msb.crm.dao.UserMapper;
import com.msb.crm.model.UserModel;
import com.msb.crm.utils.AssertUtil;
import com.msb.crm.utils.Md5Util;
import com.msb.crm.utils.UserIDBase64;
import com.msb.crm.vo.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 本层public方法会被Controller层调用
 * 业务逻辑层会调用dao层:将dao层对象注入
 * 然后调用各种具体的方法
 */
//@Service注解:告诉Spring要将这个类纳入管理并创建其实例
@Service
public class UserService extends BaseService<User,Integer> {
    @Resource
    private UserMapper userMapper;

    /**
     * 定义用户登录具体方法:
     * service层 (业务逻辑层:非空判断层,条件判断等业务逻辑处理)
     *             是整体思路的具体细节执行者
     *             1、参数判断,判断用户姓名,密码是否非空
     *                 1.1、用户名,密码为空:抛出异常(异常被控制层捕获并处理)
     *                 1.2、用户名参数不空:调用持久层方法查询用户记录,根据持久层返回的用户对象数据作进一步判断(对象数据的密码与实参密码比较)
     *                     1.2.1、密码不正确,抛出异常(异常被控制层捕获并处理)
     *                     1.2.2、密码正确,登陆成功
     * @param userName 用户姓名
     * @param userPwd 用户密码
     */
    public UserModel userLogin(String userName, String userPwd){
        //1.1、调用方法:进行参数非空判断,判断用户姓名,密码是否为空
        cheakLoginparams(userName,userPwd);
        //1.2用户名不空:调用持久层方法查询数据库中是否有该用户记录,也就是判断与该用户名匹配的用户是否存在于数据库
        User user = userMapper.queryUserByName(userName);
        //1.2.1用户不存在:
        AssertUtil.isTrue(user==null,"用户不存在");
        //1.2.2用户存在:判断密码输入是否正确
        cheakUserPwd(userPwd,user.getUserPwd());
        //1.2.3针对登陆成功的用户调用buildUserInfo方法:把所需要的用户信息封装为对象后返回
        return buildUserInfo(user);
    }

    /**
     * 1.2.3定义方法:根据传入的用户信息返回需求字段的信息
     * @param user 形参:接收一个用户对象
     * @return 返回值是UserModel类对象
     */
    private UserModel buildUserInfo(User user) {
        UserModel userModel = new UserModel();
        //给用户ID加密
        userModel.setUserIdStr(UserIDBase64.encoderUserID(user.getId()));
        userModel.setUserName(user.getUserName());
        userModel.setTrueName(user.getTrueName());
        return userModel;
    }

    /**
     * 1.2.2方法定义:密码是否正确
     * 先对前台传来的密码进行加密,然后与数据库中的密码进行比较
     * 加密工具:Md5Util
     * @param userPwd 形参:接收用户表单填写的密码
     * @param pwd 形参:接收用户数据库真实密码
     */
    private void cheakUserPwd(String userPwd, String pwd) {
        //将客户端传递的密码加密
        userPwd = Md5Util.encode(userPwd);
        //判断密码是否相等
        AssertUtil.isTrue(!userPwd.equals(pwd),"用户密码不正确");
    }

    /**
     * 1.1方法定义、用户名,密码为空:抛出异常(异常被控制层捕获并处理)
     * @param userName 形参:用户姓名
     * @param userPwd 形参:用户密码
     */
    private void cheakLoginparams(String userName, String userPwd) {
        //判断用户姓名
        AssertUtil.isTrue(StringUtils.isBlank(userName),"用户姓名不能为空");
        //判断用户密码
        AssertUtil.isTrue(StringUtils.isBlank(userPwd),"用户密码不能为空");
    }

    /**
     * 定义用户修改密码具体方法
     *      1、接收controller层传来的四个参数(用户ID、原始密码、新密码、确认密码)
     *      2、通过用户ID查询用户记录,service层拿到用户对象
     *      3、参数校验(借助判断工具AssertUtil.isTrue)
     *      4、设置用户密码
     *          将用户新密码通过指定算法进行加密(md5加密)
     *      5、执行更新操作,判断受影响的行数
     * @param userId 用户ID
     * @param oldPwd 原始密码
     * @param newPwd 新密码
     * @param repeatPwd 确认密码
     */
    //添加事务注解(除了select方法,其余dao层操作都要添加事务注解)
    @Transactional(propagation = Propagation.REQUIRED)
    public void updatePassword(Integer userId,String oldPwd,String newPwd,String repeatPwd){

        //调用dao层方法:根据用户ID查询用户信息,拿到用户对象
        User user = userMapper.selectByPrimaryKey(userId);
        //待更新用户记录是否存在
        AssertUtil.isTrue(null == user,"待更新记录不存在");
        //参数校验:执行项较多,在这里留一个调用方法,在下面定义具体方法
        checkPasswordParams(user,oldPwd,newPwd,repeatPwd);
        //过滤完之后,把新密码加密后设置到用户对象里,完成service层的用户密码更新(这一步的更新操作后得到一个更新后的user,把这个整体对象作为实参传给dao层)
        user.setUserPwd(Md5Util.encode(newPwd));
        //dao层接收user实参调用update方法完成数据库里的user更新,
        //通过返回的受影响行数判断dao层操作是否成功(若是出现系统崩溃等情况可能导致数据更新不成功)
        AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user)<1,"修改密码失败!!");
    }

    /**
     * 参数校验具体方法
     * @param user
     * @param oldPwd
     * @param newPwd
     * @param repeatPwd
     * @return void
     */
    private void checkPasswordParams(User user, String oldPwd, String newPwd, String repeatPwd) {
        //判断原始密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(oldPwd),"原始密码不能为空");
        //判断原始密码是否正确
        AssertUtil.isTrue(!user.getUserPwd().equals(Md5Util.encode(oldPwd)),"原始密码不正确");
        //判断新密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(newPwd),"新密码不能为空");
        //判断新密码与原始密码是否一致
        AssertUtil.isTrue(oldPwd.equals(newPwd),"原始密码与新密码不能相同");
        //判断确认密码是否为空
        AssertUtil.isTrue(StringUtils.isBlank(repeatPwd),"确认密码不能为空");
        //判断确认密码与新密码是否一致
        AssertUtil.isTrue(!newPwd.equals(repeatPwd),"确认密码与新密码必须相同");

    }


    /**
     * 查询所有的销售人员
     * @return
     */
    public List<Map<String,Object>> queryAllSales(){
        return userMapper.queryAllSales();
    }
}
            1.5、controller层
                (1)UserController.java
package com.msb.crm.controller;

import com.msb.crm.base.BaseController;
import com.msb.crm.base.ResultInfo;
import com.msb.crm.model.UserModel;
import com.msb.crm.service.UserService;
import com.msb.crm.utils.LoginUserUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * 接收前台请求的控制器:对接前台index页面里发送的Ajax登录请求
 */
//@Controller标记该类是一个控制器(控制器负责接收请求、处理请求,并返回响应)
@Controller
@RequestMapping("user")
public class UserController extends BaseController {
    //本层会调用service层对象里的方法,在该类里注入service层对象
    @Resource
    private UserService userService;
    @Resource
    private ResultInfo resultInfo;

    /**
     * 用户登录
     * @param userName
     * @param userPwd
     * @return
     */
    @PostMapping("login")//该注解作用:给前端机动部(index.js)提供访问路径并限定请求方式
    //以jason格式返回对象类型数据要加这个注解@ResponseBody(如果返回页面不需要加该注解)
    @ResponseBody
    //index.js根据访问路径携带表单内容给UserController发来请求;
    // UserController形参接收表单数据,用ResultInfo类型变量返回封装好的userModel信息给index.js
    public ResultInfo userLogin(String userName, String userPwd) {

        UserModel userModel = userService.userLogin(userName, userPwd);
        resultInfo.setResult(userModel);
        return resultInfo;
    }

    /**
     * 用户修改密码
     * @param request
     * @param oldPassword
     * @param newPassword
     * @param repeatPassword
     * @return
     */
    @PostMapping("updatePassword")
    @ResponseBody
    public ResultInfo updateUserPassword(HttpServletRequest request,String oldPassword,String newPassword,String repeatPassword){

        //从request中获取cookie中的userIdStr然后调用工具得到userId
        Integer userId = LoginUserUtil.releaseUserIdFromCookie(request);
        //调用service层修改密码方法
        userService.updatePassword(userId,oldPassword,newPassword,repeatPassword);
        return resultInfo;

    }

    /**
     * 接收修改密码界面的请求并执行资源返回操作
     * @return
     */
    @RequestMapping("toPasswordPage")
    public String toPasswordPage(){
        return "user/password";
    }

    /**
     * 查询所有销售人员
     * @return
     */
    @RequestMapping("queryAllSales")
    @ResponseBody
    public List<Map<String,Object>> queryAllSales(){
        return userService.queryAllSales();
    }
}
                (2)SaleChanceController.java
package com.msb.crm.controller;

import com.msb.crm.base.BaseController;
import com.msb.crm.base.ResultInfo;
import com.msb.crm.query.SaleChanceQuery;
import com.msb.crm.service.SaleChanceService;
import com.msb.crm.utils.CookieUtil;
import com.msb.crm.vo.SaleChance;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 前台访问后台的入口
 * 控制层:注入该类的Service层对象
 */
@Controller
@RequestMapping("sale_chance")
public class SaleChanceController extends BaseController {
    @Resource
    private SaleChanceService saleChanceService;

    /**
     * 营销机会分页查询控制器
     * @param saleChanceQuery
     * @return
     */
    @RequestMapping("list")
    @ResponseBody
    public Map<String,Object> querySaleChanceByParams(SaleChanceQuery saleChanceQuery){
        return saleChanceService.querySaleChanceByParams(saleChanceQuery);
    }

    /**
     * 营销机会管理页控制器:(点击主页的营销机会管理按钮)控制器返回营销机会管理页面saleChance.ftl
     */
    @RequestMapping("index")
    public String index(){
        return "saleChance/sale_chance"; // 路径写正确才会有下划线
    }

    /**
     * 添加操作:添加营销机会数据
     * @param saleChance
     * @param request
     * @return com.msb.crm.base.ResultInfo
     */
    @PostMapping("add")
    @ResponseBody
    public ResultInfo addSaleChance(SaleChance saleChance, HttpServletRequest request){
        System.out.println("添加");
        //从cookie中获取当前用户登录名
        String userName = CookieUtil.getCookieValue(request,"userName");
        //把用户名设置到当前对象中
        saleChance.setCreateMan(userName);
        //调用Service层的添加方法:把创建人的默认值填进去
        saleChanceService.addSaleChance(saleChance);
        System.out.println("操作");
        //调用方法返回ResultInfo
        return success("添加营销机会数据成功");
    }

    /**
     * 更新操作:营销机会数据
     * @param saleChance
     * @return com.msb.crm.base.ResultInfo
     */
    @PostMapping("update")
    @ResponseBody
    public ResultInfo addSaleChance(SaleChance saleChance){
        //调用Service层的添加方法:把更新值填进去
        saleChanceService.updateSaleChance(saleChance);
        //调用方法返回ResultInfo
        return success("更新营销机会数据成功");
    }

    /**
     * 进入添加/修改营销机会数据弹出框页面
     */
    @RequestMapping("toSaleChancePage")
    public String toSaleChancePage(Integer saleChanceId,HttpServletRequest request){
        //判断saleChanceId是否为空
        if (saleChanceId != null){
            //不为空,则是要执行修改操作,利用Id把后台查到的数据放入前台弹出层
            SaleChance saleChance = saleChanceService.selectByPrimaryKey(saleChanceId);
            //查到的数据放入请求域
            request.setAttribute("saleChance",saleChance);
        }
        return "saleChance/add_update";
    }

    @PostMapping("delete")
    @ResponseBody
    public ResultInfo deleteSaleChance(Integer[] ids){
        //调用service层删除方法
        saleChanceService.deleteBatch(ids);
        return success("营销机会数据删除成功!");
    }

}
         2、前端代码实现
            2.1、找到按钮控制器

                找到主页main.ftl的“营销机会管理”按钮的控制器路径

            2.2、controlller层返回申请的页面

                可以看到我们的controlller层已经写好了跳转页面的方法

点击主页面按钮:后台控制器会给我们返回 请求的 营销机会管理页面资源

            2.3、接收后台返回的页面资源

        页面资源代码(saleChance.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="customerName"
						   class="layui-input
					searchVal" placeholder="客户名" />
				</div>
				<div class="layui-input-inline">
					<input type="text" name="createMan" class="layui-input
					searchVal" placeholder="创建人" />
				</div>
				<div class="layui-input-inline">
                    <select name="state"  id="state">
                        <option value="" >分配状态</option>
                        <option value="0">未分配</option>
                        <option value="1" >已分配</option>
                    </select>
				</div>
				<a class="layui-btn search_btn" data-type="reload"><i
							class="layui-icon">&#xe615;</i> 搜索</a>
			</div>
		</form>
	</blockquote>
	<#--页面放置一个元素 <table id="xxx"></table>,然后通过 table.render() 方法指定该容器-->
	<table id="saleChanceList" class="layui-table"  lay-filter="saleChances"></table>

<#--头部工具栏-->
	<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 delNews_btn" lay-event="del">
				<i class="layui-icon">&#xe608;</i>
				删除
			</a>
		</div>
	</script>


	<!--行工具栏-->
	<script id="saleChanceListBar" 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}/js/saleChance/sale.chance.js"></script>

</body>
</html>

 页面资源代码(saleChance.ftl)在浏览器显示效果

            2.4、绑定监听事件

                然后在sale.chance.js文件中给页面中按钮绑定对应的监听事件,使按钮生效 

layui.use(['table','layer'],function(){
    var layer = parent.layer === undefined ? layui.layer : top.layer,
        $ = layui.jquery,
        table = layui.table;

    /**
     * 加载数据表格
     */
    //营销机会列表展示,指定sale_chance.ftl页面中id="saleChanceList"容器元素
    var tableIns = table.render({
        //获取选中行需要的属性,该属性被监听后可获取数据
        id:'saleChanceTable',
        //容器元素的Id属性值
        elem: '#saleChanceList',
        //访问数据的url,后台的数据接口
        url : ctx+'/sale_chance/list',
        //单元格最小宽度
        cellMinWidth : 95,
        //开启分页
        page : true,
        //容器高度 full-差值
        height : "full-125",
        //自定义每页显示条数
        limits : [10,15,20,25],
        //每页默认显示数据条数
        limit : 10,
        //头部工具栏
        toolbar: "#toolbarDemo",
        //表头
        cols : [[
            //type:设定列类型(这里设为复选框列)
            {type: "checkbox", fixed:"center"},
            //要求field属性的值要与返回数据中对应属性字段名一致
            //title:给列字段设置名  ,fixed:固定列,sort:是否允许排序
            {field: "id", title:'编号',sort:"true",fixed:"true"},
            {field: 'chanceSource', title: '机会来源',align:"center"},
            {field: 'customerName', title: '客户名称', align:'center'},
            {field: 'cgjl', title: '成功几率', align:'center'},
            {field: 'overview', title: '概要', align:'center'},
            {field: 'linkMan', title: '联系人',  align:'center'},
            {field: 'linkPhone', title: '联系电话', align:'center'},
            {field: 'description', title: '描述', align:'center'},
            {field: 'createMan', title: '创建人', align:'center'},
            {field: 'createDate', title: '创建时间', align:'center'},
            {field: 'uname', title: '指派人', align:'center'},
            {field: 'assignTime', title: '分配时间', align:'center'},
            {field: 'state', title: '分配状态', align:'center',templet:function(d){
                //调用函数,返回格式化结果。格式化函数定义在下面
                return formatterState(d.state);
                }},
            {field: 'devResult', title: '开发状态', align:'center',templet:function (d) {
                    //调用函数,返回格式化结果。格式化函数定义在下面
                    return formatterDevResult(d.devResult);
                }},
            //绑定行工具栏
            {title: '操作', templet:'#saleChanceListBar',fixed:"right",align:"center", minWidth:150}
        ]]
    });
    
    /**
     * 监听
     * 表格重载
     * 多条件查询
     * 给sale_chance.ftl页面 的搜索按钮绑定点击事件
     */
    
    $(".search_btn").on("click",function () {
        
        tableIns.reload("saleChanceListTable",{
            page:{//重新从第一页开始
                curr:1
            },
            where:{//设置需要传递给后端的参数
                customerName:$("input[name='customerName']").val(),// 客户名
                createMan:$("input[name='createMan']").val(),// 创建人
                state:$("#state").val()    //分配状态
            }
        })
    });
    
    /**
     * 监听
     * 监听头部工具栏按钮:添加、删除
     *  格式:table.on('toolbar(对应.ftl数据表格的lay_filter属性值)',function (obj) {})
     *  执行删除操作时有参数要传进来:需要删除的行记录id
     * 
     * 点击更新按钮后调用openSaleChanceDialog函数
     *  就会向后台Controller发送toSaleChancePage请求
     */

    table.on('toolbar(saleChances)',function (data) {
        if (data.event == "add"){
            //调用添加操作函数
            openSaleChanceDialog();

        }else if (data.event == "del"){
            //执行删除操作
            deleteSaleChance(data);
        }

    });

    /**
     * 监听
     * 行工具栏按钮:编辑、删除
     * 点击更新按钮后调用openSaleChanceDialog函数
     * 就会向后台Controller发送toSaleChancePage请求
     */
    table.on('tool(saleChances)',function (obj) {
        var layEvent =obj.event;
        if(layEvent == "edit"){
            //得到营销机会的Id
            var saleChanceId = obj.data.id;
            //打开修改营销机会数据的弹出层窗口
            openSaleChanceDialog(saleChanceId);
        }else if(layEvent == "del"){//删除操作
            //弹出确认框,询问用户是否确认删除
            layer.confirm("确认删除当前记录?",{icon: 3, title: "机会数据管理"},function (index) {
                //关闭确认框
                layer.close(index);
                //发送ajax请求,删除记录
                $.ajax({
                    type:"post",
                    url:ctx+"/sale_chance/delete",
                    data:{
                        ids:obj.data.id
                    },
                    success:function (result) {
                        //判断删除结果
                        if (result.code==200){
                            //提示成功
                            layer.msg("删除成功",{icon:6});
                            //刷新表格
                            tableIns.reload();
                        }else {
                            //提示失败
                            layer.msg(result.msg,{icon:5});
                        }
                    }

                });

            });
        }
    });

    /**
     * 定义格式化函数
     * 0-未分配
     * 1-已分配
     * 其他=未知
     * @param state
     * @returns {string}
     */
    function formatterState(state){
        if(state === 0){
            return "<div style='color:yellow '>未分配</div>";
        }else if(state === 1){
            return "<div style='color: green'>已分配</div>";
        }else{
            return "<div style='color: red'>未知</div>";
        }
    }

    /**
     * 函数
     * 0-未开发
     * 1-开发中
     * 2-开发成功
     * 3-开发失败
     */
    function formatterDevResult(value){

        if(value === 0){
            return "<div style='color: yellow'>未开发</div>";
        }else if(value === 1){
            return "<div style='color: #00FF00;'>开发中</div>";
        }else if(value === 2){
            return "<div style='color: #00B83F'>开发成功</div>";
        }else if(value === 3){
            return "<div style='color: red'>开发失败</div>";
        }else {
            return "<div style='color: #af0000'>未知</div>"
        }
    }

    /**
     * 函数
     * 批量删除函数:删除营销机会数据
     * @param data
     */
    function deleteSaleChance(data) {
        //获取数据表格选中的行数:table.checkStatus("数据表格的id属性value");
        var checkStatus = table.checkStatus("saleChanceTable");
        console.log(checkStatus);
        //获取所有被选中的记录对应的数据,下面data是能从控制台获取到的字段名,里面包含选中行记录
        var salChanceData = checkStatus.data;
        //判断用户是否选择某几条记录(即选中行的长度是否大于0)
        if (salChanceData.length < 1) {
            layer.msg("请选择要删除的记录!", {icon: 5});
            return;
        }
        //询问用户是否确认删除
        layer.confirm('您是否确认删除选中记录', {icon: 3, title: '营销机会管理'}, function (index) {
            //关闭确认框
            layer.close(index)
            //要传递的参数是数组  举例:ids=1&ids=2&ids=3
            var ids = "ids="
            //循环选中的行记录数据方便进行拼接
            for (var i = 0; i < salChanceData.length; i++) {
                if (i < salChanceData.length - 1) {
                    ids = ids + salChanceData[i].id + "&ids="
                } else {
                    ids = ids + salChanceData[i].id
                }
            }
            $.ajax({
                type: "post",
                url: ctx + "/sale_chance/delete",
                data: ids,//传递的实参数组
                dataType: "json",
                success: function (result) {
                    if (result.code === 200) {
                        //提示成功
                        layer.msg("删除成功", {icon: 6});
                        //刷新表格
                        tableIns.reload();
                    } else {
                        //提示失败
                        layer.msg(result.msg, {icon: 5});
                    }
                }
            });

        });

    }
    
    /**
     * 函数:打开添加/更新 弹出框:
     */
    function openSaleChanceDialog(saleChanceId) {
        //弹出层add.update.ftl标题
        var title="<h3>营销机会管理-机会添加</h3>";
        var url=ctx+"/sale_chance/toSaleChancePage";

        //判断营销机会ID是否为空
        if (saleChanceId != null && saleChanceId !== ''){
            //非空则当前执行修改操作
            title ="<h3>营销机会管理-更新信息</h3>";
            //请求地址传递营销机会的ID给controller层
            url +='?saleChanceId=' + saleChanceId;
        }
        //弹出层(iframe)
        layui.layer.open({
            title:title,
            type:2,
            area:["700px","500px"],
            maxmin:true,
            content:url
        })
    }
});
             2.5、接收后台返回的页面资源

                  点击上述页面中 添加/编辑 的按钮后台会给我们返回请求资源:弹出层页面资源

        页面资源代码(add.update.ftl) 

<!DOCTYPE html>
<html>
<head>
    <#include "../common.ftl">
</head>
<body class="childrenBody">
<form class="layui-form" style="width:80%;">
    <#--设置营销机会Id的隐藏域-->
    <input type="hidden" name="id"  value="${(saleChance.id)!}">
    <#--设置指派人的隐藏域Id,如果value不为空,则会被Ajax根据id属性获取到值来做判断-->
    <input type="hidden" id="assignManId"  value="${(saleChance.assignMan)!}">

    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">客户名称</label>
        <div class="layui-input-block">
            <input type="text" class="layui-input"
                   lay-verify="required" name="customerName" id="customerName"  value="${(saleChance.customerName)!}"  placeholder="请输入客户名称">
        </div>
    </div>
    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">机会来源</label>
        <div class="layui-input-block">
            <input type="text" class="layui-input"
                   name="chanceSource" id="chanceSource" placeholder="请输入机会来源" value="${(saleChance.chanceSource)!}">
        </div>
    </div>
    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">联系人</label>
        <div class="layui-input-block">
            <input type="text" class="layui-input"
                   name="linkMan"  lay-verify="required"
                   placeholder="请输入联系人" value="${(saleChance.linkMan)!}">
        </div>
    </div>

    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">联系电话</label>
        <div class="layui-input-block">
            <input type="text" class="layui-input"
                   lay-verify="phone" name="linkPhone" id="phone" placeholder="请输入联系电话" value="${(saleChance.linkPhone)!}">
        </div>
    </div>
    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">概要</label>
        <div class="layui-input-block">
            <input type="text" class="layui-input"
                   name="overview"  id="phone" placeholder="请输入概要" value="${(saleChance.overview)!}">
        </div>
    </div>
    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">成功几率(%)</label>
        <div class="layui-input-block">
            <input type="text" class="layui-input"
                   name="cgjl" placeholder="请输入成功几率" value="${(saleChance.cgjl)!}">
        </div>
    </div>
    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">机会描述</label>
        <div class="layui-input-block">
            <textarea placeholder="请输入机会描述信息" name="description" class="layui-textarea">${(saleChance.description)!}</textarea>
        </div>
    </div>
    <div class="layui-form-item layui-row layui-col-xs12">
        <label class="layui-form-label">指派给</label>
        <div class="layui-input-block">
            <select name="assignMan" id="assignMan">
                <option value="" >请选择</option>
            </select>
        </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="addOrUpdateSaleChance">确认
            </button>
            <button class="layui-btn layui-btn-lg layui-btn-normal" id="closeBtn">取消</button>
        </div>
    </div>
</form>
<script type="text/javascript" src="${ctx}/js/saleChance/add.update.js"></script>
</body>
</html>

页面资源代码(add.update.ftl)在浏览器的显示效果示例:点击添加按钮后页面出现弹出框

            2.6、绑定监听事件

                弹出层的按钮我们在add.update.js文件中绑定对应的监听事件,使弹出层按钮生效

代码段如下:

layui.use(['form', 'layer'], function () {
    var form = layui.form,
        layer = parent.layer === undefined ? layui.layer : top.layer,
        $ = layui.jquery;

    /**
     * 给“确认”按钮绑定监听submit表单事件
     */
    form.on('submit(addOrUpdateSaleChance)',function (data) {
        //提交数据时显示的加载效果层
        var index= top.layer.msg("数据提交中,请稍后...",{
                icon:16,
                time:false,//不关闭
                shade:0.8});//设置遮罩透明度
        //发送ajax请求,接收回调函数返回值
        var url = ctx+"/sale_chance/add";//添加操作

        //通过判断saleChanceId是否为空来判断当前执行添加还是修改操作
        //如果为空,则表示执行添加操作,如果不为空,则要进行修改操作
        //获取隐藏域的Id
        var saleChanceId =$("[name = 'id']").val();
        //若Id不为空
        if (saleChanceId != null && saleChanceId !=''){
            //执行更新操作
            url = ctx + "/sale_chance/update";
        }

        $.post(url,data.field,function (result) {
            //判断操作是否成功
            if(result.code==200){
                layer.msg("操作成功",{icon:6});
                //关闭加载层
                layer.close(index);
                //关闭弹出层
                layer.closeAll("iframe");
                //刷新父页面:显示加载的数据
                parent.location.reload();
            }else{
                layer.msg(result.msg,{icon:5});
            }
        });
        //阻止表单提交
        return false;
    });

    /**
     * 给“取消”按钮绑定关闭弹出层事件:
     * 一点击取消,弹出框关闭
     */
    $("#closeBtn").click(function () {
        var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
        parent.layer.close(index); //再执行关闭
    })


    /**
     * 加载”指派人“下拉框
     */
    $.ajax({
        type:"get",
        url:ctx + "/user/queryAllSales",
        data:{},
        success:function (data) {
            //console.log(data);
            //判断返回数据不为空
            if (data != null){
                //获取隐藏域设置的指派人ID
                var assignManId = $("#assignManId").val();
                //遍历回调函数形参得到的返回数据
                for (var i =0;i<data.length;i++){
                    //设置下拉选项
                    var opt = "<option value='"+data[i].id+"'>"+data[i].uname+"</option>";

                    //如果循环得到的Id与隐藏域的Id相等,则表示被选中
                    if (assignManId == data[i].id){
                        //下拉选项被选中,设置一个selected属性
                        opt = "<option value='"+data[i].id+"'selected>"+data[i].uname+"</option>";
                    }else{
                        //设置下拉选项
                        opt = "<option value='"+data[i].id+"'>"+data[i].uname+"</option>";
                    }
                    //将下拉项设置到下拉框
                    $("#assignMan").append(opt);
                }
            }
            //重新渲染下拉框内容
            layui.form.render("select");
        }
    })
});

二、问题记录

1、添加操作时点击弹出层的确定按钮报错如下:

纠正:把监听事件的位置放错了,修改后正常 

2、点击行工具栏页面的“编辑”按钮报错如下:

纠正:前端机动组页面监听行工具栏变量Id忘记定义

3、隐藏域id的值写错了

纠正:

4、批量删除数据时点击了复选框后控制台接收不到数据 

 解决:service层少了事务注解

去掉上图中第二个id属性及内容后正确显示: 

 三、结语

        本小节到此开发完营销机会管理模块 ,客户开发计划模块将会在下一篇文章与大家见面,感谢大家的阅读。

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值