From accec9385495ca94e2d2059e69b35cb3cb452581 Mon Sep 17 00:00:00 2001 From: hrrr Date: Tue, 16 Jun 2026 19:21:41 +0800 Subject: [PATCH 1/4] school_gengxin --- learning_center/__manifest__.py | 2 +- learning_center/models/__init__.py | 2 +- .../__pycache__/__init__.cpython-312.pyc | Bin 578 -> 543 bytes .../course_homework.cpython-312.pyc | Bin 10263 -> 14111 bytes .../course_homework_submit.cpython-312.pyc | Bin 5826 -> 7134 bytes .../course_teaching_class.cpython-312.pyc | Bin 16823 -> 16823 bytes learning_center/models/course_homework.py | 233 ++++++++++++------ .../models/course_homework_submit.py | 27 ++ .../models/course_teaching_class.py | 5 +- learning_center/models/teach_class.py | 3 +- learning_center/security/ir.model.access.csv | 2 - .../views/view_course_teaching_class.xml | 9 +- .../__pycache__/student_info.cpython-312.pyc | Bin 4195 -> 6101 bytes student_organization/models/student_info.py | 54 +++- .../views/view_student_info.xml | 2 +- 15 files changed, 256 insertions(+), 83 deletions(-) diff --git a/learning_center/__manifest__.py b/learning_center/__manifest__.py index 22aa1ac..afb027e 100644 --- a/learning_center/__manifest__.py +++ b/learning_center/__manifest__.py @@ -25,7 +25,7 @@ 'views/view_course_teaching_class.xml', 'views/view_course_student_score.xml', 'views/view_course_homework_student.xml', - 'views/view_teach_class.xml', + # 'views/view_teach_class.xml', ], diff --git a/learning_center/models/__init__.py b/learning_center/models/__init__.py index 043df1a..1245d4b 100644 --- a/learning_center/models/__init__.py +++ b/learning_center/models/__init__.py @@ -7,4 +7,4 @@ from . import course_homework_submit from . import course_score_item from . import course_student_score from . import course_teaching_class -from . import teach_class \ No newline at end of file +# from . import teach_class \ No newline at end of file diff --git a/learning_center/models/__pycache__/__init__.cpython-312.pyc b/learning_center/models/__pycache__/__init__.cpython-312.pyc index 69332b436027af9564e8fe9011a8d16bdd33c31b..d1f1900da224c398a2495a2064770d544b139bce 100644 GIT binary patch delta 70 zcmX@aGM|O_G%qg~0}wRqG|2Lu$ScWMFj2jbrIJgNd*X`I%zm0&lUo_}C+}no;SvC< VVg%x1g~{Sf3LN(sl#BR)TmW|e5C#AM delta 103 zcmbQwa)^cZG%qg~0}xE=)64Rn$ScWMGf}-zAcY}?D~BPMD~gMep^{sZXX2dGLYj=X zxJyzKlQZIza}tY-{WQ5JXEEwC74b}-#u&~e2sDEch>Mjce`i$SzRRF|k3q7CA1DF< DX!#k; diff --git a/learning_center/models/__pycache__/course_homework.cpython-312.pyc b/learning_center/models/__pycache__/course_homework.cpython-312.pyc index dce2bc4cfd6b04883fc42d398a8a8f42bc2109c7..d43fdd7c0307165e30aa081eaf9153931b75d0f6 100644 GIT binary patch literal 14111 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 Z`DZHsZ@R5Ix)4~}GT8EW3d@AZ{{Wly%K`uZ delta 4453 zcmaJ^Yj9J?6~0$5>t)Hd9=80DC0n*6zvMRtj17h;qzO(5fg}V_gztq&$P%pNfEg3h zfutrO6FZxXX-W&UNx=hcrb#CynP$@bNz-I#EeuGxp{?5insnN!ar&CfH0?R}%C16Z&>M7O+4+Jc+V>Twvzeb^+uN7X048}M>5F93)b^8X}r}!|IFHq#a!M6 z^`gv*vb7}_wCCB3Rk4iW)#2uBA5woe!`Z&Wa;01ucql)w$k^LN`*ymKHCZY^v$S4W zmd4IiW@*Yr%?fdjgL7V}T8zh@rK!%*RAy;hIU2{3##oc1angOP%~s2~IRodp;9ZQl zN}S=x^^5DcdaeQXzmQzllFrw7hpvWeI?8OV<$Qo{t{Kq7wE%iyPF;8l4Js@ZZ3}zh z+K)2lGilt~z;%FKBgRu$$8~bcV9yIHHckA~X6zD03rFP>k7{|2teNI3ZN?QjvKE}W zGDp-(w<~Ry?i^X0xTnW)zs6NLnhtc(lOyUx2WxwCWXnVc|Gg+yLs3Z4FKnnww3bR@ z4cC`-yvxNzB`^^8+J%zi)@3DXC3hDjs+;ozt{T4EyPl?0Cs-}ro7bnpYeIDNV&1(z z>}l6!HdQgL{V(JPl~Zq?PmOpEM8Bpx#>gHk{MfwUf*U zvyK^Ow?D`*hggo?%^s4`_w?2`Ue!OzmLzaFv5lw}c6umpgrzKN-tvt0n3mi#q6%9U zjFx`Kw7XbNb5y-JN&SE9v{`l<`mDjRI%{3cf{PJ0fY}jS)Gz{31TbY{<8;|th%ZoU zsmVJCsRMcbg4H;C{2>K1%y{+vUb&!*CxVcfzZ;x|rC=dw24X`b&Idx=K?gmpvCtl4 ziK-Yh#7egrZK@vVzQod=f)eEcmKa&uTTtA7jNJp1H!)Le{}e0e;zK(JLy15lG{{fM z1U4?{IX=imLQy{OL@*M^o8dT2Cv^AF_l7CK!#^`i!^mFEauJ3{M*Wvoa0d9yBp&B5w5~)Rj8-Pw5yVl|k;$;B1-kNte zytUzScld+gF9&}<>?OhY8Xz!9cwRQVu_YD!6wqALRsDh$9vB*9AWH!k(zE zaAl!RP{jGjEEWbcCS7WO9UeUDIbC%78P@{FxEvN^O*sufkonYl8(i; zS_<3*!hqkERJMU~1q6;oJD ztBW>aucD3)7uAhkFSDOG_|4w2`)13Wr+U8uosW%Wv(EaIvpwl-pXrFsIAi06S-U4? zZ%Nu)W?I8D_C4de>)wWQJ7&Dy1vq7v)Fu%AhWV@H?(^rV)MQD=TReXPt(9cAi% zP-WgE1`AczPYS@!t0Xq~A*d46>mYepVS+pw+b`(%4(*JD;*U#3$C6I4iQ_xyAhq;> zxmC9w1z2T=8Tt#eO?g#qBOdx?k&V7ySz03U2`jl@n?3b+l}+aRP@oZ~rY+@Tis!VM znX4QgO(Dqrz)v0&g3JGCg=S)8I2AzX-mbJ;<$_Eoh{oOz_+gZtdoeU%&PIIMAk7Ca89kAjfm` zP1gp!pv_$75ErMtRaSE+@}+!{FN=^b>0=Fc^)vEga`HDIou{>)(lI#@ADcyJvJn}% zG$ISDXt36jzj(MH(V|3$+ZNl1jLwyr4M14xED;bbitrH-8(0OE=7Jo$lZ8t~=lDou zjKX%&ITlYwLJO6mCy0Adv_>X+GB1fRD2sV?51bHDb23`8V9W9WeHXbXdZW#ruF-=i z#sna@1>cRl75QNI<(|z_so}*Vk03mRum!+dOyI?1$fF3Y2=xGhesDO$OYjbew?Z&3 ziNqI!RH30^Ns4!o{?T*pE zgl_O?Mu%V+{{sN*=mxS~+FF{j`jS@PjJ0L#?vIVuw5>8_t4rGIQnt3Ft!<`#^NelF zxawn*EnV0Ans>@O?!RJoryJW|+cvcg`*rDt)>K1JvY`h@-gIrl*~pp5xc|lb?@)M} zUK=$`8PKZc4pnn!s@b1x_M@&b?dwSS)+K%GaMS=4SYn?XnHV{J;Bv7q-PCzPb+x1( zqC91P*`97{7l*S=%TK7TmDJDHEg$z^GrMPNfk&?uRNrosn37?z0-y$NItuh==t?(k z`w_}IOA9y_OB3GT5DQOxSVqrS&1&+fI8flAoNSN==p(l!RP>akoGQvisx{!l36311 zxgN{jum^ZYeB05t9zXC#X71o$nEfMK@=#v%%JYljL zVGRQEzMvflMl(eQ#I?wGf*j;={QQKHkRHIT49q`Rg(We%H0cE}i9ZW)nE6C}1x>ce z?uqWxE0dXR}~b5ga5@oI;Vj&6Scd%u72 zl*Ga}-Z^>W;>+|>qrJQYRqxQ7$DX@2dHU8HFXb4lYVs5iD_97MT`@8UZy~>*ez&P{ zr=Um-@8t(QD)&hl}wwBGh z>(A~#vp-$ics6_{d|N3mG2G7A7HH=ftp=V`@X+t=p{*@Do5he7>l1?!LC5j&0TSAq z2*sj;j_~`2LWCdWqX|L1As8KQ#W*YIPg-1UtHFU(TYcCQiw@sZL9>aE@B`>TqOrWb zSS-Q^qhvibwAx1TZxCriXh-Nk5I^_S_ec5GL0CkjM!^t=uR8cBPVj@kh;f47WMmzJ zAK@MZtXZh)STvp>!B8|#@Vi0E;|}a$)sx2%b|P>9+sQ6KLDd(E2FWma9OYpIOeq;e z!0h9{BmDS`6C_8n72!#MDMljpS`?@kKmnaN3(?TVwwH}Rt^JwrJzuJCbFy#q71I{_ zVcUbs56o9A{nXul&c5S{C2+WZUg1>U$Ikm%nX+|W%_=MARWhY(PEAWXs^I_H%8oC* zGfMkyS*fz~b2+1`oWtIHmqzLO+-g-y$0x4e?^V+mJL?}7lpC>t x4W&2~;d{tQkRi#%9RPE3mSum#xRQ+PS4{n16fqgA9p5s!ZDQMB8SIN5{tZnnRU7~S diff --git a/learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc b/learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc index 076fe2ed0cfbecd92dee6758084ad9bb2ab020f3..bef74ceb1be007c9e93a9f048f1f40766492ac51 100644 GIT binary patch delta 1829 zcmZ`(eQZ-z6ujAHnzzI^RW*G42D?w+6OZNF~MjUVpIAaW1}DBzE)(G zw8R+-!QglbBO!q(CLs6+Sz?SB{}5wh{Kq=Y=98e2ZOC6%0i*t-=e({srrxCIo{!(T z_uXI5IiED&Xm@|%aybaBqo219+$bA%pAa1)A&0NL?HA-eqON+2s_p9P%a0kK33UtB zsE=O`T;dQ+!gIl zB<*n4^qF_3kH0?o;d$elV;x;E$~zZR??MRZJc!!bTIPqH)fxeL32im{pET~3o=%5n_=6ZB_*wY7(*xp7dWs}qFRUYcio6E@MT%ac z1`m~^) zfFOLZ4-Pej7ef)UN(PHMQ|_*z;q;hF!XG@q3N@&P9Bc#DZ=L7BsZ@Lx=H zlAT^c4)W>$A%*{klw&@@B8IJlvlX7Lhs_lCv;Ks}Hljc}@d zyZG)+U=CJv#FI?ddg4)Sf85w2+jm-Lg%FQL0u)?#dyn)TiH>xRxgW{$-+BGnjtRMR zTyD(CjTbt;kz4aTdAR%s&%CVT-(29G78gH)a*7x?Y-MSc?rnzxqX)PIhOCvM14!GP zRebls2a&cpFfi{U`4p#fDV{BZ6S0rxER|2xSW^Q11M-|G`aH&8az$Dd&de&s1Ka^l z5tAz+e(UPl$qzEnnp4M5-a7jJbmq`h_Wbn8_iksd{`B$i&mSEt)X>z4V-}H9uU@(J z#syXdnOhk)Ww9sgP?xO!G=*L9c*Jzh6zlH(i1xhcE*5t@me67ehW{2ridX}RM=`xn z>#P%WQ`!^KgP3YMQ41H+ilsg?EwDlcmqMxg(^dx+@0is1Rkn?lt;{;Vb$W+io`5X5DkoP> z%&)&*v*>L4bb7pId9G&pSWVk6B46#kM|ii(17%ZQXH|^SZVW$klQtO1d9S3|W_*rk z78$WnR5OL1L^Q&-K#U=EtPN2m;dnF(?3ngG7E(19>{qQ}XWF-E5iOkPkH-oOmuv)v zwNQ-JV{R>qMik8`teJ-c&J?5ZO{x}QI1&nsBV(p(W^{zLNF*3kXrY~Ol&vp}kP^hB zz*cdw&f+_@t delta 579 zcmca-en^+^G%qg~0}#~9>Sc)tPvo1#e2Rr(<5F=Jo)ohb^K_;ZixkT>R+CS#D9c)> z*sQT#%>+`-z!0UAV%NeDrJG_8B=u4pCUdaLvpX(gOmRwao~*~JF6)va15=yg+QP6J zqKzTSu+mM_ee(v^5Z1{G+;)sIo8!6F7=;yq(#6a`LP0^HNE}EP$xoiaqs6E{`7qBB zM%l?7y!njglYj7L2+IH^-87ksR6&X~K!oPxVm@a^>&@HwelqIl0!3a1fQ0oxEH@BK zAH=c&u?#?jA&_v>WGOP9d`G~Q%?QY=(wsb(M~)}GC^029J}0#-HOFIepx{hqKTV^_ z)nbns)h5S_H`m|dE-p>V%`Aye%gjl=#gD|vOUzBZ#o|$tn{$f~Dx933SCX1nQltd3 z(HKbFVo%P`%>@eG;so1M6rY&_cKJ17cc(2#}*!G89RG*x=A&2eCi|C=8320V8Si3JGN<=^GqMH#p=!urkZBePCnY z7hk~rg`JsKx54!T$K(f6$*dol_*u0lXG!Zx7sY{$fSdS>!zMRBr8Fnit|)Qx25Cvr UP)0`W8D{fsX4-sZ0I|VJ0Z*@#761SM diff --git a/learning_center/models/__pycache__/course_teaching_class.cpython-312.pyc b/learning_center/models/__pycache__/course_teaching_class.cpython-312.pyc index 08725f7ed075ec4d240b1bf1d07e20d9cd57af07..4ff25bb9644f9b954896a4155a29a001aded9544 100644 GIT binary patch delta 24 ecmdnq%(%Uok@qw&FBbz4yxVG!RlAXQl_LOOv now: + record.is_submit_open = True + else: + record.is_submit_open = False + + # ====================== 统计提交人数 ====================== 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 + # 已提交 = 状态submitted/graded + submit_ok = all_submit.filtered(lambda s: s.state in ['submitted', 'graded']) + late_submit = submit_ok.filtered(lambda s: s.is_late) - # 未提交 = 班级总人数 - 所有提交人数 - record.unsubmitted_count = record.total_students - total_submit + record.submitted_count = len(submit_ok) + record.late_count = len(late_submit) + # 未提交 = 总人数 - 已提交人数 + record.unsubmitted_count = record.total_students - len(submit_ok) + # ====================== 发布作业(核心逻辑修正) ====================== def action_publish(self): + self.ensure_one() + if self.state == 'published': + return self.state = 'published' self.publish_time = fields.Datetime.now() + # 1. 批量为本班学生生成空白未提交记录 + self._auto_create_empty_submit() + # 2. 推送作业通知给学生 + self._send_homework_notice_to_students() + def _send_homework_notice_to_students(self): + """发布作业后推送消息给教学班学生""" + self.ensure_one() + if not self.teaching_class_id: + return + # 获取当前教学班所有已选课学生 + enrolls = self.env['course.teaching_class.enrollment'].search([ + ('teaching_class_id', '=', self.teaching_class_id.id), + ('state', '=', 'enrolled') + ]) + student_users = enrolls.mapped('student_id.user_id').filtered(lambda u: u) + if not student_users: + return + # 消息内容 + subject = f"新作业发布:{self.name}" + body = f""" +

