Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

readme.md

0 基础 1 天实现 scrm 客户管理

需求调研

预期功能界面如下:

客户管理系统主要是对客户信息进行管理及分析,该系统应支持以下核心功能:

  1. 客户信息管理:添加、编辑、删除和查询客户信息
  2. 客户状态跟踪:记录与客户的所有交互,包括电话、邮件、会议等
  3. 客户统计与分析:图表展示客户信息
  4. 批量客户转移:批量转移客户到其他员工归属下
  5. 动态添加标签:快速添加标签进行分类
  6. 黑名单:添加到黑名单
  7. 公海客户展示:展示暂未分配的公共客户
  8. 权限管理:不同级别的用户访问不同级别的数据和功能

需求分析

结合上述需求调研,我们进行架构设计以及技术选型

数据架构

需要如下两张数据表,分别存储客户信息以及状态更新记录数据

客户信息表

字段 编码 类型 备注
名称 mc 文本 -
性别 xb 枚举 男/女
电话 dh 文本(电话) -
邮箱 yx 文本(邮箱) -
客户阶段 khjd 枚举 新用户/初步沟通/意向客户/无意向客户
添加渠道 tjqd 枚举 app/微信小程序
所属员工 ssyg 文本 -
标签 bq 文本 -
状态 zt 枚举 正常(近期联系)/灰度(长久没联系)/流失(已删除)
客户类型 khlx 枚举 个人/公司
备注 bz 文本 -
企业名称 qymc 文本 -
企业地址 qydz 文本 -
是否拉黑 sflh 布尔 是/否
拉黑时间 lhsj 日期时间 -
拉黑原因 lhyy 文本 -
拉黑操作人 lhczr 文本 -

客户跟踪记录表

字段 编码 类型 备注
客户 ID khId 文本 -
行为 xw 文本 添加黑名单/移出黑名单等
具体描述 jtms 文本 -

前端架构

可以将客户信息管理、客户状态跟踪、批量客户转移、客户添加标签等功能应放在同一个模块进行操作

因此前端分为如下 4 个模块:

  1. 客户列表
    列表展示客户信息,过滤条件为 是否拉黑: false所属员工: 不为空 .
    支持对客户 新增、编辑、查看、删除、转移、添加标签、拉黑、导入、导出

  2. 客户统计
    图表展示 客户总数、今日新增客户数、公海客户数、黑名单数、客户总数趋势、新增客户数趋势、客户状态分布、客户阶段分布等信息

  3. 黑名单
    列表展示已拉黑客户信息,过滤条件为 是否拉黑: true .
    支持对客户 查看、编辑、移出、删除、导入、导出

  4. 公海池
    列表展示未分配员工的客户信息,过滤条件为 是否拉黑: false所属员工: 空 .
    支持对客户 查看、领取、转移、删除、导入、导出

技术选型

客户管理场景比较多变,没有办法进行统一,针对每位使用方均会有对应的定制开发场景

因此这里选择使用 微搭低代码平台 快速搭建该系统

微搭是一个云开发的高性能低代码开发平台,支持快速创建数据源以及应用场景,而且内置链接腾讯 SaaS 生态,能快速对接微信生态、企业微信能力,并支持接入 AI 大模型,将产品与 AI 完美结合

微搭产品优势

需求开发

下方介绍使用微搭进行开发流程

进入微搭

微搭分为公有云和私有云版本

公有云: 通过微搭官方平台进行搭建页面, 打包后在本地部署

私有云: 在本地服务器搭建微搭平台进行开发并发布(功能相比公有云有缺失)

下方介绍两个版本进入方式

公有云开发

进入 微搭官网, 点击免费试用

登录后进入微搭控制台,在主页点击 从空白创建 即可进入编辑器开发页面,这里可以查看 编辑器介绍

私有云开发

安装部署文档: 本地部署管理系统开发工具

数据源开发

微搭中将所有数据集合命名为数据源,其中分为了数据模型、APIs(私有云暂只支持http、postman、openapi)、数据连接器,具体使用参考这里 数据源概述

