学生组织架构 #1

Merged
pengyuthon merged 2 commits from dev_haoran into master 2026-06-16 08:55:26 +08:00
42 changed files with 2708 additions and 0 deletions
Showing only changes of commit 30587b58b1 - Show all commits

0
edu_base/__init__.py Normal file
View File

15
edu_base/__manifest__.py Normal file
View File

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
{
'name': '教育基础权限',
'version': '18.0.1.0.0',
'summary': '通用权限组:学生、教师、教务管理员',
'description': '统一管理全项目通用角色权限组,供其他业务模块依赖使用',
'author': '',
'depends': ['base'], # 只依赖系统基础模块
'data': [
'security/groups.xml',
],
'installable': True,
'auto_install': False, # 不自动安装,手动安装一次即可
'application': False,
}

Binary file not shown.

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- 1. 学生组 -->
<record id="group_student" model="res.groups">
<field name="name">学生</field>
<field name="category_id" ref="base.module_category_education"/>
<!-- 可选:继承系统基础组 -->
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
<!-- 2. 教师组 -->
<record id="group_teacher" model="res.groups">
<field name="name">教师</field>
<field name="category_id" ref="base.module_category_education"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
<!-- 3. 教务管理员 -->
<record id="group_edu_admin" model="res.groups">
<field name="name">教务管理员</field>
<field name="category_id" ref="base.module_category_education"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
</odoo>

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,34 @@
{
'name': 'Learning Course',
'version': '18.0.1.0.0',
'category': 'Education',
'summary': '课程管理 - 课程基础信息',
'description': """
学习中心
""",
'author': 'hrrr',
'depends': [
'base',
'mail',
'student_organization',
],
'data': [
'security/ir.model.access.csv',
'security/record_rules.xml',
'views/view_learning_course.xml',
'views/view_course_chapter.xml',
'views/view_course_chapter_resource.xml',
'views/view_course_homework.xml',
'views/view_homework_submit.xml',
'views/view_course_score_item.xml',
'views/view_course_syllabus.xml',
'views/view_course_teaching_class.xml',
'views/view_course_student_score.xml',
'views/view_course_homework_student.xml',
'views/view_teach_class.xml',
],
'installable': True,
'application': True,
}

Binary file not shown.

View File

@ -0,0 +1,10 @@
from . import learning_course
from . import course_chapter
from . import course_chapter_resource
from . import course_syllabus
from . import course_homework
from . import course_homework_submit
from . import course_score_item
from . import course_student_score
from . import course_teaching_class
from . import teach_class

View File

@ -0,0 +1,32 @@
from odoo import api, fields, models
class CourseChapter(models.Model):
_name = 'course.chapter'
_description = '课程章节'
_rec_name = 'name'
_inherit = ['mail.thread']
_order = 'course_id, sequence, id'
name = fields.Char(string='章节名称', required=True)
sequence = fields.Integer(string='序号', default=10)
description = fields.Html(string='章节描述')
course_id = fields.Many2one('learning.course', string='所属课程', required=True, ondelete='cascade')
is_published = fields.Boolean(string='是否发布', default=True)
resource_count = fields.Integer(string='资源数量', compute='_compute_resource_count')
video_count = fields.Integer(string='视频数量', compute='_compute_resource_count')
doc_count = fields.Integer(string='文档数量', compute='_compute_resource_count')
resource_ids = fields.One2many('course.chapter.resource', 'chapter_id', string='章节资源')
# homework_ids = fields.One2many('course.homework', 'chapter_id', string='关联作业')
syllabus_ids = fields.One2many('course.syllabus', 'chapter_id', string='教学大纲/教案')
def _compute_resource_count(self):
for record in self:
record.resource_count = len(record.resource_ids)
record.video_count = len(record.resource_ids.filtered(lambda r: r.resource_type == 'video'))
record.doc_count = len(record.resource_ids.filtered(lambda r: r.resource_type in ['pdf', 'ppt']))
def action_publish(self):
self.is_published = True
def action_hide(self):
self.is_published = False

View File

@ -0,0 +1,80 @@
from odoo import api, fields, models
class CourseChapterResource(models.Model):
_name = 'course.chapter.resource'
_description = '章节资源'
_rec_name = 'name'
_order = 'chapter_id, sequence, id'
name = fields.Char(string='资源名称', required=True)
sequence = fields.Integer(string='序号', default=10)
description = fields.Text(string='备注说明')
chapter_id = fields.Many2one('course.chapter', string='所属章节', required=True)
course_id = fields.Many2one(related="chapter_id.course_id", string='所属课程', required=True, ondelete='cascade')
chapter_name = fields.Char(related="chapter_id.name", string="章节名称", readonly=True)
chapter_sequence = fields.Integer(related="chapter_id.sequence", string="章节序号", readonly=True)
chapter_is_published = fields.Boolean(related="chapter_id.is_published", string="章节发布状态", readonly=True)
resource_type = fields.Selection([
('video', '视频'),
('pdf', 'PDF文档'),
('ppt', 'PPT演示文稿'),
('other', '其他'),
], string='资源类型', required=True)
video_file = fields.Binary(string='视频文件', attachment=True)
video_filename = fields.Char(string='视频文件名')
video_url = fields.Char(string='视频链接')
video_duration = fields.Integer(string='时长(秒)')
doc_file = fields.Binary(string='文档文件', attachment=True)
doc_filename = fields.Char(string='文档文件名')
doc_page_count = fields.Integer(string='页数')
# 添加教学班关联(可选,资源可共享给所有教学班)
teaching_class_id = fields.Many2one('course.teaching_class', string='教学班',
ondelete='cascade')
preview_url = fields.Char(string='预览链接', compute='_compute_preview_url')
is_hidden = fields.Boolean(string='是否隐藏', default=False)
course_name = fields.Char(related="chapter_id.course_id.name", string="课程名称", readonly=True)
course_code = fields.Char(related="chapter_id.course_id.code", string="课程代码", readonly=True)
course_credit = fields.Float(related="chapter_id.course_id.credit", string="学分", readonly=True)
# 新增:批量上传附件字段(核心)
resource_attachment_ids = fields.Many2many(
comodel_name='ir.attachment',
relation='course_chapter_resource_attachment_rel',
column1='resource_id',
column2='attachment_id',
string='批量上传资源附件',
)
# 新增:附件数量统计(可选,用于列表显示)
attachment_count = fields.Integer(string="附件数", compute="_compute_attachment_count")
@api.depends('resource_attachment_ids')
def _compute_attachment_count(self):
for rec in self:
rec.attachment_count = len(rec.resource_attachment_ids)
def _compute_preview_url(self):
for record in self:
# 优先使用批量附件中的第一个文件作为预览链接
if record.resource_attachment_ids:
first_attachment = record.resource_attachment_ids[0]
record.preview_url = f'/web/content/{first_attachment.id}?download=false'
elif record.resource_type == 'video' and record.video_file:
record.preview_url = f'/web/content/course.chapter.resource/{record.id}/video_file'
elif record.resource_type in ['pdf', 'ppt'] and record.doc_file:
record.preview_url = f'/web/content/course.chapter.resource/{record.id}/doc_file'
else:
record.preview_url = False
def action_toggle_hide(self):
self.is_hidden = not self.is_hidden
def action_preview(self):
self.ensure_one()
if self.preview_url:
return {
'type': 'ir.actions.act_url',
'url': self.preview_url,
'target': 'new'
}
return False

View File

@ -0,0 +1,179 @@
from odoo import api, fields, models
from odoo.exceptions import ValidationError
class CourseHomework(models.Model):
_name = 'course.homework'
_description = '课程作业'
_rec_name = 'name'
_inherit = ['mail.thread']
_order = 'course_id, deadline, id'
name = fields.Char(string='作业名称', required=True)
description = fields.Html(string='作业描述')
requirement = fields.Html(string='作业要求')
course_id = fields.Many2one('learning.course', string='所属课程', required=True, ondelete='cascade')
chapter_id = fields.Many2one('course.chapter', string='关联章节')
total_score = fields.Float(string='作业总分', default=100.0, required=True)
publish_time = fields.Datetime(string='发布时间', default=fields.Datetime.now)
deadline = fields.Datetime(string='提交截止时间', required=True)
late_deadline = fields.Datetime(string='补交截止时间')
state = fields.Selection([
('draft', '草稿'),
('published', '已发布'),
('closed', '已关闭'),
], string='状态', default='draft', tracking=True)
is_submit_open = fields.Boolean(string='提交通道开启', default=True)
allow_late = fields.Boolean(string='允许补交', default=False)
total_students = fields.Integer(string='应提交人数', compute='_compute_submit_stats')
submitted_count = fields.Integer(string='已提交人数', compute='_compute_submit_stats')
late_count = fields.Integer(string='逾期提交人数', compute='_compute_submit_stats')
unsubmitted_count = fields.Integer(string='未提交人数', compute='_compute_submit_stats')
# 添加教学班关联
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='提交记录')
score_item_ids = fields.One2many('course.score.item', 'homework_id', string='提交记录')
def _compute_submit_stats(self):
for record in self:
# 按教学班 + 选课状态筛选学生
domain = [('state', '=', 'enrolled')]
if record.teaching_class_id:
# 优先按当前作业所属教学班统计(核心修正)
domain.append(('teaching_class_id', '=', record.teaching_class_id.id))
else:
# 无教学班时,回退到整门课程统计
domain.append(('course_id', '=', record.course_id.id))
enrollments = self.env['course.teaching_class.enrollment'].search(domain)
student_ids = enrollments.mapped('student_id')
record.total_students = len(student_ids)
# 该作业所有提交记录
base_domain = [('homework_id', '=', record.id)]
all_submit = self.env['course.homework.submit'].search(base_domain)
total_submit = len(all_submit)
deadline_val = record.deadline
if deadline_val:
# 按时提交
on_time_submit = all_submit.filtered(lambda s: s.submit_time and s.submit_time <= deadline_val)
# 逾期提交
late_submit = all_submit.filtered(lambda s: s.submit_time and s.submit_time > deadline_val)
record.submitted_count = len(on_time_submit)
record.late_count = len(late_submit)
else:
record.submitted_count = total_submit
record.late_count = 0
# 未提交 = 班级总人数 - 所有提交人数
record.unsubmitted_count = record.total_students - total_submit
def action_publish(self):
self.state = 'published'
self.publish_time = fields.Datetime.now()
def action_draft(self):
self.state = 'draft'
def action_close(self):
self.state = 'closed'
self.is_submit_open = False
@api.constrains('deadline', 'late_deadline')
def _check_deadline(self):
for record in self:
if record.late_deadline and record.late_deadline < record.deadline:
raise ValidationError('补交截止时间必须晚于提交截止时间')
def _get_current_student(self):
"""获取当前登录的学生"""
student = self.env['student.info'].search([('user_id', '=', self.env.uid)], limit=1)
return student
# 当前学生的提交记录
my_submit_id = fields.Many2one('course.homework.submit', string='我的提交',
compute='_compute_my_submit')
my_submit_state = fields.Char(string='提交状态', compute='_compute_my_submit')
my_submit_time = fields.Datetime(string='提交时间', compute='_compute_my_submit')
my_score = fields.Float(string='我的得分', compute='_compute_my_submit')
my_grade_level = fields.Char(string='我的等级', compute='_compute_my_submit')
my_comment = fields.Html(string='我的评语', compute='_compute_my_submit')
my_submit_file = fields.Binary(string='我的提交文件', compute='_compute_my_submit')
my_submit_filename = fields.Char(string='文件名', compute='_compute_my_submit')
my_submit_content = fields.Html(string='提交内容', compute='_compute_my_submit')
# 提交状态(用于前端显示)
submit_state = fields.Selection([
('not_submitted', '未提交'),
('submitted', '已提交'),
('graded', '已批改'),
('late', '逾期提交'),
], string='提交状态', compute='_compute_my_submit')
# 是否可以提交
can_submit = fields.Boolean(string='可以提交', compute='_compute_can_submit')
@api.depends('submit_ids')
def _compute_my_submit(self):
for record in self:
student = self._get_current_student()
if student:
submit = record.submit_ids.filtered(lambda s: s.student_id == student)
if submit:
record.my_submit_id = submit.id
record.my_submit_state = submit.state
record.my_submit_time = submit.submit_time
record.my_score = submit.score
record.my_grade_level = submit.grade_level
record.my_comment = submit.comment
record.my_submit_file = submit.submit_file
record.my_submit_filename = submit.submit_filename
record.my_submit_content = submit.submit_content
# 计算提交状态
if submit.state == 'graded':
record.submit_state = 'graded'
elif submit.is_late:
record.submit_state = 'late'
else:
record.submit_state = 'submitted'
else:
record.submit_state = 'not_submitted'
else:
record.submit_state = 'not_submitted'
def _compute_can_submit(self):
for record in self:
# 作业已发布、提交通道开启、未截止、且未提交
can = (record.state == 'published' and
record.is_submit_open and
record.deadline and
record.deadline > fields.Datetime.now() and
record.my_submit_state != 'submitted' and
record.my_submit_state != 'graded')
record.can_submit = can
def action_submit_homework(self):
"""学生提交作业"""
self.ensure_one()
student = self._get_current_student()
if not student:
raise ValidationError('请先关联学生信息')
# 检查提交权限
if not self.can_submit:
raise ValidationError('当前无法提交作业')
# 打开提交表单
return {
'type': 'ir.actions.act_window',
'name': '提交作业',
'res_model': 'course.homework.submit',
'view_mode': 'form',
'target': 'new',
'context': {
'default_homework_id': self.id,
'default_student_id': student.id,
},
}