课程:{self.course_id.name}

+

作业名称:{self.name}

+

截止时间:{self.deadline or '无'}

+

作业要求:{self.requirement or '无'}

+ """ + # 发送消息(关联当前作业记录,学生在消息中心可直接跳转) + self.message_post( + subject=subject, + body=body, + partner_ids=student_users.mapped('partner_id').ids, + subtype_xmlid='mail.mt_comment' + ) + + def _auto_create_empty_submit(self): + """仅发布时执行:自动给教学班所有已选课学生生成空白未提交记录""" + self.ensure_one() + if not self.teaching_class_id: + return + # 获取当前教学班已注册学生 + enroll_records = self.env['course.teaching_class.enrollment'].search([ + ('teaching_class_id', '=', self.teaching_class_id.id), + ('state', '=', 'enrolled') + ]) + student_ids = enroll_records.mapped('student_id').ids + if not student_ids: + return + + # 过滤掉已经存在提交记录的学生,避免重复生成 + exist_student_ids = self.submit_ids.mapped('student_id').ids + need_create_stu = [sid for sid in student_ids if sid not in exist_student_ids] + if not need_create_stu: + return + + submit_model = self.env['course.homework.submit'] + batch_vals = [] + for stu_id in need_create_stu: + batch_vals.append({ + 'homework_id': self.id, + 'student_id': stu_id, + 'state': 'unsubmit' # 默认未提交 + }) + # 批量创建空白提交记录 + submit_model.create(batch_vals) + + # ====================== 草稿/关闭作业 ====================== 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) @@ -103,7 +177,7 @@ class CourseHomework(models.Model): 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', '已提交'), @@ -111,69 +185,88 @@ class CourseHomework(models.Model): ('late', '逾期提交'), ], string='提交状态', compute='_compute_my_submit') - # 是否可以提交 + # 是否可以提交:严格依赖提交通道开启状态 can_submit = fields.Boolean(string='可以提交', compute='_compute_can_submit') - @api.depends('submit_ids') + @api.depends('submit_ids', 'submit_ids.student_id', 'submit_ids.state', 'submit_ids.is_late') def _compute_my_submit(self): + student = self._get_current_student() 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: + if not student: + record.my_submit_id = False record.submit_state = 'not_submitted' + continue + submit = record.submit_ids.filtered(lambda s: s.student_id == student) + if not submit: + record.my_submit_id = False + record.submit_state = 'not_submitted' + continue + submit = submit[0] + record.my_submit_id = submit.id + 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 == 'unsubmit': + record.submit_state = 'not_submitted' + elif submit.state == 'graded': + record.submit_state = 'graded' + elif submit.is_late: + record.submit_state = 'late' + else: + record.submit_state = 'submitted' + + @api.depends('state', 'is_submit_open', 'my_submit_state') 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') + # 核心条件:提交通道必须开启,且未提交/未批改 + can = False + if record.is_submit_open and record.my_submit_state not in ['submitted', 'graded']: + can = True 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('当前无法提交作业') + 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, - }, - } \ No newline at end of file + # 后续打开提交表单逻辑不变 + exist_submit = self.env['course.homework.submit'].search([ + ('homework_id', '=', self.id), + ('student_id', '=', student.id) + ], limit=1) + if exist_submit: + return { + 'type': 'ir.actions.act_window', + 'name': '提交作业', + 'res_model': 'course.homework.submit', + 'res_id': exist_submit.id, + 'view_mode': 'form', + 'target': 'new', + } + else: + 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}, + } + + # 移除原create里自动生成空白提交的代码,草稿不生成 + def create(self, vals): + homework_record = super().create(vals) + # 草稿状态不执行自动生成提交记录,移到action_publish + return homework_record \ No newline at end of file diff --git a/learning_center/models/course_homework_submit.py b/learning_center/models/course_homework_submit.py index 681e245..37a89a3 100644 --- a/learning_center/models/course_homework_submit.py +++ b/learning_center/models/course_homework_submit.py @@ -38,6 +38,7 @@ class CourseHomeworkSubmit(models.Model): grader_id = fields.Many2one('res.users', string='批改人') grade_time = fields.Datetime(string='批改时间') state = fields.Selection([ + ('unsubmit', '未提交'), ('submitted', '已提交'), ('graded', '已批改'), ], string='状态', default='submitted') @@ -87,6 +88,32 @@ class CourseHomeworkSubmit(models.Model): else: record.grade_level = False + @api.model + def create(self, vals): + submit_rec = super().create(vals) + self._check_submit_change_state(submit_rec) + return submit_rec + + def write(self, vals): + res = super().write(vals) + for rec in self: + self._check_submit_change_state(rec) + return res + + def _check_submit_change_state(self, submit_rec): + """统一提取状态判断逻辑,create和write共用""" + # 仅空白未提交状态才自动切换 + if submit_rec.state != 'unsubmit': + return + # 判断:有提交文件 或者 填写了提交内容 = 完成提交 + has_file = bool(submit_rec.submit_file) + has_content = bool(submit_rec.submit_content) + if has_file or has_content: + submit_rec.write({ + 'state': 'submitted', + 'submit_time': fields.Datetime.now() + }) + # class CourseHomeworkSubmitBatchGrade(models.TransientModel): # _name = 'course.homework.submit.batch.grade' # _description = '作业批量批改向导' diff --git a/learning_center/models/course_teaching_class.py b/learning_center/models/course_teaching_class.py index 515af67..7c249cc 100644 --- a/learning_center/models/course_teaching_class.py +++ b/learning_center/models/course_teaching_class.py @@ -288,4 +288,7 @@ class CourseTeachingClassEnrollmentWizard(models.TransientModel): if create_list: self.env['course.teaching_class.enrollment'].create(create_list) - return {'type': 'ir.actions.act_window_close'} \ No newline at end of file + return {'type': 'ir.actions.act_window_close'} + + + diff --git a/learning_center/models/teach_class.py b/learning_center/models/teach_class.py index 454f957..384b170 100644 --- a/learning_center/models/teach_class.py +++ b/learning_center/models/teach_class.py @@ -10,4 +10,5 @@ class TeachClass(models.Model): 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="年级") \ No newline at end of file + stu_grade_xx = fields.Many2one(related='student_id.stu_grade_xx', string="年级") + diff --git a/learning_center/security/ir.model.access.csv b/learning_center/security/ir.model.access.csv index 41f39ec..f137695 100644 --- a/learning_center/security/ir.model.access.csv +++ b/learning_center/security/ir.model.access.csv @@ -11,8 +11,6 @@ access_course_syllabus_sys,course.syllabus.access.sys,model_course_syllabus,base 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 diff --git a/learning_center/views/view_course_teaching_class.xml b/learning_center/views/view_course_teaching_class.xml index 772069e..b9b89b3 100644 --- a/learning_center/views/view_course_teaching_class.xml +++ b/learning_center/views/view_course_teaching_class.xml @@ -204,9 +204,14 @@ + + 我的班级 + + + - 教学班管理 - + 我的班级 + 15 diff --git a/student_organization/models/__pycache__/student_info.cpython-312.pyc b/student_organization/models/__pycache__/student_info.cpython-312.pyc index e7fb7d16d3fcc72d4f371773a8f6f87053689335..bf9112bccc43bb8cef8f45e285ec774d4ceb93d3 100644 GIT binary patch delta 2798 zcma)8e@q+K9e?NZo$veuCx-CTPEGh}AP`s}DWPfBwKQED(kRmgPNkdccMucfL+|V+ zrDi5;+L&z>M%Rp>rovgah7Hmt%BG-@O8s-%G|9-Fa8B*Y)ESb$N=7GD{bSmDcZPsO zr9DgUzCS+SAMg9#`#yi^{(Dp2Uu`xsz@yyN-0v(H&nw>Fg}Dg;0i=RpfbvoU2Crd& z_R-H^0G2lbVa@g)r*OuKoz1WX)8Cs}Ps^Rd?#I|x!S|xd3KzDsK%& zzq}cz({a#C!S7$-HgKLeI7fNwP6E#}s^w%j0>x1Hg;1~ZU*l=cf^9rB;*}6{sENmn z$^=4CJcr26MMxEwZ;mfdjOpa9QA~OahyamI$uM%^4uT{6^5`#@uiVX!-SJS^osaFN zc;zlzVbQR8#K5dPU`MH43Nl@zoJt{gxJJ{FNGc1Z0bd~WkgPKoK;@9=gHkB?x*~F8 z4mZ)@Oz{WV$YfSnz77Xz<_jph(#iKxHOhy4wH~mRAZnB^_@NgyiyFea@boQ@M7c2{ zi%5<*Fu!tper0}YWpY0I@udfU`~c@q;>uwZ@P{`Nk#I?ZVpvrA%%3+kU@O%SfGQ`U zK4H)oK8515|0fJ#VYCvmI z(4RZWThKH~wBNK@rqj>}nW&+c?xP?(YtlSo#jr7Il>fH9uYQu@))51cgZ!*{!<_lQ zO#!rQv1Fr+YzdR&sSRjdzXCs}qU;up?Xf2I9W}~ZhYXvdCK<2uJpk?R8!)$hO?TvK zibF>Y`1f77osV(Q0rR6Vw%?jdc+)4!Y$xs0i(PPq9p<*L64W=#zR6XNjB*8kZcn4pDD7E2$kMg)P6n3d5IUEr}kpUGT4+g7DQ0fbW zRO%_T8?(6KGQq$=AUtG$)hCOMeMpK73gjMjVwD5=0FMHmq_ zfw6zmdLpD}>DMm%_FF3-e~9OYZ%(hgJG~sgvoe3dy~%|5cdy*LoBi#rukQV7c_O)d z`%*UkUUvTO<{SIfz4HVU!1Qb>GAS|y5+i|Aoh zV+d%e&I^RXA`1C} zf)-x2<@Q8pQ9H5ZwRDIl)w-?@gnA{F7X*J0uSO7LaxdK*V?=LtM*%*6LynUhFO1Zv zr%Bw(UATFDGXhpwkY6-WJ6?PF$>ghPhiB2zwBTq;JDTIBOnyNMd`$d%+ zJCrVcBUSJQ&d*gob#(G*@>JT{oZ#;lxib}YNzZh9%H5WD;j!9#(~)-W&$ucx?wX9N zI)kmcW0T#PgiQs@l^TCkL;Ywk>FPg zfYUv7aPnaC#f7qci)9BE$_~u&>9S`MS{Vv5yQ`q%Tk>FYIy2ZP7uh66O?~j_L|WlTyE_UC@t15Ga?;8+gat;)@zn#!ZnepL3!5J z+D#rMMBW+I1jRuy1Z7l3IA%b?Zyq{IXj^XM{bDdE2>5+Jfu%BejE?9#&tVdgi6M%! z_!fL~`wzAr$~0H}=jKm$9#dHRUt%nz)J_OA)0J(pUlihe)r74Q~ d0_<4;dp-yCU$X*5ITO_r4dV^}0fg2({11l_=)eE~ delta 902 zcmYjPT}V?=96#rN&rL}5CM>+xr*95Tj<|W5fAX(v6r}`A45Nb#KMwo2!s-pu%5Koy#c6im@iMlB3-UwC% z+aEtc+BlzhiYiW%sG!PG)I)JEnGl$|kE;9sQ@1g-d1kMi^JLoxg%y3_FFU_E9AR4991YW#rYJ{?_vkVIksc< zd8t}1+Hk8tp~hh*#4d76%6RLUj)|*G%*qAm zA^Y+=Y$lJC(FW^|nN0~9$?5qNIaG>`tu(=AVjh=meC+7-GH%KZX{<8d%45 zWXCZJLu9NbYBLX5Z2K!%*3qhVHqn@6T%;MuA4baswz)5MYz)@KZi zG8`p=0QS)j4w7+KuqjGmW{iequ;*>QfB94Wv10x~ewXB3JuW9W?#F(58Pht*@5Vv5 zsbsRbsnm2*H)RXulH`Ir<~1FRrRR*4ZbO~!n;>QPy0eS*(pU(SanC?6PoXIzJ*}ru z1_vp72CN?TR5DYtz;u~Qbl?{sJQI-LZs;R@-nV%LNDa$3?@g{uuC;E9C-*r?j2!Sl z3RuW4#OyImG6e$}24;mYdyiP8!4$6>NKaTTaExWyepc^8Wh7~!TtXkkH)xJMtqi;T c!9xhYfZ%%&{OJ+;VPq{_?k;uz0u);AKLjV$=Kufz diff --git a/student_organization/models/student_info.py b/student_organization/models/student_info.py index ca54486..b7b06ca 100644 --- a/student_organization/models/student_info.py +++ b/student_organization/models/student_info.py @@ -1,4 +1,6 @@ from odoo import api,models,fields +from odoo.exceptions import ValidationError + class StudentInfo(models.Model): _name="student.info" @@ -24,7 +26,7 @@ class StudentInfo(models.Model): stu_begin_date = fields.Date(string="入学日期", required=True, tracking=True) stu_end_date = fields.Date(string="毕业日期") stu_grade_xx = fields.Many2one('basic.grade.xx',string="年级", tracking=True,domain = lambda self: self.env['basic.grade.xx']._get_current_year_range_domain()) - stu_grade_bx=fields.Many2one('basic.grade.xx',string='年级',readonle=1) + stu_grade_bx=fields.Many2one('basic.grade.xx',string='年级',readonly=1) stu_status = fields.Selection([ ('studying', '在读'), ('graduated', '已毕业'), @@ -42,13 +44,57 @@ class StudentInfo(models.Model): major_name = fields.Char(string="专业名称", related='major_id.name', store=True) department_id = fields.Many2one('student.organization', string="院系",store=True,domain="[('org_type', '=', 'college')]") + # 新增:关联系统登录用户(解决之前作业通知报错缺少user_id的问题) + user_id = fields.Many2one('res.users', string="系统登录账号", ondelete='restrict') - # user_id = fields.Many2one('res.users', string="系统用户", ondelete='restrict') @api.depends('parent_path') def _compute_org_path(self): for record in self: if record.class_id: - # 直接使用班级的 parent_path + 班级ID record.org_path = f"{record.class_id.parent_path}{record.class_id.id}/" else: - record.org_path = False \ No newline at end of file + record.org_path = False + + @api.model + def create(self, vals): + # 1. 先校验学号,提前取出学号避免多次读取 + stu_num = vals.get('stu_num', '').strip() + new_user = None + + # 2. 学号不为空才执行创建用户逻辑 + if stu_num: + # 校验学号对应的登录账号是否已存在 + exist_user = self.env['res.users'].search([('login', '=', stu_num)], limit=1) + if not exist_user: + # 获取两个权限组,并双重校验存在性 + internal_group = self.env.ref('base.group_user', raise_if_not_found=False) + student_group = self.env.ref('edu_base.group_student', raise_if_not_found=False) + + if not internal_group: + raise ValidationError("系统内置内部用户组 base.group_user 缺失,无法创建登录账号!") + if not student_group: + raise ValidationError("权限组 edu_base.group_student 不存在,请先创建该学生权限组!") + + # 组装用户参数,优先取学生填写的邮箱,无则自动生成 + stu_email = vals.get('stu_email') + if not stu_email: + stu_email = f"{stu_num}@edu.local" + + user_vals = { + 'name': vals.get('stu_name', ''), + 'login': stu_num, + 'password': stu_num, + 'email': stu_email, + 'phone': vals.get('stu_phone', ''), + # 同时分配后台登录组 + 学生业务权限组 + 'groups_id': [(6, 0, [student_group.id, internal_group.id])], + } + # 先创建用户,事务内失败会整体回滚 + new_user = self.env['res.users'].create(user_vals) + + # 3. 创建学生档案,如果已生成用户则绑定user_id + if new_user: + vals['user_id'] = new_user.id + student_info = super().create(vals) + + return student_info \ No newline at end of file diff --git a/student_organization/views/view_student_info.xml b/student_organization/views/view_student_info.xml index 4cfd0ec..4857473 100644 --- a/student_organization/views/view_student_info.xml +++ b/student_organization/views/view_student_info.xml @@ -3,7 +3,7 @@ student.info.list student.info - + -- 2.34.1 From 45fbe4fbbafcbd4becb4f1ab9521f5bad9d5a45e Mon Sep 17 00:00:00 2001 From: liuhaoran Date: Sat, 20 Jun 2026 19:32:29 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course_homework.cpython-312.pyc | Bin 14111 -> 16920 bytes .../course_homework_submit.cpython-312.pyc | Bin 7134 -> 7252 bytes .../course_score_item.cpython-312.pyc | Bin 3797 -> 3923 bytes .../course_student_score.cpython-312.pyc | Bin 7795 -> 8112 bytes .../course_teaching_class.cpython-312.pyc | Bin 16823 -> 17457 bytes learning_center/models/course_homework.py | 113 +++++++++--- .../models/course_homework_submit.py | 2 + learning_center/models/course_score_item.py | 4 +- .../models/course_student_score.py | 9 +- .../models/course_teaching_class.py | 22 ++- .../views/view_course_homework.xml | 7 +- .../views/view_course_student_score.xml | 132 +++++++++----- .../views/view_homework_submit.xml | 2 + .../views/view_learning_course.xml | 24 +-- permission_manager/__init__.py | 1 + permission_manager/__manifest__.py | 12 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 191 bytes permission_manager/models/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 207 bytes .../permission_role.cpython-312.pyc | Bin 0 -> 7174 bytes permission_manager/models/permission_role.py | 134 ++++++++++++++ .../security/ir.model.access.csv | 4 + permission_manager/views/role_views.xml | 166 ++++++++++++++++++ 23 files changed, 540 insertions(+), 93 deletions(-) create mode 100644 permission_manager/__init__.py create mode 100644 permission_manager/__manifest__.py create mode 100644 permission_manager/__pycache__/__init__.cpython-312.pyc create mode 100644 permission_manager/models/__init__.py create mode 100644 permission_manager/models/__pycache__/__init__.cpython-312.pyc create mode 100644 permission_manager/models/__pycache__/permission_role.cpython-312.pyc create mode 100644 permission_manager/models/permission_role.py create mode 100644 permission_manager/security/ir.model.access.csv create mode 100644 permission_manager/views/role_views.xml diff --git a/learning_center/models/__pycache__/course_homework.cpython-312.pyc b/learning_center/models/__pycache__/course_homework.cpython-312.pyc index d43fdd7c0307165e30aa081eaf9153931b75d0f6..ed50c02eb879c04f20cc56e591847d9f26ab514d 100644 GIT binary patch delta 5090 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 WntIf%^T17qZaa9}#|*Y5)&Bu^(DMrb delta 3141 zcmaJ@Yj6|S72d0tC1G1OwhWStWg#JXEh8-X5rZGt4g>-=kC>3uxDkqW!^oqDxhoay z(Ap{P#7tnoy+gnZEltV~D9jYl57I}{G}H8zVT#i-&}}khIzVXqBMvPy4KwZZoGS_J z{^? zFxJY-o0hVMvKs%>C^iCs@!qSWS4OD^4q^!v;YT$@Mj%c})x;!P&uYtu7rB5JMZvULqRUh!RVR1h^=XgMg0M%64Ql?;`` zsiaJKhH!>x4T6&$s9edeRjw$;w-thC|EUZaHX~yzYqf4J4$K+@H;j!u-t64+ZJIJa z8e`nlhu~$~RywkMT z;VS9B_YWwqOu@iuQJ&%a;QuecN z`&!6O_G{nK0qZTR?ZivdFWt1(&06cOSBi52sdwCRIM1w}S$)zECoeyB&UAk42%cMi z-5vs76Y_34{Id@K$ByQ6nd|lz;I^9PO!~57_JcaH&Oc`oO!kL@-el$}k79cko+2P{ z&j0ahk~xeGN%=mc;`w5ll7+2F>7?3+;qd}`|^Q9aJ)d2VzB$5+Vpgr z?gOt5kR`<`_GO*3Jcz!xaIXNkLPRl8$&i6TObEBE)l<47P#BzEHYqk%@#(Au;X=FL zih=4k(GCY1?UqgH4x4Y+xTkbCj1I7`tpAfcfo9m5)BqrAc&7ONQ1C*j#Q+xjo5^Xm z!QT!WR^F^y1#bBkzI*k` zy`#tO{P--`HnK-6x0Bu3zQBhXGRpU5ofitc0ggSDaE$l+6pL#r;z_fI;Okk!(}XyGd0 zXFb0|SX=1r5YP8h=t%b@UC=7LcXI*iKnnfRoeOb4D{k_VpJkhx?8LxBt7QYtM>_+c zwF8>H7Jlhb0M#6gB=fHYK6Wjyg{lRQ@hb3R{X&K95Mw!k*Fbn4J2tEs8Vo@x0d zvEwl128gd&K1CFH3LAgw#4z?mZY`ZaY6jsHfLatyCDZc$v{;mzwtXnUwxH7pj|KHhgzJUA)bLJak7cFUd`VG_KUW^?7|SESdqemU&Hr^7l`BJgpe*sghSc`!V%c| z2S{O;d|h)uGayjj4;odkWJY94BVd3fVD@&0-4qT-;}Jy(hn0Nt^ZgNFgY9--2`nWA zufcy!2%p%UGrpO?xys+$15=jUmYVCv8ouYmUS{YREBgwlsmA_Dax{dOUp+h4;Th)_ zAKq@cX~DTsO#^aVj;3R&B)=imqTW<0E=Q8QpsG0%kEiy9Z*t?-q#R1XJLzuVsinN#!uXd3_YY-lolD2JqIN$*AHpy~901xTl~mF+5=$yH zgFEig=3A_YG$aYJQG7IN0tMGhfJpE0oCclbt{5&3mX8fJHo7IHF8bJb}(I>tLv0j4}^q(Dd58fwiASOE5XVw5T{$uQ)lsC{-`BBsI5` z2WZffy>p)InDu<)?x*v*H5rRQ31qSzSJ>v+TaIwKU0{*etR|()$j`zm^_iK0jsF7^koARU ha+0(!W9j4#(vqS@jEww1O*S)azA}K=MG`=#0szh+B-eijOMgM6Lo+PwMHNd=0tC9XN=gwIj<(Xc<0+zjBWfGxv5?;)i-5x^bDnbsv(iY)tcGxu&(^U;)W;I&6D_ zc~)=t3$R3|9jg#wSB^=bzKVOeV8zNNu!Bl3$YN3DyGV-VjKH%Gi9S?K_}93R{#RC= fJY+-wcpwX)-@*8V3jpotC>LNF)&2QGBKobWJy4H z$YhFYiW-tSIj}k{WEBv0ih7F18qLXm%*y;)AQs$Yg~=0`B>A;b#1uhdo;oOEN??=S zu$ZiyqL-o%bOSR)E=ncEpoJkyHN_A}s#O|k8gG8YJcE%(lc|UksG^7mNNlcR6=zhh z5=qW4Ehh08>YIhRZ5YLF zLG{E#^~8hqO!nsqWjsE4DbF#M$}2*VlZ$xk#cxPz%n+L|KU4mKru~7sE0SRsSR@{Z WC{6yxJCiYZ@&rB!#<0mN`E&p)p>2Qw delta 293 zcmcaCcU6}6G%qg~0}#~i(atKL$UB+QX5+#nMt1fT-ZgxyStfHZDY8nXNUxEZtjDCv zD!Yg=MQ(BglRBgP4*B9t-t9&bJC2Q~&#<;f*{GZ}*>^YKeChE7)J*8u>(o?tOnJuBq0qJ3Bi#_T0kp!bRtT^(TJaK>dy{YuC_w2*v3IL9*g-HCQn~6vw4J zROOwv2#zw1Z)rXByWLL5ARfY|s<0L5rSBS?ju;-^q52?Scn0smdo|tIs^O=%kkb*z z`?p85QxlPZ8eViq>lcsA_b2MsPxRh7VliDi0fQsV8TXLA6#k z-ZYFjvc)nf<)Wo*k>sNJ>D*+a>!Fk`O_yk`O zi0OGcYx=`cesp&4(%YM#d|u1!O7Vdx%h)`@fD8hA0oV|*1h5#uFuiLopa?x?2{W9r ze1-aJhdO)E?uJ$Cng&DZJT8$Dnz4@iRhIO~A6V8S$U&$Vq2F42(Ei$=)`LhAdgtSp z)djWQ7q9Odt-qRG6Y$&^4ciMH$xMCXbkl(P2>saZ64#Z1#rU$iq}D^p+vnGm*Xl-j zovzw3+Mqs1vs0`}TXS&09G>XLa@ASk>95Fdb77_G*8g*=3uY~Na1S=I`FSh)L`2Y? zKJ0%?mv}B`Dnx0v0$Y*# z>2J~*l%Q{P|KQ%sq)o(t>|qczl00y2d6INg?r%TI-p|IEpI-WbY(v>vMZSaDwSYW* z%Qc2h(L1gS$VXpST-g^P`6$3K02m874qyg=J562!umX$%gaO6@FoT9!{{Xg+l=UuYqSok@nLAJX-p{NG&hovK@Rx=%HLD@81O} zQK>#mTk~zuws|4_ub2?3n{M}aWM7IaMexGVU9w16B~L+d>9_2k(vZ&A$X6Rf94vsU z4^*^$lFk?1nkLyCNA+hQ~(}kvLNWU^TuXzU)V%hv--;FD$LDo&HcVul^Hh@)S5B2WI+HrcunoMn)@aFjw za^Q$yRTfKqId3r#Yop{!7v~(#t@pu@RWufk%!PyT@-HOcI}H>J#?5z@N87QNwn9%+ zfyXl)^f#|Lj>o51LLE*{Q8ktv#%u3Yli{&(wmU1^DhL^YnyLuthxw{2@{APG+(B(T z!Lg(|0mSZt0eecCs^DFJy?J|md2#*8@|TCV;FG;x^z$Hyj%m^cR~_%&`}lGLFMzdh z_(euhw;?(puGEtV+*J;dbJ@4bYogcU6dt%vktlq3U9a@A9<&}s9OHnP+c}3*W&Mb9 z1pXLo0AWI$Kc=Mjb+UKX#I?a6dcmk<%RB}`&Vuai@@nqw x6@D8!C*pK!TJ##S&4$awZ@Eozl7 zS6UF-K)$KkMY*859bG2_)!)uI3JY{nJmHJ@yG6Vf)))ah$$kCwX0fXBQ{o8-HSp4p$j@r>mE%q z{W+R6JiS6vkeZV$5aLO*-L7J5R4fXDHP&Fk2mCpd_eWe(wTW{Z5^Koco_Vt?swy5F z`egjbnfn97zom|kfBG?qzH3z9zjpS)g^T0YPmt2-%Z>PTx*l%?Y$9C?*P*-Q^1`-* zcpX?^lQA?L&H~sbzem+sq-esS?oiy#=VzEBOuJ2rMoPp)tY`yR^v9vpas0p(0JSS0B8hIrAnprE zai0{3VruvK0%5--`FxU|2CA5P`Y;p)-yjETJSrZM&uS`cx#^ZcPui0ba>eGsvUFKW zJE`R?cJf2bih~nc&gK~GOm~ht>&C20Zdx11tc^KS=}>J(7%9jWj2f$QCi{?UsAqWp z$^D~7cg|Fiab={Do@~#k(K8{an+hg$-1L$OJ!f0_m{Z%#DZ`^euE>!y7WJ<=yk^u= zHD;{7X{;SH*5=Aw!#hsy$d%6-?mF3(n=^mJu{FE(k)WUqW3=6^+PiXP5OtTP%B@ddKiYc~voCp)9@Q>6gLEAOw_wp*ZUX}m!u10o;rsOftX{Sx9sA73ym=2_i zEo67?L-dxse(@^RESAy+I&qfIcNH_RL|P%*0djH4vRc+A{V+ZbfLn;&c8b;?i;0n7 zzGomwdLcr$;P1%H`o;8K+gRT~i!1lnpI4)!q@khC!nzoG7k>?aZ{yqKNJIJZ{0CwD zGlkoR@6eZ`ZV!b;)|rYb7R)F43po8JDRQr2^^zC*mcw^pvHq2P0WlU2MI&qr-Nvcx zVEsM7ucWQ9M!?^L-b~(a>_ArepT>)bIK8FYSv4~-#SYvED0TyDSA`;eydVD#7AUu( zgDlwv*ax;JfX@NYA^Gau0tI+NoXrxtMM$&P_6Hp+s!$XQAha=mB3r|lwd z8Ab^s0l_>V7*Sb_Z&4DL8%LIq=m$QK;69KzH?J%vMvU=;FQF#J59;~f)&#vtf9H8S z&v|m5^K^QWU3-aD->RxwW)a`dpN94y>zb~1c-djS#v8P;o%*A`V~p+5Kl5i88`0Zq z-(a-~5gM@bq*%BDi~=L{ZC#NKlh)v)AL~z=(o|Vr(|DvL=`)Qd7#lT%hF8q92}pWx z(+G!UKvw3-${j*kQ7JoF8ZjYv3WPd zr+~eH42%K$fCF^5WxdGfZ|z#E!k_^h$O99=ivor{lT9jVUIPQ^yfr4VA$=z3XKWjN zv39Ru`?^tfozAbDYdDP!&Ro6_SLKYtAIF|bU=JN>e{+Rhh&J)N_ocuEcF}^PO5Z6v zMLL3&dB?woqc)my`>gxjG~Ll=s}SnJKA*%Jj+RB|fz2YXJMSUydcVWE-4d`BT4^xU zM(09(?k7bWJ`6lfUxkL)60Pps-5GEi_FO?zxFIFDBInB$jv#Ia@C>jEkOTq}{oPs9 z<{FpNsbpL&WDHk4o=D5NTs)pbz)F0_c|A7Vq-VQ2tg?m9bgi`A@zv6eu0HRg=Yh#( zyb-yY_<6C=>)p-a3dCOq%)5CT(iOnGFWe!&Az-+0k=nkjs_?7yTX&uNEx62*R1J zUiJFvyU0&$T%X%8U|nUFv`siZwB1*uS;!Ew9i~uEPq%r4uRuQw;CY&3U`Vp2DQdDb z9Vk*vN*%nn=yFe3Jowu^8?C=sbWiWc73?%!-xR6GJn<6D%3#GeTC6;(b$InP3bq->>7L_p=kM3RyD6NP+6`J z`|kitv=9xs4TtDSQc?4KJ5~3OF{?h_{|TEwYxxD>HQ*v}2{2o2HrVX#d$5^vD-EPn znIGcc!-BV9I8nYiHsdOH~X-6E7femx|Sb93Myf#75# diff --git a/learning_center/models/course_homework.py b/learning_center/models/course_homework.py index d071fd8..697fb0d 100644 --- a/learning_center/models/course_homework.py +++ b/learning_center/models/course_homework.py @@ -14,6 +14,7 @@ class CourseHomework(models.Model): 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='发布时间') deadline = fields.Datetime(string='提交截止时间', required=True) @@ -28,12 +29,13 @@ class CourseHomework(models.Model): 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') + course_score_item_id=fields.Many2one('course.score.item',string='作业类型') 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='成绩项') + score_item_ids = fields.One2many('course.score.item', 'homework_id', string='成绩项目') # ====================== 新增:自动计算提交通道是否开启 ====================== @api.depends('state', 'deadline') @@ -80,37 +82,61 @@ class CourseHomework(models.Model): self.publish_time = fields.Datetime.now() # 1. 批量为本班学生生成空白未提交记录 self._auto_create_empty_submit() + # 新增:自动生成对应作业的学生成绩明细 + self._auto_create_homework_score_detail() # 2. 推送作业通知给学生 self._send_homework_notice_to_students() - def _send_homework_notice_to_students(self): - """发布作业后推送消息给教学班学生""" + def _auto_create_homework_score_detail(self): self.ensure_one() - if not self.teaching_class_id: + # 修正字段名 course_score_item_id + if not self.teaching_class_id or not self.course_score_item_id: return - # 获取当前教学班所有已选课学生 - enrolls = self.env['course.teaching_class.enrollment'].search([ + score_item = self.course_score_item_id + + # 获取教学班在册学生 + enroll_records = self.env['course.teaching_class.enrollment'].search([ ('teaching_class_id', '=', self.teaching_class_id.id), ('state', '=', 'enrolled') ]) - student_users = enrolls.mapped('student_id.user_id').filtered(lambda u: u) - if not student_users: + student_ids = enroll_records.mapped('student_id').ids + if not student_ids: return - # 消息内容 - subject = f"新作业发布:{self.name}" - body = f""" -

