微搭低代码MBA 培训管理系统实战 19——教务管理:从订单到课时卡的自动转化

微搭低代码MBA 培训管理系统实战 19——教务管理:从订单到课时卡的自动转化

目录

前情回顾

上一篇中我们讲解了销售在订单成交后,录入订单。此时订单的状态还是待支付的状态,需要财务确认收款情况。财务人员点击了"确认收款",订单状态变更为 已清账。此时,资金流已经闭环,但学员在系统里还只是一个"商机客户",没有上课的权限。本节我们要解决如何让系统自动识别已付钱的客户,并为其发放"数字资产"——课时卡

本节目标:

  1. 学籍自动转化:将 CRM 中的"客户"自动转录为"正式学员"。
  2. 课时自动充值:根据订单中的产品,自动生成对应的课时卡余额。

一、 数据源设计

在原有订单表的基础上,我们再创建两张表,用来记录学员的学籍和课时卡信息

1.1 学员档案表 (MBA_StudentProfiles)

定位:学员的"基本法",记录自然人属性。

字段名称字段标识字段类型说明
学员ID_id文本主键,系统自动生成
学员姓名student_name文本姓名
手机号mobile文本用于登录或通知
关联客户rel_customer_id关联关系关联 MBA_Customer 表,追溯来源
OpenIDopenid文本学员微信OpenID,用于小程序端登录和权限控制
学籍状态status枚举1-在读、2-休学、3-毕业、4-退费
入学时间enroll_date日期订单支付成功的日期
创建时间created_at日期时间自动生成
更新时间updated_at日期时间自动更新
在这里插入图片描述

1.2 课时卡表 (MBA_LearningCards)

定位:系统的"资产层"。它是财务与教务的交接单,也是待分班列表的数据源。

字段名称字段标识字段类型说明
卡片ID_id文本主键
关联学员rel_student_id关联关系属于哪个学员
关联订单rel_order_id关联关系关联 MBA_Orders 表,追溯交易来源
关联产品rel_prod_id关联关系购买的课程产品(如:MBA面试突击班)
总课时total_hours数字初始发放数
剩余课时remain_hours数字实际可用数(消课扣减此处)
分班状态assign_status枚举核心控制位:1-待分班(pending)、2-已进班(assigned)
关联班级rel_class_id关联关系当前这张卡绑定的班级(方便直接显示)
过期日期expiry_date日期课时卡有效期,默认一年
创建时间created_at日期时间自动生成
更新时间updated_at日期时间自动更新
在这里插入图片描述

二 创建管理页面

2.1 搭建财务布局

目前财务需要专属的工作台来进行资金到账的确认动作,我们来给财务创建一个布局。

点击布局设计,点击新建布局

在这里插入图片描述


选择左侧导航布局

在这里插入图片描述


重命名为财务布局

在这里插入图片描述

2.2 搭建待支付列表页面

点击创建页面的图标,创建订单确认页面,选择财务布局

切换到布局设计,添加菜单

在这里插入图片描述


切回到页面设计,在财务布局的内容插槽里添加布局组件

在这里插入图片描述


修改标题为订单确认

在这里插入图片描述


添加顶部选项卡,标签改为待办、已办

在这里插入图片描述


添加数据表格,数据模型选择订单表

在这里插入图片描述


设置数据筛选,配置为订单状态等于待支付

在这里插入图片描述


将操作列的按钮改为确认支付

在这里插入图片描述

2.3 搭建确认支付弹窗

在页面组件下添加弹窗组件

在这里插入图片描述


添加表单容器,数据模型选择订单表,场景选择更新

在这里插入图片描述


数据标识绑定为弹窗的入参

在这里插入图片描述

将订单的字段的状态改为只读

在这里插入图片描述


财务确认人的选中值绑定为当前登录对象的数据标识

在这里插入图片描述


给确认支付按钮绑定点击事件,打开弹窗,传入所在行的数据

在这里插入图片描述

2.4 自动化开课

当财务选择了已清账,需要自动给学员创建学籍,开通课时卡。我们需要创建一个自定义方法来完成操作。