View File

@ -0,0 +1,102 @@
from odoo import api, fields, models
class CourseHomeworkSubmit(models.Model):
_name = 'course.homework.submit'
_description = '作业提交记录'
_rec_name = 'display_name'
_inherit = ['mail.thread']
_order = 'homework_id, student_id'
display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True)
student_id = fields.Many2one('student.info', string='学生', required=True)
homework_id = fields.Many2one('course.homework', string='作业', required=True, ondelete='cascade')
@api.depends('homework_id.name', 'student_id.stu_name')
def _compute_display_name(self):
for record in self:
record.display_name = f"{record.student_id.stu_name} - {record.homework_id.name}"
course_name = fields.Char(related="homework_id.course_id.name", string="课程名称", readonly=True)
course_code = fields.Char(related="homework_id.course_id.code", string="课程代码", readonly=True)
course_credit = fields.Float(related="homework_id.course_id.credit", string="学分", readonly=True)
homework_name = fields.Char(related="homework_id.name", string="作业名称", readonly=True)
homework_total_score = fields.Float(related="homework_id.total_score", string="作业总分", readonly=True)
homework_deadline = fields.Datetime(related="homework_id.deadline", string="截止时间", readonly=True)
homework_late_deadline = fields.Datetime(related="homework_id.late_deadline", string="补交截止时间", readonly=True)
student_name = fields.Char(related="student_id.stu_name", string="姓名", readonly=True)
student_no = fields.Char(related="student_id.stu_num", string="学号", readonly=True)
student_class_id = fields.Many2one(related="student_id.class_id", string="班级", readonly=True)
student_major_id = fields.Many2one(related="student_id.major_id", string="专业", readonly=True)
student_phone = fields.Char(related="student_id.stu_phone", string="手机号", readonly=True)
submit_file = fields.Binary(string='提交文件', attachment=True)
submit_filename = fields.Char(string='文件名')
submit_content = fields.Html(string='提交内容')
submit_time = fields.Datetime(string='提交时间')
score = fields.Float(string='得分')
comment = fields.Html(string='批改评语')
grader_id = fields.Many2one('res.users', string='批改人')
grade_time = fields.Datetime(string='批改时间')
state = fields.Selection([
('submitted', '已提交'),
('graded', '已批改'),
], string='状态', default='submitted')
is_late = fields.Boolean(string='是否逾期', compute='_compute_is_late')
def _compute_is_late(self):
for record in self:
deadline = record.homework_id.deadline
if deadline and record.submit_time:
record.is_late = record.submit_time > deadline
else:
record.is_late = False
def action_grade(self):
self.state = 'graded'
self.grade_time = fields.Datetime.now()
def action_regrade(self):
self.state = 'submitted'
self.grade_time = False
# 在 CourseHomeworkSubmit 类中添加
grade_level = fields.Selection([
('A', '优秀(A)'),
('B', '良好(B)'),
('C', '中等(C)'),
('D', '及格(D)'),
('F', '不及格(F)'),
], string='等级', compute='_compute_grade_level', store=True)
@api.depends('score', 'homework_id.total_score')
def _compute_grade_level(self):
for record in self:
if record.score and record.homework_id.total_score:
percent = record.score / record.homework_id.total_score * 100
if percent >= 90:
record.grade_level = 'A'
elif percent >= 80:
record.grade_level = 'B'
elif percent >= 70:
record.grade_level = 'C'
elif percent >= 60:
record.grade_level = 'D'
else:
record.grade_level = 'F'
else:
record.grade_level = False
# class CourseHomeworkSubmitBatchGrade(models.TransientModel):
# _name = 'course.homework.submit.batch.grade'
# _description = '作业批量批改向导'
#
# homework_id = fields.Many2one('course.homework', string='作业')
# total_count = fields.Integer(string='待批改总数')
# score = fields.Float(string='统一分数')
# comment = fields.Text(string='统一评语')
#
# # 批量批改执行方法
# def action_batch_grade(self):
# # 自行补充批量更新分数、评语、状态的业务逻辑
# return {'type': 'ir.actions.act_window_close'}

View File

@ -0,0 +1,54 @@
from odoo import api, fields, models
class CourseScoreItem(models.Model):
_name = 'course.score.item'
_description = '成绩项目'
_rec_name = 'name'
_order = 'course_id, weight desc, id'
_inherit = ['mail.thread']
name = fields.Char(string='项目名称', required=True)
description = fields.Char(string='项目描述')
course_id = fields.Many2one('learning.course', string='课程', required=True, ondelete='cascade')
course_name = fields.Char(related="course_id.name", string="课程名称", readonly=True)
course_code = fields.Char(related="course_id.code", string="课程代码", readonly=True)
course_credit = fields.Float(related="course_id.credit", string="学分", readonly=True)
course_exam_type = fields.Selection(related="course_id.exam_type", string="考核方式", readonly=True)
homework_id = fields.Many2one('course.homework', string='作业', required=True, ondelete='cascade')
sequence = fields.Integer(string="排序", default=10)
score_type = fields.Selection([
('homework', '作业'),
('exam', '考试'),
('experiment', '实验'),
('attendance', '考勤'),
('midterm', '期中考试'),
('final', '期末考试'),
('other', '其他'),
], string='成绩类型', required=True)
weight = fields.Float(string='权重(%)', required=True)
full_score = fields.Float(string='满分', default=100.0)
is_active = fields.Boolean(string='是否启用', default=True)
homework_ids = fields.Many2many('course.homework', string='关联作业')
# 统计字段
student_count = fields.Integer(string='学生人数', compute='_compute_stats')
avg_score = fields.Float(string='平均分', compute='_compute_stats')
max_score = fields.Float(string='最高分', compute='_compute_stats')
min_score = fields.Float(string='最低分', compute='_compute_stats')
score_detail_ids = fields.One2many('course.student.score.detail', 'score_item_id', string='成绩明细')
def action_toggle_active(self):
for record in self:
record.is_active = not record.is_active
def _compute_stats(self):
for record in self:
details = self.env['course.student.score.detail'].search([
('score_item_id', '=', record.id)
])
scores = details.mapped('score')
record.student_count = len(details)
record.avg_score = sum(scores) / len(scores) if scores else 0
record.max_score = max(scores) if scores else 0
record.min_score = min(scores) if scores else 0

View File

@ -0,0 +1,112 @@
from odoo import api, fields, models
from odoo.exceptions import ValidationError
class CourseStudentScore(models.Model):
_name = 'course.student.score'
_description = '学生成绩'
_rec_name = 'display_name'
_order = 'course_id, student_id'
_inherit = ['mail.thread']
display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True)
@api.depends('course_name', 'stu_name')
def _compute_display_name(self):
for record in self:
record.display_name = f"{record.stu_name} - {record.course_name}"
course_id = fields.Many2one('learning.course', string='课程', required=True, ondelete='cascade')
# 课程扩展只读字段(替代视图嵌套写法)
course_code = fields.Char(string="课程代码", related="course_id.code", readonly=True)
course_credit = fields.Float(string="学分", related="course_id.credit", readonly=True)
course_exam_type = fields.Selection(string="考核方式", related="course_id.exam_type", readonly=True)
course_name = fields.Char(related='course_id.name', string='课程', required=True, ondelete='cascade')
student_id = fields.Many2one('student.info', string='学生', required=True)
student_no = fields.Char(string="学号", related="student_id.stu_num", readonly=True)
student_class_id = fields.Many2one( string="班级", related="student_id.class_id", readonly=True)
student_major_id = fields.Many2one( string="专业", related="student_id.major_id", readonly=True)
stu_name=fields.Char(related='student_id.stu_name',required=True, ondelete='cascade',string='学生姓名')
score_ids = fields.One2many('course.student.score.detail', 'student_score_id', string='成绩明细')
teaching_class_id=fields.Many2one('course.teaching_class',string='教学班')
# 教学班相关只读关联字段
teaching_class_name = fields.Char(string="教学班名称", related="teaching_class_id.display_name", readonly=True)
teaching_class_semester = fields.Selection(string="学期", related="teaching_class_id.semester", readonly=True)
teaching_class_main_teacher = fields.Many2one('hr.employee', string="主讲教师",
related="teaching_class_id.main_teacher_id", readonly=True)
total_score = fields.Float(string='综合成绩', compute='_compute_total_score', store=True)
grade_level = fields.Selection([
('A', '优秀(A)'),
('B', '良好(B)'),
('C', '中等(C)'),
('D', '及格(D)'),
('F', '不及格(F)'),
], string='等级', compute='_compute_total_score', store=True)
@api.depends('score_ids.score', 'score_ids.weight')
def _compute_total_score(self):
for record in self:
total = 0.0
for detail in record.score_ids:
if detail.score and detail.weight:
total += detail.score * detail.weight / 100
record.total_score = round(total, 2)
if record.total_score >= 90:
record.grade_level = 'A'
elif record.total_score >= 80:
record.grade_level = 'B'
elif record.total_score >= 70:
record.grade_level = 'C'
elif record.total_score >= 60:
record.grade_level = 'D'
else:
record.grade_level = 'F'
class CourseStudentScoreDetail(models.Model):
_name = 'course.student.score.detail'
_description = '学生成绩明细'
_rec_name = 'display_name'
_order = 'student_score_id, score_item_id'
_inherit = ['mail.thread']
display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True)
@api.depends('student_score_displayname', 'score_item_id.name')
def _compute_display_name(self):
for record in self:
record.display_name = f"{record.student_score_displayname} - {record.score_item_id.name}"
# 关联学生成绩主表
student_score_id = fields.Many2one('course.student.score', string='学生成绩', required=True, ondelete='cascade')
student_score_displayname=fields.Char(related='student_score_id.display_name',required=True, ondelete='cascade',string='显示名称')
# 关联成绩项目
score_item_id = fields.Many2one('course.score.item', string='成绩项目', required=True, ondelete='restrict')
# 得分
score = fields.Float(string='得分', help='该项目实际得分')
# 从成绩项目继承的字段(用于显示和计算)
weight = fields.Float(string='权重(%)', related='score_item_id.weight', store=True, readonly=True)
full_score = fields.Float(string='满分', related='score_item_id.full_score', store=True, readonly=True)
score_type = fields.Selection(string='成绩类型', related='score_item_id.score_type', store=True, readonly=True)
# 备注
remark = fields.Char(string='备注')
# 关联课程和学生(用于视图显示)
course_id = fields.Many2one('learning.course', string='课程', related='student_score_id.course_id', store=True,
readonly=True)
student_id = fields.Many2one('student.info', string='学生', related='student_score_id.student_id', store=True,
readonly=True)
# 完成率(得分/满分)
completion_rate = fields.Float(string='完成率(%)', compute='_compute_completion_rate', store=True)
@api.depends('score', 'full_score')
def _compute_completion_rate(self):
for record in self:
if record.full_score and record.score:
record.completion_rate = round(record.score / record.full_score * 100, 1)
else:
record.completion_rate = 0.0
@api.constrains('score', 'full_score')
def _check_score(self):
for record in self:
if record.score and record.full_score and record.score > record.full_score:
raise ValidationError(f'得分({record.score})不能超过满分({record.full_score})')
if record.score and record.score < 0:
raise ValidationError('得分不能为负数')

