其他深度

Odoo 在线学习为什么不只是“看过几个课件”:成员状态、完成度、邀请码与下一课推荐链路讲透

Odoo eLearning 最有意思的地方,不是能上传视频,而是它把“课程”和“成员关系”拆成了独立模型。看懂 slide.channel 与 slide.channel.partner,才能真正理解邀请入学、学习进度、结课邮件和下一课推荐是怎么跑起来的。

其他
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo 的在线学习系统,真正的核心不是课件本身,而是人和课程之间的关系

/home/ubuntu/odoo-temp/addons/website_slides/models/slide_channel.pyslide_channel_partner.py 来看,官方把这件事拆成了两层:

  • slide.channel:课程容器
  • slide.channel.partner:某个成员与这门课之间的关系

这层拆分让系统可以同时处理:

  • 公开课与邀请制课程
  • 学员加入状态
  • 学习完成度
  • 下一课推荐
  • 结课奖励与邮件通知

所以如果你只把 eLearning 理解成“网站上放几篇文章或几个视频”,会低估它很多。

它真正要解决的是:

一个人是否被允许进课、进来后学到哪、学完后系统怎么识别并触发后续动作。


第一层:为什么课程和成员关系不能混在一张表里

slide.channel 负责课程本身:

  • 课程名称和描述
  • 可见性 visibility
  • 报名策略 enroll
  • 课程内容统计
  • 评分、访问量、课程时长
  • 先修课程 prerequisite_channel_ids

但这些都还只是“课程定义”。

真正一旦涉及到某个具体学习者,系统关心的问题就变成:

  • 他有没有被邀请
  • 是刚加入、学习中还是已完成
  • 完成了多少内容
  • 下一节该看什么
  • 是否需要发结课通知

这些显然不该塞回课程主表,于是 Odoo 建了 slide.channel.partner

这张关系表非常关键,它告诉我们:

在 Odoo 的设计里,学习不是课程字段,而是成员关系状态。


第二层:成员状态为什么不是简单二元值

slide.channel.partnermember_status 有四种状态:

  • invited
  • joined
  • ongoing
  • completed

这已经说明 Odoo 不把学员关系理解成“在课里 / 不在课里”这么简单。

它至少想表达三层阶段感:

  1. 还没真正进入课程,只是收到了邀请
  2. 已经加入,但还没开始或刚开始
  3. 正在学习
  4. 已经完成

这对运营很重要,因为不同阶段应该触发不同动作:

  • invited:催加入
  • joined:引导开课
  • ongoing:推动继续学习
  • completed:发祝贺、证书或推荐下一门课

如果状态只有一个 enrolled,系统就没法做精细化学习运营。


第三层:完成度为什么要单独计算,而不是手填

_recompute_completion() 是这套学习关系的核心之一。

它会按:

  • 当前课程
  • 当前成员
  • 已发布且 active 的内容
  • 对应成员是否完成每个 slide.slide

来统计 completed_slides_countcompletion 百分比。

这说明 Odoo 对学习进度的理解非常务实:

  • 进度不是人工标注
  • 也不是纯前端动画效果
  • 而是基于成员和内容之间的完成关系实时汇总

更有意思的是,源码里还保留了状态回退逻辑:

  • 之前已经 100%
  • 后来课程内容增加,或完成记录变化
  • 就可能从 completed 回退到 ongoing

这非常符合真实培训场景。

因为课程不是永远静止的,内容更新后,老学员未必还算“完整学完”。


第四层:为什么系统要计算“下一课”

_compute_next_slide_id() 这个方法特别能体现产品思路。

它不是让学习者自己从目录里慢慢翻,而是直接查出:

  • 当前课程中
  • 已发布、未归档、不是分类节点的内容
  • 按 sequence 排序后
  • 第一条尚未完成的内容

然后作为 next_slide_id

这个设计背后的重点不是技术,而是降低学习摩擦。

因为大部分学习平台真正流失的地方,不是“内容不够多”,而是学员每次回来都不知道下一步该点哪里。

Odoo 通过 next_slide_id 其实在做一件很产品化的事情:

尽量让用户少做导航判断,只做继续学习这个动作。


第五层:邀请链接为什么要做哈希

invitation_link 里会拼上:

  • invite_partner_id
  • invite_hash

其中哈希来自 _get_invitation_hash()

这说明 Odoo 的邀请并不是“发一个公开课程链接”那么粗糙,而是希望:

  • 链接能对应特定成员
  • 邀请关系不能被轻易伪造
  • 邀请制课程仍能保持一定访问控制

也就是说,课程邀请并不只是 UX 文案问题,而是访问边界的一部分。

这点在企业培训、内部文档学习、客户赋能课程里很重要。


第六层:为什么完成课程会触发积分和邮件

_recompute_completion() 发现成员达到 100% 时,会把记录放进 completed_records,随后调用:

  • _post_completion_update_hook()
  • _send_completed_mail()

前者会按课程设置给用户加 karma,后者会发结课邮件。

这说明 Odoo 的课程完成不是一个被动统计值,而是工作流触发点

完成课程后,系统认为应该有后续动作:

  • 奖励
  • 通知
  • 社区活跃度提升
  • 后续课程引导

所以学习平台在 Odoo 里不是静态内容仓库,而是一个会驱动行为的运营系统。


最容易误解的三个点

误区一:课程成员就是 Many2many 关系

表面上像,但官方显然不满足于“有成员名单”这种弱关系,所以单独做了带状态、进度和邀请信息的中间模型。

误区二:完成度是前端展示字段

不是。它依赖内容完成记录和后端聚合,直接影响成员状态、结课通知与奖励。

误区三:课程页面能打开,就说明学习链路完整

也不是。真正完整的是:

  • 可见性
  • 报名策略
  • 成员加入
  • 学习推进
  • 完成触发
  • 后续通知

实战上最该关注什么

如果你在做 Odoo 培训站或客户学院,最该检查的是这些边界:

  1. 课程是公开、登录可见、成员可见,还是仅链接可见
  2. 报名是开放、邀请制,还是依赖群组自动加入
  3. 完成度是否只统计有效发布内容
  4. 内容更新后,老学员状态是否允许重新计算
  5. 结课邮件、奖励和推荐下一课是否要继续扩展

最后一句

Odoo 在线学习最值得学的,不是它怎么放视频,而是它把“学习”真正建模成了一种成员关系演化:

  • 先邀请
  • 再加入
  • 然后学习
  • 最后完成并触发后续动作

理解 slide.channelslide.channel.partner 这组设计之后,你会发现它其实已经很接近一个轻量 LMS 了。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。