这里我们使用微搭的数据模型进行开发 数据模型概述

公有云

点击编辑器左侧数据源标签,即可进入数据源编辑页面

私有云

点击云数据库进入数据模型新增页面

点击新建数据模型,名称填写为客户信息,标识为数据模型唯一标识,会自动生成,这里不做调整

点击 创建 按钮,成功后进入模型配置页面,点击编辑,添加字段,按照上述数据架构录入所有字段信息

其中枚举类型字段需要关联数据集,这里点击立即创建

然后录入对应字典数据,这里以客户类型举例,点击立即创建,输入名称为 scrm-客户类型,我们默认使用1/2 选项标识,分别对应个人/企业。点击确定后即可绑定该选项集到客户类型字段上

同理创建 客户跟踪记录表

页面开发

回到页面设计页签,这里我们确认有4个页面模块的开发,因此我们先新建四个空页面

  1. 点击新建页面按钮

  1. 选择表格与表单页模板,数据模型选择刚创建的客户管理,页面布局暂时选择左侧布局

  1. 点击新建后 微搭 会自动帮我们创建三个页面,其中页面布局和页面主体是分开配置的,这里我们先配置出所有页面入口

  1. 这里我们克隆客户列表两次,将克隆出的页面分别命名为黑名单、公海池

并将编辑客户信息、客户信息详情等二级页面分到一个组里,方便后续维护

  1. 所有页面入口创建完毕后,我们进行页面布局的配置,点击头部切换到布局设计,选择左侧布局,点击根据页面一键生成按钮,则帮我们生成好了和上述页面管理目录结构一致的目录树

  1. 因为详情页面不能直接展示在目录上,因此删除客户详情管理目录,ctrl+s保存,点击头部切换到页面设计,即可看到左侧目录数也更新了

下面进行单个模块开发

客户管理

效果如图:

点击编辑器中的列表,在右侧配置中调整如下

  1. 过滤条件为 是否拉黑: false所属员工: 不为空

  1. 排序字段选择 更新时间倒序

  1. 筛选器选择名称、电话、状态、标签等字段

  1. 列排序为如图顺序

  1. 全局按钮包含新增、批量转移客户、批量拉黑、批量删除、导出、导入

其中新增、删除、导出、导入为默认内置的功能按钮,这里我们修改下名称即可

选择左侧大纲树中的全局按钮,点击右侧添加/组件中的按钮即可添加,添加批量转移客户、批量拉黑按钮

  1. 操作按钮包含 查看、编辑、拉黑、删除

其中查看、编辑、删除按钮为默认内置的操作按钮

同添加全局按钮一样,选择左侧大纲树中的操作按钮,添加拉黑按钮,并调整位置到第三位

  1. 客户管理页面初步搭建完成,现在可以点击右上角播放按钮进行预览

点击新建,我们填写好信息点击保存

返回到列表中可以看到已经新增了一条数据

点击编辑也可正常回显,编辑数据后保存也可正常更新数据
下面我们开始完善转移客户、拉黑、自定义列展示功能

批量转移

点击批量转移时需要选择新的所属员工进行更新当前条数据
因此用弹窗进行所属员工选择,确认后修改当前项数据所属员工信息,我们的逻辑线为:

操作步骤:

  1. 新增弹窗组件,用来存放选择所属员工

  1. 点击批量转移按钮事件中的点击事件,选择逻辑分支

  1. 判断条件选择表达式,填入下方表达式
If(!!$w.table1.selectedRecords.length, true, false)

  1. 满足条件时,选择打开弹窗组件

  1. 选择刚新增的弹窗,执行方法选择打开弹窗,modal3为新增的弹窗id

  1. 不满足条件时,选择打开提示弹窗

  1. 标题为 系统提示,内容为 请选择需要转移的客户

  1. 点击右上角保存即可

  2. 继续回到刚新增的modal框中,我们往其中添加一个人员字段

  3. 配置弹窗底部确认按钮事件,选择逻辑分支,判断条件为如下表达式: merber2为刚新增的所属员工人员字段id

