feat: 新建课程作业模块(基于校园公告模板),实现 v1 教师端与 v2 学生/家长端

以 CampusAnnouncement 为模板建立课程作业模块,重命名标识符与文案(notice→homework、公告→作业),
并保留其顶栏/左栏外壳,按课程作业业务重搭数据模型与页面。

- mock(src/assets/mock/homeworkapi.ts):作业化数据模型(学科/截止/提交方式/流程状态),
  班级花名册→学生个体提交记录与批改(确定性分布),端点 List/SendList/Submissions/
  SubmissionDetail/Grade/Remind/Statis 等;左栏菜单按角色返回。
- v1 教师端:布置作业(新增学科/截止/提交方式)、我布置的(状态标签+提交/批改进度)、
  提交情况(Submissions,含内联批改)、批改中心(Grade 逐份批改)、作业统计(成绩分布+进度)。
- v2 学生/家长端(端分离):SetRole + viewerRole 切换身份;StudentHomeworks.vue 承担
  今日作业/待订正(学生可提交/重交)与孩子作业(家长只读+提醒);新增 MyHomeworks/Submit/
  MySubmission/ParentNudge 接口与类型。
- 类型与 api 模块同步;dev:mock 三角色 curl 端到端验证通过。
This commit is contained in:
lijing
2026-09-14 18:40:20 +08:00
commit d75aab8d07
344 changed files with 35558 additions and 0 deletions
+378
View File
@@ -0,0 +1,378 @@
/*-------------------------------------
zTree Style
version: 3.4
author: Hunter.z
email: hunter.z@263.net
website: http://code.google.com/p/jquerytree/
-------------------------------------*/
.ztree * {
padding: 0;
margin: 0;
font-size: 14px;
font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif
}
.ztree {
margin: 0;
padding: 5px;
color: #333
}
.ztree li {
padding: 0;
margin: 0;
list-style: none;
line-height: 17px;
text-align: left;
white-space: nowrap;
outline: 0
}
.ztree li ul {
margin: 0;
padding: 0 0 0 18px
}
.ztree li ul.line {
background: url(./img/line_conn.png) 0 0 repeat-y;
}
.ztree li a {
padding-right: 3px;
margin: 0;
cursor: pointer;
height: 21px;
color: #333;
background-color: transparent;
text-decoration: none;
vertical-align: top;
display: inline-block
}
.ztree li a:hover {
text-decoration: underline
}
.ztree li a.curSelectedNode {
padding-top: 0px;
background-color: #e5e5e5;
color: black;
height: 21px;
opacity: 0.8;
}
.ztree li a.curSelectedNode_Edit {
padding-top: 0px;
background-color: #e5e5e5;
color: black;
height: 21px;
border: 1px #666 solid;
opacity: 0.8;
}
.ztree li a.tmpTargetNode_inner {
padding-top: 0px;
background-color: #aaa;
color: white;
height: 21px;
border: 1px #666 solid;
opacity: 0.8;
filter: alpha(opacity=80)
}
.ztree li a.tmpTargetNode_prev {}
.ztree li a.tmpTargetNode_next {}
.ztree li a input.rename {
height: 14px;
width: 80px;
padding: 0;
margin: 0;
font-size: 12px;
border: 1px #585956 solid;
*border: 0px
}
.ztree li span {
line-height: 21px;
margin-right: 2px
}
.ztree li span.button {
line-height: 0;
margin: 0;
padding: 0;
width: 21px;
height: 21px;
display: inline-block;
vertical-align: middle;
border: 0 none;
cursor: pointer;
outline: none;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
background-image: url("./img/bootstrap.png");
}
.ztree li span.button.chk {
width: 13px;
height: 13px;
margin: 0 2px;
cursor: auto
}
.ztree li span.button.chk.checkbox_false_full {
background-position: -5px -5px;
}
.ztree li span.button.chk.checkbox_false_full_focus {
background-position: -5px -26px;
}
.ztree li span.button.chk.checkbox_false_part {
background-position: -5px -48px;
}
.ztree li span.button.chk.checkbox_false_part_focus {
background-position: -5px -68px;
}
.ztree li span.button.chk.checkbox_false_disable {
background-position: -5px -89px;
}
.ztree li span.button.chk.checkbox_true_full {
background-position: -26px -5px;
}
.ztree li span.button.chk.checkbox_true_full_focus {
background-position: -26px -26px;
}
.ztree li span.button.chk.checkbox_true_part {
background-position: -26px -48px;
}
.ztree li span.button.chk.checkbox_true_part_focus {
background-position: -26px -68px;
}
.ztree li span.button.chk.checkbox_true_disable {
background-position: -26px -89px;
}
.ztree li span.button.chk.radio_false_full {
background-position: -47px -5px;
}
.ztree li span.button.chk.radio_false_full_focus {
background-position: -47px -26px;
}
.ztree li span.button.chk.radio_false_part {
background-position: -47px -47px;
}
.ztree li span.button.chk.radio_false_part_focus {
background-position: -47px -68px;
}
.ztree li span.button.chk.radio_false_disable {
background-position: -47px -89px;
}
.ztree li span.button.chk.radio_true_full {
background-position: -68px -5px;
}
.ztree li span.button.chk.radio_true_full_focus {
background-position: -68px -26px;
}
.ztree li span.button.chk.radio_true_part {
background-position: -68px -47px;
}
.ztree li span.button.chk.radio_true_part_focus {
background-position: -68px -68px;
}
.ztree li span.button.chk.radio_true_disable {
background-position: -68px -89px;
}
.ztree li span.button.switch {
width: 21px;
height: 21px
}
.ztree li span.button.root_open {
background-position: -105px -63px
}
.ztree li span.button.root_close {
background-position: -126px -63px
}
.ztree li span.button.roots_open {
background-position: -105px 0;
}
.ztree li span.button.roots_close {
background-position: -126px 0;
}
.ztree li span.button.center_open {
background-position: -105px -21px;
}
.ztree li span.button.center_close {
background-position: -126px -21px;
}
.ztree li span.button.bottom_open {
background-position: -105px -42px;
}
.ztree li span.button.bottom_close {
background-position: -126px -42px;
}
.ztree li span.button.noline_open {
background-position: -105px -84px;
}
.ztree li span.button.noline_close {
background-position: -126px -84px;
}
.ztree li span.button.root_docu {
background-position: -105px -63px;
}
.ztree li span.button.roots_docu {
background-position: -84px 0;
}
.ztree li span.button.center_docu {
background-position: -84px -21px;
}
.ztree li span.button.bottom_docu {
background-position: -84px -42px;
}
.ztree li span.button.noline_docu {
background: none;
}
.ztree li span.button.ico_open {
margin-right: 2px;
background-position: -147px -21px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.ico_close {
margin-right: 2px;
margin-right: 2px;
background-position: -147px 0;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.ico_docu {
margin-right: 2px;
background-position: -147px -43px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.edit {
margin-left: 2px;
margin-right: -1px;
background-position: -189px -21px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.edit:hover {
background-position: -168px -21px;
}
.ztree li span.button.remove {
margin-left: 2px;
margin-right: -1px;
background-position: -189px -42px;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.remove:hover {
background-position: -168px -42px;
}
.ztree li span.button.add {
margin-left: 2px;
margin-right: -1px;
background-position: -189px 0;
vertical-align: top;
*vertical-align: middle
}
.ztree li span.button.add:hover {
background-position: -168px 0;
}
ul.tmpTargetzTree {
background-color: #FFE6B0;
opacity: 0.8;
filter: alpha(opacity=80)
}
span.tmpzTreeMove_arrow {
width: 16px;
height: 21px;
display: inline-block;
padding: 0;
margin: 2px 0 0 1px;
border: 0 none;
position: absolute;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
background-position: -168px -84px;
background-image: url("./img/bootstrap.png");
z-index: 10000;
}
span.tmpzTreeMove_prev {
background: red;
}
ul.ztree.zTreeDragUL {
margin: 0;
padding: 0;
position: absolute;
width: auto;
height: auto;
overflow: hidden;
background-color: #cfcfcf;
border: 1px #00B83F dotted;
opacity: 0.8;
filter: alpha(opacity=80)
}
.ztreeMask {
z-index: 10000;
background-color: #cfcfcf;
opacity: 0.0;
filter: alpha(opacity=0);
position: absolute
}