Compare commits
19
Commits
zhou
...
d73bd82769
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d73bd82769 | ||
|
|
0d6d3e0bb9 | ||
|
|
84df154ce2 | ||
|
|
ba32af9e04 | ||
|
|
07c29e451d | ||
|
|
194594ffa5 | ||
|
|
2b89ca6cb5 | ||
|
|
013aa37ebc | ||
|
|
9f909e4833 | ||
|
|
544de24893 | ||
|
|
1b6ea810b2 | ||
|
|
f75aca9fd5 | ||
|
|
aa07c87bbb | ||
|
|
0bcbba4383 | ||
|
|
ad7bc5877d | ||
|
|
2b186521ff | ||
|
|
47dc1c428f | ||
|
|
f5967ae13d | ||
|
|
40a9ed9bd1 |
@@ -58,6 +58,9 @@
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'college/static/src/scss/college_theme.scss',
|
||||
'college/static/src/js/hide_company_menu.js',
|
||||
'college/static/src/js/portal_indicator.js',
|
||||
'college/static/src/xml/portal_indicator.xml',
|
||||
],
|
||||
'web.assets_web_dark': [
|
||||
'college/static/src/scss/college_theme_dark.scss',
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
<field name="end_date">2026-01-15</field>
|
||||
<field name="introduction"><![CDATA[<p>面向零基础开发者,系统讲解 Odoo 18 的模块结构、模型(Model)、视图(View)与控制器(Controller),带你跑通第一个自定义模块。</p>]]></field>
|
||||
<field name="objectives"><![CDATA[<ul><li>理解 Odoo 的 MVC 架构</li><li>能独立创建并安装一个模块</li><li>掌握模型字段与关系(M2O / O2M / M2M)</li></ul>]]></field>
|
||||
<field name="syllabus"><![CDATA[<ol><li>开发环境搭建</li><li>模块清单与目录结构</li><li>模型定义与字段类型</li><li>视图(list / form / kanban)</li><li>菜单与权限(ACL)</li></ol>]]></field>
|
||||
<field name="features"><![CDATA[<p>配套视频讲解 + 可运行示例代码,支持线下实训环境动手练习。</p>]]></field>
|
||||
<field name="student_ids" eval="[(6, 0, [ref('student_wang'), ref('student_01'), ref('student_02'), ref('student_03')])]"/>
|
||||
<field name="state">published</field>
|
||||
@@ -102,7 +101,6 @@
|
||||
<field name="end_date">2026-06-30</field>
|
||||
<field name="introduction"><![CDATA[<p>深入 Odoo 的视图体系:列表、表单、看板、搜索、图形,以及 CSS 与 JS 资产定制。</p>]]></field>
|
||||
<field name="objectives"><![CDATA[<ul><li>掌握 list/form/kanban 视图语法</li><li>能用 inherit 扩展已有视图</li><li>理解静态资源(assets)加载机制</li></ul>]]></field>
|
||||
<field name="syllabus"><![CDATA[<ol><li>视图类型总览</li><li>视图继承与 xpath</li><li>看板与搜索视图</li><li>前端资产与主题定制</li></ol>]]></field>
|
||||
<field name="features"><![CDATA[<p>视频 + PPT 双形态,含实操演练。</p>]]></field>
|
||||
<field name="student_ids" eval="[(6, 0, [ref('student_02'), ref('student_04')])]"/>
|
||||
<field name="state">draft</field>
|
||||
@@ -120,7 +118,6 @@
|
||||
<field name="end_date">2027-01-10</field>
|
||||
<field name="introduction"><![CDATA[<p>以 PPT 讲义为主,讲解 QWeb 报表、PDF 打印与数据导出。</p>]]></field>
|
||||
<field name="objectives"><![CDATA[<ul><li>掌握 QWeb 报表模板</li><li>能定制 PDF 打印</li></ul>]]></field>
|
||||
<field name="syllabus"><![CDATA[<ol><li>报表模型与 action</li><li>QWeb 模板语法</li><li>打印与导出</li></ol>]]></field>
|
||||
<field name="features"><![CDATA[<p>适合线下培训,讲师直接分发 PPT。</p>]]></field>
|
||||
<field name="state">draft</field>
|
||||
</record>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * college
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 18.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-09-21 11:31:00+0000\n"
|
||||
"PO-Revision-Date: 2026-09-21 11:31:00+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"Language: zh_CN\n"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_education
|
||||
msgid "Education"
|
||||
msgstr "教育"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_game
|
||||
msgid "Game"
|
||||
msgstr "游戏"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_backend
|
||||
msgid "Backend"
|
||||
msgstr "后端"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_themes
|
||||
msgid "Themes"
|
||||
msgstr "主题"
|
||||
|
||||
# 以下四项 base 自带翻译已存在,这里补一份,
|
||||
# 保证 college 模块单独升级时这几个类别也一定是中文。
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_tools
|
||||
#: model:ir.module.category,name:base.module_category_hidden_tools
|
||||
msgid "Tools"
|
||||
msgstr "工具"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_uncategorized
|
||||
msgid "Uncategorized"
|
||||
msgstr "未分类"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_localization
|
||||
msgid "Localization"
|
||||
msgstr "本地化"
|
||||
|
||||
#. module: base
|
||||
#: model:ir.module.category,name:base.module_category_manufacturing_maintenance
|
||||
msgid "Maintenance"
|
||||
msgstr "维修"
|
||||
@@ -75,6 +75,7 @@ class SchoolCourse(models.Model):
|
||||
introduction = fields.Html(string='课程介绍', sanitize=True)
|
||||
objectives = fields.Html(string='课程目标', sanitize=True)
|
||||
features = fields.Html(string='课程特色', sanitize=True)
|
||||
syllabus = fields.Html(string='课程大纲', sanitize=True)
|
||||
business_scenario = fields.Html(string='业务情景', sanitize=True)
|
||||
|
||||
# 学员分配
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 隐藏导航栏「公司切换器」(YourCompany 那一块)
|
||||
*
|
||||
* 原理:Odoo 导航栏右侧的系统托盘 (systray) 是一个组件注册表,
|
||||
* web 模块在启动时把 SwitchCompanyMenu 注册了进去(见
|
||||
* odoo18/addons/web/static/src/webclient/switch_company_menu/switch_company_menu.js
|
||||
* 最后一行 registry.category("systray").add(...))。
|
||||
* 这里在资源包加载阶段把它从注册表里摘掉,导航栏就不会渲染它。
|
||||
*
|
||||
* 单公司场景下该组件无意义;如需恢复,删除本文件并把
|
||||
* __manifest__.py assets 里对应的一行去掉即可。
|
||||
*
|
||||
* 注意:本文件改动需要「升级模块 + 重启」才会生效
|
||||
* (-d <库名> -u college 重启主进程),并强刷浏览器 (Ctrl+Shift+R)。
|
||||
*/
|
||||
/** @odoo-module **/
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
registry.category("systray").remove("SwitchCompanyMenu");
|
||||
@@ -0,0 +1,31 @@
|
||||
/** @odoo-module **/
|
||||
import { registry } from "@web/core/registry";
|
||||
import { user } from "@web/core/user";
|
||||
import { Component, onWillStart, useState } from "@odoo/owl";
|
||||
|
||||
export class PortalIndicator extends Component {
|
||||
static template = "college.PortalIndicator";
|
||||
|
||||
setup() {
|
||||
this.state = useState({ label: "" });
|
||||
onWillStart(async () => {
|
||||
// 顺序:管理员 -> 老师 -> 学生(高权限优先)
|
||||
if (await user.hasGroup("base.group_system")) {
|
||||
this.state.label = "管理员端";
|
||||
} else if (await user.hasGroup("college.group_teacher")) {
|
||||
this.state.label = "教师端";
|
||||
} else if (await user.hasGroup("college.group_student")) {
|
||||
this.state.label = "学生端";
|
||||
} else {
|
||||
this.state.label = "用户端";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// sequence 越小越靠右(user_menu 是 0)。想贴最右边用负数。
|
||||
registry.category("systray").add(
|
||||
"college.PortalIndicator",
|
||||
{ Component: PortalIndicator },
|
||||
{ sequence: 1}
|
||||
);
|
||||
@@ -267,3 +267,26 @@
|
||||
p, li { color: $o-main-text-color; }
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 隐藏右上角「公司切换器」(我的学校)
|
||||
// 项目为单学校场景,不需要用户切换公司。
|
||||
// ============================================================
|
||||
.o_switch_company_menu {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
// 角色提示徽章:避免被 Odoo 导航栏 .badge 通知样式影响
|
||||
.o_college_portal_indicator {
|
||||
align-self: center; // 在 systray 中垂直居中,不被拉伸/裁切
|
||||
}
|
||||
|
||||
.o_portal_badge {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.7em;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.2;
|
||||
color: black;
|
||||
white-space: nowrap; // 不换行
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<div t-name="college.PortalIndicator"
|
||||
class="o_college_portal_indicator d-flex align-items-center ms-2">
|
||||
<span class="o_portal_badge" t-esc="state.label"/>
|
||||
</div>
|
||||
</templates>
|
||||
@@ -140,7 +140,6 @@
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="课程内容">
|
||||
<field name="syllabus" readonly="1" string="课程大纲"/>
|
||||
<separator string="课程章节(按顺序学习视频与资料)"/>
|
||||
<field name="chapter_ids" readonly="1">
|
||||
<list>
|
||||
@@ -197,6 +196,10 @@
|
||||
<filter name="group_state" string="状态"
|
||||
context="{'group_by': 'state'}"/>
|
||||
</group>
|
||||
<searchpanel>
|
||||
<field name="course_type" string="课程模块" enable_counters="1"/>
|
||||
<field name="college" string="学院" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
+28
-1
@@ -388,8 +388,35 @@ else:
|
||||
</record>
|
||||
<menuitem id="menu_yuthon_about_question_import"
|
||||
name="题库导入"
|
||||
parent="menu_yuthon_exam_root"
|
||||
parent="menu_yuthon_exam_question"
|
||||
action="action_yuthon_about_question_import"
|
||||
sequence="60"
|
||||
groups="college.group_teacher,base.group_system"/>
|
||||
|
||||
<!-- ===================== 应用类别配置(挂在「实训模块」下) ===================== -->
|
||||
<!-- Odoo 默认只有 form 视图,没有 list 视图,需要先补一个 -->
|
||||
<record id="view_yuthon_module_category_list" model="ir.ui.view">
|
||||
<field name="name">ir.module.category.list (college)</field>
|
||||
<field name="model">ir.module.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="应用类别">
|
||||
<field name="name" string="名称"/>
|
||||
<field name="description" string="描述"/>
|
||||
<field name="sequence" string="排序"/>
|
||||
<field name="parent_id" string="上级应用"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_yuthon_module_category" model="ir.actions.act_window">
|
||||
<field name="name">应用类别配置</field>
|
||||
<field name="res_model">ir.module.category</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_yuthon_module_category"
|
||||
name="应用类别配置"
|
||||
parent="menu_shixun_module"
|
||||
action="action_yuthon_module_category"
|
||||
sequence="10"/>
|
||||
</odoo>
|
||||
|
||||
@@ -35,15 +35,7 @@ class CourseHomework(models.Model):
|
||||
teaching_class_id = fields.Many2one('course.teaching_class', string='教学班',
|
||||
ondelete='cascade', domain="[('course_id', '=', course_id)]")
|
||||
submit_ids = fields.One2many('course.homework.submit', 'homework_id', string='提交记录')
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
score_item_ids = fields.One2many('course.score.item', 'homework_id', string='成绩项目')
|
||||
=======
|
||||
score_item_ids = fields.One2many('course.score.item', 'homework_id', string='成绩项')
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
=======
|
||||
score_item_ids = fields.One2many('course.score.item', 'homework_id', string='成绩项')
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
|
||||
# ====================== 新增:自动计算提交通道是否开启 ======================
|
||||
@api.depends('state', 'deadline')
|
||||
@@ -90,8 +82,6 @@ class CourseHomework(models.Model):
|
||||
self.publish_time = fields.Datetime.now()
|
||||
# 1. 批量为本班学生生成空白未提交记录
|
||||
self._auto_create_empty_submit()
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
# 新增:自动生成对应作业的学生成绩明细
|
||||
self._auto_create_homework_score_detail()
|
||||
# 2. 推送作业通知给学生
|
||||
@@ -147,15 +137,7 @@ class CourseHomework(models.Model):
|
||||
|
||||
if detail_vals_list:
|
||||
self.env['course.student.score.detail'].create(detail_vals_list)
|
||||
=======
|
||||
# 2. 推送作业通知给学生
|
||||
self._send_homework_notice_to_students()
|
||||
|
||||
=======
|
||||
# 2. 推送作业通知给学生
|
||||
self._send_homework_notice_to_students()
|
||||
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
def _send_homework_notice_to_students(self):
|
||||
"""发布作业后推送消息给教学班学生"""
|
||||
self.ensure_one()
|
||||
@@ -184,10 +166,6 @@ class CourseHomework(models.Model):
|
||||
partner_ids=student_users.mapped('partner_id').ids,
|
||||
subtype_xmlid='mail.mt_comment'
|
||||
)
|
||||
<<<<<<< HEAD
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
|
||||
def _auto_create_empty_submit(self):
|
||||
"""仅发布时执行:自动给教学班所有已选课学生生成空白未提交记录"""
|
||||
@@ -215,53 +193,12 @@ class CourseHomework(models.Model):
|
||||
batch_vals.append({
|
||||
'homework_id': self.id,
|
||||
'student_id': stu_id,
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
'course_score_item_id':self.course_score_item_id.id,
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
'state': 'unsubmit' # 默认未提交
|
||||
})
|
||||
# 批量创建空白提交记录
|
||||
submit_model.create(batch_vals)
|
||||
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
def _send_homework_notice_to_students(self):
|
||||
"""发布作业后推送消息给教学班学生"""
|
||||
self.ensure_one()
|
||||
if not self.teaching_class_id:
|
||||
return
|
||||
# 获取当前教学班所有已选课学生
|
||||
enrolls = self.env['course.teaching_class.enrollment'].search([
|
||||
('teaching_class_id', '=', self.teaching_class_id.id),
|
||||
('state', '=', 'enrolled')
|
||||
])
|
||||
student_users = enrolls.mapped('student_id.user_id').filtered(lambda u: u)
|
||||
if not student_users:
|
||||
return
|
||||
# 消息内容
|
||||
subject = f"新作业发布:{self.name}"
|
||||
body = f"""
|
||||
<p>课程:{self.course_id.name}</p>
|
||||
<p>作业名称:{self.name}</p>
|
||||
<p>截止时间:{self.deadline or '无'}</p>
|
||||
<p>作业要求:{self.requirement or '无'}</p>
|
||||
"""
|
||||
# 发送消息(关联当前作业记录,学生在消息中心可直接跳转)
|
||||
self.message_post(
|
||||
subject=subject,
|
||||
body=body,
|
||||
partner_ids=student_users.mapped('partner_id').ids,
|
||||
subtype_xmlid='mail.mt_note'
|
||||
)
|
||||
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
# ====================== 草稿/关闭作业 ======================
|
||||
def action_draft(self):
|
||||
self.state = 'draft'
|
||||
@@ -388,21 +325,14 @@ class CourseHomework(models.Model):
|
||||
def create(self, vals):
|
||||
homework_record = super().create(vals)
|
||||
# 草稿状态不执行自动生成提交记录,移到action_publish
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
|
||||
target_a = self.env["course.score.item"].search([
|
||||
("name", "=", "作业"),
|
||||
("create_uid", "=", self.env.uid)
|
||||
], limit=1)
|
||||
|
||||
if target_a:
|
||||
# 将刚新建的B追加到A的多对多字段
|
||||
# 将新建的作业追加到"作业"成绩项目的多对多字段
|
||||
target_a.write({
|
||||
"homework_ids": [(4, homework_record.id)]
|
||||
})
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
return homework_record
|
||||
@@ -93,13 +93,6 @@ class CourseHomeworkSubmit(models.Model):
|
||||
def create(self, vals):
|
||||
submit_rec = super().create(vals)
|
||||
self._check_submit_change_state(submit_rec)
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
=======
|
||||
>>>>>>> 0b2a587b69524dafde97f76bad27721afebdcddb
|
||||
return submit_rec
|
||||
|
||||
def write(self, vals):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
'name': 'student_organization',
|
||||
'name': '学生组织',
|
||||
'version': '1.3',
|
||||
'summary': '',
|
||||
'summary': '管理学生组织架构、班级、年级等基础信息',
|
||||
'sequence': 11,
|
||||
'depends': ['base','hr'],
|
||||
'data':[
|
||||
@@ -14,6 +14,5 @@
|
||||
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user