If(!!$w.member2.value.length, true, false)
  1. 满足条件时,调用数据源方法

  1. 数据源选择客户管理,方法修改多条

我们只需要更新所属员工字段,所以data参数结构如下:

({
    "ssyg": $w.app.common.transSSYG($w.member2.value),
    "params": {
        "filter": {
            "where": {
                "$and": [{
                    "$and": [{
                        "_id": {
                            "$in": $w.table1.selectedRecords.map(it => it._id)
                        }
                    }]
                }]
            },
            "relateWhere": {}
        }
    }
})

因为人员字段存储为数组格式,而表中的所属员工字段是字符串格式,因此这里在全局新建一个transSSYG方法用来对数组进行转换

具体transSSYG代码如下:

export default function(arr) {
    return arr ? typeof arr === 'string' ? arr : arr.join(',') : ''
}
  1. 查询条件为数据标识等于任意一个所选行的id集合

  1. 成功时关闭弹窗

  1. 继续提示成功消息

  1. 刷新列表当前页

  1. 点击保存,此时完成了整个转移功能开发
拉黑

点击 拉黑、批量拉黑 时需要填写拉黑原因 因此用弹窗进行拉黑原因填写,确认后修改当前项数据 是否拉黑:true拉黑原因: 所填写文本内容拉黑时间: 当前时间拉黑操作人: 当前登录人userId 等信息,我们的逻辑线为:

点击拉黑时弹窗后无法获取到点击行数据,因此需要创建一个全局变量用来存储当前点击行数据,在当前页添加一个对象变量

大体流程和上方批量转移功能相似,这里稍简表示开发流程

  1. 新建弹窗

弹窗中添加一个多行文本字段用来存放拉黑原因

  1. 点击批量拉黑、拉黑时,打开该弹窗

点击批量拉黑时先判断列表是否有选中项,若没有则提示用户需要选择拉黑客户
若点击的是操作列的拉黑按钮,则需要设置全局变量

  1. 编辑弹窗中确认按钮的点击事件

先添加判断条件判断拉黑原因是否为空, 表达式如下:
textarea1 为拉黑原因文本框id

If(!!$w.textarea1.value, true, false)
  1. 若满足条件则判断全局变量 cur_kh 是否有值
If(!!$w.page.dataset.state.cur_kh._id, true, false)
  1. 若有值则更新单条数据,没有值则为批量拉黑,则更新多条数据
    单条更新查询条件如下:

单条更新入参如下:

({
    "lhczr": $w.auth.currentUser.name,
    "lhsj": $w.Now(),
    "lhyy": $w.textarea1.value,
    "sflh": true,
    "params": {
        "filter": {
            "where": {
                "$and": [{
                    "$and": [{
                        "_id": {
                            "$eq": $w.page.dataset.state.cur_kh._id
                        }
                    }]
                }]
            },
            "relateWhere": {}
        }
    }
})

多条更新查询条件如下:

多条更新入参如下:

({
    "sflh": true,
    "lhyy": $w.textarea1.value,
    "lhczr": $w.auth.currentUser.nickName,
    "lhsj": $w.Now(),
    "params": {
        "filter": {
            "where": {
                "$and": [{
                    "$and": [{
                        "_id": {
                            "$in": $w.table1.selectedRecords.map(it => it._id)
                        }
                    }]
                }]
            },
            "relateWhere": {}
        }
    }
})
  1. 更新成功后调用客户跟踪记录表新增记录,单条更新成功后创建单条记录,多条更新成功后创建多条记录

创建单条参数结构如下:

({
    "xw": "添加黑名单",
    "czr": {
        _id: $w.auth.currentUser.userId
    },
    "jtms": $w.textarea1.value,
    "khId": $w.page.dataset.state.cur_kh._id
})

创建多条参数结构如下:

$w.table1.selectedRecords.map(it => ({
    "xw": "添加黑名单",
    "czr": {
        _id: $w.auth.currentUser.userId
    },
    "jtms": $w.textarea1.value,
    "khId": it._id
}))
  1. 关闭弹窗时置空 cur_kh 变量
自定义标签

