diff --git a/college/static/src/js/hide_about_edit.js b/college/static/src/js/hide_about_edit.js index f1c0f9b..954e5c4 100644 --- a/college/static/src/js/hide_about_edit.js +++ b/college/static/src/js/hide_about_edit.js @@ -1,22 +1,48 @@ /** * 隐藏「关于页」(yuthon.about.page) 表单右上角的「编辑」按钮。 * - * 原理:form 视图虽已写 edit="false",但教师/管理员组对该模型有写权限时, - * Odoo 18 控制面板仍会渲染「编辑」按钮。CSS 选择器无法稳定命中控制面板 - * (它与 .o_form_view 是兄弟节点,且资产缓存/浏览器兼容性容易失效), - * 因此通过 patch FormController,在当前模型为 yuthon.about.page 时, - * 在 mounted/patched 生命周期里把控制面板中的编辑按钮隐藏掉。 + * 原理:form 视图已写 edit="false",Odoo 18 控制面板本就不该渲染编辑按钮; + * 但为保险(防止某些角色/动作仍带出编辑入口),这里在 FormController 上 patch: + * 当模型为 yuthon.about.page 时,用 MutationObserver 持续监听控制面板, + * 一旦编辑按钮(无论何时、以何种形式出现)被渲染,立刻隐藏。 * * 注意:本文件改动需要「升级模块」才会生效(-d <库名> -u college), - * 并强刷浏览器 (Ctrl+Shift+R)。 + * 并强刷浏览器 (Ctrl+Shift+R)。仅 git pull + 重启不会重建前端资源包。 */ /** @odoo-module **/ import { patch } from "@web/core/utils/patch"; import { FormController } from "@web/views/form/form_controller"; -import { onMounted, onPatched } from "@odoo/owl"; +import { onMounted, onWillUnmount } from "@odoo/owl"; const ABOUT_MODEL = "yuthon.about.page"; +// 判定一个按钮是否为「编辑」按钮(兼容不同渲染形态) +function isEditButton(btn) { + if (!btn || btn.tagName !== "BUTTON") { + return false; + } + if (btn.classList.contains("o_form_button_edit")) { + return true; + } + if (btn.getAttribute("data-hotkey") === "e") { + return true; + } + const text = (btn.textContent || "").trim(); + if (text === "编辑" || text.toLowerCase() === "edit") { + return true; + } + return false; +} + +// 在控制面板内隐藏所有编辑按钮 +function hideAboutEditButtons(root) { + (root || document).querySelectorAll(".o_control_panel button").forEach((btn) => { + if (isEditButton(btn)) { + btn.style.display = "none"; + } + }); +} + patch(FormController.prototype, { setup() { super.setup(); @@ -24,23 +50,19 @@ patch(FormController.prototype, { return; } - const hideEditButton = () => { - // Odoo 18 控制面板中「编辑」按钮的常见形态: - // 1) class="o_form_button_edit" - // 2) 快捷键 data-hotkey="e" 的主按钮 - const selectors = [ - ".o_control_panel .o_form_button_edit", - ".o_control_panel button[data-hotkey='e']", - ]; - for (const selector of selectors) { - document.querySelectorAll(selector).forEach((btn) => { - btn.style.display = "none"; - }); + let observer = null; + onMounted(() => { + hideAboutEditButtons(document); + // 控制面板按钮可能异步/重渲染后才出现,持续监听最稳妥 + const cp = document.querySelector(".o_control_panel"); + const target = cp || document.body; + observer = new MutationObserver(() => hideAboutEditButtons(target)); + observer.observe(target, { childList: true, subtree: true }); + }); + onWillUnmount(() => { + if (observer) { + observer.disconnect(); } - }; - - // 首次渲染及后续 patch 都兜底隐藏,避免异步渲染导致按钮闪现 - onMounted(hideEditButton); - onPatched(hideEditButton); + }); }, }); diff --git a/college/static/src/xml/sidenav_tooltip.xml b/college/static/src/xml/sidenav_tooltip.xml deleted file mode 100644 index 504d77e..0000000 --- a/college/static/src/xml/sidenav_tooltip.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - ue.sidenavWidth < 142 ? (app.label or app.name) : false - right - - - - ue.sidenavWidth < 142 ? (currentApp.label or currentApp.name) : false - right - - - diff --git a/learning_center/models/learning_course.py b/learning_center/models/learning_course.py index b5f66b5..5ec5c22 100644 --- a/learning_center/models/learning_course.py +++ b/learning_center/models/learning_course.py @@ -27,8 +27,8 @@ class LearningCourse(models.Model): syllabus_ids = fields.One2many('course.syllabus', 'course_id', string='教学大纲/教案') syllabus_count = fields.Integer(string='大纲/教案数', compute='_compute_syllabus_count', store=True) # 按类型统计 - syllabus_count_total = fields.Integer(string='大纲总数', compute='_compute_syllabus_count') - lesson_plan_count = fields.Integer(string='教案总数', compute='_compute_syllabus_count') + syllabus_count_total = fields.Integer(string='大纲总数', compute='_compute_syllabus_type_count') + lesson_plan_count = fields.Integer(string='教案总数', compute='_compute_syllabus_type_count') # ==================== 统计资源(通过章节关联) ==================== resource_count = fields.Integer(string='资源总数', compute='_compute_resource_count', store=True) video_count = fields.Integer(string='视频数', compute='_compute_resource_count', store=True) @@ -56,10 +56,14 @@ class LearningCourse(models.Model): for record in self: record.chapter_count = len(record.chapter_ids) - @api.depends('syllabus_ids', 'syllabus_ids.syllabus_type') + @api.depends('syllabus_ids') def _compute_syllabus_count(self): for record in self: record.syllabus_count = len(record.syllabus_ids) + + @api.depends('syllabus_ids', 'syllabus_ids.syllabus_type') + def _compute_syllabus_type_count(self): + for record in self: record.syllabus_count_total = len(record.syllabus_ids.filtered(lambda s: s.syllabus_type == 'syllabus')) record.lesson_plan_count = len(record.syllabus_ids.filtered(lambda s: s.syllabus_type == 'lesson_plan'))