引言:报名,销售旅程的终点,机构运营的起点
在之前的教程中,我们循序渐进地搭建了招生CRM系统的各个模块,从线索管理到跟进记录,再到试听安排。现在,我们来到了整个招生业务的终点,也是教培机构运营的起点——报名管理。
报名不仅仅是数据记录,它涉及多方面的复杂逻辑:
- 学员转化
- 课程与课时
:记录学员报名的具体课程、费用和课时数,为后续排课消课提供数据基础。
- 业绩计算与提成
:记录销售顾问的提成,并处理复杂的退费扣减逻辑,确保财务数据的可追溯性。
- 财务处理
本篇作为本套教程的收官之作,我们将搭建一个完整的报名管理模块,打通从CRM到实际教务管理的最后一公里,展现一个业务的完整闭环。
第一部分:数据模型搭建——报名管理的核心基石
为了支持报名管理的复杂逻辑,我们需要新增几个关键的数据模型:学生表 (Students)、课程表 (Courses)、报名表 (Enrollments) 和 提成表 (Commissions)。
1.1 学生表 (Students)
该表用于将线索转化为正式学员,存储学员的永久信息。
|
|
|
|
|
|
id |
INT
|
|
|
|
full_name |
VARCHAR |
|
|
|
phone_number |
VARCHAR |
|
|
|
source_channel |
VARCHAR |
|
|
|
created_at |
DATETIME |
|
|
|
添加字段,学员姓名(full_name),类型选择文本
添加字段,联系电话(phone_number),类型选择电话
添加字段,来源渠道(source_channel),类型选择枚举
1.2 课程表 (Courses)
该表用于存储教培机构的课程信息,是报名表的数据来源。
|
|
|
|
|
|
id |
INT
|
|
|
|
course_name |
VARCHAR |
|
|
|
total_price |
FLOAT |
|
|
|
total_hours |
INT |
|
|
|
commission_rate |
FLOAT |
|
|
|
添加字段,课程名称(course_name),类型选择文本
添加字段,课程总价(total_price),类型选择数字
添加字段,总课时数(total_hours),类型选择数字
添加字段,销售提成比例(commission_rate),类型选择数字
1.3 报名表 (Enrollments)
这是连接所有业务的核心表,将学员、课程、顾问和财务信息关联起来。
|
|
|
|
|
|
id |
INT
|
|
|
|
student_id |
INT
|
|
|
|
course_id |
INT
|
|
|
|
adviser_id |
INT
|
|
|
|
lead_id |
INT
|
|
|
|
enrollment_at |
DATETIME |
|
|
|
actual_payment |
FLOAT |
|
|
|
payment_status |
ENUM |
(‘paid’, ‘partial’, ‘refunded’)
|
|
|
total_hours_left |
INT |
|
|
|
添加字段,学员ID(student_id),类型选择关联关系,关联到学生表
添加字段,课程ID (course_id),类型选择关联关系,关联到课程表
添加字段,课程顾问ID(adviser_id),类型选择关联关系,关联到课程顾问ID
添加字段,线索ID(lead_id),类型选择关联关系,关联到线索表
添加字段,报名时间(enrollment_at),类型选择日期时间
添加字段,实际支付金额(actual_payment),类型选择数字
添加字段,支付状态(payment_status),类型选择枚举
添加字段,剩余课时数(total_hours_left),类型选择数字
1.4 提成表 (Commissions)
该表用于记录每一笔报名产生的提成,并支持退费扣减的追溯。通过不覆盖历史记录,确保了财务核算的完整性。
|
|
|
|
|
|
id |
INT
|
|
|
|
enrollment_id |
INT
|
|
|
|
adviser_id |
INT
|
|
|
|
commission_amount |
FLOAT |
|
|
|
adjustment_type |
ENUM |
(‘initial’, ‘refund_deduction’)
|
|
|
related_commission_id |
INT
|
|
|
|
created_at |
DATETIME |
|
|
|
添加字段,报名记录ID(enrollment_id),类型选择关联关系,关联到报名表
添加字段,课程顾问ID(adviser_id),类型选择关联关系,关联到销售顾问表
添加字段,提成金额(commission_amount),类型选择数字
添加字段,调整类型(adjustment_type),类型选择枚举
添加字段,关联提成ID(related_commission_id),类型选择关联关系,关联到提成表
第二部分:课程顾问端——转报名功能实现
在课程顾问的“我的线索”页面,当线索试听完成后,我们将提供一个“转报名”按钮。
2.1 “转报名”弹窗表单与核心逻辑
在数据表格的操作列添加一个报名按钮
选择页面组件,添加弹窗组件
弹窗内容下添加表单容器,数据模型选择报名表
给课程顾问ID绑定全局变量的数据标识
给线索ID绑定数据,绑定为弹窗组件的入参
给报名按钮配置点击事件,打开弹窗,传入数据表格所在行的数据标识
2.2 核心功能实现:转报名云函数
云函数代码示例: 创建一个名为 enrollStudent 的云函数。
添加入参
添加如下代码
module.exports=asyncfunction(params, context){ try{ const{ leadId, adviserId, courseId, actualPayment, paymentStatus }= params;
// 参数校验...
// 1. 查询线索信息,用于创建学生记录 const leadRecord =await context.callModel({ dataSourceName:'Leads_jw', methodName:'wedaGetItemV2',// 获取单条数据 params:{ select:{"$master":true}, filter:{// 使用 filter 包裹 where where:{ _id:{ $eq: leadId // 使用 $eq 比较运算符 } } } } }); if(!leadRecord || Object.keys(leadRecord).length==0)thrownewError('Lead not found.');
// 2. 查询课程信息,用于计算提成和课时 const courseRecord =await context.callModel({ dataSourceName:'Courses_jw', methodName:'wedaGetItemV2',// 获取单条数据 params:{ select:{"$master":true}, filter:{// 使用 filter 包裹 where where:{ _id:{ $eq: courseId // 使用 $eq 比较运算符 } } } } }); if(!courseRecord || Object.keys(courseRecord).length==0)thrownewError('Course not found.');
// 3. 创建学生记录(如果不存在) const studentData ={ full_name: leadRecord.full_name, phone_number: leadRecord.phone_number, source_channel: leadRecord.source_channel, }; const studentResult =await context.callModel({ dataSourceName:'Students_jw', methodName:'wedaCreateV2', params:{data: studentData }, }); const studentId = studentResult.id;
// 4. 创建报名记录 const enrollmentData ={ student_id:{_id:studentId}, course_id:{_id:courseId}, adviser_id:{_id:adviserId}, lead_id:{_id:leadId}, actual_payment: actualPayment, payment_status: paymentStatus, enrollment_at:Date.now(), total_hours_left: courseRecord.total_hours,// 剩余课时等于课程总课时 }; const enrollmentResult =await context.callModel({ dataSourceName:'Enrollments', methodName:'wedaCreateV2', params:{data: enrollmentData }, }); const enrollmentId = enrollmentResult.id;
// 5. 计算并创建初始提成记录 const commissionAmount = actualPayment * courseRecord.commission_rate; const commissionData ={ enrollment_id:{_id:enrollmentId}, adviser_id:{_id:adviserId}, commission_amount: commissionAmount, adjustment_type:'1',// 标记为初始提成 }; await context.callModel({ dataSourceName:'Commissions', methodName:'wedaCreateV2', params:{data: commissionData }, });
// 6. 更新线索状态为已报名 await context.callModel({ dataSourceName:'Leads_jw', methodName:'wedaUpdateV2', params:{ data:{status:'5'}, filter:{where:{_id:{$eq: leadId }}} }, });
return{success:true,data:{ studentId, enrollmentId }}; }catch(error){ return{success:false,message: error.message }; } };
2.3 调用云函数
选中表单容器,设置提交事件
讲原理的方法改为我们的API的报名方法
修改入参,改为如下的结构
({leadId:$w.form3.submitParams.data.lead_id._id, adviserId:$w.form3.submitParams.data.adviser_id?._id, courseId:$w.form3.submitParams.data.course_id._id, actualPayment:$w.form3.submitParams.data.actual_payment, paymentStatus:$w.form3.submitParams.data.actual_payment })
总结:从CRM到教务的呈上启下
恭喜!通过本篇教程,我们为招生CRM系统构建了最后的堡垒——报名管理。我们不仅实现了从线索到正式学员的转化,更重要的是,我们通过多张数据表之间的联动和更严谨的提成追溯设计,为后续的教务管理和财务核算打下了坚实的数据基础。
- 数据闭环
:线索、跟进、试听、报名、提成,所有业务环节的数据都已贯通。
- 财务严谨性
:通过“新增记录不覆盖”的设计,确保了提成数据的完整可追溯。
- 功能扩展
:报名表中的total_hours_left字段,为后续的排课、消课、课时统计等教务功能预留了关键数据接口。
至此,我们的“免费又好用”的招生CRM系统系列教程圆满结束。希望本套教程能够帮助您快速掌握低代码平台的应用搭建技巧,并理解如何将复杂的业务逻辑分解并实现。
|