因需要动态添加标签,且以 tag 的形式展示,因此自定义一个标签组件,在客户列表中自定义列展示,也在新增、编辑等页面展示

具体创建流程如下:

  1. 选择标签列为自定义列

  1. 自定义插槽添加如下节点

循环展示普通容器,普通容器中的文本为标签内容,按钮为删除按钮,我们给这个普通容器添加一点样式

循环展示下方的按钮为新增按钮
数据来源为当前行标签数据,标签存储为字符串格式,因此需要转成数组格式渲染

循环展示数据表达式如下: $w.table1.cell_bq.record 为当前行数据

!!$w.table1.cell_bq.record.bq ?
    $w.table1.cell_bq.record.bq.split(",").map((it) => ({
        label: it,
        value: it,
    })) : [];
  1. 点击新增按钮

点击时设置全局变量 cur_kh 为当前行数据并打开弹窗

弹窗中放入一个文本字段标签内容,点击确定时调用修改单条方法更新当前行数据

更新当前行数据入参为:

$w.page.dataset.state.cur_kh 为当前行信息
$w.input1.value 弹窗中文本内容

({
    "bq": $w.page.dataset.state.cur_kh.bq ? `${$w.page.dataset.state.cur_kh.bq},${$w.input1.value}` : $w.input1.value,
    "params": {
        "filter": ({
            "where": {
                "$and": [{
                    "$and": [{
                        "_id": {
                            "$eq": $w.page.dataset.state.cur_kh._id
                        }
                    }]
                }]
            },
            "relateWhere": {}
        })
    }
})

并调用客户跟踪记录表新增记录,参数结构如下:

({
    "xw": "添加标签",
    "czr": {
        _id: $w.auth.currentUser.userId
    },
    "jtms": `添加【${$w.input1.value}标签`,
    "khId": $w.page.dataset.state.cur_kh._id
})
  1. 关闭弹窗时置空 cur_kh 变量

  2. 点击删除按钮

点击删除按钮时弹窗进行二次确认,成功后获取当前行数据进行更新即可,参数如下: $w.table1.cell_bq.record 为当前行数据 $w.index_repeater1 为当前点击删除按钮的下标

({
    "bq": $w.table1.cell_bq.record.bq.split(',').filter((_, idx) => idx !== $w.index_repeater1).join(','),
    "params": {
        "filter": ({
            "where": {
                "$and": [{
                    "$and": [{
                        "_id": {
                            "$eq": $w.table1.cell_bq.record._id
                        }
                    }]
                }]
            },
            "relateWhere": {}
        })
    }
})
客户编辑页面

  1. 因需要展示客户动态, 因此可以通过 tab 来分别展示基本信息、客户动态
  2. 是否拉黑拉黑 时展示拉黑原因模块展示拉黑相关信息

  1. 客户类型公司 时展示公司模块表单可录入公司信息

  1. 客户动态用数据列表展示选择数据模型为 客户跟踪记录

数据筛选条件如下:

  1. 所属员工字段改为人员字段,因人员字段可以接收字符串格式数据展示,但是存储的数据格式为数组,因此在保存时需要对该字段转为字符串,将表单的提交事件参数改为如下:
({
    ...$w.form2.submitParams,
    _id: $w.page.dataset.params._id,
    data: {
        ...$w.form2.submitParams.data,
        ssyg: $w.app.common.transSSYG($w.form2.submitParams.data.ssyg)
    },
})
  1. 标签字段在详情页中也与列表项中一致

创建一个容器,用文本字段代替label标签,用循环展示组件展示标签内容,后方添加一个按钮用来新增
循环展示组件的内容和外部列表的标签列一致

循环展示组件数据为当前表单项的标签字段数据,因表单中标签数据为字符串,因此需要转成数组赋值给循环组件

表达式内容如下:

!!$w.form2.value.bq ? $w.form2.value.bq.split(',').map(it => ({
    "label": it,
    "value": it,
})) : []

点击新增按钮时,需要弹窗填写新增标签内容,同外部列表操作方式一致 在当前页面中新增一个弹窗容器