export default async function afterUpdate({ event, data }){ // data.target 直接包含当前订单的完整信息(包括关联字段) const order = data.target; const orderId = order._id; const customer = order.rel_customer_id; // 关联的客户对象 const product = order.rel_prod_id; // 关联的产品对象 const order_status =$w.select10.value // 判断订单状态是否为"已清账"(3),是则执行开课逻辑 if(order_status ==='3'){ try { await $w.utils.showLoading({ title: '正在开课...'}); // 1. 查询是否已存在学员档案(避免重复创建) const studentRes = await $w.cloud.callDataSource({ dataSourceName: 'MBA_StudentProfiles', methodName: 'wedaGetRecordsV2', params: { filter: { where: { rel_customer_id: {$eq: customer._id }}}, select: {$master:true}}});let studentId;if(studentRes.records && studentRes.records.length >0){ // 更新已有学员档案 const existingStudent = studentRes.records[0]; await $w.cloud.callDataSource({ dataSourceName: 'MBA_StudentProfiles', methodName: 'wedaUpdateV2', params: { data: { status: '1', // 在读 enroll_date: Date.now(), }, filter: { where: { _id: {$eq: existingStudent._id }}}}}); studentId = existingStudent._id;}else{ // 创建新学员档案 const newStudentRes = await $w.cloud.callDataSource({ dataSourceName: 'MBA_StudentProfiles', methodName: 'wedaCreateV2', params: { data: { student_name: customer.name, mobile: customer.phone, rel_customer_id: { _id: customer._id }, openid: null, // 待学员首次登录小程序时绑定 status: '1', // 在读 enroll_date: Date.now(), }}}); studentId = newStudentRes.id;} // 2. 创建课时卡(待分班状态) const expiryDate = new Date(); expiryDate.setFullYear(expiryDate.getFullYear() + 1); await $w.cloud.callDataSource({ dataSourceName: 'MBA_LearningCards', methodName: 'wedaCreateV2', params: { data: { rel_student_id: { _id: studentId }, rel_order_id: { _id: orderId }, rel_prod_id: { _id: product._id }, total_hours: order.product_hours || product.total_hours ||0, remain_hours: order.product_hours || product.total_hours ||0, assign_status: '1', // 待分班 expiry_date: expiryDate.getTime(), }}}); console.log(`学员档案和课时卡创建成功:订单 ${orderId}`);$w.utils.showToast({ title: '自动化开课成功', icon: 'success'});} catch (error){ console.error('自动化开课失败:', error);$w.utils.showToast({ title: '开课失败:' + error.message, icon: 'error'});} finally {$w.utils.hideLoading();}}}

在表单提交的时候,调用此方法

在这里插入图片描述

三 配置门户数据

先创建财务角色

在这里插入图片描述


然后添加人员

在这里插入图片描述


配置财务门户数据

在这里插入图片描述

需要完善一下全局登录方法,添加财务岗位映射关系

 /* * 函数里面访问:通过 app.common.[name] 访问这里定义的方法或值 * 函数外面访问:通过 import(如在页面的 handler 引用的例子:import sayHi from '../../common/[name]') */ export default async function login({ event, data }){ try {$w.utils.showLoading({ title: '加载工作台中...'}); // 1. 从云开发原生 auth 对象中获取当前已登录的手机号 const phone =$w.auth.currentUser?.phone ||$w.input1.value;if(!phone){return$w.utils.showToast({ title: '获取授权信息失败,请重新登录', icon: 'error'});} // 1. 先查询是否是渠道用户 const channelRes = await $w.cloud.callDataSource({ dataSourceName: 'MBA_ChannelPartners', methodName: 'wedaGetRecordsV2', params: { filter: { where: { phone: {$eq: phone }}}, select: {$master: true, }}}); console.log("channelRes", channelRes)if(channelRes.records && channelRes.records.length >0){ // 渠道用户登录成功 const channelInfo = channelRes.records[0];$w.app.dataset.state.currentChannel = channelInfo; // 渠道用户固定角色,用于门户跳转判断 $w.app.dataset.state.userRoles =['ROLE_CHANNEL'];$w.utils.showToast({ title: '渠道登录成功', icon: 'success'});return;} // 2. 根据手机号查询业务库中的用户信息(关联查询部门和岗位) const userRes = await $w.cloud.callDataSource({ dataSourceName: 'MBA_Users', methodName: 'wedaGetRecordsV2', params: { filter: { where: { phone: {$eq: phone }}}, select: {$master: true, department_id: true, position_id: true}}});if(!userRes.records.length){return$w.utils.showToast({ title: '该手机号未在系统中注册,请联系管理员', icon: 'error'});} const user = userRes.records[0]; console.log("user", user) // 3. 异步更新用户的最后登录时间 (不阻塞后续逻辑)$w.cloud.callDataSource({ dataSourceName: 'MBA_Users', methodName: 'wedaUpdateV2', params: { data: { last_login: Date.now()}, filter: { where: { _id: {$eq: user._id }}}}}).catch(e => console.error('更新登录时间失败', e)); // 4. 获取用户关联的角色信息 const roleRes = await $w.cloud.callDataSource({ dataSourceName: 'MBA_RoleUsers', methodName: 'wedaGetRecordsV2', params: { filter: { where: { user_id: {$eq: user._id }}}, select: {$master: true, role_id: true}}}); console.log("roleRes", roleRes) // 提取角色编码 (例如: ['ROLE_ADMIN', 'ROLE_TEACHER']) const roleCodes = roleRes.records.map(item => item.role_id?.code).filter(Boolean); console.log("roleCodes", roleCodes) // 5. 构造全局 User 对象并写入页面状态 const userInfo ={...user, deptInfo: user.department_id, postInfo: user.position_id, }; // 5. 根据岗位信息确定用户类型 const userType = getUserTypeByPosition(user.position_id);$w.app.dataset.state.currentUser = userInfo;$w.app.dataset.state.userRoles = roleCodes;$w.app.dataset.state.userType = userType;} catch (e){ console.error('初始化门户失败', e);$w.utils.showToast({ title: '系统加载失败,请刷新重试', icon: 'error'});} finally {$w.utils.hideLoading();}} // 根据岗位信息确定用户类型 exportfunction getUserTypeByPosition(position){if(!position){return'employee';} const positionName = position.name ||''; const positionCode = position.code ||''; // 岗位到用户类型的映射 const positionToTypeMap ={ // 销售相关岗位 '销售':'sales', '销售经理':'sales-manager', '销售总监':'sales-manager', // 教师相关岗位 '教师':'teacher', '讲师':'teacher', '教授':'teacher', // 其他岗位 '客服':'employee', '行政':'employee', '财务':'finance'}; // 优先根据岗位编码匹配 if(positionCode){if(positionCode.includes('SALES'))return'sales';if(positionCode.includes('TEACHER'))return'teacher';if(positionCode.includes('MANAGER'))return'sales-manager';if(positionCode.includes('POST-FM'))return'finance';} // 其次根据岗位名称匹配 return positionToTypeMap[positionName]||'employee';}

最终效果

财务人员访问首页,输入手机号

在这里插入图片描述


跳转到对应的工作台进行相关的操作

在这里插入图片描述

总结

本篇我们介绍了财务确认相关业务流程的搭建,创建了相关的表结构。在财务人员点击确认后,会自动开通学籍及课时卡信息,下一篇我们介绍班级管理版块,敬请期待。

Read more

免费部署openClaw龙虾机器人(经典)

免费部署openClaw龙虾机器人(经典)

前几天出了个免费玩龙虾的详细教程,很多小伙伴觉得不错,但是还有一些新手留言反馈内容不够详细,这次我将重新梳理一遍,做一期更细致的攻略,同时扩展补充配置好之后的推荐(我认为是必要)操作,争取一篇文章让大家可以收藏起来,随时全套参照复用。 先看效果测试 部署完成基础运行效果测试,你可以直接问clawdbot当前的模型: 1.Token平台准备 首先,还是准备好我们可以免费撸的API平台 这里我找到了两个可以免费使用的API,测试之后执行效率还可以,下面将分别进行细致流程拆解。 1.1 硅基流动获取ApiKey (相对免费方案 推荐) 硅基流动地址:https://cloud.siliconflow.cn/i/6T57VxS2 如果有账号的直接登录,没有的注册一个账号,这个认证就送16元,可以直接玩收费模型,真香。认证完成后在API秘钥地方新建秘钥。 硅基流动里面很多模型原来是免费的,有了16元注册礼,很多收费的模型也相当于免费用了,我体验一下了原来配置免费模型还能用,也是值得推荐的。建议使用截图的第一个模型体验一下,我一直用它。 1.2 推理时代

VLA机器人革命:解析当下10篇最关键的视觉-语言-动作模型论文

VLA机器人革命:解析当下10篇最关键的视觉-语言-动作模型论文

VLA机器人革命:解析当下10篇最关键的视觉-语言-动作模型论文 概览 2024-2026年,机器人领域正经历一场范式转换:从传统的任务特定编程转向视觉-语言-动作(Vision-Language-Action, VLA)模型。这些模型将视觉感知、自然语言理解和动作执行统一在单一框架中,让机器人能够像人类一样理解指令、推理场景并执行复杂操作。 本文精选5篇最fundamental的基础性论文和5篇热度最高的前沿论文,深入剖析VLA领域的核心思想、技术演进和未来方向。这些论文代表了从Google DeepMind、NVIDIA、斯坦福、Physical Intelligence等顶尖机构的最新突破,涵盖了从单臂操作到双臂人形机器人、从模拟环境到真实家庭场景的全方位进展。 Part I: 五篇Fundamental基础性论文 这些论文奠定了VLA领域的理论基础和技术范式,是理解整个领域发展脉络的关键。 1. RT-2: New Model Translates Vision and Language into Action 发表机构:Google DeepMind 时间:

龙虾机器人(OpenClaw)本地部署完全技术指南

龙虾机器人(OpenClaw)本地部署完全技术指南

龙虾机器人(OpenClaw)本地部署完全技术指南 前言:什么是“龙虾机器人”? 在开始部署之前,我们需要明确部署的对象。通常所说的“龙虾机器人”指的是开源项目 OpenClaw(曾用名:Clawdbot、Moltbot)。它由程序员彼得·斯坦伯格开发,是一个开源的、可本地部署的通用型AI代理系统。与ChatGPT等对话式AI不同,OpenClaw被赋予了操作系统的权限:它可以执行终端命令、读写文件、操控浏览器、安装软件,甚至通过MCP协议调用外部工具。 由于其强大的系统操控能力,安全性是部署时需关注的首要问题。官方及社区普遍建议:不要在主力机或存有敏感数据的生产环境直接裸奔部署,最好使用虚拟机、Docker容器或专用硬件(如Mac Mini或AI开发盒子)进行隔离。 第一章:环境准备与核心依赖 在安装OpenClaw之前,必须准备好运行环境。OpenClaw的核心由TypeScript编写,因此Node.js是必不可少的运行环境。此外,根据安装方式的不同,可能还需要Git、Docker或Python环境。 1.1 硬件建议与系统选择 * Linux

爆火 OpenClaw「龙虾」从 0 到 1 保姆级全指南:安装→QQ 机器人→运维→卸载全流程,附全网高频报错解决方案

爆火 OpenClaw「龙虾」从 0 到 1 保姆级全指南:安装→QQ 机器人→运维→卸载全流程,附全网高频报错解决方案

引言:OpenClaw:一爪入魂,万事自动。 🔥 前言:为什么全网都在「养龙虾」? 最近 AI 圈顶流非 OpenClaw(昵称「龙虾」)莫属! 这个能住在你电脑里的 AI 智能体,不仅能读写本地文件、操控浏览器、自动化办公、一键搭建网站,甚至能接入 QQ 变身私人机器人,让你随时随地都能「养虾」调用。 但随之而来的是乱象丛生:网上出现数百元的上门安装服务,甚至深圳腾讯大厦门口曾出现千人排队免费安装的盛况。其实自己安装全程免费,30 分钟就能搞定,还能彻底规避他人操作电脑带来的数据泄露风险! 本文整合OpenClaw 官方权威文档+ 全网高频踩坑解决方案,带你从 0 到 1 零失败上手,从安装配置、QQ 机器人接入、日常运维到彻底卸载,保姆级一步到位,新手也能轻松玩转。 📋 前置准备与安全红线 1.