View File

@ -0,0 +1,80 @@
from odoo import api, fields, models
from odoo.tools import human_size
import base64
import os
class CourseSyllabus(models.Model):
_name = 'course.syllabus'
_description = '教学大纲/教案'
_rec_name = 'title'
_order = 'course_id, syllabus_type, version desc'
_inherit = ['mail.thread']
title = fields.Char(string='标题', required=True)
syllabus_type = fields.Selection([
('syllabus', '教学大纲'),
('lesson_plan', '教案'),
], string='类型', required=True)
course_id = fields.Many2one('learning.course', string='所属课程', required=True, ondelete='cascade')
course_name = fields.Char(related="course_id.name", string="课程名称", readonly=True)
course_code = fields.Char(related="course_id.code", string="课程代码", readonly=True)
course_credit = fields.Float(related="course_id.credit", string="学分", readonly=True)
course_exam_type = fields.Selection(related="course_id.exam_type", string="考核方式", readonly=True)
chapter_id = fields.Many2one('course.chapter', string='关联章节')
chapter_name = fields.Char(related="chapter_id.name", string="章节名称", readonly=True)
chapter_sequence = fields.Integer(related="chapter_id.sequence", string="章节序号", readonly=True)
chapter_is_published = fields.Boolean(related="chapter_id.is_published", string="发布状态", readonly=True)
# 文件核心字段
file = fields.Binary(string='文件', attachment=True, required=True)
file_name = fields.Char(string='文件名')
file_size = fields.Integer(string='文件大小(字节)', readonly=True)
file_size_str = fields.Char(string='文件大小', readonly=True) # 友好显示KB/MB
file_suffix = fields.Char(string='文件格式', readonly=True) # 后缀docx/pptx/pdf
version = fields.Char(string='版本号', default='1.0')
version_note = fields.Char(string='版本说明')
publish_date = fields.Date(string='发布日期', default=fields.Date.today)
is_published = fields.Boolean(string='是否发布', default=True)
download_count = fields.Integer(string='下载次数', default=0)
teaching_class_id = fields.Many2one(
'course.teaching_class',
string='教学班',
ondelete='cascade',
domain="[('course_id', '=', course_id)]"
)
# 监听文件上传,自动赋值文件名、大小、后缀
@api.onchange('file', 'file_name')
def _onchange_file_upload(self):
for record in self:
if record.file and record.file_name:
# 计算文件大小base64 换算)
file_data = base64.b64decode(record.file)
size_bytes = len(file_data)
record.file_size = size_bytes
record.file_size_str = human_size(size_bytes)
# 提取文件后缀
name, suffix = os.path.splitext(record.file_name)
record.file_suffix = suffix.lower().strip('.')
else:
record.file_size = 0
record.file_size_str = ''
record.file_suffix = ''
# 修复批量下载问题 + 优化下载响应
def action_download(self):
for rec in self:
rec.download_count += 1
if rec.file_name:
# 携带真实文件名,浏览器正常识别
url = f'/web/content/course.syllabus/{rec.id}/file/{rec.file_name}?download=true'
else:
url = f'/web/content/course.syllabus/{rec.id}/file?download=true'
return {
'type': 'ir.actions.act_url',
'url': url,
'target': 'self', # self 强制下载new 新标签页打开
}

View File

@ -0,0 +1,291 @@
from odoo import api, fields, models
from odoo.exceptions import ValidationError
import base64
from io import BytesIO
try:
import pandas as pd
except ImportError:
pd = None
class CourseTeachingClass(models.Model):
_name = 'course.teaching_class'
_description = '教学班'
_rec_name = 'display_name'
_order = 'course_id, semester, name'
_inherit = ['mail.thread', 'mail.activity.mixin']
# ==================== 显示名称 ====================
display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True)
name = fields.Char(string='教学班名称', required=True, help='1班、2班、周一班')
code = fields.Char(string='班级代码', help='CS101-01')
semester = fields.Selection([
('2024-2025-1', '2024-2025学年第一学期'),
('2024-2025-2', '2024-2025学年第二学期'),
('2025-2026-1', '2025-2026学年第一学期'),
('2025-2026-2', '2025-2026学年第二学期'),
], string='学期', required=True, default=lambda self: self._get_current_semester())
# ==================== 关联课程 ====================
course_id = fields.Many2one('learning.course', string='课程', required=True, ondelete='cascade')
course_name = fields.Char(related='course_id.name', string='课程名称')
@api.depends('course_name', 'name', 'semester')
def _compute_display_name(self):
for record in self:
semester_map = dict(self._fields['semester'].selection)
semester_name = semester_map.get(record.semester, '')
record.display_name = f"{record.course_name} - {record.name}({semester_name})"
# ==================== 基本信息 ====================
course_code = fields.Char(string='课程代码', related='course_id.code', store=True)
course_credit = fields.Float(string='学分', related='course_id.credit', store=True)
course_exam_type = fields.Selection(string='考核方式', related='course_id.exam_type', store=True)
# ==================== 教师信息 ====================
teacher_ids = fields.Many2many('hr.employee', string='授课教师',
relation='teaching_class_teacher_rel')
main_teacher_id = fields.Many2one('hr.employee', string='主讲教师')
assistant_ids = fields.Many2many('hr.employee', string='助教',
relation='teaching_class_assistant_rel')
# ==================== 学生信息(保留仅做展示,数据以 enrollment 为准) ====================
student_ids = fields.Many2many('student.info', string='选课学生',
relation='teaching_class_student_rel')
student_count = fields.Integer(string='选课人数', compute='_compute_student_count')
# ==================== 上课信息 ====================
schedule = fields.Text(string='上课时间地点', help='如:周一 1-2节 教学楼101')
start_date = fields.Date(string='开课日期')
end_date = fields.Date(string='结课日期')
total_weeks = fields.Integer(string='教学周数', default=16)
# ==================== 人数限制 ====================
max_students = fields.Integer(string='人数上限', default=60)
min_students = fields.Integer(string='开课人数下限', default=20)
is_full = fields.Boolean(string='是否满员', compute='_compute_is_full')
# ==================== 状态 ====================
state = fields.Selection([
('draft', '未开放'),
('open', '选课中'),
('teaching', '教学中'),
('closed', '已结课'),
('cancelled', '已取消'),
], string='状态', default='draft', tracking=True)
# ==================== 教学进度 ====================
current_chapter = fields.Integer(string='当前进度章节', help='当前教学进度')
progress_rate = fields.Float(string='教学进度(%)', compute='_compute_progress_rate')
# ==================== 统计字段 ====================
homework_count = fields.Integer(string='作业数量', compute='_compute_homework_count')
submitted_count = fields.Integer(string='已提交作业数', compute='_compute_homework_count')
resource_count = fields.Integer(string='资源数量', compute='_compute_resource_count')
# ==================== 关联子表(核心:所有业务依赖 enrollment_ids ====================
homework_ids = fields.One2many('course.homework', 'teaching_class_id', string='班级作业')
student_score_ids = fields.One2many('course.student.score', 'teaching_class_id', string='班级成绩')
enrollment_ids = fields.One2many('course.teaching_class.enrollment', 'teaching_class_id', string='选课记录')
course_syllabus_ids = fields.One2many('course.syllabus', 'teaching_class_id', string='教案/大纲')
# ==================== 计算方法(全部走选课记录) ====================
def _compute_student_count(self):
for record in self:
valid_enroll = record.enrollment_ids.filtered(lambda e: e.state == 'enrolled')
record.student_count = len(valid_enroll)
def _compute_is_full(self):
for record in self:
record.is_full = record.max_students > 0 and record.student_count >= record.max_students
def _compute_progress_rate(self):
for record in self:
if record.total_weeks and record.current_chapter:
record.progress_rate = record.current_chapter / record.total_weeks * 100
else:
record.progress_rate = 0
def _compute_homework_count(self):
for record in self:
homeworks = self.env['course.homework'].search([('teaching_class_id', '=', record.id)])
record.homework_count = len(homeworks)
record.submitted_count = 0
def _compute_resource_count(self):
for record in self:
resources = self.env['course.chapter.resource'].search([
('teaching_class_id', '=', record.id)
])
record.resource_count = len(resources)
# ==================== 业务按钮方法 ====================
def action_open_enroll(self):
self.state = 'open'
def action_start_teaching(self):
self.state = 'teaching'
def action_close(self):
self.state = 'closed'
def action_cancel(self):
self.state = 'cancelled'
def action_add_students(self):
"""打开批量添加学生向导(底层批量生成选课记录)"""
return {
'type': 'ir.actions.act_window',
'name': '添加学生',
'res_model': 'course.teaching_class.enrollment.wizard',
'view_mode': 'form',
'target': 'new',
'context': {'default_teaching_class_id': self.id},
}
def action_import_students(self):
"""导入入口,复用向导"""
return self.action_add_students()
@api.model
def _get_current_semester(self):
import datetime
now = datetime.datetime.now()
year = now.year
if now.month >= 9:
return f'{year}-{year + 1}-1'
elif now.month >= 2:
return f'{year - 1}-{year}-2'
else:
return f'{year - 1}-{year}-1'
# 可选:双向同步 student_ids 和 enrollment_ids保证两边显示一致后期可删除 student_ids
@api.depends('enrollment_ids.student_id')
def _sync_student_ids(self):
for rec in self:
stu_ids = rec.enrollment_ids.mapped('student_id').ids
rec.student_ids = [(6, 0, stu_ids)]
student_ids = fields.Many2many(
'student.info',
string='选课学生',
relation='teaching_class_student_rel',
compute='_sync_student_ids',
store=True
)
class CourseTeachingClassEnrollment(models.Model):
_name = 'course.teaching_class.enrollment'
_description = '教学班选课记录'
_rec_name = 'display_name'
_order = 'teaching_class_id, student_id'
display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True)
course_id = fields.Many2one(related="teaching_class_id.course_id", string="课程", store=True)
teaching_class_id = fields.Many2one('course.teaching_class', string='教学班', required=True, ondelete='cascade')
student_id = fields.Many2one('student.info', string='学生', required=True, ondelete='cascade')
stu_name = fields.Char(related='student_id.stu_name', string='学生姓名')
stu_phone = fields.Char(related='student_id.stu_phone', string='学生电话')
# 选课信息
enroll_date = fields.Date(string='选课日期', default=fields.Date.today)
state = fields.Selection([
('enrolled', '已选课'),
('dropped', '已退课'),
('failed', '不及格'),
('passed', '已通过'),
], string='状态', default='enrolled', tracking=True)
# 成绩(最终成绩)
final_score = fields.Float(string='最终成绩')
grade_level = fields.Selection([
('A', '优秀'),
('B', '良好'),
('C', '中等'),
('D', '及格'),
('F', '不及格'),
], string='等级')
@api.depends('teaching_class_id.display_name', 'student_id.stu_name')
def _compute_display_name(self):
for record in self:
record.display_name = f"{record.student_id.stu_name} - {record.teaching_class_id.display_name}"
@api.model
def create(self, vals):
"""新增选课记录校验人数上限"""
res = super().create(vals)
cls = res.teaching_class_id
valid_num = len(cls.enrollment_ids.filtered(lambda e: e.state == 'enrolled'))
if cls.max_students and valid_num > cls.max_students:
raise ValidationError("该教学班人数已达上限,无法继续添加学生!")
return res
# ==================== 批量添加/导入学生 向导(临时模型) ====================
class CourseTeachingClassEnrollmentWizard(models.TransientModel):
_name = 'course.teaching_class.enrollment.wizard'
_description = '批量添加&导入学生向导'
teaching_class_id = fields.Many2one(
'course.teaching_class', string='教学班', required=True
)
student_ids = fields.Many2many('student.info', string='选择学生')
file = fields.Binary(string='上传Excel文件')
filename = fields.Char(string='文件名')
def action_add_students(self):
"""手动勾选学生 → 批量生成选课记录"""
self.ensure_one()
cls = self.teaching_class_id
exist_stu_ids = set(cls.enrollment_ids.mapped('student_id').ids)
create_list = []
for stu in self.student_ids:
if stu.id not in exist_stu_ids:
create_list.append({
'teaching_class_id': cls.id,
'student_id': stu.id,
'state': 'enrolled'
})
if create_list:
self.env['course.teaching_class.enrollment'].create(create_list)
return {'type': 'ir.actions.act_window_close'}
def action_import_excel(self):
"""Excel导入 → 批量生成选课记录"""
self.ensure_one()
if not self.file:
raise ValidationError("请先选择Excel文件")
if not pd:
raise ValidationError("缺少 pandas 库请先安装pip install pandas openpyxl")
cls = self.teaching_class_id
exist_stu_ids = set(cls.enrollment_ids.mapped('student_id').ids)
create_list = []
try:
file_data = base64.b64decode(self.file)
excel_file = BytesIO(file_data)
df = pd.read_excel(excel_file, engine='openpyxl')
for _, row in df.iterrows():
stu_code = str(row.get('学号', '')).strip()
if not stu_code:
continue
student = self.env['student.info'].search([('stu_id', '=', stu_code)], limit=1)
if student and student.id not in exist_stu_ids:
create_list.append({
'teaching_class_id': cls.id,
'student_id': student.id,
'state': 'enrolled'
})
except Exception as e:
raise ValidationError(f"解析Excel失败{str(e)}")
if create_list:
self.env['course.teaching_class.enrollment'].create(create_list)
return {'type': 'ir.actions.act_window_close'}