点击新增按钮打开弹窗,弹窗中放置一个文本字段

点击弹窗确认按钮时,判断标签内容是否填写,判断成功后执行js脚本,将当前表单的标签字段值重新赋值,加上新增标签内容

js脚本如下: $w.input4.value 为弹窗中文本内容

({
    event
}) => {
    const bq = $w.input4.value
    if ($w.form2.value.bq) {
        $w.input1.setValue({
            value: `${$w.form2.value.bq},${bq}`
        })
    } else {
        $w.input1.setValue({
            value: bq
        })
    }
}
客户新增页面

因新增页面不展示客户动态,因此复制编辑页面一份,删除 tab 组件,只保留主表单子段
修改表单场景为新增

提交事件参数调整如下:

({
    ...$w.form2.submitParams,
    data: {
        ...$w.form2.submitParams.data,
        ssyg: $w.app.common.transSSYG($w.form2.submitParams.data.ssyg)
    }
})
客户详情页面

详情页面和编辑页面一致,因此可以共用编辑页面,列表点击查看跳转详情页面时选择编辑页面, formType 传递为 read

编辑页面中的提交按钮,标签删除、新增按钮均需判断当前表单是否不为只读场景

是否可见表达式如下:

$w.page.dataset.params.formType !== "read"

客户统计

效果如图:

图表展示如下维度客户信息

名称 图表类型 数据源
客户总数 统计卡片 客户信息/统计
今日新增客户数 统计卡片 客户信息/统计
公海客户数 统计卡片 客户信息/统计
黑名单数 统计卡片 客户信息/统计
客户总数趋势 折线图 自定义APIs
新增客户数趋势 折线图 客户信息
客户状态分布 饼图 事件流/自定义变量
客户阶段分布 饼图 事件流/自定义变量
客户总数
  1. 使用统计卡片组件进行渲染,数据源选择统计

  1. 筛选规则我们去掉拉黑用户

  1. 字段选择我们选择所有人,统计方式选择计数即可

今日新增客户数
  1. 同客户总数,数据源选择客户信息统计

  2. 过滤条件为:创建事件大于今天0点是否拉黑:false
    今天0点时间戳 new Date(new Date().toLocaleDateString()).getTime()

公海客户数
  1. 同客户总数,数据源选择客户信息统计
  2. 过滤条件为: 所属员工:空是否拉黑:false

黑名单数
  1. 同客户总数,数据源选择客户信息统计

  2. 过滤条件为: 是否拉黑:true

客户总数趋势

该图表主要展示客户信息表数据根据创建时间进行累加,因此需要对表数据进行处理,这里使用自定义APIs开发,这里新加一个APIs方法,使用自定义代码进行处理

具体自定义代码如下:

const dayjs = require("dayjs");

module.exports = async function(params, context) {
    const res = await context.callModel({
        dataSourceName: "khxx_dpevgv2", // 数据模型名称
        methodName: "wedaGetRecordsV2", // 方法名
        params: {
            select: {
                createdAt: true,
            },
            orderBy: [{
                createdAt: "asc",
            }, ],
        },
    });

    const formatStemp = (time) => {
        return dayjs(time).format("YYYY-MM-DD");
    };

    const transData = ({
        x,
        y
    }) => {
        return {
            XLabel: {
                Value: x
            },
            YLabels: [{
                Name: "总数",
                Value: y
            }],
        };
    };

    const getX = (data) => {
        return data.XLabel.Value;
    };

    const getY = (data) => {
        return data.YLabels[0].Value;
    };

    const result = res.records.reduce((arr, itm) => {
        if (!arr.length) {
            arr.push(
                transData({
                    x: formatStemp(itm.createdAt),
                    y: 1,
                })
            );
        } else if (getX(arr[arr.length - 1]) === formatStemp(itm.createdAt)) {
            arr[arr.length - 1].YLabels[0].Value += 1;
        } else {
            arr.push(
                transData({
                    x: formatStemp(itm.createdAt),
                    y: getY(arr[arr.length - 1]) + 1,
                })
            );
        }
        return arr;
    }, []);

    return {
        result
    };
};
新增客户趋势

