Merge pull request 'zhou' (#21) from zhou into master
Reviewed-on: #21
This commit was merged in pull request #21.
This commit is contained in:
@@ -45,6 +45,17 @@
|
||||
'views/about_page_views.xml',
|
||||
'views/menus.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'college/static/src/scss/college_theme.scss',
|
||||
],
|
||||
'web.assets_web_dark': [
|
||||
'college/static/src/scss/college_theme_dark.scss',
|
||||
],
|
||||
'web.assets_backend_lazy_dark': [
|
||||
'college/static/src/scss/college_theme_dark.scss',
|
||||
],
|
||||
},
|
||||
'application': True,
|
||||
'installable': True,
|
||||
'license': 'LGPL-3',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import re
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
@@ -53,6 +55,191 @@ class CourseChapterAttachment(models.Model):
|
||||
return super().write(vals)
|
||||
|
||||
|
||||
class CourseChapterExercise(models.Model):
|
||||
"""章节训练习题——老师按章节布置的随堂简答题。
|
||||
|
||||
一个章节可挂多道;学生可以自由作答(不计分、不强制),
|
||||
学员的回答存于 `yuthon.school.course.chapter.exercise.answer`。
|
||||
"""
|
||||
|
||||
_name = 'yuthon.school.course.chapter.exercise'
|
||||
_description = '章节训练习题'
|
||||
_order = 'chapter_id, sequence, id'
|
||||
_rec_name = 'exercise_label'
|
||||
|
||||
chapter_id = fields.Many2one(
|
||||
'yuthon.school.course.chapter', string='章节',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
question = fields.Html(string='题目', sanitize=True, required=True)
|
||||
analysis = fields.Html(
|
||||
string='参考解析', sanitize=True,
|
||||
help='给学员的参考答案/思路(仅展示,不参与评分)')
|
||||
|
||||
exercise_label = fields.Char(
|
||||
string='显示名', compute='_compute_exercise_label',
|
||||
help='内嵌列表与表单标题用:第 N 题')
|
||||
|
||||
answer_ids = fields.One2many(
|
||||
'yuthon.school.course.chapter.exercise.answer', 'exercise_id',
|
||||
string='学员作答')
|
||||
answer_count = fields.Integer(
|
||||
string='作答人数', compute='_compute_answer_count', store=True)
|
||||
course_id = fields.Many2one(
|
||||
'yuthon.school.course', string='课程',
|
||||
related='chapter_id.course_id', store=True, index=True)
|
||||
|
||||
# 当前学员的回答(depends_context('uid') 跟随当前登录用户切换)
|
||||
my_answer_content = fields.Html(
|
||||
string='我的回答(全文)',
|
||||
compute='_compute_my_answer', depends_context='uid')
|
||||
my_answer_preview = fields.Char(
|
||||
string='我的回答',
|
||||
compute='_compute_my_answer_preview', depends_context='uid',
|
||||
help='去除 Html 标签后的纯文本预览,便于在列表里紧凑显示')
|
||||
|
||||
@api.depends('sequence')
|
||||
def _compute_exercise_label(self):
|
||||
for rec in self:
|
||||
rec.exercise_label = f'第 {rec.sequence} 题'
|
||||
|
||||
@api.depends('answer_ids')
|
||||
def _compute_answer_count(self):
|
||||
for rec in self:
|
||||
rec.answer_count = len(rec.answer_ids)
|
||||
|
||||
@api.depends_context('uid')
|
||||
def _compute_my_answer(self):
|
||||
"""当前登录学员对本习题的回答(未作答则为 False)。"""
|
||||
Answer = self.env['yuthon.school.course.chapter.exercise.answer']
|
||||
student = self.env['yuthon.school.student'].sudo().search(
|
||||
[('user_id', '=', self.env.uid)], limit=1)
|
||||
answers = {}
|
||||
if student:
|
||||
for a in Answer.search([
|
||||
('student_id', '=', student.id),
|
||||
('exercise_id', 'in', self.ids),
|
||||
]):
|
||||
answers[a.exercise_id.id] = a
|
||||
for rec in self:
|
||||
ans = answers.get(rec.id)
|
||||
rec.my_answer_content = ans.content if ans else False
|
||||
|
||||
@api.depends_context('uid')
|
||||
def _compute_my_answer_preview(self):
|
||||
"""去除 Html 标签后的纯文本预览(80 字以内)。"""
|
||||
for rec in self:
|
||||
content = rec.my_answer_content or ''
|
||||
text = re.sub(r'<[^>]+>', ' ', content)
|
||||
text = re.sub(r'\s+', ' ', text).strip()
|
||||
if not text:
|
||||
rec.my_answer_preview = ''
|
||||
elif len(text) > 80:
|
||||
rec.my_answer_preview = text[:80] + '…'
|
||||
else:
|
||||
rec.my_answer_preview = text
|
||||
|
||||
def action_answer(self):
|
||||
"""学生端:弹窗回答本题。
|
||||
|
||||
若当前用户已对本题作答过,则打开已有作答;否则新建一条空作答。
|
||||
"""
|
||||
self.ensure_one()
|
||||
Answer = self.env['yuthon.school.course.chapter.exercise.answer']
|
||||
student = self.env['yuthon.school.student'].sudo().search(
|
||||
[('user_id', '=', self.env.uid)], limit=1)
|
||||
if not student:
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
answer = Answer.search([
|
||||
('exercise_id', '=', self.id),
|
||||
('student_id', '=', student.id),
|
||||
], limit=1)
|
||||
if not answer:
|
||||
answer = Answer.create({
|
||||
'exercise_id': self.id,
|
||||
'student_id': student.id,
|
||||
})
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '作答',
|
||||
'res_model': 'yuthon.school.course.chapter.exercise.answer',
|
||||
'res_id': answer.id,
|
||||
'view_mode': 'form',
|
||||
'view_id': self.env.ref(
|
||||
'college.yuthon_school_course_chapter_exercise_answer_form').id,
|
||||
'views': [(self.env.ref(
|
||||
'college.yuthon_school_course_chapter_exercise_answer_form').id,
|
||||
'form')],
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def action_view_answers(self):
|
||||
"""老师端:弹窗查看本题所有学员作答。
|
||||
|
||||
弹出只读列表(学员 / 回答 / 作答时间),不可编辑(不参与评分)。
|
||||
"""
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': f'学员作答 · {self.exercise_label}',
|
||||
'res_model': 'yuthon.school.course.chapter.exercise.answer',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('exercise_id', '=', self.id)],
|
||||
'views': [
|
||||
(self.env.ref(
|
||||
'college.yuthon_school_course_chapter_exercise_answer_view_tree_teacher').id,
|
||||
'list'),
|
||||
(False, 'form'),
|
||||
],
|
||||
'target': 'new',
|
||||
'context': {'default_exercise_id': self.id},
|
||||
}
|
||||
|
||||
|
||||
class CourseChapterExerciseAnswer(models.Model):
|
||||
"""学员对章节训练习题的回答(不计分、自由提交、可修改)。"""
|
||||
|
||||
_name = 'yuthon.school.course.chapter.exercise.answer'
|
||||
_description = '习题作答'
|
||||
_order = 'exercise_id, student_id, id'
|
||||
_rec_name = 'exercise_id'
|
||||
|
||||
exercise_id = fields.Many2one(
|
||||
'yuthon.school.course.chapter.exercise', string='习题',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
student_id = fields.Many2one(
|
||||
'yuthon.school.student', string='学员',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
user_id = fields.Many2one(
|
||||
'res.users', string='账号',
|
||||
related='student_id.user_id', store=True, index=True)
|
||||
content = fields.Html(
|
||||
string='我的回答', sanitize=True,
|
||||
help='学员的作答内容,可随时修改(不计分)')
|
||||
submit_time = fields.Datetime(
|
||||
string='最后作答时间', default=fields.Datetime.now)
|
||||
|
||||
chapter_id = fields.Many2one(
|
||||
'yuthon.school.course.chapter', string='章节',
|
||||
related='exercise_id.chapter_id', store=True, index=True)
|
||||
course_id = fields.Many2one(
|
||||
'yuthon.school.course', string='课程',
|
||||
related='exercise_id.course_id', store=True, index=True)
|
||||
question_display = fields.Html(
|
||||
string='题目', related='exercise_id.question', readonly=True)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
vals_list = [dict(v, submit_time=fields.Datetime.now())
|
||||
for v in vals_list]
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
if 'content' in vals:
|
||||
vals['submit_time'] = fields.Datetime.now()
|
||||
return super().write(vals)
|
||||
|
||||
|
||||
class CourseChapter(models.Model):
|
||||
"""课程章节——老师端在课程内容里维护,学生端作为学习目录。
|
||||
|
||||
@@ -81,6 +268,18 @@ class CourseChapter(models.Model):
|
||||
attachment_ids = fields.One2many(
|
||||
'yuthon.school.course.chapter.attachment', 'chapter_id', string='附件')
|
||||
|
||||
# 训练习题:一个章节可挂多道简答题(学生可自由作答,不计分)
|
||||
exercise_ids = fields.One2many(
|
||||
'yuthon.school.course.chapter.exercise', 'chapter_id',
|
||||
string='训练习题')
|
||||
exercise_count = fields.Integer(
|
||||
string='习题数', compute='_compute_exercise_count', store=True)
|
||||
|
||||
@api.depends('exercise_ids')
|
||||
def _compute_exercise_count(self):
|
||||
for chapter in self:
|
||||
chapter.exercise_count = len(chapter.exercise_ids)
|
||||
|
||||
# 随堂笔记:老师按章节记录的富文本笔记(与章节编辑表单共用同一字段)
|
||||
notes = fields.Html(string='随堂笔记', sanitize=True)
|
||||
|
||||
|
||||
@@ -15,4 +15,16 @@
|
||||
<field name="category_id" ref="module_category_education"/>
|
||||
<field name="comment">可查看自己选课的课程、提交作业、查看自己的学习进展,不能创建课程。</field>
|
||||
</record>
|
||||
|
||||
<!-- 学生只能访问自己的习题作答 -->
|
||||
<record id="rule_exercise_answer_student_own" model="ir.rule">
|
||||
<field name="name">习题作答:学生仅能访问自己的回答</field>
|
||||
<field name="model_id" ref="model_yuthon_school_course_chapter_exercise_answer"/>
|
||||
<field name="groups" eval="[(4, ref('college.group_student'))]"/>
|
||||
<field name="domain_force">[('user_id', '=', user.id)]</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -30,6 +30,12 @@ access_yuthon_school_course_chapter_student,yuthon.school.course.chapter.student
|
||||
access_yuthon_school_course_chapter_attachment_admin,yuthon.school.course.chapter.attachment.admin,model_yuthon_school_course_chapter_attachment,base.group_system,1,1,1,1
|
||||
access_yuthon_school_course_chapter_attachment_teacher,yuthon.school.course.chapter.attachment.teacher,model_yuthon_school_course_chapter_attachment,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_course_chapter_attachment_student,yuthon.school.course.chapter.attachment.student,model_yuthon_school_course_chapter_attachment,college.group_student,1,0,0,0
|
||||
access_yuthon_school_course_chapter_exercise_admin,yuthon.school.course.chapter.exercise.admin,model_yuthon_school_course_chapter_exercise,base.group_system,1,1,1,1
|
||||
access_yuthon_school_course_chapter_exercise_teacher,yuthon.school.course.chapter.exercise.teacher,model_yuthon_school_course_chapter_exercise,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_course_chapter_exercise_student,yuthon.school.course.chapter.exercise.student,model_yuthon_school_course_chapter_exercise,college.group_student,1,0,0,0
|
||||
access_yuthon_school_course_chapter_exercise_answer_admin,yuthon.school.course.chapter.exercise.answer.admin,model_yuthon_school_course_chapter_exercise_answer,base.group_system,1,1,1,1
|
||||
access_yuthon_school_course_chapter_exercise_answer_teacher,yuthon.school.course.chapter.exercise.answer.teacher,model_yuthon_school_course_chapter_exercise_answer,college.group_teacher,1,0,0,0
|
||||
access_yuthon_school_course_chapter_exercise_answer_student,yuthon.school.course.chapter.exercise.answer.student,model_yuthon_school_course_chapter_exercise_answer,college.group_student,1,1,1,0
|
||||
access_yuthon_school_training_admin,yuthon.school.training.admin,model_yuthon_school_training,base.group_system,1,1,1,1
|
||||
access_yuthon_school_training_teacher,yuthon.school.training.teacher,model_yuthon_school_training,college.group_teacher,1,1,1,1
|
||||
access_yuthon_school_training_student,yuthon.school.training.student,model_yuthon_school_training,college.group_student,1,1,1,1
|
||||
|
||||
|
@@ -0,0 +1,149 @@
|
||||
// ============================================================
|
||||
// college 看板主题适配
|
||||
// 使用 Odoo SCSS 变量,自动跟随 udoo_om_ux 等主题的浅色/深色色板。
|
||||
// 需同时注册到 web.assets_backend(浅色)与 web.assets_web_dark
|
||||
// / web.assets_backend_lazy_dark(深色)。
|
||||
// ============================================================
|
||||
|
||||
.college-course-kanban {
|
||||
.college-kanban-card {
|
||||
background-color: $o-view-background-color;
|
||||
color: $o-main-text-color;
|
||||
border: 1px solid rgba($o-main-text-color, 0.08);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.college-kanban-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
|
||||
.college-kanban-meta {
|
||||
font-size: 13px;
|
||||
color: $o-gray-600;
|
||||
|
||||
&.text-muted,
|
||||
.text-muted {
|
||||
color: $o-gray-600 !important;
|
||||
}
|
||||
|
||||
.fa {
|
||||
color: $o-gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
.college-kanban-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 老师端:蓝调专业风 ----------------
|
||||
&.college-kanban-teacher .college-kanban-card {
|
||||
.college-kanban-badge-hours {
|
||||
background: rgba($o-info, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
|
||||
.college-kanban-badge-students {
|
||||
background: rgba($o-success, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 学生-我的课程:书本青蓝风 ----------------
|
||||
&.college-kanban-my .college-kanban-card {
|
||||
.college-kanban-badge-type {
|
||||
background: rgba($o-info, 0.85);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.college-kanban-badge-public {
|
||||
background: rgba($o-success, 0.85);
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 学生-课程学习:活力橙风 ----------------
|
||||
&.college-kanban-study .college-kanban-card {
|
||||
.college-kanban-badge-type {
|
||||
background: rgba($o-view-background-color, 0.92);
|
||||
color: $o-danger;
|
||||
}
|
||||
|
||||
.college-kanban-badge-hours {
|
||||
background: rgba($o-warning, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
|
||||
.college-kanban-badge-chapters {
|
||||
background: rgba($o-info, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 学习进展:深森林绿 ----------------
|
||||
&.college-kanban-progress .college-kanban-card {
|
||||
.college-kanban-title {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.college-kanban-badge-score {
|
||||
background: rgba($o-view-background-color, 0.92);
|
||||
color: $o-success;
|
||||
}
|
||||
|
||||
.college-kanban-progress-rate {
|
||||
color: $o-main-text-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 我的实训:紫罗兰 ----------------
|
||||
&.college-kanban-training .college-kanban-card {
|
||||
.college-kanban-title {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.college-kanban-badge-purple {
|
||||
background: rgba($o-info, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
|
||||
.college-kanban-badge-pink {
|
||||
background: rgba($o-danger, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 作业提交:珊瑚红 ----------------
|
||||
&.college-kanban-homework .college-kanban-card {
|
||||
.college-kanban-title {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.college-kanban-badge-score {
|
||||
background: rgba($o-view-background-color, 0.9);
|
||||
color: $o-danger;
|
||||
}
|
||||
|
||||
.college-kanban-badge-state {
|
||||
background: rgba($o-danger, 0.15);
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
// ============================================================
|
||||
// college 看板「深色模式」专属样式
|
||||
// 本文件只注册在 web.assets_web_dark / web.assets_backend_lazy_dark,
|
||||
// 这两个 bundle 仅当用户开启深色主题时才会加载,因此下面的颜色
|
||||
// 全部硬编码,不依赖任何主题 SCSS 变量(避免跨模块编译顺序导致
|
||||
// 变量未切换成深色值的问题)。
|
||||
// 深色页面底色约 #111827,卡片用略亮的 slate-800 (#1e293b) 形成层次。
|
||||
// ============================================================
|
||||
|
||||
// 顶部同级菜单段(如「我的课程 / 全部课程」)夜间白字加粗
|
||||
.nav-segment .nav-link {
|
||||
color: #f1f5f9 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.nav-segment .nav-link.active {
|
||||
color: #ffffff !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.college-course-kanban {
|
||||
.college-kanban-card {
|
||||
background-color: #1e293b;
|
||||
color: #f1f5f9;
|
||||
border: 1px solid #334155;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.college-kanban-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: #f8fafc !important;
|
||||
}
|
||||
|
||||
.college-kanban-body {
|
||||
background-color: #1e293b;
|
||||
}
|
||||
|
||||
.college-kanban-meta {
|
||||
font-size: 13px;
|
||||
color: #94a3b8 !important;
|
||||
|
||||
&.text-muted,
|
||||
.text-muted {
|
||||
color: #94a3b8 !important;
|
||||
}
|
||||
|
||||
.fa {
|
||||
color: #64748b !important;
|
||||
}
|
||||
}
|
||||
|
||||
.college-kanban-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 老师端:蓝调专业风 ----------------
|
||||
&.college-kanban-teacher .college-kanban-card {
|
||||
// 头部渐变稍压暗,避免与深色页面「糊」在一起,白字依旧清晰
|
||||
> div:first-child {
|
||||
background: linear-gradient(135deg, #2563eb, #4f46e5) !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-hours {
|
||||
background: rgba(96, 165, 250, 0.18);
|
||||
color: #93c5fd !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-students {
|
||||
background: rgba(52, 211, 153, 0.18);
|
||||
color: #6ee7b7 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 学生-我的课程:书本青蓝风 ----------------
|
||||
&.college-kanban-my .college-kanban-card {
|
||||
> div:first-child {
|
||||
background: linear-gradient(135deg, #0ea5e9, #06b6d4) !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-type {
|
||||
background: #38bdf8;
|
||||
color: #0f172a !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-public {
|
||||
background: #34d399;
|
||||
color: #0f172a !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 学生-课程学习:活力橙风 ----------------
|
||||
&.college-kanban-study .college-kanban-card {
|
||||
> div:first-child {
|
||||
background: linear-gradient(120deg, #f97316, #ef4444) !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-type {
|
||||
background: rgba(251, 146, 60, 0.22);
|
||||
color: #fdba74 !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-hours {
|
||||
background: rgba(251, 191, 36, 0.18);
|
||||
color: #fcd34d !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-chapters {
|
||||
background: rgba(96, 165, 250, 0.18);
|
||||
color: #93c5fd !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 学习进展:深森林绿 ----------------
|
||||
&.college-kanban-progress .college-kanban-card {
|
||||
> div:first-child {
|
||||
background: linear-gradient(135deg, #2d6a4f, #40916c) !important;
|
||||
}
|
||||
|
||||
.college-kanban-title {
|
||||
color: #f8fafc !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-score {
|
||||
background: rgba(52, 211, 153, 0.2);
|
||||
color: #6ee7b7 !important;
|
||||
}
|
||||
|
||||
.college-kanban-progress-rate {
|
||||
color: #f1f5f9 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 我的实训:紫罗兰 ----------------
|
||||
&.college-kanban-training .college-kanban-card {
|
||||
> div:first-child {
|
||||
background: linear-gradient(135deg, #7c3aed, #c026d3) !important;
|
||||
}
|
||||
|
||||
.college-kanban-title {
|
||||
color: #f8fafc !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-purple {
|
||||
background: rgba(167, 139, 250, 0.2);
|
||||
color: #c4b5fd !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-pink {
|
||||
background: rgba(244, 114, 182, 0.2);
|
||||
color: #f9a8d4 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 作业提交:珊瑚红 ----------------
|
||||
&.college-kanban-homework .college-kanban-card {
|
||||
> div:first-child {
|
||||
background: linear-gradient(135deg, #e11d48, #f97316) !important;
|
||||
}
|
||||
|
||||
.college-kanban-title {
|
||||
color: #f8fafc !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-score {
|
||||
background: rgba(248, 113, 113, 0.2);
|
||||
color: #fca5a5 !important;
|
||||
}
|
||||
|
||||
.college-kanban-badge-state {
|
||||
background: rgba(248, 113, 113, 0.18);
|
||||
color: #fca5a5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,19 @@
|
||||
<field name="description" widget="html" string="章节说明"/>
|
||||
<field name="notes" widget="html" string="随堂笔记"/>
|
||||
</group>
|
||||
<separator string="训练习题(均为简答题,可添加多道;学生可自由作答,不计分)"/>
|
||||
<field name="exercise_ids" string="训练习题">
|
||||
<list editable="bottom" decoration-muted="sequence < 0">
|
||||
<field name="sequence" widget="handle" string="排序"/>
|
||||
<field name="question" string="题目"/>
|
||||
<field name="analysis" string="参考解析" optional="show"/>
|
||||
<field name="answer_count" string="作答人数"/>
|
||||
<button name="action_view_answers" type="object"
|
||||
string="查看作答" class="btn-link"
|
||||
icon="fa-comments"
|
||||
title="查看本题所有学员的回答"/>
|
||||
</list>
|
||||
</field>
|
||||
<group>
|
||||
<field name="video_file" filename="video_filename"/>
|
||||
<field name="video_filename" invisible="1"/>
|
||||
@@ -69,11 +82,72 @@
|
||||
nolabel="1"/>
|
||||
</list>
|
||||
</field>
|
||||
<!-- 训练习题:可自由作答,不计分 -->
|
||||
<separator string="训练习题(可自由作答,不计分)" invisible="not exercise_ids"/>
|
||||
<field name="exercise_ids" readonly="1"
|
||||
invisible="not exercise_ids">
|
||||
<list editable="bottom" create="0" delete="0">
|
||||
<field name="sequence" string="序号"/>
|
||||
<field name="question" string="题目" readonly="1"/>
|
||||
<field name="my_answer_preview" string="我的回答"
|
||||
placeholder="(未作答)" optional="show"/>
|
||||
<field name="my_answer_content" string="我的回答(详细)"
|
||||
optional="hide"/>
|
||||
<field name="answer_count" string="已作答人数" optional="show"/>
|
||||
<button name="action_answer" type="object"
|
||||
string="作答 / 修改" class="btn-primary"
|
||||
icon="fa-pencil"/>
|
||||
</list>
|
||||
</field>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ===================== 学员作答:弹窗表单 ===================== -->
|
||||
<record id="yuthon_school_course_chapter_exercise_answer_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.school.course.chapter.exercise.answer.form</field>
|
||||
<field name="model">yuthon.school.course.chapter.exercise.answer</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="exercise_id" invisible="1"/>
|
||||
<field name="student_id" invisible="1"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="submit_time" invisible="1"/>
|
||||
</group>
|
||||
<div class="text-muted small mb-1">
|
||||
所属课程:<field name="course_id" readonly="1" nolabel="1" class="oe_inline"/>
|
||||
· 所属章节:<field name="chapter_id" readonly="1" nolabel="1" class="oe_inline"/>
|
||||
</div>
|
||||
<separator string="题目"/>
|
||||
<field name="question_display" widget="html" readonly="1" nolabel="1"/>
|
||||
<separator string="我的回答(自由作答,不计分,可随时修改)"/>
|
||||
<field name="content" widget="html" nolabel="1"
|
||||
placeholder="请输入你的回答..."/>
|
||||
<div class="text-muted small mt-2" invisible="not submit_time">
|
||||
上次作答时间:<field name="submit_time" readonly="1" nolabel="1" class="oe_inline"/>
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ===================== 学员作答:老师只读列表(弹窗查看用) ===================== -->
|
||||
<record id="yuthon_school_course_chapter_exercise_answer_view_tree_teacher" model="ir.ui.view">
|
||||
<field name="name">yuthon.school.course.chapter.exercise.answer.tree.teacher</field>
|
||||
<field name="model">yuthon.school.course.chapter.exercise.answer</field>
|
||||
<field name="groups_id" eval="[(4, ref('college.group_teacher')), (4, ref('base.group_system'))]"/>
|
||||
<field name="arch" type="xml">
|
||||
<list editable="bottom" create="0" delete="0">
|
||||
<field name="student_id" string="学员" readonly="1"/>
|
||||
<field name="content" string="回答内容" readonly="1"/>
|
||||
<field name="submit_time" string="作答时间" readonly="1"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ===================== 课程学习:学生专用表单(仅学生可见,避免覆盖老师默认表单) ===================== -->
|
||||
<record id="yuthon_school_course_study_form" model="ir.ui.view">
|
||||
<field name="name">yuthon.school.course.study.form</field>
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="state"
|
||||
default_order="semester,college,name"
|
||||
class="o_kanban_mobile">
|
||||
class="college-course-kanban college-kanban-teacher o_kanban_mobile">
|
||||
<field name="name"/>
|
||||
<field name="college"/>
|
||||
<field name="semester"/>
|
||||
@@ -214,8 +214,8 @@
|
||||
<field name="state"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click"
|
||||
style="padding:0; border-radius:8px; overflow:hidden; box-shadow:0 1px 4px rgba(59,130,246,.15); border:1px solid rgba(59,130,246,.1);">
|
||||
<div class="oe_kanban_global_click college-kanban-card"
|
||||
style="padding:0; border-radius:8px; overflow:hidden;">
|
||||
<!-- 顶帽:蓝调 + 课程编号 -->
|
||||
<div style="background:linear-gradient(135deg,#3B82F6,#6366F1); padding:10px 14px; display:flex; align-items:center; justify-content:space-between;">
|
||||
<div style="color:#fff; font-size:11px; opacity:.85; letter-spacing:.5px;">
|
||||
@@ -227,21 +227,21 @@
|
||||
</span>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div style="padding:10px 14px; background:#fff;">
|
||||
<div style="font-size:14px; font-weight:600; color:#1E3A5F; margin-bottom:6px;">
|
||||
<div class="college-kanban-body" style="padding:10px 14px;">
|
||||
<div class="college-kanban-title">
|
||||
<field name="name"/>
|
||||
</div>
|
||||
<div class="text-muted small mb-1">
|
||||
<div class="college-kanban-meta text-muted small mb-1">
|
||||
<i class="fa fa-building"/> <field name="college"/> · <field name="semester"/>
|
||||
</div>
|
||||
<div class="small mb-1">
|
||||
<div class="college-kanban-meta small mb-1">
|
||||
<i class="fa fa-user text-muted"/> <field name="teacher_id"/>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px; margin-top:8px;">
|
||||
<span style="background:#EFF6FF; color:#1D4ED8; padding:3px 10px; border-radius:12px; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-hours">
|
||||
<i class="fa fa-clock-o"/> <field name="hours"/> 课时
|
||||
</span>
|
||||
<span style="background:#F0FDF4; color:#15803D; padding:3px 10px; border-radius:12px; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-students">
|
||||
<i class="fa fa-users"/> <field name="student_count"/> 学员
|
||||
</span>
|
||||
</div>
|
||||
@@ -262,7 +262,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="semester"
|
||||
default_order="college,name"
|
||||
class="o_kanban_mobile">
|
||||
class="college-course-kanban college-kanban-my o_kanban_mobile">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="college"/>
|
||||
@@ -276,8 +276,8 @@
|
||||
colors='{"done": "success", "warning": "warning"}'/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click"
|
||||
style="padding:0; border-radius:8px; overflow:hidden; box-shadow:0 1px 3px rgba(0,0,0,.08);">
|
||||
<div class="oe_kanban_global_click college-kanban-card"
|
||||
style="padding:0; border-radius:8px; overflow:hidden;">
|
||||
<!-- 顶帽:彩色条 + 课程编号 -->
|
||||
<div style="background:linear-gradient(135deg,#5B86E5,#36D1DC); padding:10px 14px;">
|
||||
<div style="color:#fff; font-size:11px; opacity:.85; letter-spacing:.5px;">
|
||||
@@ -288,24 +288,22 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div style="padding:10px 14px; background:#fff;">
|
||||
<div class="college-kanban-body" style="padding:10px 14px;">
|
||||
<div class="mb-2">
|
||||
<span class="badge text-white"
|
||||
style="background:#36D1DC; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-type">
|
||||
<field name="course_type"/>
|
||||
</span>
|
||||
<t t-if="record.is_public.raw_value">
|
||||
<span class="badge text-white ml-1"
|
||||
style="background:#43e97b; font-size:11px;">公开</span>
|
||||
<span class="college-kanban-badge college-kanban-badge-public ml-1">公开</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="text-muted small mb-1">
|
||||
<div class="college-kanban-meta text-muted small mb-1">
|
||||
<field name="college"/>
|
||||
</div>
|
||||
<div class="small mb-1">
|
||||
<div class="college-kanban-meta small mb-1">
|
||||
<i class="fa fa-user-circle-o text-muted"/> <field name="teacher_id" widget="many2one_avatar_user"/>
|
||||
</div>
|
||||
<div class="small text-muted">
|
||||
<div class="college-kanban-meta small text-muted">
|
||||
<i class="fa fa-clock-o"/> <field name="hours"/> 课时 · 共 <field name="chapter_count"/> 章节
|
||||
</div>
|
||||
</div>
|
||||
@@ -325,7 +323,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="college"
|
||||
default_order="semester,name"
|
||||
class="o_kanban_mobile">
|
||||
class="college-course-kanban college-kanban-study o_kanban_mobile">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="college"/>
|
||||
@@ -337,33 +335,33 @@
|
||||
<field name="is_public"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click"
|
||||
style="padding:0; border-radius:10px; overflow:hidden; box-shadow:0 2px 6px rgba(255,140,0,.15); border:1px solid rgba(255,140,0,.12);">
|
||||
<div class="oe_kanban_global_click college-kanban-card"
|
||||
style="padding:0; border-radius:10px; overflow:hidden;">
|
||||
<!-- 顶帽:橙色渐变 + 课程类型徽章 -->
|
||||
<div style="background:linear-gradient(120deg,#FF9966,#FF5E62); padding:8px 14px; display:flex; align-items:center; justify-content:space-between;">
|
||||
<div style="color:#fff; font-size:11px; opacity:.92;">
|
||||
<i class="fa fa-book"/> <field name="code"/>
|
||||
</div>
|
||||
<span style="background:rgba(255,255,255,.92); color:#FF5E62; padding:2px 8px; border-radius:10px; font-size:10px; font-weight:600;">
|
||||
<span class="college-kanban-badge college-kanban-badge-type">
|
||||
<field name="course_type"/>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div style="padding:12px 14px; background:#fff;">
|
||||
<div style="font-size:14px; font-weight:600; color:#333; margin-bottom:8px; min-height:36px;">
|
||||
<div class="college-kanban-body" style="padding:12px 14px;">
|
||||
<div class="college-kanban-title" style="min-height:36px;">
|
||||
<field name="name"/>
|
||||
</div>
|
||||
<div class="text-muted small mb-2">
|
||||
<div class="college-kanban-meta text-muted small mb-2">
|
||||
<i class="fa fa-calendar"/> <field name="semester"/>
|
||||
</div>
|
||||
<div class="small mb-1">
|
||||
<div class="college-kanban-meta small mb-1">
|
||||
<i class="fa fa-user text-muted"/> <field name="teacher_id" widget="many2one_avatar_user"/>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px; margin-top:8px;">
|
||||
<span style="background:#FFF3E0; color:#E65100; padding:3px 10px; border-radius:12px; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-hours">
|
||||
<i class="fa fa-clock-o"/> <field name="hours"/> 课时
|
||||
</span>
|
||||
<span style="background:#E3F2FD; color:#1565C0; padding:3px 10px; border-radius:12px; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-chapters">
|
||||
<i class="fa fa-list"/> <field name="chapter_count"/> 章
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="state"
|
||||
default_order="due_date desc, id"
|
||||
class="o_kanban_mobile">
|
||||
class="college-course-kanban college-kanban-homework o_kanban_mobile">
|
||||
<field name="assignment_id"/>
|
||||
<field name="student_id"/>
|
||||
<field name="score"/>
|
||||
@@ -155,28 +155,28 @@
|
||||
<field name="submit_time"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click"
|
||||
style="padding:0; border-radius:8px; overflow:hidden; box-shadow:0 1px 4px rgba(245,101,101,.15); border:1px solid rgba(245,101,101,.12);">
|
||||
<div class="oe_kanban_global_click college-kanban-card"
|
||||
style="padding:0; border-radius:8px; overflow:hidden;">
|
||||
<!-- 顶帽:珊瑚渐变 + 得分 -->
|
||||
<div style="background:linear-gradient(135deg,#F56565,#F6AD55); padding:10px 14px; display:flex; align-items:center; justify-content:space-between;">
|
||||
<div style="color:#fff; font-size:13px; font-weight:600; max-width:70%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">
|
||||
<div class="college-kanban-title" style="color:#fff; font-size:13px; max-width:70%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">
|
||||
<field name="assignment_id"/>
|
||||
</div>
|
||||
<span style="background:rgba(255,255,255,.9); color:#C53030; padding:2px 10px; border-radius:10px; font-size:12px; font-weight:700;">
|
||||
<span class="college-kanban-badge college-kanban-badge-score">
|
||||
<field name="score"/> 分
|
||||
</span>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div style="padding:10px 14px; background:#fff;">
|
||||
<div class="small mb-2" groups="college.group_teacher">
|
||||
<div class="college-kanban-body" style="padding:10px 14px;">
|
||||
<div class="college-kanban-meta small mb-2" groups="college.group_teacher">
|
||||
<i class="fa fa-user text-muted"/> <field name="student_id"/>
|
||||
</div>
|
||||
<div class="mb-2" style="display:flex; gap:6px; flex-wrap:wrap;">
|
||||
<span style="background:#FED7D7; color:#C53030; padding:2px 8px; border-radius:8px; font-size:10px; font-weight:600;">
|
||||
<span class="college-kanban-badge college-kanban-badge-state">
|
||||
<field name="state"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small text-muted" style="line-height:1.5;">
|
||||
<div class="college-kanban-meta small text-muted" style="line-height:1.5;">
|
||||
<div><i class="fa fa-calendar-check-o"/> 截止:<field name="due_date"/></div>
|
||||
<t t-if="record.submit_time.raw_value">
|
||||
<div><i class="fa fa-clock-o"/> 提交:<field name="submit_time"/></div>
|
||||
|
||||
@@ -139,7 +139,7 @@ else:
|
||||
<field name="name">yuthon.school.progress.kanban</field>
|
||||
<field name="model">yuthon.school.progress</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="status" class="o_kanban_mobile">
|
||||
<kanban default_group_by="status" class="college-course-kanban college-kanban-progress o_kanban_mobile">
|
||||
<field name="course_id"/>
|
||||
<field name="student_id"/>
|
||||
<field name="teacher_id"/>
|
||||
@@ -150,28 +150,28 @@ else:
|
||||
<field name="status"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click"
|
||||
style="padding:0; border-radius:8px; overflow:hidden; box-shadow:0 1px 4px rgba(67,233,123,.15); border:1px solid rgba(67,233,123,.12);">
|
||||
<div class="oe_kanban_global_click college-kanban-card"
|
||||
style="padding:0; border-radius:8px; overflow:hidden;">
|
||||
<div style="background:linear-gradient(135deg,#2D6A4F,#52B788); padding:10px 14px; display:flex; align-items:center; justify-content:space-between;">
|
||||
<div style="color:#fff; font-size:14px; font-weight:600;">
|
||||
<div class="college-kanban-title" style="color:#fff; font-size:14px;">
|
||||
<field name="course_id"/>
|
||||
</div>
|
||||
<span style="background:rgba(255,255,255,.92); color:#1B4332; padding:2px 10px; border-radius:10px; font-size:12px; font-weight:700;">
|
||||
<span class="college-kanban-badge college-kanban-badge-score">
|
||||
<field name="score"/> 分
|
||||
</span>
|
||||
</div>
|
||||
<div style="padding:10px 14px; background:#fff;">
|
||||
<div class="small mb-2" groups="college.group_teacher">
|
||||
<div class="college-kanban-body" style="padding:10px 14px;">
|
||||
<div class="college-kanban-meta small mb-2" groups="college.group_teacher">
|
||||
<i class="fa fa-user text-muted"/> <field name="student_id"/>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div style="display:flex; align-items:center; gap:8px;">
|
||||
<span class="small text-muted">章节 <field name="chapter_done"/>/<field name="chapter_total"/></span>
|
||||
<span class="college-kanban-meta small text-muted">章节 <field name="chapter_done"/>/<field name="chapter_total"/></span>
|
||||
<span style="flex:1;"/>
|
||||
<span class="small" style="color:#1B4332; font-weight:600;"><field name="progress_rate"/>%</span>
|
||||
<span class="college-kanban-progress-rate small"><field name="progress_rate"/>%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="small text-muted">
|
||||
<div class="college-kanban-meta small text-muted">
|
||||
<i class="fa fa-user-circle"/> <field name="teacher_id"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,31 +4,31 @@
|
||||
<field name="name">yuthon.school.training.kanban</field>
|
||||
<field name="model">yuthon.school.training</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="name" class="o_kanban_mobile">
|
||||
<kanban default_group_by="name" class="college-course-kanban college-kanban-training o_kanban_mobile">
|
||||
<field name="name"/>
|
||||
<field name="note"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click"
|
||||
style="padding:0; border-radius:10px; overflow:hidden; box-shadow:0 2px 8px rgba(139,92,246,.18); border:1px solid rgba(139,92,246,.1);">
|
||||
<div class="oe_kanban_global_click college-kanban-card"
|
||||
style="padding:0; border-radius:10px; overflow:hidden;">
|
||||
<!-- 顶帽:紫色渐变 -->
|
||||
<div style="background:linear-gradient(135deg,#8B5CF6,#D946EF); padding:14px; text-align:center;">
|
||||
<div style="font-size:28px; opacity:.25; color:#fff; margin-bottom:4px;">🏋️</div>
|
||||
<div style="color:#fff; font-size:16px; font-weight:700;">
|
||||
<div class="college-kanban-title" style="color:#fff; font-size:16px;">
|
||||
<field name="name"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div style="padding:12px 14px; background:#fff;">
|
||||
<div class="college-kanban-body" style="padding:12px 14px;">
|
||||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||||
<span style="background:#F3E8FF; color:#7C3AED; padding:4px 10px; border-radius:10px; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-purple">
|
||||
<i class="fa fa-graduation-cap"/> 实训中
|
||||
</span>
|
||||
<span style="background:#FDF2F8; color:#BE185D; padding:4px 10px; border-radius:10px; font-size:11px;">
|
||||
<span class="college-kanban-badge college-kanban-badge-pink">
|
||||
<i class="fa fa-clock-o"/> 进行中
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-muted small mt-2" style="line-height:1.4; max-height:40px; overflow:hidden;">
|
||||
<div class="college-kanban-meta text-muted small mt-2" style="line-height:1.4; max-height:40px; overflow:hidden;">
|
||||
<field name="note"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user