View File

@ -0,0 +1,113 @@
from odoo import api, fields, models
class LearningCourse(models.Model):
_name = 'learning.course'
_description = '课程'
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string='课程名称', required=True)
code = fields.Char(string='课程代码', required=True, index=True)
english_name = fields.Char(string='英文名称')
credit = fields.Float(string='学分', required=True)
exam_type = fields.Selection([
('exam', '考试'),
('assessment', '考查'),
], string='考核方式')
description = fields.Html(string='课程简介')
objectives = fields.Html(string='教学目标')
state = fields.Selection([
('draft', '草稿'),
('published', '已发布'),
], default='draft', required=True)
# ==================== 关联章节 ====================
chapter_ids = fields.One2many('course.chapter', 'course_id', string='章节')
chapter_count = fields.Integer(string='章节数', compute='_compute_chapter_count', store=True)
# ==================== 关联教学大纲/教案 ====================
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')
# ==================== 统计资源(通过章节关联) ====================
resource_count = fields.Integer(string='资源总数', compute='_compute_resource_count', store=True)
video_count = fields.Integer(string='视频数', compute='_compute_resource_count', store=True)
doc_count = fields.Integer(string='文档数', compute='_compute_resource_count', store=True)
# 汇总所有章节的资源
resource_all_ids = fields.One2many(
comodel_name='course.chapter.resource',
inverse_name=None,
compute='_compute_resource_all_ids',
string='资源列表',
readonly=True
)
@api.depends('chapter_ids', 'chapter_ids.resource_ids')
def _compute_resource_all_ids(self):
for record in self:
# 取出所有章节下的资源记录
all_resources = record.chapter_ids.mapped('resource_ids')
record.resource_all_ids = all_resources
# ==================== 计算字段方法 ====================
@api.depends('chapter_ids')
def _compute_chapter_count(self):
for record in self:
record.chapter_count = len(record.chapter_ids)
@api.depends('syllabus_ids', 'syllabus_ids.syllabus_type')
def _compute_syllabus_count(self):
for record in self:
record.syllabus_count = len(record.syllabus_ids)
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'))
@api.depends('chapter_ids.resource_ids', 'chapter_ids.resource_ids.resource_type')
def _compute_resource_count(self):
for record in self:
resources = record.chapter_ids.mapped('resource_ids')
record.resource_count = len(resources)
record.video_count = len(resources.filtered(lambda r: r.resource_type == 'video'))
record.doc_count = len(resources.filtered(lambda r: r.resource_type in ['pdf', 'ppt']))
# ==================== 业务方法 ====================
def action_publish(self):
"""发布课程"""
self.state = 'published'
def action_draft(self):
"""退回草稿"""
self.state = 'draft'
def action_view_chapters(self):
"""查看章节"""
return {
'type': 'ir.actions.act_window',
'name': '课程章节',
'res_model': 'course.chapter',
'view_mode': 'list,form',
'domain': [('course_id', '=', self.id)],
'context': {'default_course_id': self.id},
}
def action_view_syllabus(self):
"""查看教学大纲/教案"""
return {
'type': 'ir.actions.act_window',
'name': '教学大纲/教案',
'res_model': 'course.syllabus',
'view_mode': 'list,form',
'domain': [('course_id', '=', self.id)],
'context': {'default_course_id': self.id},
}
def action_view_resources(self):
"""查看所有资源"""
return {
'type': 'ir.actions.act_window',
'name': '教学资源',
'res_model': 'course.chapter.resource',
'view_mode': 'list,form',
'domain': [('chapter_id.course_id', '=', self.id)],
}

View File

@ -0,0 +1,13 @@
from odoo import api,fields,models
class TeachClass(models.Model):
_name = 'teach.class'
course_teaching_class=fields.Many2one('course.teaching_class',string="教学班")
student_id=fields.Many2one('student.info',string='学生')
stu_num=fields.Char(related='student_id.stu_num',string='学号')
stu_name=fields.Char(related='student_id.stu_name',string='姓名')
stu_sex = fields.Selection(related='student_id.stu_sex', string="性别")
stu_phone = fields.Char(related='student_id.stu_phone', string="手机号")
stu_grade_xx = fields.Many2one(related='student_id.stu_grade_xx', string="年级")

View File

@ -0,0 +1,24 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_learning_course_sys,learning.course.access.sys,model_learning_course,base.group_system,1,1,1,1
access_course_chapter_sys,course.chapter.access.sys,model_course_chapter,base.group_system,1,1,1,1
access_course_chapter_resource_sys,course.chapter.resource.access.sys,model_course_chapter_resource,base.group_system,1,1,1,1
access_course_homework_sys,course.homework.access.sys,model_course_homework,base.group_system,1,1,1,1
access_course_homework_submit_sys,course.homework.submit.access.sys,model_course_homework_submit,base.group_system,1,1,1,1
access_course_score_item_sys,course.score.item.access.sys,model_course_score_item,base.group_system,1,1,1,1
access_course_student_score_sys,course.student.score.access.sys,model_course_student_score,base.group_system,1,1,1,1
access_course_student_score_detail_sys,course.student.score.detail.access.sys,model_course_student_score_detail,base.group_system,1,1,1,1
access_course_syllabus_sys,course.syllabus.access.sys,model_course_syllabus,base.group_system,1,1,1,1
access_course_teaching_class_sys,course.teaching.class.access.sys,model_course_teaching_class,base.group_system,1,1,1,1
access_course_teaching_class_enrollment_sys,course.teaching.class.enrollment.access.sys,model_course_teaching_class_enrollment,base.group_system,1,1,1,1
access_course_teaching_class_enrollment_wizard_sys,course.teaching.class.enrollment.access.sys,model_course_teaching_class_enrollment_wizard,base.group_system,1,1,1,1
access_teach_class_teacher,teach.class.access.teacher,model_teach_class,edu_base.group_teacher,1,1,0,0
access_teach_class_sys,teach.class.access.sys,model_teach_class,base.group_system,1,1,1,1
access_course_teaching_class_teacher,course.teaching.class.access.teacher,model_course_teaching_class,edu_base.group_teacher,1,0,0,0
access_course_teaching_class_enrollment_teacher,course.teaching.class.enrollment.access.teacher,model_course_teaching_class_enrollment,edu_base.group_teacher,1,0,0,0
access_course_homework_teacher,course.homework.access.teacher,model_course_homework,edu_base.group_teacher,1,1,1,0
access_course_homework_submit_teacher,course.homework.submit.access.teacher,model_course_homework_submit,edu_base.group_teacher,1,1,1,0
access_learning_course_teacher,learning.course.access.teacher,model_learning_course,edu_base.group_teacher,1,0,0,0
access_course_chapter_teacher,course.chapter.access.teacher,model_course_chapter,edu_base.group_teacher,1,1,1,0
access_course_chapter_resource_teacher,course.chapter.resource.access.teacher,model_course_chapter_resource,edu_base.group_teacher,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_learning_course_sys learning.course.access.sys model_learning_course base.group_system 1 1 1 1
3 access_course_chapter_sys course.chapter.access.sys model_course_chapter base.group_system 1 1 1 1
4 access_course_chapter_resource_sys course.chapter.resource.access.sys model_course_chapter_resource base.group_system 1 1 1 1
5 access_course_homework_sys course.homework.access.sys model_course_homework base.group_system 1 1 1 1
6 access_course_homework_submit_sys course.homework.submit.access.sys model_course_homework_submit base.group_system 1 1 1 1
7 access_course_score_item_sys course.score.item.access.sys model_course_score_item base.group_system 1 1 1 1
8 access_course_student_score_sys course.student.score.access.sys model_course_student_score base.group_system 1 1 1 1
9 access_course_student_score_detail_sys course.student.score.detail.access.sys model_course_student_score_detail base.group_system 1 1 1 1
10 access_course_syllabus_sys course.syllabus.access.sys model_course_syllabus base.group_system 1 1 1 1
11 access_course_teaching_class_sys course.teaching.class.access.sys model_course_teaching_class base.group_system 1 1 1 1
12 access_course_teaching_class_enrollment_sys course.teaching.class.enrollment.access.sys model_course_teaching_class_enrollment base.group_system 1 1 1 1
13 access_course_teaching_class_enrollment_wizard_sys course.teaching.class.enrollment.access.sys model_course_teaching_class_enrollment_wizard base.group_system 1 1 1 1
14 access_teach_class_teacher teach.class.access.teacher model_teach_class edu_base.group_teacher 1 1 0 0
15 access_teach_class_sys teach.class.access.sys model_teach_class base.group_system 1 1 1 1
16 access_course_teaching_class_teacher course.teaching.class.access.teacher model_course_teaching_class edu_base.group_teacher 1 0 0 0
17 access_course_teaching_class_enrollment_teacher course.teaching.class.enrollment.access.teacher model_course_teaching_class_enrollment edu_base.group_teacher 1 0 0 0
18 access_course_homework_teacher course.homework.access.teacher model_course_homework edu_base.group_teacher 1 1 1 0
19 access_course_homework_submit_teacher course.homework.submit.access.teacher model_course_homework_submit edu_base.group_teacher 1 1 1 0
20 access_learning_course_teacher learning.course.access.teacher model_learning_course edu_base.group_teacher 1 0 0 0
21 access_course_chapter_teacher course.chapter.access.teacher model_course_chapter edu_base.group_teacher 1 1 1 0
22 access_course_chapter_resource_teacher course.chapter.resource.access.teacher model_course_chapter_resource edu_base.group_teacher 1 1 1 0