该图标需要根据创建时间按天累计进行展示,因此直接使用折线图即可,选择x轴维度为创建时间,y轴统计方式为计数

客户状态分布/客户阶段分布

该图表需要对数据的状态、客户阶段进行翻译 (该两字段为枚举),然后对客户信息表数据根据状态、阶段进行统计计数
操作步骤如下:

  1. 当前页面新建对象变量:pieChatData

  1. 当前页面新建 事件流:setPieChatData

  2. setPieChatData 中第一步获取 客户信息表 全量数据    因这里只需要 状态、客户阶段 字段,因此配置 关联表查询选择 (对象)如下:

{
    "zt": true,
    "khjd": true
}

  1. 获取数据成功后执行如下js代码:
({
    event
}) => {
    const arr = event.detail.records;

    const transData = ({
        x,
        y
    }) => {
        return {
            XLabel: {
                Value: x
            },
            YLabels: [{
                Name: "总数",
                Value: y
            }],
        };
    };

    const formatVal = (val, code) => {
        return $w.app.utils.formatEnum(val, code, $w.app);
    };

    const getChatVal = (type, code) => {
        return Object.entries(newArr[type]).map(([key, value]) => {
            const newKey = key === "other" ? "未知" : formatVal(key, code);
            return transData({
                x: newKey,
                y: value
            });
        });
    };

    const newArr = arr.reduce(
        (obj, itm) => {
            const ztKey = itm.zt || "other";
            obj["zt"][ztKey] = obj["zt"][ztKey] ? obj["zt"][ztKey] + 1 : 1;

            const jdKey = itm.khjd || "other";
            obj["jd"][jdKey] = obj["jd"][jdKey] ? obj["jd"][jdKey] + 1 : 1;

            return obj;
        }, {
            zt: {},
            jd: {},
        }
    );

    const obj = {
        zt: getChatVal("zt", "scrm_status"),
        jd: getChatVal("jd", "scrm_followStatus"),
    };

    $w.page.dataset.state.pieChatData = obj;
};
  1. 当前页面显示时调用 setPieChatData

黑名单

该页面和客户管理页面相似,只是数据过滤条件不同,功能按钮不同,因此复制客户管理页面后进行修改

  1. 过滤条件为 是否拉黑: true

  2. 全局按钮包含 批量移出客户、批量删除、导出、导入

  3. 操作按钮包含 查看、编辑、移出、删除

移出

同客户管理拉黑
点击 移出、批量移出 时弹窗进行移出原因填写,确认后修改当前项数据 是否拉黑:false拉黑原因: 空拉黑时间: 空拉黑操作人: 空 等信息 逻辑线如下:

公海池

该页面和客户管理页面相似,只是数据过滤条件不同,功能按钮不同,因此复制客户管理页面后进行修改

  1. 过滤条件为 是否拉黑: false所属员工:空

  2. 全局按钮包含 新建、批量删除、批量转移客户、批量领取、导出、导入

  3. 操作按钮包含 查看、领取、删除

批量转移

同客户管理批量转移

登录

进入左侧应用设置,选择访问控制,其中选择登录后访问,选择账号密码登录

退出登录

我们在这里添加一个退出登录功能,可以在文档中心查询退出登录功能如何实现

这里我们点进去看到可以通过点击按钮执行js脚本完成退出登录功能
如法炮制,我们在编辑器左下角代码区的全局区域单击 + 号,在弹出层中选择新建JavaScript方法

在弹窗的代码编辑器中复制上述文档中提示的脚本粘贴进去,修改方法名为 signout 点击右上角保存

继续我们删除设计器左下角产品文档文本组件,修改左侧icon,并添加一个按钮,修改按钮名称以及类型

点击右下角事件中的点击,选择JavaScript方法

选择自定义方法signout

点击事件框右上角保存即可

发布

上述配置完成后,即可发布到体验版查看,发布应用

发布成功后会提供体验版入口,进入即可看到页面

体验版

登录页

首页

客户管理