课程:{self.course_id.name}

-

作业名称:{self.name}

-

截止时间:{self.deadline or '无'}

-

作业要求:{self.requirement or '无'}

- """ - # 发送消息(关联当前作业记录,学生在消息中心可直接跳转) - self.message_post( - subject=subject, - body=body, - partner_ids=student_users.mapped('partner_id').ids, - subtype_xmlid='mail.mt_comment' - ) + + # 查询当前作业+当前分项已存在明细 + exist_details = self.env['course.student.score.detail'].search([ + ('course_id', '=', self.course_id.id), + ('score_item_id', '=', score_item.id), + ('homework_id', '=', self.id), + ('student_id', 'in', student_ids) + ]) + exist_student_ids = exist_details.mapped('student_id').ids + target_student_ids = [sid for sid in student_ids if sid not in exist_student_ids] + if not target_student_ids: + return + + # 批量查询学生总成绩,避免循环查库 + all_student_scores = self.env['course.student.score'].search([ + ('course_id', '=', self.course_id.id), + ('student_id', 'in', target_student_ids) + ]) + score_map = {rec.student_id.id: rec for rec in all_student_scores} + + detail_vals_list = [] + for stu_id in target_student_ids: + student_score = score_map.get(stu_id) + if not student_score: + continue + detail_vals_list.append({ + 'student_score_id': student_score.id, + 'homework_id': self.id, + 'score_item_id': score_item.id, + 'score': 0.0, + 'remark': f'{self.course_score_item_id.name}:{self.name}' + }) + + if detail_vals_list: + self.env['course.student.score.detail'].create(detail_vals_list) def _auto_create_empty_submit(self): """仅发布时执行:自动给教学班所有已选课学生生成空白未提交记录""" @@ -138,11 +164,41 @@ class CourseHomework(models.Model): batch_vals.append({ 'homework_id': self.id, 'student_id': stu_id, + 'course_score_item_id':self.course_score_item_id.id, 'state': 'unsubmit' # 默认未提交 }) # 批量创建空白提交记录 submit_model.create(batch_vals) + def _send_homework_notice_to_students(self): + """发布作业后推送消息给教学班学生""" + self.ensure_one() + if not self.teaching_class_id: + return + # 获取当前教学班所有已选课学生 + enrolls = self.env['course.teaching_class.enrollment'].search([ + ('teaching_class_id', '=', self.teaching_class_id.id), + ('state', '=', 'enrolled') + ]) + student_users = enrolls.mapped('student_id.user_id').filtered(lambda u: u) + if not student_users: + return + # 消息内容 + subject = f"新作业发布:{self.name}" + body = f""" +

