Odoo 14 eLearning模块如何实现章节顺序解锁功能
Odoo 14 eLearning模块章节顺序锁定实现方案
现有实现的核心问题
- 你定义的
previous_category_complete是普通存储字段,默认值固定为True,不会根据当前登录用户的幻灯片完成进度动态计算,完全起不到校验作用 - 模板里的判断逻辑写反了:前序章节没完成的时候应该锁,你现在写的
previous_category_complete is False反而给未完成状态的内容放行了 - 只做前端链接隐藏没用,用户直接拼接幻灯片URL就能直接访问锁定内容,没有后端权限校验等于锁了个寂寞
完整实现步骤
这套方案不需要写自定义JavaScript,所有逻辑都在Odoo后端层处理,兼容性远好于纯前端实现,不会因为前端缓存、JS加载失败出现锁失效问题。
第一步:修正模型层逻辑,用计算字段动态返回当前用户的解锁状态
不要用固定存储的布尔字段,加基于当前登录用户、关联幻灯片完成记录的实时计算字段即可:
from odoo import models, fields from odoo.http import request class SlideSlide(models.Model): _inherit = 'slide.slide' is_locked = fields.Boolean( string='是否锁定', compute='_compute_is_locked', compute_sudo=False ) def _compute_is_locked(self): current_user = request.env.user for slide in self: # 课程管理员/发布者、标记为预览的幻灯片、未归类的幻灯片永远不锁 if slide.channel_id.can_publish or slide.is_preview or not slide.category_id: slide.is_locked = False continue # 按章节排序序号定位前序章节 current_section_seq = slide.category_id.sequence previous_section = request.env['slide.slide.category'].search([ ('channel_id', '=', slide.channel_id.id), ('sequence', '<', current_section_seq) ], order='sequence desc', limit=1) # 没有前序章节即为第一个章节,直接开放 if not previous_section: slide.is_locked = False continue # 校验前序章节下所有幻灯片当前用户是否全部完成 previous_slides = self.env['slide.slide'].search([ ('channel_id', '=', slide.channel_id.id), ('category_id', '=', previous_section.id) ]) completed_count = request.env['slide.slide.partner'].search_count([ ('partner_id', '=', current_user.partner_id.id), ('slide_id', 'in', previous_slides.ids), ('completed', '=', True) ]) slide.is_locked = completed_count != len(previous_slides)
第二步:修正QWeb模板逻辑
替换原有错误的判断规则,锁定状态下不渲染跳转链接,增加明确的锁定标识:
<odoo> <data> <template id="section_lock" inherit_id='website_slides.course_slides_list_slide'> <xpath expr="//div[@class='text-truncate mr-auto']" position="replace"> <div class="text-truncate mr-auto d-flex align-items-center"> <a t-if="not slide.is_locked" class="o_wslides_js_slides_list_slide_link" t-attf-href="/slides/slide/#{slug(slide)}"> <span t-field="slide.name"/> </a> <t t-else=""> <i class="fa fa-lock text-muted mr-2" title="完成前序章节后解锁"></i> <span class="text-muted" t-esc="slide.name"/> </t> </div> </xpath> </template> </data> </odoo>
第三步:增加后端路由拦截,防止URL绕过
继承幻灯片详情的原生路由,访问前先校验锁定状态,直接拦截非法访问:
from odoo.addons.website_slides.controllers.main import WebsiteSlides from odoo.http import request, route class SectionLockSlides(WebsiteSlides): @route() def slide_view(self, slide, **kwargs): if slide.is_locked and not slide.channel_id.can_publish: return request.render('website.403', status=403) return super().slide_view(slide, **kwargs)
补充说明
- 章节排序直接复用eLearning模块自带的
slide.slide.category的sequence字段,你在后台拖拽调整章节顺序,解锁逻辑会自动适配,不需要额外修改配置 - 计算字段为实时计算,用户完成前序章节最后一张幻灯片后,刷新页面下一章就会自动解锁,不需要配置定时任务
- 完成状态读取的是Odoo原生的
slide.slide.partner表,这张表本来就用来存储每个用户的幻灯片完成记录,不需要额外新建存储表
内容的提问来源于stack exchange,提问作者Francesco Garzillo
相关产品推荐
相关产品推荐

