完善教育
This commit is contained in:
@@ -1 +1,2 @@
|
||||
from . import controllers
|
||||
from . import models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
'name': '教育',
|
||||
'version': '18.0.3.0.0',
|
||||
'version': '18.0.3.0.4',
|
||||
'summary': 'Odoo 18 教学管理平台 — 师生管理 + 课程管理 + 作业/进展(老师·学生双角色)',
|
||||
'description': """
|
||||
Odoo 18 教学管理平台(面向老师与学生,双角色权限)
|
||||
@@ -40,11 +40,17 @@
|
||||
'views/assignment_batch_wizard_views.xml',
|
||||
'views/import_wizard_views.xml',
|
||||
'views/homework_views.xml',
|
||||
'views/exam_views.xml',
|
||||
'views/exam_take_templates.xml',
|
||||
'views/training_views.xml',
|
||||
'views/course_import_wizard_views.xml',
|
||||
'data/about_pages.xml',
|
||||
'views/about_page_views.xml',
|
||||
'views/menus.xml',
|
||||
'views/shixun_kanban_view.xml',
|
||||
'data/shixun_module_data.xml',
|
||||
'data/module_info_data.xml',
|
||||
'views/module_info_views.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
|
||||
@@ -10,3 +10,5 @@ from . import import_wizard
|
||||
from . import about_page
|
||||
from . import training
|
||||
from . import course_import_wizard
|
||||
from . import ir_module_module_info
|
||||
from . import exam
|
||||
|
||||
@@ -240,6 +240,21 @@ class CourseChapterExerciseAnswer(models.Model):
|
||||
return super().write(vals)
|
||||
|
||||
|
||||
class CourseChapterTask(models.Model):
|
||||
"""章节任务清单——老师按章节维护的学习任务,学生端可见但不可编辑。"""
|
||||
|
||||
_name = 'yuthon.school.course.chapter.task'
|
||||
_description = '章节任务'
|
||||
_order = 'chapter_id, sequence, id'
|
||||
|
||||
chapter_id = fields.Many2one(
|
||||
'yuthon.school.course.chapter', string='章节',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
name = fields.Char(string='任务名称', required=True)
|
||||
is_done = fields.Boolean(string='已完成', default=False)
|
||||
|
||||
|
||||
class CourseChapter(models.Model):
|
||||
"""课程章节——老师端在课程内容里维护,学生端作为学习目录。
|
||||
|
||||
@@ -256,6 +271,7 @@ class CourseChapter(models.Model):
|
||||
name = fields.Char(string='章节标题', required=True, index=True)
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
description = fields.Html(string='章节说明', sanitize=True)
|
||||
class_hours = fields.Integer(string='课时', default=1, help='本章所占课时数')
|
||||
|
||||
# 视频与附件
|
||||
video_file = fields.Binary(string='视频文件', attachment=True)
|
||||
@@ -280,6 +296,11 @@ class CourseChapter(models.Model):
|
||||
for chapter in self:
|
||||
chapter.exercise_count = len(chapter.exercise_ids)
|
||||
|
||||
# 任务列表:老师按章节维护的任务清单
|
||||
task_ids = fields.One2many(
|
||||
'yuthon.school.course.chapter.task', 'chapter_id',
|
||||
string='任务列表')
|
||||
|
||||
# 随堂笔记:老师按章节记录的富文本笔记(与章节编辑表单共用同一字段)
|
||||
notes = fields.Html(string='随堂笔记', sanitize=True)
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ class SchoolCourse(models.Model):
|
||||
objectives = fields.Html(string='课程目标', sanitize=True)
|
||||
syllabus = fields.Html(string='课程大纲', sanitize=True)
|
||||
features = fields.Html(string='课程特色', sanitize=True)
|
||||
business_scenario = fields.Html(string='业务情景', sanitize=True)
|
||||
|
||||
# 学员分配
|
||||
student_ids = fields.Many2many(
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
"""课程批量导入向导 —— CSV 模板下载 + 批量创建课程(导入大纲即可)。
|
||||
"""课程批量导入向导 —— CSV 模板下载 + 批量创建课程(可选连带章节与章节任务)。
|
||||
|
||||
模板列:课程名称、课程编号、所属学院、学期、课程类型、课时、课程大纲。
|
||||
导入时直接创建 yuthon.school.course 记录。
|
||||
模板列(前 8 列为课程本体,后 5 列为可选章节/任务):
|
||||
课程名称、课程编号、所属学院、学期、课程类型、课时、课程大纲、业务情景、
|
||||
章节标题、章节说明、章节课时、任务名称、是否完成。
|
||||
|
||||
- 仅填前 8 列:行为与旧版一致,只创建课程;
|
||||
- 填了「章节标题」:自动按 (课程, 章节标题) 找/建章节;
|
||||
- 填了「任务名称」:在对应章节下创建任务列表明细行(is_done 由「是否完成」决定)。
|
||||
同一课程 / 同一章节多行时自动复用,不重复创建。
|
||||
"""
|
||||
|
||||
import base64
|
||||
@@ -58,10 +64,13 @@ class CourseImportWizard(models.TransientModel):
|
||||
'<li>点击下方「下载模板」按钮下载 CSV 模板;</li>'
|
||||
'<li>用 Excel / WPS 打开模板,按示例填写数据:<br/>'
|
||||
'<b>课程名称</b>、<b>课程编号</b> 为必填;<br/>'
|
||||
'<b>所属学院、学期、课程类型、课时、课程大纲</b> 为选填;</li>'
|
||||
'<b>所属学院、学期、课程类型、课时、课程大纲、业务情景</b> 为选填;</li>'
|
||||
'<li>课程类型可选:理论 / 实践</li>'
|
||||
'<li><b>章节 / 任务(可选)</b>:填「章节标题」会自动建/复用章节,'
|
||||
'填「任务名称」会在该章节下建一条任务列表明细(是否完成填 是/否);'
|
||||
'同一课程、同一章节多行会自动合并,不会重复创建;</li>'
|
||||
'<li>保存为 CSV 后上传并点击「开始导入」;</li>'
|
||||
'<li>若课程编号已存在则跳过,不会重复创建。</li>'
|
||||
'<li>若课程名称已存在则复用,不会重复创建课程。</li>'
|
||||
'</ol>'
|
||||
),
|
||||
)
|
||||
@@ -71,10 +80,15 @@ class CourseImportWizard(models.TransientModel):
|
||||
def action_download_template(self):
|
||||
"""生成 CSV 模板并提供下载。"""
|
||||
header = ['课程名称', '课程编号', '所属学院', '学期',
|
||||
'课程类型(理论/实践)', '课时', '课程大纲']
|
||||
'课程类型(理论/实践)', '课时', '课程大纲', '业务情景',
|
||||
'章节标题', '章节说明', '章节课时',
|
||||
'任务名称', '是否完成']
|
||||
sample = ['Python 编程基础', 'PY101', '计算机学院',
|
||||
'2025-2026第1学期', '理论', '48',
|
||||
'Python基础语法、数据结构、面向对象编程']
|
||||
'Python基础语法、数据结构、面向对象编程',
|
||||
'通过电商订单管理场景贯穿课程',
|
||||
'第1章 环境搭建', '本章介绍开发环境', '4',
|
||||
'安装Python', '否']
|
||||
|
||||
buf = io.StringIO()
|
||||
writer = csv.writer(buf)
|
||||
@@ -122,6 +136,10 @@ class CourseImportWizard(models.TransientModel):
|
||||
col_map = self._normalize_columns(reader.fieldnames)
|
||||
|
||||
created = 0
|
||||
reused_course = 0
|
||||
created_chapter = 0
|
||||
reused_chapter = 0
|
||||
created_task = 0
|
||||
skipped = 0
|
||||
errors = []
|
||||
|
||||
@@ -135,46 +153,86 @@ class CourseImportWizard(models.TransientModel):
|
||||
errors.append(_('第 %d 行:课程名称为必填,跳过。') % row_idx)
|
||||
continue
|
||||
|
||||
# 编号去重
|
||||
if code:
|
||||
existing = self.env['yuthon.school.course'].sudo().search(
|
||||
[('code', '=', code)], limit=1)
|
||||
if existing:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
try:
|
||||
vals = {
|
||||
'name': name,
|
||||
'code': code,
|
||||
'state': 'draft',
|
||||
}
|
||||
# 课程:按名称优先复用,其次按编号;都不存在才新建
|
||||
course = self.env['yuthon.school.course'].sudo().search(
|
||||
[('name', '=', name)], limit=1)
|
||||
if not course and code:
|
||||
course = self.env['yuthon.school.course'].sudo().search(
|
||||
[('code', '=', code)], limit=1)
|
||||
|
||||
college_raw = row.get('college', '')
|
||||
if college_raw:
|
||||
vals['college'] = COLLEGE_NAME_MAP.get(college_raw, 'other')
|
||||
if not course:
|
||||
vals = {
|
||||
'name': name,
|
||||
'code': code,
|
||||
'state': 'draft',
|
||||
}
|
||||
college_raw = row.get('college', '')
|
||||
if college_raw:
|
||||
vals['college'] = COLLEGE_NAME_MAP.get(college_raw, 'other')
|
||||
semester = row.get('semester', '')
|
||||
if semester:
|
||||
vals['semester'] = semester
|
||||
course_type_raw = row.get('course_type', '')
|
||||
if course_type_raw:
|
||||
vals['course_type'] = COURSE_TYPE_MAP.get(
|
||||
course_type_raw, 'theory')
|
||||
hours_raw = row.get('hours', '')
|
||||
if hours_raw:
|
||||
try:
|
||||
vals['hours'] = int(float(hours_raw))
|
||||
except ValueError:
|
||||
pass
|
||||
syllabus = row.get('syllabus', '')
|
||||
if syllabus:
|
||||
vals['syllabus'] = syllabus
|
||||
business_scenario = row.get('business_scenario', '')
|
||||
if business_scenario:
|
||||
vals['business_scenario'] = business_scenario
|
||||
course = self.env['yuthon.school.course'].sudo().create(vals)
|
||||
created += 1
|
||||
else:
|
||||
reused_course += 1
|
||||
|
||||
semester = row.get('semester', '')
|
||||
if semester:
|
||||
vals['semester'] = semester
|
||||
# 章节:填了章节标题才处理(按 课程+标题 复用)
|
||||
chapter_title = row.get('chapter', '').strip()
|
||||
chapter = None
|
||||
if chapter_title:
|
||||
chapter = self.env['yuthon.school.course.chapter'].sudo().search([
|
||||
('course_id', '=', course.id),
|
||||
('name', '=', chapter_title),
|
||||
], limit=1)
|
||||
if not chapter:
|
||||
chapter_vals = {'course_id': course.id, 'name': chapter_title}
|
||||
chapter_desc = row.get('chapter_desc', '').strip()
|
||||
if chapter_desc:
|
||||
chapter_vals['description'] = chapter_desc
|
||||
chapter_hours_raw = row.get('chapter_hours', '').strip()
|
||||
if chapter_hours_raw:
|
||||
try:
|
||||
chapter_vals['class_hours'] = int(float(chapter_hours_raw))
|
||||
except ValueError:
|
||||
pass
|
||||
chapter = self.env['yuthon.school.course.chapter'].sudo().create(
|
||||
chapter_vals)
|
||||
created_chapter += 1
|
||||
else:
|
||||
reused_chapter += 1
|
||||
|
||||
course_type_raw = row.get('course_type', '')
|
||||
if course_type_raw:
|
||||
vals['course_type'] = COURSE_TYPE_MAP.get(course_type_raw, 'theory')
|
||||
|
||||
hours_raw = row.get('hours', '')
|
||||
if hours_raw:
|
||||
try:
|
||||
vals['hours'] = float(hours_raw)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
syllabus = row.get('syllabus', '')
|
||||
if syllabus:
|
||||
vals['syllabus'] = syllabus
|
||||
|
||||
self.env['yuthon.school.course'].sudo().create(vals)
|
||||
created += 1
|
||||
# 任务列表:填了任务名称才在对应章节下创建明细行
|
||||
task_name = row.get('task_name', '').strip()
|
||||
if task_name and chapter:
|
||||
is_done = row.get('is_done', '').strip() in (
|
||||
'是', 'y', 'yes', 'true', '1', '完成')
|
||||
task_vals = {
|
||||
'chapter_id': chapter.id,
|
||||
'name': task_name,
|
||||
'is_done': is_done,
|
||||
'sequence': 10,
|
||||
}
|
||||
self.env['yuthon.school.course.chapter.task'].sudo().create(
|
||||
task_vals)
|
||||
created_task += 1
|
||||
|
||||
except Exception as exc:
|
||||
skipped += 1
|
||||
@@ -183,9 +241,12 @@ class CourseImportWizard(models.TransientModel):
|
||||
|
||||
summary = _(
|
||||
'导入完成!\n'
|
||||
'新建课程:%d\n'
|
||||
'新建课程:%d(复用 %d)\n'
|
||||
'新建章节:%d(复用 %d)\n'
|
||||
'新建任务:%d\n'
|
||||
'跳过:%d'
|
||||
) % (created, skipped)
|
||||
) % (created, reused_course, created_chapter, reused_chapter,
|
||||
created_task, skipped)
|
||||
|
||||
if errors:
|
||||
summary += '\n' + _('注意事项:\n') + '\n'.join(errors[:10])
|
||||
@@ -223,6 +284,18 @@ class CourseImportWizard(models.TransientModel):
|
||||
mapping[f] = 'hours'
|
||||
elif f_lower in ('课程大纲', 'syllabus', '大纲'):
|
||||
mapping[f] = 'syllabus'
|
||||
elif f_lower in ('业务情景', 'business_scenario', 'scenario'):
|
||||
mapping[f] = 'business_scenario'
|
||||
elif f_lower in ('章节标题', 'chapter', '章节', 'chapter_name'):
|
||||
mapping[f] = 'chapter'
|
||||
elif f_lower in ('章节说明', 'chapter_desc', 'chapter_description'):
|
||||
mapping[f] = 'chapter_desc'
|
||||
elif f_lower in ('章节课时', 'chapter_hours', 'chapter_class_hours'):
|
||||
mapping[f] = 'chapter_hours'
|
||||
elif f_lower in ('任务名称', 'task_name', '任务', 'task'):
|
||||
mapping[f] = 'task_name'
|
||||
elif f_lower in ('是否完成', 'is_done', '完成', 'done'):
|
||||
mapping[f] = 'is_done'
|
||||
else:
|
||||
mapping[f] = f # 保留原名
|
||||
return mapping
|
||||
|
||||
@@ -34,4 +34,27 @@
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
</record>
|
||||
|
||||
<!-- 考试模块:学生仅能访问自己的答卷与答题记录 -->
|
||||
<record id="rule_exam_paper_student_own" model="ir.rule">
|
||||
<field name="name">考试答卷:学生仅能访问自己的答卷</field>
|
||||
<field name="model_id" ref="model_yuthon_school_exam_paper"/>
|
||||
<field name="groups" eval="[(4, ref('college.group_student'))]"/>
|
||||
<field name="domain_force">[('user_id', '=', user.id)]</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="rule_exam_answer_student_own" model="ir.rule">
|
||||
<field name="name">考试答题:学生仅能访问自己的答题记录</field>
|
||||
<field name="model_id" ref="model_yuthon_school_exam_answer"/>
|
||||
<field name="groups" eval="[(4, ref('college.group_student'))]"/>
|
||||
<field name="domain_force">[('paper_id.user_id', '=', user.id)]</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -38,6 +38,9 @@ access_yuthon_school_course_import_wizard_teacher,yuthon.school.course.import.wi
|
||||
access_yuthon_school_course_chapter_exercise_answer_admin,yuthon.school.course.chapter.exercise.answer.admin,model_yuthon_school_course_chapter_exercise_answer,base.group_system,1,1,1,1
|
||||
access_yuthon_school_course_chapter_exercise_answer_teacher,yuthon.school.course.chapter.exercise.answer.teacher,model_yuthon_school_course_chapter_exercise_answer,college.group_teacher,1,0,0,0
|
||||
access_yuthon_school_course_chapter_exercise_answer_student,yuthon.school.course.chapter.exercise.answer.student,model_yuthon_school_course_chapter_exercise_answer,college.group_student,1,1,1,0
|
||||
access_yuthon_school_course_chapter_task_admin,yuthon.school.course.chapter.task.admin,model_yuthon_school_course_chapter_task,base.group_system,1,1,1,1
|
||||
access_yuthon_school_course_chapter_task_teacher,yuthon.school.course.chapter.task.teacher,model_yuthon_school_course_chapter_task,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_course_chapter_task_student,yuthon.school.course.chapter.task.student,model_yuthon_school_course_chapter_task,college.group_student,1,0,0,0
|
||||
access_yuthon_school_training_admin,yuthon.school.training.admin,model_yuthon_school_training,base.group_system,1,1,1,1
|
||||
access_yuthon_school_training_teacher,yuthon.school.training.teacher,model_yuthon_school_training,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_training_student,yuthon.school.training.student,model_yuthon_school_training,college.group_student,1,1,1,1
|
||||
@@ -46,3 +49,21 @@ access_yuthon_about_page_teacher,yuthon.about.page.teacher,model_yuthon_about_pa
|
||||
access_yuthon_about_page_student,yuthon.about.page.student,model_yuthon_about_page,college.group_student,1,0,0,0
|
||||
access_ir_module_module_teacher,ir.module.module.teacher,base.model_ir_module_module,college.group_teacher,1,1,1,1
|
||||
access_ir_module_module_student,ir.module.module.student.read,base.model_ir_module_module,college.group_student,1,0,0,0
|
||||
access_yuthon_school_exam_question_admin,yuthon.school.exam.question.admin,model_yuthon_school_exam_question,base.group_system,1,1,1,1
|
||||
access_yuthon_school_exam_question_teacher,yuthon.school.exam.question.teacher,model_yuthon_school_exam_question,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_exam_question_student,yuthon.school.exam.question.student,model_yuthon_school_exam_question,college.group_student,1,0,0,0
|
||||
access_yuthon_school_exam_question_option_admin,yuthon.school.exam.question.option.admin,model_yuthon_school_exam_question_option,base.group_system,1,1,1,1
|
||||
access_yuthon_school_exam_question_option_teacher,yuthon.school.exam.question.option.teacher,model_yuthon_school_exam_question_option,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_exam_question_option_student,yuthon.school.exam.question.option.student,model_yuthon_school_exam_question_option,college.group_student,1,0,0,0
|
||||
access_yuthon_school_exam_admin,yuthon.school.exam.admin,model_yuthon_school_exam,base.group_system,1,1,1,1
|
||||
access_yuthon_school_exam_teacher,yuthon.school.exam.teacher,model_yuthon_school_exam,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_exam_student,yuthon.school.exam.student,model_yuthon_school_exam,college.group_student,1,0,0,0
|
||||
access_yuthon_school_exam_line_admin,yuthon.school.exam.line.admin,model_yuthon_school_exam_line,base.group_system,1,1,1,1
|
||||
access_yuthon_school_exam_line_teacher,yuthon.school.exam.line.teacher,model_yuthon_school_exam_line,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_exam_line_student,yuthon.school.exam.line.student,model_yuthon_school_exam_line,college.group_student,1,0,0,0
|
||||
access_yuthon_school_exam_paper_admin,yuthon.school.exam.paper.admin,model_yuthon_school_exam_paper,base.group_system,1,1,1,1
|
||||
access_yuthon_school_exam_paper_teacher,yuthon.school.exam.paper.teacher,model_yuthon_school_exam_paper,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_exam_paper_student,yuthon.school.exam.paper.student,model_yuthon_school_exam_paper,college.group_student,1,1,1,0
|
||||
access_yuthon_school_exam_answer_admin,yuthon.school.exam.answer.admin,model_yuthon_school_exam_answer,base.group_system,1,1,1,1
|
||||
access_yuthon_school_exam_answer_teacher,yuthon.school.exam.answer.teacher,model_yuthon_school_exam_answer,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_exam_answer_student,yuthon.school.exam.answer.student,model_yuthon_school_exam_answer,college.group_student,1,1,1,0
|
||||
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
@@ -266,3 +266,4 @@
|
||||
h4 { font-size: 15px; margin: 16px 0 8px; }
|
||||
p, li { color: $o-main-text-color; }
|
||||
}
|
||||
|
||||
|
||||
@@ -299,3 +299,4 @@
|
||||
h4 { font-size: 15px; margin: 16px 0 8px; color: #f8fafc; }
|
||||
p, li { color: #cbd5e1; }
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,14 @@
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="course_id" readonly="1"/>
|
||||
<field name="sequence" invisible="1"/>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="course_id" readonly="1"/>
|
||||
<field name="sequence" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="class_hours" string="课时"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="description" widget="html" string="章节说明"/>
|
||||
@@ -29,6 +34,14 @@
|
||||
title="查看本题所有学员的回答"/>
|
||||
</list>
|
||||
</field>
|
||||
<separator string="任务列表"/>
|
||||
<field name="task_ids" string="任务列表">
|
||||
<list editable="bottom" decoration-muted="is_done == True">
|
||||
<field name="sequence" widget="handle" string="排序"/>
|
||||
<field name="name" string="任务名称"/>
|
||||
<field name="is_done" string="已完成" optional="show"/>
|
||||
</list>
|
||||
</field>
|
||||
<group>
|
||||
<field name="video_file" filename="video_filename"/>
|
||||
<field name="video_filename" invisible="1"/>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<field name="chapter_ids">
|
||||
<list editable="top">
|
||||
<field name="name"/>
|
||||
<field name="class_hours" string="课时"/>
|
||||
<field name="video_filename_display" string="视频"/>
|
||||
<button name="action_open_edit" type="object"
|
||||
string="编辑章节" icon="fa-pencil"
|
||||
@@ -103,6 +104,9 @@
|
||||
<page string="课程特色">
|
||||
<field name="features"/>
|
||||
</page>
|
||||
<page string="业务情景">
|
||||
<field name="business_scenario"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
@@ -144,6 +148,7 @@
|
||||
<field name="chapter_ids" readonly="1">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="class_hours" string="课时"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
@@ -159,6 +164,9 @@
|
||||
<page string="课程特色">
|
||||
<field name="features" readonly="1"/>
|
||||
</page>
|
||||
<page string="业务情景">
|
||||
<field name="business_scenario" readonly="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
|
||||
+36
-6
@@ -2,8 +2,6 @@
|
||||
<!-- ===================== 产品介绍(顶级菜单,置顶,位于「我的实训」上方) ===================== -->
|
||||
<!-- 在当前页面的内容区以表单形式打开预置记录 about_page_product,
|
||||
其 content 富文本字段即为 H5 页面内容(介绍本教育产品本身)。 -->
|
||||
<!-- 先删除上一轮遗留的 act_url 记录,避免同 external id 模型冲突(ParseError) -->
|
||||
<delete model="ir.actions.act_url" id="action_yuthon_product_intro"/>
|
||||
<record id="action_yuthon_product_intro" model="ir.actions.act_window">
|
||||
<field name="name">产品介绍</field>
|
||||
<field name="res_model">yuthon.about.page</field>
|
||||
@@ -163,6 +161,42 @@ else:
|
||||
sequence="10"
|
||||
groups="college.group_teacher,base.group_system"/>
|
||||
|
||||
<!-- ===================== 考试(与课程管理同级,顶级菜单,无 parent 才能带 web_icon) ===================== -->
|
||||
<menuitem id="menu_yuthon_exam_root"
|
||||
name="考试"
|
||||
web_icon="college,static/src/img/exam.png"
|
||||
sequence="15"/>
|
||||
<menuitem id="menu_yuthon_exam_question"
|
||||
name="题库"
|
||||
parent="menu_yuthon_exam_root"
|
||||
action="action_yuthon_school_exam_question"
|
||||
sequence="10"
|
||||
groups="college.group_teacher,base.group_system"/>
|
||||
<menuitem id="menu_yuthon_exam_manage"
|
||||
name="考试管理"
|
||||
parent="menu_yuthon_exam_root"
|
||||
action="action_yuthon_school_exam"
|
||||
sequence="20"
|
||||
groups="college.group_teacher,base.group_system"/>
|
||||
<menuitem id="menu_yuthon_exam_grade"
|
||||
name="评阅试卷"
|
||||
parent="menu_yuthon_exam_root"
|
||||
action="action_yuthon_school_exam_paper_grade"
|
||||
sequence="30"
|
||||
groups="college.group_teacher,base.group_system"/>
|
||||
<menuitem id="menu_yuthon_exam_result"
|
||||
name="考试结果"
|
||||
parent="menu_yuthon_exam_root"
|
||||
action="action_yuthon_school_exam_result"
|
||||
sequence="40"
|
||||
groups="college.group_teacher,base.group_system"/>
|
||||
<menuitem id="menu_yuthon_exam_my"
|
||||
name="我的考试"
|
||||
parent="menu_yuthon_exam_root"
|
||||
action="action_yuthon_school_exam_paper_student"
|
||||
sequence="50"
|
||||
groups="college.group_student"/>
|
||||
|
||||
<!-- 我的学习:学生端专用(简单表单 + 去学习按钮) -->
|
||||
<menuitem id="menu_yuthon_course_study"
|
||||
name="我的学习"
|
||||
@@ -239,10 +273,6 @@ else:
|
||||
groups="college.group_teacher,college.group_student,base.group_system"/>
|
||||
|
||||
<!-- ===================== 关于系统说明 ===================== -->
|
||||
<!-- 移除早期占位的 act_url 记录 -->
|
||||
<delete model="ir.actions.act_url" id="action_yuthon_about_system"/>
|
||||
<delete model="ir.actions.act_url" id="action_yuthon_about_operation"/>
|
||||
|
||||
<!-- 系统说明:打开预置记录 about_page_system -->
|
||||
<record id="action_yuthon_about_system" model="ir.actions.act_window">
|
||||
<field name="name">系统说明</field>
|
||||
|
||||
Reference in New Issue
Block a user