课程:{self.course_id.name}

+

作业名称:{self.name}

+

截止时间:{self.deadline or '无'}

+

作业要求:{self.requirement or '无'}

+ """ + # 发送消息(关联当前作业记录,学生在消息中心可直接跳转) + self.message_post( + subject=subject, + body=body, + partner_ids=student_users.mapped('partner_id').ids, + subtype_xmlid='mail.mt_note' + ) + # ====================== 草稿/关闭作业 ====================== def action_draft(self): self.state = 'draft' @@ -269,4 +325,15 @@ class CourseHomework(models.Model): def create(self, vals): homework_record = super().create(vals) # 草稿状态不执行自动生成提交记录,移到action_publish + + target_a = self.env["course.score.item"].search([ + ("name", "=", "作业"), + ("create_uid", "=", self.env.uid) + ], limit=1) + + if target_a: + # 将刚新建的B追加到A的多对多字段 + target_a.write({ + "homework_ids": [(4, homework_record.id)] + }) return homework_record \ No newline at end of file diff --git a/learning_center/models/course_homework_submit.py b/learning_center/models/course_homework_submit.py index 37a89a3..a6d2ccb 100644 --- a/learning_center/models/course_homework_submit.py +++ b/learning_center/models/course_homework_submit.py @@ -28,6 +28,7 @@ class CourseHomeworkSubmit(models.Model): 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) + course_score_item_id = fields.Many2one('course.score.item', string='作业类型') student_phone = fields.Char(related="student_id.stu_phone", string="手机号", readonly=True) submit_file = fields.Binary(string='提交文件', attachment=True) submit_filename = fields.Char(string='文件名') @@ -92,6 +93,7 @@ class CourseHomeworkSubmit(models.Model): def create(self, vals): submit_rec = super().create(vals) self._check_submit_change_state(submit_rec) + return submit_rec def write(self, vals): diff --git a/learning_center/models/course_score_item.py b/learning_center/models/course_score_item.py index d04617c..c5982ec 100644 --- a/learning_center/models/course_score_item.py +++ b/learning_center/models/course_score_item.py @@ -15,7 +15,7 @@ class CourseScoreItem(models.Model): 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') + homework_id = fields.Many2one('course.homework', string='作业', ondelete='cascade') sequence = fields.Integer(string="排序", default=10) score_type = fields.Selection([ ('homework', '作业'), @@ -30,7 +30,7 @@ class CourseScoreItem(models.Model): full_score = fields.Float(string='满分', default=100.0) is_active = fields.Boolean(string='是否启用', default=True) homework_ids = fields.Many2many('course.homework', string='关联作业') - + course_student_score=fields.Many2one('course.student.score',string='学生成绩') # 统计字段 student_count = fields.Integer(string='学生人数', compute='_compute_stats') avg_score = fields.Float(string='平均分', compute='_compute_stats') diff --git a/learning_center/models/course_student_score.py b/learning_center/models/course_student_score.py index e01ba2e..3e8157d 100644 --- a/learning_center/models/course_student_score.py +++ b/learning_center/models/course_student_score.py @@ -24,15 +24,16 @@ class CourseStudentScore(models.Model): 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_item_ids=fields.One2many('course.score.item','course_student_score',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) + related="teaching_class_id.main_teacher_id", readonly=True) total_score = fields.Float(string='综合成绩', compute='_compute_total_score', store=True) - + course_score_item_id = fields.Many2one('course.score.item', string='成绩分项') grade_level = fields.Selection([ ('A', '优秀(A)'), ('B', '良好(B)'), @@ -77,8 +78,8 @@ class CourseStudentScoreDetail(models.Model): 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_item_id = fields.Many2one('course.score.item', string='成绩项目', ondelete='restrict') + homework_id=fields.Many2one('course.homework',string='作业') # 得分 score = fields.Float(string='得分', help='该项目实际得分') diff --git a/learning_center/models/course_teaching_class.py b/learning_center/models/course_teaching_class.py index 7c249cc..c522eda 100644 --- a/learning_center/models/course_teaching_class.py +++ b/learning_center/models/course_teaching_class.py @@ -215,12 +215,32 @@ class CourseTeachingClassEnrollment(models.Model): @api.model def create(self, vals): - """新增选课记录校验人数上限""" + """新增选课记录校验人数上限 + 自动生成学生总成绩记录""" res = super().create(vals) cls = res.teaching_class_id + student = res.student_id + course = cls.course_id + + # 1. 人数上限校验原有逻辑保留 valid_num = len(cls.enrollment_ids.filtered(lambda e: e.state == 'enrolled')) if cls.max_students and valid_num > cls.max_students: raise ValidationError("该教学班人数已达上限,无法继续添加学生!") + + # 2. 查找是否已经存在该学生+该课程+该教学班的成绩主记录,避免重复创建 + exist_score = self.env['course.student.score'].search([ + ('student_id', '=', student.id), + ('course_id', '=', course.id), + ('teaching_class_id', '=', cls.id) + ], limit=1) + + # 不存在则自动创建一条空成绩主记录 + if not exist_score: + self.env['course.student.score'].create({ + 'course_id': course.id, + 'student_id': student.id, + 'teaching_class_id': cls.id + }) + return res diff --git a/learning_center/views/view_course_homework.xml b/learning_center/views/view_course_homework.xml index 28cf3db..536c112 100644 --- a/learning_center/views/view_course_homework.xml +++ b/learning_center/views/view_course_homework.xml @@ -6,7 +6,7 @@ - + @@ -38,9 +38,10 @@ - - + + + diff --git a/learning_center/views/view_course_student_score.xml b/learning_center/views/view_course_student_score.xml index 4b7f81b..c0a5c26 100644 --- a/learning_center/views/view_course_student_score.xml +++ b/learning_center/views/view_course_student_score.xml @@ -45,17 +45,11 @@ + + + - - - - - - - - - - + @@ -89,6 +83,74 @@
+ + list.course.student.score.detail.ids.om + course.student.score.detail + + + + + + + + + + + + + + + list.course.student.score.item.om + course.score.item + + + + + + + + + + + + + + 学生成绩 + course.student.score + list,form + + + + + + 学生成绩 + course.student.score + list,form + + [('course_id', '=', active_id)] + {'default_course_id': active_id} + + + + + 学生成绩 + course.student.score + list,form + + [('teaching_class_id', '=', active_id)] + {'default_teaching_class_id': active_id} + + + + + 学生成绩 + + + 60 + + + + @@ -148,16 +210,18 @@ - - - - 学生成绩 - course.student.score - list,form - + + view.course.student.score.detail.search + course.student.score.detail + + + + + + + - - + 成绩明细 course.student.score.detail @@ -165,35 +229,7 @@ - - - 学生成绩 - course.student.score - list,form - - [('course_id', '=', active_id)] - {'default_course_id': active_id} - - - - - 学生成绩 - course.student.score - list,form - - [('teaching_class_id', '=', active_id)] - {'default_teaching_class_id': active_id} - - - - - 学生成绩 - - - 60 - - - + 成绩明细 diff --git a/learning_center/views/view_homework_submit.xml b/learning_center/views/view_homework_submit.xml index 217931d..19e0e7e 100644 --- a/learning_center/views/view_homework_submit.xml +++ b/learning_center/views/view_homework_submit.xml @@ -36,6 +36,8 @@ + + diff --git a/learning_center/views/view_learning_course.xml b/learning_center/views/view_learning_course.xml index aecf80c..e1f7692 100644 --- a/learning_center/views/view_learning_course.xml +++ b/learning_center/views/view_learning_course.xml @@ -104,18 +104,18 @@ - - - - - - - - - - - - + + course.syllabus.list + course.syllabus + + + + + + + + + course.chapter.resource.list diff --git a/permission_manager/__init__.py b/permission_manager/__init__.py new file mode 100644 index 0000000..43559cd --- /dev/null +++ b/permission_manager/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/permission_manager/__manifest__.py b/permission_manager/__manifest__.py new file mode 100644 index 0000000..abb3074 --- /dev/null +++ b/permission_manager/__manifest__.py @@ -0,0 +1,12 @@ +{ + 'name': 'Permission Manager', + 'version': '18.0.1.0.0', + 'category': 'Tools', + 'summary': '权限管理', + 'depends': ['base'], + 'data': [ + 'security/ir.model.access.csv', + 'views/role_views.xml', + ], + 'installable': True, +} \ No newline at end of file diff --git a/permission_manager/__pycache__/__init__.cpython-312.pyc b/permission_manager/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6127cd4510d9e3946814c7faca6a34fdb7bef92 GIT binary patch literal 191 zcmX@j%ge<81jc!KS)xGtF^B^LOi;#W0U%>KLkdF*V-77Ii%)HE!_;|g7%3mBdKyyoTQtgU3fQEtWDh4q=Ff%eT L-eV9gVgqsjtxqq& literal 0 HcmV?d00001 diff --git a/permission_manager/models/__init__.py b/permission_manager/models/__init__.py new file mode 100644 index 0000000..8108826 --- /dev/null +++ b/permission_manager/models/__init__.py @@ -0,0 +1 @@ +from . import permission_role \ No newline at end of file diff --git a/permission_manager/models/__pycache__/__init__.cpython-312.pyc b/permission_manager/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca83b567ad83b37f3a463351a53c63611d4f9aba GIT binary patch literal 207 zcmX@j%ge<81dh3SS+YR-F^B^LOi;#W0U%>KLkdF*V-72CgqWqjxKTW1v3`NX9$(0PBK}P&?PO*x~Psz_Ww1_EAEhVvzLbCgvrkgXHs5Qge!9;^Q;(GE3s)^$IF~ao7L_OLJ1~ia3B~g6u8^ RF+MOeGBVy{kS$^ZasaMuHlqLl literal 0 HcmV?d00001 diff --git a/permission_manager/models/__pycache__/permission_role.cpython-312.pyc b/permission_manager/models/__pycache__/permission_role.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12213e5274ab9ab30b813916926cdaa1d8a5d1dd GIT binary patch literal 7174 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 + + + + + permission.role.list + permission.role + + + + + + + + + + + + + + + permission.role.form + permission.role + +
+ +
+

+ +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+
+ + + + permission.role.search + permission.role + + + + + + + + + + + + + + + + 角色管理 + permission.role + list,form + + + + + + permission.copy.wizard.form + permission.copy.wizard + +
+ + + + + + + +
+
+
+
+
+
+ + + + res.users.form.inherit + res.users + + + + + + + +
+
+
+
+
+
+
+ + + + + + + 权限管理 + 100 + + + + + + 角色管理 + + + 10 + + + +
+ -- 2.34.1 From 0a1b8922dbe4d892654c53597b3d1c86dc9bfb54 Mon Sep 17 00:00:00 2001 From: liuhaoran Date: Sat, 20 Jun 2026 19:43:22 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BB=93=E5=BA=93?= =?UTF-8?q?=E5=86=85=E6=97=A0=E7=94=A8=E7=9A=84pyc=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/__pycache__/__init__.cpython-312.pyc | Bin 543 -> 0 bytes .../__pycache__/course_chapter.cpython-312.pyc | Bin 2954 -> 0 bytes .../course_chapter_resource.cpython-312.pyc | Bin 5240 -> 0 bytes .../__pycache__/course_homework.cpython-312.pyc | Bin 16920 -> 0 bytes .../course_homework_submit.cpython-312.pyc | Bin 7252 -> 0 bytes .../course_score_item.cpython-312.pyc | Bin 3923 -> 0 bytes .../course_student_score.cpython-312.pyc | Bin 8112 -> 0 bytes .../__pycache__/course_syllabus.cpython-312.pyc | Bin 4843 -> 0 bytes .../course_teaching_class.cpython-312.pyc | Bin 17457 -> 0 bytes .../__pycache__/learning_course.cpython-312.pyc | Bin 6893 -> 0 bytes .../__pycache__/teach_class.cpython-312.pyc | Bin 1263 -> 0 bytes 11 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 learning_center/models/__pycache__/__init__.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_chapter.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_chapter_resource.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_homework.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_score_item.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_student_score.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_syllabus.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/course_teaching_class.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/learning_course.cpython-312.pyc delete mode 100644 learning_center/models/__pycache__/teach_class.cpython-312.pyc diff --git a/learning_center/models/__pycache__/__init__.cpython-312.pyc b/learning_center/models/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index d1f1900da224c398a2495a2064770d544b139bce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 543 zcmY+B%SyyB6oyZF?+i04c-bh5m&I&EcOoLbfIdJdgiafrYHuX1(w%SNGx!KTgKscU zH?G_XvzwJCu|>_|=gW6a%SrM!8Vvx~)9cCIH39fgn|>J`EJ}oDh#@8^WP}o;*g!U@ zq1i+>sj1mQwy34qMz*P~*+F)wquE7vsjJyT_Nb@XNA{^tpczbtpEwUp$b2Q`p~#c` zmPJJ^Bu6#=Ar{TTvf={G)_=nUm)IPs=9R7_n=}olwfv)IMaCZsagS=V>*^Jg^)yQ= ztgQ9lM}^=lsd$ERy_Z!T^SokG713{WzT#mt(=(@`lsA*X9E6GI5ta&Dg`>h%;i>Rd zsK*dPj2Bp7!tyFU4~n=bPR|0##RC^X)`YmvWxz!l{9X+Xp^8P!QyDOptcmiuj;WyFqU+I|D4-y}QocHGx>W zX-UQY1opvVUm9#1#Xuu%($x6S_OZ4PE@h3IsY#nOi}=!5XjoO5P>DlE)L(5}}u^@nW;{mv&wvt|d2`(QARFv5b2LV{linf#`Z*>4t*3B8K2 zX&7NMG50$R#pQm=tdITHL5tV=kWaj3W|ksBX6p$O8LP||3S%Oxfn_Cxz!R-4{wVM- z6XX{#@|&>WH)E6Eg3W#_w)6^q8@BrGCPW1|1i@xqJ*06QCD1D4ez{BM)m#pbw zDPA{Sw&Y>ynz-^6xOHpdDpugiG+fgv{;kKAcmtf;xW$S!ksAS7m4jT5tA~-l64!v- zfNMc+9CUjI>-em=l~>xbf|S$@d>jO)R|kHnS*Fhzu2k zq@e7J_E93?p$c6`4B{rYO3uWH5+F_PAl8(1wanOu53bD|^O~4Vjnbgf%N!JtK}v9p z$5!UnXlC@AhdlJXCYlEwvt!aD#pGy?mHE-ph3{s(f(95Wl8HnWu;tUguL0*T#xq}j zqI=Bj0Z9!=n0U>a2Ic0NBdkDplPJ;gmv3aou4YCPnVauu3kzQl&)*uGzclmk!YHc{ z1L06479}DjDi9MOun<$COFm||bsN>uRXZ+)mE6yUl|Ex(*Sn$WaR;}_y>q_ zbPnxDry>ZwDMXi0=Y;-j8gd1r8Od}`5SMoUOQ+v%XfO9z7)FLIqX(PW^h4;GY(h~p zY#BY+G)f}+fLhQX)UwVMRPbYP$`;)qI2HZSKi#k}uo&F_@|`2Mk0iyOpF4UM z`2km_f!D{iX*jEs09k5|;2sc>C@ljGS^+{oJ>}n|ycj>T*Ie1~+H+^??XAgE1GBFU z(2cO}wK20y6y{uFKL{_9YiXusA9M5sWuTT|R-j#%o|G&PhXY1_GK)&&9%iE?5T;n= zao~3A&KGg#8~+#O{BcrGfrz7D$~TO(-*0$+(spn2?%B<|=Nei@+EY%?eNV&0@q3Ls zXB&6kYkYYYe*1dn8hhtFeSEv-er?@E^S%1!*?N$BX5qJYV6I-Cs|}5`-*r~~X-5?s zwUhtrzO)SHuP8k9!Z{?uNN*73rp{v!k$Tsvmr-HrENyvJ;)& zD&`PH{`80<%NIpRs+i2jPEkA)ljQ7{Es*N;;EZ;9CtLelmU${fZ^#w-V-A(<8AnsgkNl)>#`g|Iw`NO(S>cr*LH za2S$bpPq!F(NE3dAU3my(C z&+K88c2>n-Ntb%!9qHoo_`!5>^~hWC1L?v|@%G;e%14?d((?!)I zXGhOpJU?-AhNg;k0kEWcY}5Fb#FmNEsgfP>L+Rq$G23`iqA2O!cGH(UdLr39kSdnJ zaH(gkdAv2zI$87mx>RX9e6Os2?D+WU#OcY_WLsCN>{PrnUE&67zJzbmmE8M!s>II? z)__4*!Zo2JTTi5lPjXXrU}{fdPqMz{rkp$~rAoWw9gl2iUA?isV@6IMdLvaT#XBCG zELKH$>=dk?MVnx))A`^mbV7l!@Zw83AKL9v{sb`VVg9F8V~XzOTfCZR6hfWVqotL$ l!5XjOD&Kr$76jo})G&)0{<2gHbz|-09f^*=5ezlue*hqS0^$Gw diff --git a/learning_center/models/__pycache__/course_chapter_resource.cpython-312.pyc b/learning_center/models/__pycache__/course_chapter_resource.cpython-312.pyc deleted file mode 100644 index 1a09887021324d423735b9955f40cadf5e82c085..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5240 zcmai2TTola89urq5FiO81jc}Dt}-BEf*s$}7^2z@CYjoki%d{t?E-Rzr0kJwqp>|o zLt~sY0kw6&O%sz#V`p$C&a`n|JCpdWbo$VPqYRqU&Xk#$+nXJ`FL~;}dn9pWi}XAk z&hCEyzyJOJ#XpLQ3OIQFR@-{?wt?fmql@&TNqyYg3m+34;*i464JllTA*D+>q;jbg zoRa$~hm<26Qeo9mU7B$9@3cz#c4>yycFhW1*j1v+6Y`1LejoNDUepc+5%%-mRU(ed zOD*oTtLe>{b14w#QX+**g_JHeQn@rp?b0eaoOjeHCzQUC25B$nO)I69E1%)aIdD3Z zf4Lxo(=%Lo4xIjS;j|*ft%#x4=Rg&qVs>v@XTzFE12Q5lGF>j22L0&cGBRu~T}qJ| zxLPunG%;i@ZOV`}3t7UD4blzrH!4RJSx7TOZjxi9?*R_2`#^yzv-B!sXvf27v>tF( z8GDv9TrQoeW%jIC6ICNatz)QMTH9o($~7h1kR{prHSgRg<5soiowYJlHACf!hdNXb zK5oc(u4c_!8&T6`d&X`yhRfx*O{iHGuN&6n*MeHJ{JU{Yqyx2OA!`|OUk=|sf;ML% z>lv~;2eKVKiaO91wDt01)2SNbYGmkK{@aGO%XDu7oc-vb99(y#GZ5_@;igjnS2Nl* z!ns<|Zg{t%J@9r6KW_htXz2__2#-4lJ)tlrKgT>Qy*O(1vTcV~+INuDL8K5EE=^A@ zzy8bRFGd!xkBjPnX9!2jQ$V*5wb*$4as&swxW(o}j6i}ejK8^b@ya2)Qq=Nc;tLFj zIs!-^!6>2ywhPzC7RLUvLhGzuN%G;3n1^t`C*lt?E(;%>S^U$b<Xxzi!nIeIUcb5+d&RB>TWXH^5Dqc}E?<0Y<%2lvsY0kfLJjy#mviy$ zGmGzk$Tmaa2(&KlnP(0ye)+qlkFLYf(xtB{k6?HZ6Uhm`x_bM@+e|dcYfGQsSa|OZ zX@l_xs@pfNrae^P35Px2!66)wm`gH97_f+pZsoUMExz@~h#n+ZoVdDj?(3$di@&im zfFz?t#6*;DP%bn)R^I<&@!XZDCFSujhHD{+++M$j=b5&P=gu#D`tj1(rzznG)s|hb z^1;aR#ZgHD(d_mHheDAsc83T)=EKL`5#mqllb1S^Y4lY@QMcwTiA1+P360OY1*9&Rk3rjxv^y7um*P=x};#jq|*pQMT zO`T3r_bSE>p)Be%2Rl5ON2rH2Vj&oV4jpc) zB+XVx3|}w+*%I_eh60<@AMGsMnGYmdaFke)F|+JWkU0<*tr?MIM?S=RQ?mm|#c{Ob z(+T086J8VCNv?}~5xU1IML2^xsW_UNT>z4K()I78!ksz&b+wus<~~vM(5cFg1H=Y! z(I~r~Nd~!~=CQwDR1xguDYeb^!_#O-Zx988o457ym>k2TcW4;WIvC)4F$wkhv4;d$ zAVLn%LpG-MuHhX=XqeOh-)LKBuEOhB(`b(Z5l<;&+;^qc(awL@HcatzjeBPs_kL5` zIokPcq3y1UGnd~32$$QCU0}GBA>W~f1oKhw0}rXsy^j-=1-)$BY1c||tAtF}%Zis+lu4-Ya0rV9tE@y_ni@J& zJ@6B?5ZXb4L}R~?@L^fC;AytmY&OzJ?=GWvZ~8w$DwAOw;Q4pq732O@wroJw(OhTvQOyPKT{*rzc8--*0?cgvd)?6 zXHE5&thY>$TzPhGi}ThNXR@(-=GlL~@b?#Ho)VrrBGh{yz*f(i9=qoJ`swRWXCYq_ z>OBlOU%!d{y=&pDl>`DWJ3FW&S(%|HG&^$TL?P_E;aqx#A-3Slt`PH~OAq=G!huf| z%(^_SO_Bx05|5WwOLsUpFyO}&hoeoo4f-(hN#MiNp9C>3S+(Ip-}yeFqIp#PX7R%s zWC~?3z?lY_0tp+bCp`!%sD?Rmix`n2_X$!W)gM#`Ir_u2Ct5Z+Q>o{H{h!yYn#!%nED1vtP*2zCbpm^6bhgcUNGnTk`&r(!8u_oF6Cq4ohMo^k^7 z=nBUSXAKEmMN)5=(^uZoSI(EWB(0Tm*2Y1-8{9q_ztHoD!x;|87<6$J@z(H z=Vpz~?G_8%ZYbLk@RD0Bbh}@Uc>J{G!Ac|bzCt&`yqEYwtpDXhWA#c0S~uhpCWJac zRCf+~2%$Ai%-at|VE_|Rmmc>-^&xyBEb8TqbO$_v;dU^MSdebxklOiDk$@=>I&f+t zWF6R;US)XZ?F|N@0R_a>Iaf9}iung&Y-QdeEmSJ)USGgNhDj@36t7kZ#ywwJQ~#xo zP=v6CPv~!0u`pdp7`m9QLY@H(9gFsKQ}#dx!b|RMr=9eP&p1(p8 zh8?ke$&#w^hKc5Q^Hg7=q$BoJ(qtPio2ZG`2pcwEa|j2YOPHRI{VZv$8P`r2;s&8< z&&|`qOGpTwNEnCVp3>^^trI)rJB7w=H>(9#U!v3vB3SFkk4>D8pB5aQGd%+KC9FpU zwK-X7pWJ$3&-pz<`%}W9L4iM>s5~L4%ai81ap#=5Zq{7)J*R2VLMR)mro#928cS>J zz@0*_qy}WFidRhqZkiJ&C&**5jXyhaIDS}Y+MclNi1j3ml^~!#uAkbIFt&qSmRbPx z#rrPpPFS|XxnVshe(LP0sh(@$grN%*&q&_zSfX?r2%RC>maufhdgjX;C$$$0=RxPk zXY|RMh~950>oF>>V%lBq8p7WTfFu=atS=QYOI!83hGc7J^3Q(f z-0qfT(N1<#``6wg*M09j_uTh6zkBXc{wX^xRn5PNpy7ldP@~sUSx()3Hn$l2DQ;hBc#pnatt{jEo%-?sl z(s#S*jKO1khzXBY)cQ{bMMGyW5Mnsd&>dj{A}gjj)hqf@B~X z><)Cy@T4e%ocOXHzFvVY2dH+Mq1rVJ-L7Rc?K(!=u4i<|=yn66Z#QbFfT_!#&OrKR z420OPKYR@8cP8B-y^{jVknaVmRl_iZTn^2Xi@Uk-5jFHK?ZhKcJbF|G#o6F<@ zPo;mkgl?V+Pdk$jBPmEtww+Mcs!%%8`dBb0m2=j-IOe1)OylMxRNg1sJVr6DU(ieu zQw&^7QloYe`Xx`&Go_3hD9ci#DV~$EoT<28nVO#xLbp1t=ul@mI(wXS38)7GzIPJW(Q{3_?a+n3z7p7)$9-(bj8MBvJ#4Lu^l>=Bk zCuJQ_Hl|V50A+1gn+ne*%u;0*nPnHKcV&|HdgiGMRJ(^+4)J_u1;h=^N{AOQs~}#; ztcKXjtbuqD;r+Y{@1;yriuc+y-i=H%)LTM&uQtbCW*xI0R#zG4QbMVA+BXn7(r2_364Q?0Y;R?pe))3fN-%-Qai zS#(W=PW>D|1Ls(pMP;_v5^A+myp`FOcIKLaPJK^pXLc}c%uZ!TGtZ{2{kl18En#*s z&naup>`tq*p4kKYWka0mq?x@JOzj)v)C+X`rrnfhpO~{L(!+9rEs^fP=?HtG*VaMO z-s5scj}@l-!TZ0zKl;OazkBQ6tv5wo*xw!KwRHP~A#e0J8}Ku|g;FJ7kXcZ{Kt?DS z4lJk$GNiIpZF1nX``2#l@n}Q?7iELtW1@)-e7`5i2GXgfE?s)?@eL2nTAXkj|^4D0WV_JG!=9=z6n zfAnL>GoS1^8VYj9VQ$QjKY8<4lcW)xy^c_XOUr-x*AIu@Ben0p`kSe~^K33uP)2Wq zZ_yNG{T(M@($YHju=YKr;+rG(x_r*eAN2L2?Pc-1;dX9Dnqdu6Oa5xZ34OuQ0 z^;|T<2INUQ|KOLmq#?C>G}2^ab3GVMe)PID3HLtwXzGm{q9d~fF6xhRN;OBS+Rb03 zS0nv>*!TOXx2~jTf1M{UBG&=E@dl%T?zCmQ|H19apZ}2bV(P7T((Cm)Aiig)UiqD{1`OrQp}JOhq-FrDIeJbr=xuSxrpSg&Qv;F!YIfiejsv z)Ra*KNw!cuKSrNufl?C#Tz#qbFFwU+XQkKbs56vD*T&`nuRX0E1B;+fG_}a6R@8}yh2bK%#Wdue83!_@2OGe@86*{#F+NY^-{Tv+OjsYB1Hq^Iqj8SSEjnNlD z7rIatWQ3ST>CIVfOxu;6Q4C4OkfP8i}7&EHUWTnxV(#Bv^YQh-E1s3_Hm7CJaQ*#I7L&cC0 z(rTr+_5x4fjEa+l0s7)Ha%3%SZ)?f96zR31DG+8Op-_Mk^Ja@vkaR2v4@xwrgyz?> z{PfPI^hzwc;V6n(T(pOQ53F4Rwb^2bX6=3yayXM;mO+HOUu~~5^eGBZji&8w(4mqH zjzSj=$5?;_%-b~S{@b)ja~#fo1zQdA*QTbBzxycTZ|+_GEeD>cEpJmO(%}zr&F~@B zYXL4CDuh1jhX3ZV503F0_6y7Rvo(-4YY^Bd83Yb*u0iak-lp5&o^J%f7XqQkE(PMW z{<2R&`nz^@GxEZn4_*EK%`?9`LptfnX6HkmXz-r|5zB}gScV47&<4V%0I&h->NpNo z2`pwrZ72{HbE1)`Kjf3wjT23s!4UKnifyTh2YK0pi;JU>zw>&+8O0tmi#G|j3L`vH zqGe`daH3^qXF%epp9}aTr7LFnL(o1!EXrd0A}2%(X-&%K5IuojkOEn4wh*#I;m14+%;w9N+}L!>nOL<;ShXv$YLBpL z4_~(T)7*U%Qu*Z{jBdK&Of+r~8aE^wTZG0IzHIY&ZtFyG*_Ha?dcJD2P~4g*-XRq4 z_+#f-@!t5hWN}TRc!5y7VD!*f@#^@tFRJTCEo0To;;rM>%863X=+Ya8o8}M9e93CQ zcn#1Oxv#i}UHrV&LeZK;(MF+YE&m@bhB<8}x z^<%{w;@j@k)Q=YZ?Ga=??~976k!@oYi!tGzs9Tt*YZB_3e#_lib^Ar3Zb!WJGi&vu z2GCDWZf-oGL_hr*KFH>lB^)GEK>;B&o?xtz5oG8=p8lb`I}Mlr9oV7mbxR#&tkCVX`JnwSuX3+*D7#7YU|C zHDs`inYSZr*;r^wP1^#K`{u#RdyzmLK13*WW+x52vjf^W0z&gx>i?=Vh%Oxr?TGIVH;Q5~AYF!zY7V)|1wM_)9>41=1B79Dlg z2)V{@m=DW;+kD`-j4-a5^)tmx&_i>FCWt+RhR&K}W;Oe|+6>3cKh|6AEv|27R$GPcpWi$oJ zpHfUV>?+lgpJ|z#w^DnVrY@e;Q85c!KF1l8b}r(;j1aRZBd6gKc?Ra1hX2kQPAgyL z)0D^7#x8(*1kn&E%GP0WAw<0;fJngF<&}k^S27_;GE_o5*^*dAtAYYX0S<+G3)E`L z)*-NZposd{-@fV5i@6G5kr~N=b~g~f1s_cocx&zUvnM<`>^AJ#d@Pdr%Tirw9xmw= z+l0|-jMgHhHppc8U%QwvmUCdV6kZK})R)AVMTx)~;-o^~Y^z8}}pY1q!HJGKWCT#f$Tg_ct z&FG%Q!q&SBTZzUhN;tfN!yC^6tOSUR;HVa%Xmg@yyHK<}nO!kbH4;tKtrhClChFD; zb?bTShNQK2TCZ)Rv%aLX#g=%^w23OLNjMt>XT#|BG3Tm;bFJW98@GIJD~2`@gt@Pn zhE05Bv*22naJ34q)?~Kpa@FPNl^2I!Oq4Gc$`|w2#$+1v5n@?Wc!bld5cN+ zk6Aj1|4&}omTcXudmCPuBoG2S>brsvP)!IbRA30BA*#s;tz-lSU;@;ERx^W|!302s zK20gnaOt;X)=M{ybfqr&GgN33lzWOtG9!Ekeqj9r)u>BT-T(q(T3LDPWaX^~XrTXw z88YGwoi%`ZG{*Fx9+yMP1cnn8I1clbGVRQCKW2h_T%If(ZG<5Iw%aY+9o&l!%uRXYW5p=|ZSKgU?b@cx2;gr!CUNENK z>IWsR346c~r!{^VW)_5cup=8zr(P}>moLh2*_S8nWwks&G()`!va5Q(;MAiyZM7?ALyRc1p> ztzy*r^bht<;w-QCrgP5C8?#BP^GTmJ% zU2>KPrAux!jg_uXl(q<^Ehu~EKlNGhzLBN3^7)p%cUSFwb17fEFK&bAb6Xkqsjy_| zg~1p2ij_j)s<<`jD2!+Q$yoy;(&|iD-GbGvNWrq|WL<-#b`o`)gt|@1qN+z`eK|-x zJxDw)RaiTnOPL)BQ;A?IxxDpLQ{7)4yQz}z(HtJ`e<(G#Wb6K+RtNDciG~*#BGJHI z<$sby%Z71f1jd+VNR_1dLz?HGe zkQv_^GC~?f&dNoMJ^Y5oiD@i=5%Aj7m0_uW{w+CKe0O-xyc4*Hb22i}Pq9WZ*u`A&7Z3+yY zbWfUbLb7sh%oGFPX61O&IC~S=b7%qTql9O75d(wt5c-oF@=(dsDhTEtyt`zjfzYOt z&C;_n7S4mhrbQ>4GYFLF!q@F@AWMG@Mlw8mQ$r))%vE~z2J+tA%$CKhlYTY|mL-_s zUMqQv?~eMw>J#wjL?g)Du0Tgr)E$j5XGF^kDF?8-=VAHbU%6A0Z5gf}QOMJd0 zt3sw*vdr#;yxztC)fImaIputl0IdujlC^@pIbq){*f)O@sDGN^+k8vh2=KP3 z;!4hN4qvxs%+-`|Z5CXcKRGexdM=**xeY+3eWIXtBzo=4)iWa}c>5Blp`i<0NmnUW zl8ml=;eu(3URag{s2v;*UOosZ4@q?oci$~rHrm6xpMt#Qn3pK?3T58AWh-vf@a~n6 zyUGe!Ki3x5P3KVN?1ZUE0NqkhlFV}?T{Q{U0>OnAV%O?~3+@%o$>Mr|z~*954d$#T zEolfMiO5G31TKweUxhCzNR~^KdF&F5o`opwG>TT)7D${GdP_1EDZTKYuqLV(FcUgT ztJe&thoiNneu5k6(Ux_4d^8oA*BYk>q8NE^@$Y;T%*WFX}AHUYJW1 zXyny}!>&|Fk71$>ygvdRC%_;ex$*RtWvq2Z`8d?&aLe>j|3V%~@NuMS%vLpONYpn8 z^-Z@wUpQ;{+WlkB1AOj*M|#yK1ROV+-&62G?pg3RGsq@bq{|4h2{t1a zlWMmvFyPUQ?z&!avBOn_$3sI88lE2f=;q|5pG^Ml$CLf9-52Me;XF%aDDYX4p*reh6Hs zWIq?=d;h)u`yX9P%Xskqg$M7yC+Xv~mZyI5%DvmakvwzACwPygH8lCxFHipRLyr#J zp|U~c$?qia(ksz2Q|b z<`Y*CcvL=1_iH&Dh<1AB=?vs4?ZYEZ!bJzj9+l^UE|n*ZxVDpKv=>qi1;jS+&D>jJ z8b(L%>iDFA7Rii|-ZP+3u|NPt$`S$;sFN}RP^5Yb6e{=`C{mUWpg>@k5r86fR{#oB zEExePQjdW^QISy$NuWsCAAq7-l>*@|2|$645gCEepMYHAHI=?f59XjY$kYaCduC1l z1E}X`Foq;+W{l}{;L1?|H=neckmDwL#oX4){t&9n+KAWyLF@D2;|+Q)f!t5r#bhK8 zzMFWLfMd1{{;+X~Bq`S?fjr{8uryPsDGrD!IrAir{}1GZSGGU*QMW2TUhv_9Ki1t{ zEdhG;h@#jaMtHc{ix}bA_c+;p_#;|VjM4P0*d&O%9XY)0daQvqc5pb5PA7Sl&6%l( zX?7n{m@tzV@-4)%#1{&j3WP+YO-~zPP?B>C6e!;cckq@7kQ#DpBrSVR_%MM^wxWHe z`BYwxT%#ibE^OdkkvBslXGtgt^#Ry_aOsGa2g5rVn6xB_WB_`vmlow!NcC2J>!SQS zka2mS;$R6t(Io5*g1uqPzA$bi{t=(&7bj~Q1`Ol5Rms|?q`zR{b(BbE;e=z6;8--a zc-NTYxp?d6`9`T97}pH?)wi zI8jPl;x!=eoj2E(m|^3B?ZDxomhs<&y)eFsc*s=WwN;Ng6P|T~XC43a5y5jL=`0@5 zCM&Aqt)E)m#LMx?TMC+P$qa>n@wcfy;<2Fu1m6WF7!cBN7IiocCKVMmIEy;Q#HWo81x%dQEy1?40QWs%WuH zL5h+~SKM6j!3zGl1BvGj3GlDv@C>yiAkxJj9$F$GzJLz|C3qK?LO<9^Ujy_UOWm5` z0IA;nvXDS@vbqqu*d2>SznGw`P0J?!N`s;?&EfSn^*a~n;wq#U>BsdzI)Q@qe z<`^AJ^%}&Q1`edTjYZ%Jdx`8vJV4}!9`d2cl6}SCUMaabq|TLSRW=fw2<{<{#A5{K zgC00H>_JGS?bcTyDe6zN;2|LGT-kc3!xwwemSQA14Zx2{BtHPZX!c3JpYZuOys!Y6 zsE{EZw$SUy*uhd~H{*_d3CaOMd{JCJTsQ0;Ef_2I#%-{h3S2`g2UqgoG?u?Ok-tL7 zUy+1&VR-glI-pqw|Ak)7pf5lucHVlAIf%<`e!=n3Js)#v+u zk3S@r=m`mAG6AlG4W2}=IhX*L6RE)D3xNXwsvy!CJZHab= zL`zzI_B4{1cKE|*mY|DZ117UNq#q`sB-6KsBL1joksWOja7x~T+ksNDb;w}@MjJ8OkI^QK=0hZ!c7_8> zx}jeL8jCrSH;3$!!m)Vx@MloyDa?@{N)Vq~b{8^e!)OOaXw79~7`+G)j0}E+0l!2F zhB@{;<`VfifL|jR{TQRyG5QHcmmv}j8-rm#dxm`zbKb(}=NJuQM1=0E_=QM?y@3&K zJTY6|mmL9c5B9-zrc4>^nvoPE+_u~)7|x$BP)V!1Z*wxgvTr*$_4YlJ%yq}l z^=(OJ*Y>qeSe)_Ym)7*Jxg5R`9k(>~wIuECf!d*l!G@6|+lP%xhNOyAZCdl~RrFt}hOd@JxrX579T_~p+V zSU$9FaNVePJbx8*$yOFWb?IFHIlgxFojv2Wt-%K4^sc3vqTF6TW>ciP5_cJn$gh}T{=5IedT8h(D<<>z&d30ECt+J{klI|l8vkR zP0UwXx~P-J!kKwmb!#oZ%Qv3)JoXC*;2ZSuH7jo|1!TojC${vTFOv6jbD!ooccEU@e+%^@o{mZeh2-ylP=TOKVDCl=(8R-(R%k| zgH~S+jx>e>;B(~sk%6rvwlV$UM;fiZokm8D)8zB9RjV%qI+%O1JbcxfJ8j8^b8gUMwG3NEoB2)O8+Yx88Ab70J+M5HUnS&MJ*MHUhtH&v@Qm*qr)Yd1g!b^5y)>t^D@q$MpV3nlk+ooR_2YG=5I6 zr_HkMn3sm(#Qw{%2xxdo2>FIKq(nEuX{*A(K!sP!05Qz?T diff --git a/learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc b/learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc deleted file mode 100644 index be97ef3503d20857dd7cf894ab3c6ebf1902f736..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7252 zcmb7IYj9IXmcDvgwq(n18~G(0zl5<21`Gkm5ZjSS08eU}VTmxg5$bC!TMy5@QW9%S zP^y?gPM|DjlGyC9i+46NArlxfTU!Z%gyJVv`{ybsCC!~wEw$qZRBhE7$ZT!RuRY!O zVabtFv$s^OzNf!Fefsoy^tu0DSXe;8^Iw6U@jX=(^=JGdKRT)Nv>!V26rzyIOZikz zl~3(d`!r6Cic(WU6jGm~kcQEW8{~=W|DR~YzEd})wdo$=7n?@VxF$VNw5hv(< z0mOJY_xdD?(n~K-yFrHYur@tf z^e7J*uH`FI6cA)(7Gwc30@9=)O*xT;s0bO5`C9QOT9J>l5U@q#^;x)3<){MWs8r-A$%(8&)fvcAf^5wq#U^CQK$hp^S%PXZkQF(3)}p!$WFn1S4sQ_fPCs5Jvwn-kfF+B1-KIgvKB z znxg$K9}_nETpq7IIL0zA6t0q4&>pna$^}D+@du$FG6AcVg*&Ss-dc`bT>a=%p@Mb? ze3PLdL#K25F{A-K7i2yD(?XsE5OiEHz%pTz#Ln*Vj|M_|V7Pq!x2x}6v8h>{tONtg z{50fY85A~e*bf1V8v(8^&h0{sO+#j}g=A{L56OlJGU4L14cN*4%GP&bhc4N)Tk;{8 zOHnx9<9zls49z?>O$|~fdnoFRYFaf8l#S20WWVY3UqKE9w3Ip0N5=6!H$1+y@QmFVwQuK#*v{>K|?||I<4*6*-7-`36ZQ#{#fhY*Q;U@2p(DwLJSdnJWgW zl@HD@-Tq7t3| zo43`j{Wvg<2wfwQ>tl-hMxEY@hEw+riMIubp2nx1OOK$ zJ&@GE;yMIU1LRUTeijc3hC%2OooW1m*M$ONYeb13tBCG6oaRJ*2_~02=n42~0tz=~ zRa`m*M{W*VXM{>s)J3%y3cj^iuXJ7NN?JPOmd^W@uBi5+`3DqYg}ECQg4D1vCHKO{ zG{eLL9AM9_fM;#E*#b?v=tYuTEF%iP`GC1)Hk0R~Q*)XY}kRHz5SpLmd?frx_Afj$wU%fulK0ru=gtR>S_R8Xy?Sq8mAWpk< z^P)s`*hDYCJ_CVNC|CSfJR>jj8smkt#F-((oUkbob7}`IN$z_wxBIehfIBKi26Lq+ zo4K*404oF1{{MCkVTd+J6^7a!hX|ye7=gnwAbgj>GLz@RaTw7`Bf5+c21fMKNM6PW z3nK<;BtK*1EGo!&KaY$V@3SPRn1&xASpAU`8Wxv2k6yyPF5GkA-ZtFp#XTGg*luWW z7}|+nNGvj@rE0;Lc1Uo|RHBfOH_5R0x|A7-b^w>KEvrptJN6d=&Ru{;z89G*W~bkt zUeqV8-EnJo(%Sd6wJ!y}w)N81tCdOHzPN2)(l!)_pJnLY=D6iZEH71NSvd9Xvnkuw znB$xB)>K99qWayFf7|N=Y0`t1EiwH!#Z8avl)#p5Ns1*N1X15t%~L`67oQo;G<6ZI zU|J>DqF@iyxcps7hQa@|T1Kd#f0X)IH4IlY9Tx&c3VOIsK>!mhw0n$kPtZ~laF4nC zrx}{WIXEM%eL?%0%ge#Fn3Od%_>7QG)8dVV=Cpu-v=9;V0*>?HnyjZGt_Ma-aV^mN zZ-iQ^u+07a+$)QN_bY7Cf|S9OG_=JHZC48th8+*gn|Q+}F~FrO1}{fk^cZwDC`Ox2 zF;Gr`jhz9dWmS=8T}2lvv_wtpeqarjcL4qb-Rmsetk`}`(uu}6faw~zz2L^pJ`b-P z);?%KR>KgyhAmmuK=`@w9PBEfg>Q?>W=_xe76$JZHAXdmDyxbPq)f$0Q%Bs?adqGu z)3!AYRbKtTTpBI-zB=%_L>>PL9f(+2V+>MF>;_j;O{s$zOCCUCRc?4>Wt_=GW~rhS zq-I*psi!sUcHoGwW*Z))2^Pqtaa_i3c*e~e2=FSWVWhpBX2DbHDYZ=(+692s+gFxu zM&O#aJo~{axyda@KV13X`lHD0hj-@w`^yWWtu4QMfoOaA=YLpz?xvq_t+XucP1fv;*X+Dsxhrb?qp@u6XDOIvs*Rg!Q=6Ku|5P{BBWww5kR${ao2dX7 z@=3;zI8yrxMmPD&B65{qaQ!Ig9NvH{C=^NnID04)g+irr!;%W?^ zT&a*UYCb{!h$2d%d?@e-gkrhEk}J7&id?%1<&uQt;z8qr4JtaJP@YMOGC|+(@w?b5 z_Apj~S+YQERAd|4gF&B{J%Sa5jhEz5@~H=xXF@(now!aUS2-d7D14S77f;c~^ZLQY z8JC}J#&fN>>A+1VZhCQpv#FpXUn5u?%SD^VHY*fLG2hL2y)+G#B?)}^I(a~h{rE!7 z;s&1{msCS^J4dBV&5`F*Wo?nesp9&`3#sC|=-J4@RAFnx@t~|e)-%6vZr`Gx@B0aV z(v>JX1+Wrpta83#u3@qMrs3YsM9E8$7gME;vDW#nxh}qG$IXNHg8VC|6QyI3Ln&Qx zzlsu746iNEMXuQb0`9-GpYQ0q`(~o%7#41QD}8r=hLv7^3bs<(0NUuB>s);E zZgZk^2=r6g7#p3Rn47p-lc?Mk`4L>>W5?!C%$>Mel&IJp8CH(uYJH+~58zGJQOE4z znZt{Qgvka+UbHDXIy*5lu~?rd+7=l~6*t86^X578qVdy1iQ)rb3i3e%$CBN!H&boY zA%>_Yl(t?ECugo&G=7(_E$oauzg9q*>wu$w#=khs_YNnDeiRvcqSx!%o)oKf+nyNI zIxAqxHpg0%rA_hDrYDrXS-)li9=x^ZCi<>WUpAwAPt{tT1=G!Ixc8k&t1J5-lSwC*UBuFdZF)hAKl71@CFTa4 zk_Fun{6UXkKBh=KB|h?3L$4S|``8e`u=9{AZ%w08ss4j%j#JIwX<3!ZEE?8dAZe?_ G<^B)+rejS2 diff --git a/learning_center/models/__pycache__/course_score_item.cpython-312.pyc b/learning_center/models/__pycache__/course_score_item.cpython-312.pyc deleted file mode 100644 index 396f546bca8856ea357f907fb6de016bdcce71d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3923 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 B@LK=? diff --git a/learning_center/models/__pycache__/teach_class.cpython-312.pyc b/learning_center/models/__pycache__/teach_class.cpython-312.pyc deleted file mode 100644 index 9652096e02b63942ab93f9066c6c700591d8862f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1263 zcmZ`(OH30%7@qC+{Q{}-mMAewH7U^;V!%KY5fs6Lilj8zY&rv!Y`1l{CA0^rkwY7! zE%8xEOuR`9ka#c=IdLTMQj#V%bMasb@n(WvI5{)hN=2E&?Dx~L5CS#7V{ zrylD7_(p~DGL*pXRRXdA0?0`q$a%S-&Z`UZUY-Lw&<~()4nQ99Q|7Ya{&$(zu-6dN zyA9u|;N~$eh6C6*9zYUQu`w8eNK*a#MgZtb!fqQ!BO~DDAn@uS=jC+(>8DuEl?H%h z0r?gEGO2+suklcx0U9fKCdRAQtSWbCg60*=AAgoZc~)qv;8_{3w$hV^p&dFZc=kj6 zIbl@=&%t>AtG5~+so*(dHEtKS-bJE+vR4vSHExSg?C~?r$dlu8-{qbT(9Ve^nE z$1ad?xYRn~@77`Keq5~YofH*pA}6#V*vtTlhAnrHg#3{}NY=EZK5U^{RtctU7Rm{~ z1G^+J*z1Lzz7PzB&R_DWNSQ{8FBlVvEUP}Ggnbec6`4(t%!ex3>+!Mdw5fW+F~vkY zv5mfA^%>dbK*8RS=qoh37f!!vUu@5vy|USqZ@ib&Hx#N`lGEwg)a=5;_oMl$?!?W4 zy)Jn@J(wEIow&F*khk|G`U{Tw Date: Sat, 20 Jun 2026 19:48:40 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0gitignore=EF=BC=8C?= =?UTF-8?q?=E6=B0=B8=E4=B9=85=E5=BF=BD=E7=95=A5Python=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc -- 2.34.1