View File

@ -0,0 +1,41 @@
<odoo>
<!-- 教师:仅查看自己创建的班级关联数据 -->
<record id="rule_teaching_class_teacher_own" model="ir.rule">
<field name="name">教师-仅查看自己的班级数据</field>
<field name="model_id" ref="model_course_teaching_class"/>
<!-- 仅对教师组生效 -->
<field name="groups" eval="[(6,0, [ref('edu_base.group_teacher')])]"/>
<!-- create_uid 是系统内置字段记录创建人uid 当前登录用户-->
<field name="domain_force">[('main_teacher_id.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_course_homework_teacher_own" model="ir.rule">
<field name="name">作业发布-仅查看自己发布的作业</field>
<field name="model_id" ref="model_course_homework"/>
<!-- 仅对教师组生效 -->
<field name="groups" eval="[(6,0, [ref('edu_base.group_teacher')])]"/>
<!-- create_uid 是系统内置字段记录创建人uid 当前登录用户-->
<field name="domain_force">[('create_uid', '=', 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>
<record id="rule_course_homework_submit_teacher_own" model="ir.rule">
<field name="name">作业提价-仅查看自己发布的作业的提交情况</field>
<field name="model_id" ref="model_course_homework_submit"/>
<!-- 仅对教师组生效 -->
<field name="groups" eval="[(6,0, [ref('edu_base.group_teacher')])]"/>
<!-- create_uid 是系统内置字段记录创建人uid 当前登录用户-->
<field name="domain_force">[('homework_id.create_uid', '=', 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>

View File

@ -0,0 +1,135 @@
<odoo>
<record id="list_course_chapter" model="ir.ui.view">
<field name="name">course.chapter.list</field>
<field name="model">course.chapter</field>
<field name="arch" type="xml">
<list>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="course_id"/>
<field name="resource_count" sum="合计"/>
<field name="video_count"/>
<field name="doc_count"/>
<field name="is_published" widget="boolean_toggle"/>
</list>
</field>
</record>
<record id="form_course_chapter" model="ir.ui.view">
<field name="name">course.chapter.form</field>
<field name="model">course.chapter</field>
<field name="arch" type="xml">
<form string="章节">
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="章节名称"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_publish" type="object" string="发布" class="btn-primary"
invisible="is_published == True"/>
<button name="action_hide" type="object" string="隐藏" class="btn-secondary"
invisible="is_published == False"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="course_id" options="{'no_create': True}"/>
<field name="sequence"/>
<field name="is_published" widget="boolean_toggle"/>
</group>
<group>
<field name="resource_count" readonly="1"/>
<field name="video_count" readonly="1"/>
<field name="doc_count" readonly="1"/>
</group>
</group>
<group name="description" string="章节描述">
<field name="description" placeholder="章节描述"/>
</group>
<notebook>
<page string="教学资源">
<field name="resource_ids" view_id="view_course_chapter_resource_sub_list"/>
</page>
<page string="关联作业">
<!-- <field name="homework_ids" view_id="view_course_chapter_homework_sub_list"-->
<!-- context="{'default_course_id': course_id}"/>-->
</page>
<page string="教学大纲/教案">
<field name="syllabus_ids" view_id="view_course_chapter_syllabus_sub_list"
context="{'default_course_id': course_id, 'default_chapter_id': id}"/>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_course_chapter_search" model="ir.ui.view">
<field name="name">course.chapter.search</field>
<field name="model">course.chapter</field>
<field name="arch" type="xml">
<search>
<searchpanel>
<field name="course_id" string="课程" />
</searchpanel>
</search>
</field>
</record>
<!-- <record id="view_course_chapter_resource_sub_list" model="ir.ui.view">-->
<!-- <field name="name">course.chapter.resource.sub.list</field>-->
<!-- <field name="model">course.chapter.resource</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <list editable="bottom">-->
<!-- <field name="sequence" widget="handle"/>-->
<!-- <field name="name"/>-->
<!-- <field name="resource_type" widget="badge"/>-->
<!-- <field name="is_hidden" widget="boolean_toggle"/>-->
<!-- </list>-->
<!-- </field>-->
<!-- </record>-->
<!-- <record id="view_course_chapter_homework_sub_list" model="ir.ui.view">-->
<!-- <field name="name">course.chapter.homework.sub.list</field>-->
<!-- <field name="model">course.homework</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <list>-->
<!-- <field name="name"/>-->
<!-- <field name="deadline"/>-->
<!-- <field name="state" widget="badge"/>-->
<!-- </list>-->
<!-- </field>-->
<!-- </record>-->
<!-- 内嵌大纲/教案列表视图(用于一对多) -->
<record id="view_course_chapter_syllabus_sub_list" model="ir.ui.view">
<field name="name">course.chapter.syllabus.sub.list</field>
<field name="model">course.syllabus</field>
<field name="arch" type="xml">
<list editable="bottom">
<field name="title"/>
<field name="syllabus_type" widget="badge"/>
<field name="version"/>
<field name="is_published" widget="boolean_toggle"/>
</list>
</field>
</record>
<record id="act_course_chapter" model="ir.actions.act_window">
<field name="name">章节管理</field>
<field name="res_model">course.chapter</field>
<field name="view_mode">list,form</field>
</record>
<record id="menu_course_chapter" model="ir.ui.menu">
<field name="name">章节管理</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_chapter"/>
<field name="groups_id" eval="[(6, 0, [ref('base.group_system'),ref('edu_base.group_teacher')])]"/>
<field name="sequence">20</field>
</record>
</odoo>

View File

@ -0,0 +1,107 @@
<odoo>
<record id="list_course_chapter_resource" model="ir.ui.view">
<field name="name">course.chapter.resource.list</field>
<field name="model">course.chapter.resource</field>
<field name="arch" type="xml">
<list>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="resource_type" widget="badge"/>
<field name="chapter_id"/>
<field name="course_id"/>
<field name="is_hidden" widget="boolean_toggle"/>
</list>
</field>
</record>
<record id="form_course_chapter_resource" model="ir.ui.view">
<field name="name">course.chapter.resource.form</field>
<field name="model">course.chapter.resource</field>
<field name="arch" type="xml">
<form string="教学资源">
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="资源名称"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_toggle_hide" type="object" string="切换隐藏状态" class="btn-secondary"/>
<button name="action_preview" type="object" string="预览" class="btn-primary"
invisible="preview_url == False"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="chapter_id" options="{'no_create': True}"/>
<field name="course_id" readonly="1"/>
<field name="sequence"/>
<field name="resource_type"/>
<field name="is_hidden" widget="boolean_toggle"/>
</group>
<group>
<field name="description" placeholder="备注说明" nolabel="1"/>
</group>
</group>
<!-- 原有视频区域 保留不变 -->
<group name="video_info" string="视频信息" invisible="resource_type != 'video'">
<group>
<field name="video_file" filename="video_filename" widget="binary"/>
<field name="video_filename" invisible="1"/>
<field name="video_duration" help="时长(秒)"/>
<field name="video_url" placeholder="外部视频链接"/>
</group>
</group>
<!-- 原有文档区域 保留不变 -->
<group name="doc_info" string="文档信息" invisible="resource_type not in ['pdf', 'ppt']">
<group>
<field name="doc_file" filename="doc_filename" widget="binary"/>
<field name="doc_filename" invisible="1"/>
<field name="doc_page_count" readonly="1"/>
</group>
</group>
<!-- 新增:批量上传附件区域 独立分组 -->
<group string="批量上传附件">
<field name="resource_attachment_ids" widget="many2many_binary"
string="多文件上传(可Ctrl/Shift多选)"/>
<field name="attachment_count" string="附件总数" readonly="1"/>
</group>
<notebook>
<page string="所属课程信息">
<group string="课程信息">
<field name="course_id" readonly="1"/>
<field name="course_name" string="课程名称" readonly="1"/>
<field name="course_code" string="课程代码" readonly="1"/>
<field name="course_credit" string="学分" readonly="1"/>
</group>
</page>
<page string="关联章节信息">
<group string="章节信息">
<field name="chapter_name" string="章节名称" readonly="1"/>
<field name="chapter_sequence" string="章节序号" readonly="1"/>
<field name="chapter_is_published" string="章节发布状态" readonly="1"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="act_course_chapter_resource" model="ir.actions.act_window">
<field name="name">教学资源</field>
<field name="res_model">course.chapter.resource</field>
<field name="view_mode">list,form</field>
</record>
<record id="menu_course_chapter_resource" model="ir.ui.menu">
<field name="name">教学资源</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_chapter_resource"/>
<field name="groups_id" eval="[(6, 0, [ref('base.group_system'),ref('edu_base.group_teacher')])]"/>
<field name="sequence">30</field>
</record>
</odoo>

View File

@ -0,0 +1,123 @@
<odoo>
<record id="list_course_homework" model="ir.ui.view">
<field name="name">course.homework.list</field>
<field name="model">course.homework</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="course_id"/>
<field name="chapter_id"/>
<field name="total_score"/>
<field name="deadline"/>
<field name="submitted_count" sum="合计"/>
<field name="unsubmitted_count" sum="合计"/>
<field name="state" widget="badge"/>
<field name="is_submit_open" widget="boolean_toggle"/>
</list>
</field>
</record>
<record id="form_course_homework" model="ir.ui.view">
<field name="name">course.homework.form</field>
<field name="model">course.homework</field>
<field name="arch" type="xml">
<form string="课程作业">
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="作业名称"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_publish" type="object" string="发布" class="btn-primary"
invisible="state in ['published', 'closed']"/>
<button name="action_close" type="object" string="关闭" class="btn-danger"
invisible="state != 'published'"/>
<button name="action_draft" type="object" string="退回草稿" class="btn-secondary"
invisible="state != 'published'"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="teaching_class_id"/>
<field name="course_id" options="{'no_create': True}"/>
<field name="chapter_id" options="{'no_create': True}"/>
<field name="total_score"/>
<field name="state" widget="statusbar"/>
</group>
<group>
<field name="publish_time" readonly="1"/>
<field name="deadline"/>
<field name="late_deadline"/>
<field name="is_submit_open" widget="boolean_toggle"/>
<field name="allow_late" widget="boolean_toggle"/>
</group>
</group>
<notebook>
<page string="作业内容">
<group>
<field name="description" placeholder="作业描述"/>
<field name="requirement" placeholder="作业要求"/>
</group>
</page>
<page string="提交情况">
<group string="统计信息">
<group>
<field name="total_students"/>
<field name="submitted_count"/>
</group>
<group>
<field name="late_count"/>
<field name="unsubmitted_count"/>
</group>
</group>
<!-- <field name="submit_ids" view_id="view_course_homework_submit_sub_list"/>-->
</page>
<page string="成绩关联">
<group string="关联成绩项目">
<!-- <field name="score_item_ids" context="{'default_course_id': course_id}">-->
<!-- <list>-->
<!-- <field name="name"/>-->
<!-- <field name="score_type" widget="badge"/>-->
<!-- <field name="weight"/>-->
<!-- <field name="full_score"/>-->
<!-- </list>-->
<!-- </field>-->
</group>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- <record id="view_course_homework_submit_sub_list" model="ir.ui.view">-->
<!-- <field name="name">course.homework.submit.sub.list</field>-->
<!-- <field name="model">course.homework.submit</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <list editable="bottom">-->
<!-- <field name="student_id"/>-->
<!-- <field name="submit_time"/>-->
<!-- <field name="is_late" widget="boolean_toggle"/>-->
<!-- <field name="score"/>-->
<!-- <field name="state" widget="badge"/>-->
<!-- </list>-->
<!-- </field>-->
<!-- </record>-->
<record id="act_course_homework" model="ir.actions.act_window">
<field name="name">作业管理</field>
<field name="res_model">course.homework</field>
<field name="view_mode">list,form</field>
</record>
<record id="menu_course_homework" model="ir.ui.menu">
<field name="name">作业发布</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_homework"/>
<field name="groups_id" eval="[(6,0,[ref('base.group_system'),ref('edu_base.group_teacher')])]"/>
<field name="sequence">40</field>
</record>
</odoo>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ==================== 学生端作业列表视图(门户/前台) ==================== -->
<record id="view_course_homework_student_list" model="ir.ui.view">
<field name="name">course.homework.student.list</field>
<field name="model">course.homework</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="course_id"/>
<field name="teaching_class_id"/>
<field name="total_score"/>
<field name="deadline"/>
<field name="submit_state" widget="badge"/>
<field name="my_score"/>
</list>
</field>
</record>
<!-- ==================== 学生端作业表单视图(门户/前台) ==================== -->
<record id="view_course_homework_student_form" model="ir.ui.view">
<field name="name">course.homework.student.form</field>
<field name="model">course.homework</field>
<field name="arch" type="xml">
<form string="作业详情">
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="作业名称"/>
</h1>
</div>
<group name="basic_info" string="作业信息">
<group>
<field name="course_id"/>
<field name="teaching_class_id"/>
<field name="total_score"/>
<field name="deadline"/>
<field name="submit_state" widget="badge"/>
</group>
<group>
<field name="my_score"/>
<field name="my_grade_level" widget="badge"/>
<field name="my_submit_time"/>
</group>
</group>
<group name="content" string="作业内容">
<field name="description" placeholder="作业描述"/>
<field name="requirement" placeholder="作业要求"/>
</group>
<notebook>
<page string="提交作业" invisible="can_submit == False">
<group string="提交内容">
<field name="my_submit_file" filename="my_submit_filename" widget="binary"/>
<field name="my_submit_content" placeholder="填写你的答案或说明"/>
<div class="oe_button_box">
<button name="action_submit_homework" type="object" string="提交作业" class="btn-primary"/>
</div>
</group>
</page>
<page string="批改反馈" invisible="my_submit_state != 'graded'">
<group string="批改信息">
<field name="my_score"/>
<field name="my_grade_level" widget="badge"/>
<field name="my_comment" placeholder="教师评语"/>
</group>
<group string="我的提交">
<field name="my_submit_file" filename="my_submit_filename" widget="binary" readonly="1"/>
<field name="my_submit_content" readonly="1"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="act_course_homework_student" model="ir.actions.act_window">
<field name="name">我的作业</field>
<field name="res_model">course.homework</field>
<field name="view_mode">list,form</field>
<!-- <field name="domain">[('teaching_class_id.student_ids.user_id', '=', uid)]</field>-->
<!-- <field name="context">{'default_student_id': active_id}</field>-->
</record>
<record id="menu_student_root" model="ir.ui.menu">
<field name="name">学生作业</field>
<field name="sequence">20</field>
<!-- <field name="groups_id" eval="[(4, ref('student_info.group_student'))]"/>-->
<field name="action" ref="act_course_homework_student"/>
</record>
<!-- 学生端作业菜单 -->
<!-- <record id="menu_student_homework" model="ir.ui.menu">-->
<!-- <field name="name">我的作业</field>-->
<!-- <field name="parent_id" ref="menu_student_root"/>-->
<!-- <field name="action" ref="act_course_homework_student"/>-->
<!-- <field name="sequence">10</field>-->
<!--&lt;!&ndash; <field name="groups_id" eval="[(4, ref('student_info.group_student'))]"/>&ndash;&gt;-->
<!-- </record>-->
</odoo>

View File

@ -0,0 +1,119 @@
<odoo>
<record id="list_course_score_item" model="ir.ui.view">
<field name="name">course.score.item.list</field>
<field name="model">course.score.item</field>
<field name="arch" type="xml">
<list>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="course_id"/>
<field name="score_type" widget="badge"/>
<field name="weight"/>
<field name="full_score"/>
<field name="is_active" widget="boolean_toggle"/>
</list>
</field>
</record>
<record id="form_course_score_item" model="ir.ui.view">
<field name="name">course.score.item.form</field>
<field name="model">course.score.item</field>
<field name="arch" type="xml">
<form string="成绩项目">
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="项目名称"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_toggle_active" type="object" string="启用/禁用" class="btn-secondary"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="course_id" options="{'no_create': True}" required="1"/>
<field name="sequence"/>
<field name="score_type" required="1"/>
<field name="is_active" widget="boolean_toggle"/>
</group>
<group>
<field name="weight" required="1"/>
<field name="full_score"/>
<field name="description" placeholder="项目描述"/>
</group>
</group>
<notebook>
<page string="课程信息">
<group string="课程详情">
<field name="course_name" string="课程名称" readonly="1"/>
<field name="course_code" string="课程代码" readonly="1"/>
<field name="course_credit" string="学分" readonly="1"/>
<field name="course_exam_type" string="考核方式" readonly="1"/>
</group>
</page>
<page string="成绩统计">
<group string="统计信息">
<group>
<!-- <field name="student_count" string="学生人数" readonly="1"/>-->
<field name="student_count" string="提交人数" readonly="1"/>
<field name="avg_score" string="平均分" readonly="1"/>
</group>
<group>
<field name="max_score" string="最高分" readonly="1"/>
<field name="min_score" string="最低分" readonly="1"/>
</group>
</group>
<field name="score_detail_ids" view_id="view_score_detail_list"/>
</page>
<page string="关联作业">
<field name="homework_ids">
<list>
<field name="name"/>
<field name="deadline"/>
<field name="state" widget="badge"/>
</list>
</field>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_score_detail_list" model="ir.ui.view">
<field name="name">course.student.score.detail.list</field>
<field name="model">course.student.score.detail</field>
<field name="arch" type="xml">
<list>
<field name="student_id"/>
<field name="score"/>
<field name="remark"/>
</list>
</field>
</record>
<record id="act_course_score_item" model="ir.actions.act_window">
<field name="name">成绩项目</field>
<field name="res_model">course.score.item</field>
<field name="view_mode">list,form</field>
</record>
<record id="act_course_score_item_by_course" model="ir.actions.act_window">
<field name="name">成绩项目</field>
<field name="res_model">course.score.item</field>
<field name="view_mode">list,form</field>
<field name="view_id" ref="list_course_score_item"/>
<!-- <field name="domain">[('course_id', '=', active_id)]</field>-->
<!-- <field name="context">{'default_course_id': active_id}</field>-->
</record>
<record id="menu_course_score_item" model="ir.ui.menu">
<field name="name">成绩项目</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_score_item"/>
<field name="sequence">50</field>
</record>
</odoo>

View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ==================== 学生成绩列表视图 ==================== -->
<record id="list_course_student_score" model="ir.ui.view">
<field name="name">course.student.score.list</field>
<field name="model">course.student.score</field>
<field name="arch" type="xml">
<list>
<field name="student_id"/>
<field name="stu_name"/>
<field name="course_id"/>
<field name="course_name"/>
<field name="teaching_class_id"/>
<field name="total_score"/>
<field name="grade_level" widget="badge"/>
</list>
</field>
</record>
<!-- ==================== 学生成绩表单视图 ==================== -->
<record id="form_course_student_score" model="ir.ui.view">
<field name="name">course.student.score.form</field>
<field name="model">course.student.score</field>
<field name="arch" type="xml">
<form string="学生成绩">
<sheet>
<div class="oe_title">
<h1>
<field name="display_name" placeholder="成绩记录"/>
</h1>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="course_id" options="{'no_create': True}"/>
<field name="course_name" readonly="1"/>
<field name="teaching_class_id" options="{'no_create': True}"
domain="[('course_id', '=', course_id)]"/>
<field name="student_id" options="{'no_create': True}"/>
<field name="stu_name" readonly="1"/>
</group>
<group>
<field name="total_score"/>
<field name="grade_level" widget="badge"/>
</group>
</group>
<notebook>
<page string="成绩明细">
<field name="score_ids">
<list editable="bottom">
<field name="score_item_id" options="{'no_create': True}"/>
<field name="score"/>
<field name="full_score" readonly="1"/>
<field name="weight" readonly="1"/>
<field name="completion_rate" widget="progressbar"/>
<field name="remark"/>
</list>
</field>
</page>
<page string="课程信息">
<group string="课程详情">
<field name="course_name" string="课程名称" readonly="1"/>
<field name="course_code" string="课程代码" readonly="1"/>
<field name="course_credit" string="学分" readonly="1"/>
<field name="course_exam_type" string="考核方式" readonly="1"/>
</group>
</page>
<page string="教学班信息" invisible="not teaching_class_id">
<group string="教学班详情">
<field name="teaching_class_name" string="教学班名称" readonly="1"/>
<field name="teaching_class_semester" string="学期" readonly="1"/>
<field name="teaching_class_main_teacher" string="主讲教师" readonly="1"/>
</group>
</page>
<page string="学生信息">
<group string="学生详情">
<field name="stu_name" string="姓名" readonly="1"/>
<field name="student_no" string="学号" readonly="1"/>
<field name="student_class_id" string="班级" readonly="1"/>
<field name="student_major_id" string="专业" readonly="1"/>
</group>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- ==================== 学生成绩明细列表视图 ==================== -->
<record id="view_course_student_score_detail_list" model="ir.ui.view">
<field name="name">course.student.score.detail.list</field>
<field name="model">course.student.score.detail</field>
<field name="arch" type="xml">
<list>
<field name="student_id"/>
<field name="student_score_displayname"/>
<field name="score_item_id"/>
<field name="score"/>
<field name="full_score"/>
<field name="weight"/>
<field name="completion_rate" widget="progressbar"/>
<field name="remark"/>
</list>
</field>
</record>
<!-- ==================== 学生成绩明细表单视图 ==================== -->
<record id="view_course_student_score_detail_form" model="ir.ui.view">
<field name="name">course.student.score.detail.form</field>
<field name="model">course.student.score.detail</field>
<field name="arch" type="xml">
<form string="成绩明细">
<sheet>
<div class="oe_title">
<h1>
<field name="display_name" placeholder="成绩明细"/>
</h1>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="student_score_id" options="{'no_create': True}"/>
<field name="student_score_displayname" readonly="1"/>
<field name="score_item_id" options="{'no_create': True}"/>
<field name="score"/>
</group>
<group>
<field name="full_score" readonly="1"/>
<field name="weight" readonly="1"/>
<field name="score_type" readonly="1"/>
<field name="completion_rate" widget="progressbar" readonly="1"/>
</group>
</group>
<group name="related_info" string="关联信息">
<group>
<field name="course_id" readonly="1"/>
<field name="student_id" readonly="1"/>
</group>
<group>
<field name="remark" placeholder="备注"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- ==================== 学生成绩动作 ==================== -->
<record id="act_course_student_score" model="ir.actions.act_window">
<field name="name">学生成绩</field>
<field name="res_model">course.student.score</field>
<field name="view_mode">list,form</field>
</record>
<!-- ==================== 学生成绩明细动作 ==================== -->
<record id="act_course_student_score_detail" model="ir.actions.act_window">
<field name="name">成绩明细</field>
<field name="res_model">course.student.score.detail</field>
<field name="view_mode">list,form</field>
</record>
<!-- ==================== 按课程查看学生成绩的动作 ==================== -->
<record id="act_course_student_score_by_course" model="ir.actions.act_window">
<field name="name">学生成绩</field>
<field name="res_model">course.student.score</field>
<field name="view_mode">list,form</field>
<field name="view_id" ref="list_course_student_score"/>
<field name="domain">[('course_id', '=', active_id)]</field>
<field name="context">{'default_course_id': active_id}</field>
</record>
<!-- ==================== 按教学班查看学生成绩的动作 ==================== -->
<record id="act_course_student_score_by_teaching_class" model="ir.actions.act_window">
<field name="name">学生成绩</field>
<field name="res_model">course.student.score</field>
<field name="view_mode">list,form</field>
<field name="view_id" ref="list_course_student_score"/>
<field name="domain">[('teaching_class_id', '=', active_id)]</field>
<field name="context">{'default_teaching_class_id': active_id}</field>
</record>
<!-- ==================== 二级菜单 ==================== -->
<record id="menu_course_student_score" model="ir.ui.menu">
<field name="name">学生成绩</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_student_score"/>
<field name="sequence">60</field>
</record>
<!-- ==================== 成绩明细二级菜单 ==================== -->
<record id="menu_course_student_score_detail" model="ir.ui.menu">
<field name="name">成绩明细</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_student_score_detail"/>
<field name="sequence">65</field>
</record>
</odoo>

View File

@ -0,0 +1,134 @@
<odoo>
<!-- 列表视图 -->
<record id="list_course_syllabus" model="ir.ui.view">
<field name="name">course.syllabus.list</field>
<field name="model">course.syllabus</field>
<field name="arch" type="xml">
<list decoration-muted="not is_published">
<field name="title" string="标题"/>
<field name="syllabus_type" string="类型"/>
<field name="course_id" string="所属课程"/>
<field name="teaching_class_id" string="教学班"/>
<field name="chapter_id" string="关联章节"/>
<field name="file_suffix" string="文件格式"/>
<field name="version" string="版本号"/>
<field name="publish_date" string="发布日期"/>
<field name="is_published" widget="boolean_toggle" string="已发布"/>
<field name="download_count" string="下载次数"/>
<!-- 列表快速下载按钮 -->
<button name="action_download" type="object" string="下载" icon="fa-download" class="btn-sm"/>
</list>
</field>
</record>
<!-- 表单视图 -->
<record id="form_course_syllabus" model="ir.ui.view">
<field name="name">course.syllabus.form</field>
<field name="model">course.syllabus</field>
<field name="arch" type="xml">
<form string="教学大纲/教案">
<sheet>
<div class="oe_title">
<h1>
<field name="title" placeholder="请输入文档标题"/>
</h1>
</div>
<!-- 顶部按钮区 -->
<div class="oe_button_box" name="button_box">
<button name="action_download" type="object" string="下载文件" icon="fa-download" class="btn-primary"/>
</div>
<!-- 基础信息分组 分两列排版 -->
<group name="basic_info" string="基础信息" col="2">
<group>
<field name="syllabus_type" string="文档类型"/>
<field name="course_id" string="所属课程" options="{'no_create': True}"/>
<field name="teaching_class_id" string="教学班" options="{'no_create': True}"/>
<field name="chapter_id" string="关联章节" options="{'no_create': True}"
context="{'default_course_id': course_id}"
domain="[('course_id', '=', course_id)]"/>
</group>
<group>
<field name="version" string="版本号"/>
<field name="version_note" string="版本说明" placeholder="填写版本更新内容"/>
<field name="publish_date" string="发布日期"/>
<field name="is_published" widget="boolean_toggle" string="是否发布"/>
<field name="download_count" string="下载次数" readonly="1"/>
</group>
</group>
<!-- 文件上传区域 增加格式限制与展示 -->
<group name="file_info" string="附件文档" class="oe_mt16">
<field name="file"
filename="file_name"
widget="binary"
required="1"
accept=".doc,.docx,.ppt,.pptx,.pdf"
string="上传文件"/>
<!-- 隐藏原始文件名字段,后台自动赋值 -->
<field name="file_name" invisible="1"/>
<!-- 友好展示:文件格式、文件大小,隐藏原始字节数 -->
<group col="3" readonly="1" class="oe_pl16">
<field name="file_suffix" string="文件格式"/>
<field name="file_size_str" string="文件大小"/>
<field name="file_size" invisible="1"/>
</group>
</group>
<!-- 标签页区域 -->
<notebook class="oe_mt16">
<page string="课程信息">
<group string="课程基础资料" col="2">
<field name="course_name" string="课程名称" readonly="1"/>
<field name="course_code" string="课程代码" readonly="1"/>
<field name="course_credit" string="学分" readonly="1"/>
<field name="course_exam_type" string="考核方式" readonly="1"/>
</group>
</page>
<!-- 章节页:无章节时自动隐藏 -->
<page string="章节信息" >
<group string="章节详情" col="2">
<field name="chapter_name" string="章节名称" readonly="1"/>
<field name="chapter_sequence" string="章节序号" readonly="1"/>
<field name="chapter_is_published" string="章节发布状态" readonly="1"/>
</group>
</page>
<page string="沟通记录">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- 主动作窗口:绑定列表、表单、搜索视图 -->
<record id="act_course_syllabus" model="ir.actions.act_window">
<field name="name">教学大纲/教案</field>
<field name="res_model">course.syllabus</field>
<field name="view_mode">form</field>
<!-- <field name="view_id" ref="form_course_syllabus"/>-->
</record>
<!-- 课程详情内嵌视图:过滤当前课程数据 -->
<!-- <record id="act_course_syllabus_by_course" model="ir.actions.act_window">-->
<!-- <field name="name">教学大纲/教案</field>-->
<!-- <field name="res_model">course.syllabus</field>-->
<!-- <field name="view_mode">list,form</field>-->
<!-- <field name="view_id" ref="list_course_syllabus"/>-->
<!-- <field name="domain">[('course_id', '=', active_id)]</field>-->
<!-- <field name="context">{'default_course_id': active_id}</field>-->
<!-- </record>-->
<!-- 二级菜单 -->
<record id="menu_course_syllabus" model="ir.ui.menu">
<field name="name">教学大纲/教案</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_syllabus"/>
<field name="sequence">35</field>
</record>
</odoo>

View File

@ -0,0 +1,215 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="list_course_teaching_class" model="ir.ui.view">
<field name="name">course.teaching_class.list</field>
<field name="model">course.teaching_class</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="course_id"/>
<field name="semester" widget="badge"/>
<field name="main_teacher_id"/>
<field name="student_count" sum="合计"/>
<field name="max_students"/>
<field name="state" widget="badge"/>
</list>
</field>
</record>
<record id="form_course_teaching_class" model="ir.ui.view">
<field name="name">course.teaching_class.form</field>
<field name="model">course.teaching_class</field>
<field name="arch" type="xml">
<form string="教学班">
<sheet>
<div class="oe_title">
<h1>
<field name="display_name" placeholder="教学班名称"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_open_enroll" type="object" string="开放选课" class="btn-primary"
invisible="state not in ['draft']"/>
<button name="action_start_teaching" type="object" string="开始教学" class="btn-success"
invisible="state not in ['open']"/>
<button name="action_close" type="object" string="结课" class="btn-danger"
invisible="state not in ['teaching']"/>
<button name="action_cancel" type="object" string="取消课程" class="btn-warning"
invisible="state in ['closed','cancelled']"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="name"/>
<field name="code"/>
<field name="course_id" options="{'no_create': True}"/>
<field name="semester"/>
<field name="state" widget="statusbar"/>
</group>
<group>
<field name="main_teacher_id" options="{'no_create': True}"/>
<field name="teacher_ids" widget="many2many_tags"/>
<field name="assistant_ids" widget="many2many_tags"/>
</group>
</group>
<group name="schedule_info" string="上课安排">
<group>
<field name="schedule"/>
<field name="start_date"/>
<field name="end_date"/>
<field name="total_weeks"/>
</group>
<group>
<field name="max_students"/>
<field name="min_students"/>
<field name="student_count" readonly="1"/>
<field name="is_full" widget="boolean_toggle" readonly="1"/>
</group>
</group>
<notebook>
<page string="选课学生">
<field name="student_ids" view_id="view_student_info_list_in_class"/>
<div class="oe_button_box" style="margin-top:8px;">
<button name="action_add_students" type="object" string="批量添加学生" class="btn-secondary"/>
<button name="action_import_students" type="object" string="导入学生名单" class="btn-secondary"/>
</div>
</page>
<!-- 选课记录:开启顶部行内编辑,支持连续快速新增多条 -->
<page string="选课记录">
<field name="enrollment_ids" view_id="view_enrollment_list"/>
</page>
<page string="课程作业">
<field name="homework_ids" context="{'default_course_id': course_id, 'default_teaching_class_id': id}" view_id="view_homework_list"/>
</page>
<page string="学生成绩">
<field name="student_score_ids" context="{'default_course_id': course_id, 'default_teaching_class_id': id}" view_id="view_student_score_list"/>
</page>
<page string="教学大纲/教案">
<field name="course_syllabus_ids" context="{'default_course_id': course_id}" view_id="view_course_syllabus_list_inside"/>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_student_info_list_in_class" model="ir.ui.view">
<field name="name">student.info.list.in.class</field>
<field name="model">student.info</field>
<field name="arch" type="xml">
<list editable="bottom">
<field name="stu_num"/>
<field name="stu_name"/>
<field name="class_id"/>
<field name="stu_phone"/>
</list>
</field>
</record>
<!-- 重点editable="top" 顶部快速新建,可连续添加多条选课记录 -->
<record id="view_enrollment_list" model="ir.ui.view">
<field name="name">course.teaching.class.enrollment.list</field>
<field name="model">course.teaching_class.enrollment</field>
<field name="arch" type="xml">
<list editable="top">
<field name="student_id"/>
<field name="enroll_date"/>
<field name="state" widget="badge"/>
<field name="final_score"/>
<field name="grade_level" widget="badge"/>
</list>
</field>
</record>
<record id="view_homework_list" model="ir.ui.view">
<field name="name">course.homework.list</field>
<field name="model">course.homework</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="deadline"/>
<field name="total_score"/>
<field name="submitted_count"/>
<field name="state" widget="badge"/>
</list>
</field>
</record>
<record id="view_course_syllabus_list_inside" model="ir.ui.view">
<field name="name">course.syllabus.list.inside</field>
<field name="model">course.syllabus</field>
<field name="arch" type="xml">
<list>
<field name="title"/>
<field name="syllabus_type" widget="badge"/>
<field name="version"/>
</list>
</field>
</record>
<record id="view_student_score_list" model="ir.ui.view">
<field name="name">course.student.score.list</field>
<field name="model">course.student.score</field>
<field name="arch" type="xml">
<list>
<field name="student_id"/>
<field name="total_score"/>
<field name="grade_level" widget="badge"/>
</list>
</field>
</record>
<!-- 批量添加/导入学生 向导弹窗视图 -->
<record id="view_teaching_class_enrollment_wizard_form" model="ir.ui.view">
<field name="name">course.teaching_class.enrollment.wizard.form</field>
<field name="model">course.teaching_class.enrollment.wizard</field>
<field name="arch" type="xml">
<form string="批量添加学生">
<group col="2">
<field name="teaching_class_id" readonly="1"/>
</group>
<group string="手动选择学生">
<field name="student_ids" widget="many2many_tags" colspan="4"/>
</group>
<group string="Excel批量导入">
<field name="file" filename="filename"/>
<p style="color:gray;">Excel模板要求首列标题为【学号】按学号匹配学生</p>
</group>
<footer>
<button name="action_add_students" string="确认添加选中学生" type="object" class="btn-primary"/>
<button name="action_import_excel" string="执行Excel导入" type="object" class="btn-success"/>
<button string="关闭" special="cancel" class="btn-secondary"/>
</footer>
</form>
</field>
</record>
<!-- 教学班动作 -->
<record id="act_course_teaching_class" model="ir.actions.act_window">
<field name="name">教学班管理</field>
<field name="res_model">course.teaching_class</field>
<field name="view_mode">list,form</field>
</record>
<!-- 按课程查看教学班的动作 -->
<record id="act_course_teaching_class_by_course" model="ir.actions.act_window">
<field name="name">教学班</field>
<field name="res_model">course.teaching_class</field>
<field name="view_mode">list,form</field>
<field name="view_id" ref="list_course_teaching_class"/>
<field name="domain">[('course_id', '=', active_id)]</field>
<field name="context">{'default_course_id': active_id}</field>
</record>
<!-- 二级菜单 -->
<record id="menu_course_teaching_class" model="ir.ui.menu">
<field name="name">教学班管理</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_teaching_class"/>
<field name="sequence">15</field>
<field name="groups_id" eval="[(6,0,[ref('base.group_system'),ref('edu_base.group_teacher')])]"/>
</record>
</odoo>

View File

@ -0,0 +1,140 @@
<odoo>
<record id="list_course_homework_submit" model="ir.ui.view">
<field name="name">course.homework.submit.list</field>
<field name="model">course.homework.submit</field>
<field name="arch" type="xml">
<list>
<field name="homework_id"/>
<field name="student_id"/>
<field name="submit_time"/>
<field name="is_late" widget="boolean_toggle"/>
<field name="score"/>
<field name="state" widget="badge"/>
<field name="grader_id"/>
<field name="grade_time"/>
</list>
</field>
</record>
<record id="form_course_homework_submit" model="ir.ui.view">
<field name="name">course.homework.submit.form</field>
<field name="model">course.homework.submit</field>
<field name="arch" type="xml">
<form string="作业提交">
<sheet>
<div class="oe_title">
<h1>
<field name="display_name" placeholder="提交记录"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_grade" type="object" string="批改" class="btn-primary"
invisible="state == 'graded'"/>
<button name="action_regrade" type="object" string="重新批改" class="btn-secondary"
invisible="state != 'graded'"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="homework_id" options="{'no_create': True}"/>
<field name="student_id" options="{'no_create': True}"/>
<field name="submit_time" readonly="1"/>
<field name="is_late" widget="boolean_toggle" readonly="1"/>
</group>
<group>
<field name="state" widget="statusbar"/>
<field name="score"/>
<field name="grader_id" readonly="1"/>
<field name="grade_time" readonly="1"/>
</group>
</group>
<notebook>
<page string="提交内容">
<group string="提交文件">
<field name="submit_file" filename="submit_filename" widget="binary"/>
<field name="submit_filename" invisible="1"/>
<field name="submit_content" placeholder="提交内容"/>
</group>
</page>
<page string="批改内容">
<group string="批改信息">
<field name="comment" placeholder="批改评语"/>
</group>
</page>
<page string="课程信息">
<group string="课程信息">
<field name="course_name" string="课程名称" readonly="1"/>
<field name="course_code" string="课程代码" readonly="1"/>
<field name="course_credit" string="学分" readonly="1"/>
</group>
</page>
<page string="作业信息">
<group string="作业信息">
<field name="homework_name" string="作业名称" readonly="1"/>
<field name="homework_total_score" string="作业总分" readonly="1"/>
<field name="homework_deadline" string="截止时间" readonly="1"/>
<field name="homework_late_deadline" string="补交截止时间" readonly="1"/>
</group>
</page>
<page string="学生信息">
<group string="学生信息">
<field name="student_name" string="姓名" readonly="1"/>
<field name="student_no" string="学号" readonly="1"/>
<field name="student_class_id" string="班级" readonly="1"/>
<field name="student_major_id" string="专业" readonly="1"/>
<field name="student_phone" string="手机号" readonly="1"/>
</group>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- <record id="view_course_homework_submit_batch_grade_wizard" model="ir.ui.view">-->
<!-- <field name="name">course.homework.submit.batch.grade.wizard</field>-->
<!-- <field name="model">course.homework.submit.batch.grade</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <form string="批量批改">-->
<!-- <group>-->
<!-- <group>-->
<!-- <field name="homework_id" readonly="1"/>-->
<!-- <field name="total_count" readonly="1"/>-->
<!-- <field name="score"/>-->
<!-- </group>-->
<!-- <group>-->
<!-- <field name="comment" placeholder="统一评语"/>-->
<!-- </group>-->
<!-- </group>-->
<!-- <footer>-->
<!-- <button name="action_batch_grade" type="object" string="确认批改" class="btn-primary"/>-->
<!-- <button string="取消" class="btn-secondary" special="cancel"/>-->
<!-- </footer>-->
<!-- </form>-->
<!-- </field>-->
<!-- </record>-->
<record id="act_course_homework_submit" model="ir.actions.act_window">
<field name="name">作业提交</field>
<field name="res_model">course.homework.submit</field>
<field name="view_mode">list,form</field>
</record>
<!-- <record id="act_course_homework_submit_by_homework" model="ir.actions.act_window">-->
<!-- <field name="name">作业提交情况</field>-->
<!-- <field name="res_model">course.homework.submit</field>-->
<!-- <field name="view_mode">list,form</field>-->
<!--&lt;!&ndash; <field name="domain">[('homework_id.active_id', '=', active_id)]</field>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="context">{'default_homework_id': active_id}</field>&ndash;&gt;-->
<!-- </record>-->
<record id="menu_course_homework_submit" model="ir.ui.menu">
<field name="name">作业提交</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_course_homework_submit"/>
<field name="groups_id" eval="[(6,0,[ref('base.group_system'),ref('edu_base.group_teacher')])]"/>
<field name="sequence">45</field>
</record>
</odoo>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- 课程列表视图 -->
<record id="list_learning_course" model="ir.ui.view">
<field name="name">learning.course.list</field>
<field name="model">learning.course</field>
<field name="arch" type="xml">
<list>
<field name="code"/>
<field name="name"/>
<field name="credit"/>
<field name="exam_type" widget="badge"/>
<field name="chapter_count"/>
<field name="syllabus_count"/>
<field name="state" widget="badge"/>
</list>
</field>
</record>
<!-- 课程表单视图 -->
<record id="form_learning_course" model="ir.ui.view">
<field name="name">learning.course.form</field>
<field name="model">learning.course</field>
<field name="arch" type="xml">
<form string="课程">
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="课程名称"/>
</h1>
</div>
<div class="oe_button_box" name="button_box">
<button name="action_publish" type="object" string="发布" class="btn-primary"
invisible="state != 'draft'"/>
<button name="action_draft" type="object" string="退回草稿" class="btn-secondary"
invisible="state == 'draft'"/>
</div>
<group name="basic_info" string="基本信息">
<group>
<field name="code"/>
<field name="english_name"/>
<field name="credit"/>
<field name="exam_type"/>
</group>
<group>
<field name="state" widget="statusbar"/>
</group>
</group>
<!-- 统计卡片 -->
<group name="statistics" string="课程统计" col="3">
<field name="chapter_count" widget="statinfo" string="章节数"/>
<field name="syllabus_count" widget="statinfo" string="大纲/教案数"/>
<field name="resource_count" widget="statinfo" string="教学资源"/>
</group>
<notebook>
<page string="课程简介">
<field name="description"/>
<field name="objectives"/>
</page>
<page string="章节管理">
<field name="chapter_ids" view_id="view_course_chapter_list">
</field>
<div class="oe_button_box">
<button name="action_view_chapters" type="object" string="管理章节" class="btn-primary"/>
</div>
</page>
<page string="教学大纲/教案">
<field name="syllabus_ids" view_id="view_course_syllabus_list"/>
<div class="oe_button_box">
<button name="action_view_syllabus" type="object" string="管理大纲/教案" class="btn-primary"/>
</div>
</page>
<page string="教学资源">
<field name="resource_all_ids" string="资源列表" view_id="view_course_chapter_resource_list">
</field>
<div class="oe_button_box">
<button name="action_view_resources" type="object" string="管理资源" class="btn-primary"/>
</div>
</page>
<page string="消息">
<field name="message_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_course_chapter_list" model="ir.ui.view">
<field name="name">course.chapter.list</field>
<field name="model">course.chapter</field>
<field name="arch" type="xml">
<list>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="resource_count"/>
<field name="is_published" widget="boolean_toggle"/>
</list>
</field>
</record>
<!-- <record id="view_course_syllabus_list" model="ir.ui.view">-->
<!-- <field name="name">course.syllabus.list</field>-->
<!-- <field name="model">course.syllabus</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <list>-->
<!-- <field name="title"/>-->
<!-- <field name="syllabus_type" widget="badge"/>-->
<!-- <field name="version"/>-->
<!-- <field name="is_published" widget="boolean_toggle"/>-->
<!-- </list>-->
<!-- </field>-->
<!-- </record>-->
<record id="view_course_chapter_resource_list" model="ir.ui.view">
<field name="name">course.chapter.resource.list</field>
<field name="model">course.chapter.resource</field>
<field name="arch" type="xml">
<list>
<field name="chapter_id"/>
<field name="name"/>
<field name="resource_type" widget="badge"/>
<field name="is_hidden" widget="boolean_toggle"/>
</list>
</field>
</record>
<record id="view_course_chapter_resource_list" model="ir.ui.view">
<field name="name">course.chapter.resource.list</field>
<field name="model">course.chapter.resource</field>
<field name="arch" type="xml">
<list>
<field name="chapter_id"/>
<field name="name"/>
<field name="resource_type" widget="badge"/>
<field name="is_hidden" widget="boolean_toggle"/>
</list>
</field>
</record>
<!-- 课程动作 -->
<record id="act_learning_course" model="ir.actions.act_window">
<field name="name">课程管理</field>
<field name="res_model">learning.course</field>
<field name="view_mode">list,form</field>
</record>
<record id="menu_learning_center_root" model="ir.ui.menu">
<field name="name">学习中心</field>
<field name="sequence">11</field>
<field name="groups_id" eval="[(6, 0, [ref('base.group_system'),ref('edu_base.group_teacher')])]"/>
</record>
<!-- 二级菜单 -->
<record id="menu_learning_course" model="ir.ui.menu">
<field name="name">课程管理</field>
<field name="parent_id" ref="menu_learning_center_root"/>
<field name="action" ref="act_learning_course"/>
<field name="sequence">10</field>
<field name="groups_id" eval="[(6, 0, [ref('base.group_system')])]"/>
</record>
</odoo>

View File

@ -0,0 +1,51 @@
<odoo>
<record id="view_teach_class_list" model="ir.ui.view">
<field name="name">view.teach.class.list</field>
<field name="model">teach.class</field>
<field name="arch" type="xml">
<list>
<field name="stu_num"/>
<field name="stu_name"/>
<field name="stu_sex"/>
<field name="stu_phone"/>
<field name="stu_grade_xx"/>
<field name="course_teaching_class"/>
</list>
</field>
</record>
<record id="view_teach_class_form" model="ir.ui.view">
<field name="name">view.teach.class.form</field>
<field name="model">teach.class</field>
<field name="arch" type="xml">
<form>
<field name="course_teaching_class"/>
</form>
</field>
</record>
<record id="view_teach_class_search" model="ir.ui.view">
<field name="name">teach.class.search</field>
<field name="model">teach.class</field>
<field name="arch" type="xml">
<search>
<searchpanel>
<field name="course_teaching_class" string="我的班级" group="1"/>
</searchpanel>
</search>
</field>
</record>
<record id="act_teach_class" model="ir.actions.act_window">
<field name="name">我的班级</field>
<field name="res_model">teach.class</field>
<field name="view_mode">list</field>
</record>
<record id="menu_teach_class" model="ir.ui.menu">
<field name="name">我的班级</field>
<field name="action" ref="act_teach_class"/>
<field name="sequence">11</field>
</record>
</odoo>