我们在线索部分已经实现了线索的录入和线索的跟进,尝试着用agent的能力去做智能评估。但问题是云开发本质是一种serverless无服务架构,他要求结果即刻返回。agent需要一系列的推导,很容易就超时了,目前这种集成是无法顺畅完成的,那就等待技术有进一步发展再引入。

有了线索之后,经过一系列的跟进,有付费意愿的客户会最终做出决策,要么成为学员、要么成为客户,所以如何让线索变成客户就是我们本篇需要探讨的。

1 创建数据模型

线索转化为客户,其实是将线索阶段得到的基本信息复制到客户表里。为了保存转化后的客户信息,需要先搭建数据模型。

点击MySQL数据库,点击+号创建数据模型

输入数据模型的名称和标识

录入客户名称,字段类型选择文本

录入客户类型,字段类型选择枚举,枚举值输入学员客户和项目客户

录入联系电话,类型选择电话

录入微信号,类型选择文本

录入线索摘要,类型选择文本

录入关联线索,类型选择关联关系,关联到线索表

设置数据表权限,选择读取全部数据,修改本人数据,点击创建完成数据模型的创建

2 创建API

在线索管理里,我们准备增加一个转化的操作,让用户自主选择是转化为学员还是客户,或者二者都是。在写入客户的时候,我们要提取线索以及跟进记录的内容,为此需要创建一个后端的API来完成具体的操作。

点击资源连接,创建API

选择自定义代码

录入API的名称和标识

输入方法的名称和标识

输入如下代码

/**
 * 线索转化 API(CloudBase 低码平台服务端函数)
 * 入参:leadId(线索标识)、summary(线索摘要)、type(客户类型)
 * 逻辑:
 * 1) 根据 leadId 查询 crm_leads 获取基础信息(姓名、手机号、微信等)
 * 2) 检查 customers 是否已存在同一线索的客户,避免重复创建
 * 3) 创建 customers 记录,写入 name/phone/wechat/type/summary/lead_id
 * 4) 返回创建结果(或已存在的客户信息)
 *
 * 参考:
 * - 数据模型 CRUD:wedaCreateV2 / wedaGetItemV2 / wedaGetRecordsV2
 * - 复杂查询:wedaGetRecordsV2 + filter.where
 *
 * 提示:此函数应部署在 CloudBase 低码平台的「业务逻辑」/「服务」中,
 * 在平台运行时通过 context.callModel 访问数据模型。
 */

module.exports = async function(params, context){
  const p = params ||{}
  const leadId = p.leadId
  const summary = typeof p.summary ==='string' ? p.summary :''
  const type= p.type

  // 参数校验
if(!leadId){
return{ code: 400, message: '缺少参数:leadId'}
}
if(!type){
return{ code: 400, message: '缺少参数:type(客户类型)'}
}


  try {
    // 1) 查询线索基础信息
    const leadQuery = await context.callModel({
      dataSourceName: 'crm_leads',
      methodName: 'wedaGetRecordsV2',
      params: {
        // 仅通过 _id 精确匹配
        filter: { where: { _id: {$eq: leadId }}},
        select: {$master:true},
},
      fetchOption: { useAdmin: true},
})

    // 解析 records 字段(与平台实际返回一致)
let leadRecords = leadQuery && leadQuery.records
let lead = Array.isArray(leadRecords) ? leadRecords[0]: null
if(!lead){
return{ code: 404, message: `未找到线索:${leadId}`}
}

    // 2) 去重:检查是否已存在由该线索转化的客户
    const existQuery = await context.callModel({
客户关系管理系统05线索转化
      dataSourceName: 'customers',
      methodName: 'wedaGetRecordsV2',
      params: {
        // 仅通过 lead_id 精确匹配
        filter: { where: { lead_id: {$eq: leadId }}},
        select: {$master:true},
},
      fetchOption: { useAdmin: true},
})

    const existRecordsArr = existQuery && existQuery.records
    const existRecords = Array.isArray(existRecordsArr) ? existRecordsArr :[]
if(existRecords.length >0){
      const existed = existRecords[0]
return{
        code: 200,
        message: '客户已存在(按 lead_id 去重)',
        data: { existed: true, id: existed._id, customer: existed },
}
}

    // 3) 组装客户数据
    const customerData ={
      name: lead.name ||'未命名客户',
      phone: lead.phone ||'',
      wechat: lead.wechat ||'',
      type: type,
      summary,
      // 多对一:直接写入线索记录 id;如平台要求引用对象结构,请按实际模型调整
      lead_id: { _id: leadId },
}

    // 4) 创建客户记录
    const createRes = await context.callModel({
      dataSourceName: 'customers',
      methodName: 'wedaCreateV2',
      params: { data: customerData },
      fetchOption: { useAdmin: true},
})

let newId = createRes &&(createRes.id || createRes.Id )

    try {
      await context.callModel({
        dataSourceName: 'crm_leads',
        methodName: 'wedaUpdateV2',
        params: {
          filter: { where: { _id: {$eq: leadId }}},
          data: { status: '5'},
},
        fetchOption: { useAdmin: true},
})
} catch (e){}
return{
      code: 200,
      message: '线索转化成功',
      data: { id: newId, customer: { id: newId, ...customerData }},
}
} catch (err){
return{ code: 500, message: '线索转化失败', error: String(err && err.message ? err.message : err)}
}
}

我们的逻辑是先根据线索ID查询线索信息,然后拷贝到客户表,之后把线索的状态更新为已成交

3 前端调用

后端API写好之后,需要搭建我们的前端操作。在线索管理页面的操作列继续增加一个转化的按钮

在页面组件下边添加一个弹窗组件

在弹窗内容里添加一个标签选择组件,选项设置为转化为学员、转化为客户

给转化按钮配置点击事件,选择打开弹窗

点击info右边的fx,传入所在行的数据标识

给确认按钮设置点击事件,调用数据源方法,选择客户管理的线索转化方法

leadId传入弹窗的入参

转化类型绑定为标签选择的选中值

给转化按钮配置条件展示,只有在状态为1、2、3的任意情况此按钮才可以出现

最终效果

打开线索管理,可以对线索进行转换

点击转化需要选择是转化成学员还是客户

总结

本篇我们介绍了如何将线索转化为客户的功能,涉及到多个表操作的,我们通常都先编制后端的API,然后再在前端进行调用。后端API的好处是,后续如果数据有问题,我们可以通过日志进行排查,如果直接通过可视化他很难看到调用日志,不利于后续的运维排错。