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, }, }