瀏覽代碼

feat: 试卷抽查

zhangjie 8 月之前
父節點
當前提交
7f0381b20a

二進制
public/templates/关联考生信息表-模板.xlsx


二進制
public/templates/考生信息表-模板.xlsx


二進制
public/templates/试卷抽查-模板.xlsx


+ 27 - 1
src/api.js

@@ -479,12 +479,19 @@ export const taskSnSearch = (type, code, questionId, stage) => {
   }
 };
 // mark step change level
-export const markStepChangeLevel = ({ subjectId, paperId, level, userId }) => {
+export const markStepChangeLevel = ({
+  subjectId,
+  paperId,
+  level,
+  userId,
+  paperCheckId,
+}) => {
   // paperId,level
   return $post(`/api/changelevel/${subjectId}/changeLevel`, {
     paperId,
     level,
     userId,
+    paperCheckId,
   });
 };
 export const changeLevelPaperList = (datas) => {
@@ -547,6 +554,25 @@ export const logTypeList = () => {
   return $get(`/api/marklog/listTypes`);
 };
 
+// paper check
+export const paperCheckList = (datas) => {
+  return $get(`/api/paperCheck/list`, datas);
+};
+export const paperCheckSave = (datas) => {
+  return $post(`/api/paperCheck/add`, datas);
+};
+export const paperCheckListStudent = (datas) => {
+  return $post(`/api/paperCheck/listStudent`, datas);
+};
+export const paperCheckProgress = (datas) => {
+  // paperCheckId=
+  return $get(`/api/paperCheck/getSelectInfo`, datas);
+};
+export const paperCheckUpdateProgress = (datas) => {
+  // paperCheckId=&pageNumber=&secretNumber=
+  return $post(`/api/paperCheck/updateSelectInfo`, datas);
+};
+
 // notice -------------------------->
 export const userSendNoticeList = (datas) => {
   // subject=&stage=&sendUserId=

+ 269 - 259
src/assets/styles/iview-custom.less

@@ -1,259 +1,269 @@
-/* form */
-.ivu-form {
-  .ivu-form-item-error-tip {
-    font-size: 14px;
-    margin-top: 3px;
-    padding-left: 20px;
-    padding-top: 0;
-    line-height: 20px;
-    white-space: nowrap;
-    background-image: url(../images/icon-error-tips.png);
-    background-size: 16px 16px;
-    background-repeat: no-repeat;
-    background-position: 0 2px;
-  }
-  .ivu-form-item-label {
-    font-weight: 600;
-    color: @dark-color;
-  }
-}
-.ivu-form-inline {
-  .ivu-form-item {
-    margin-bottom: 10px;
-    margin-right: 20px;
-  }
-  .ivu-form-item-label,
-  .ivu-form-item-content {
-    display: inline-block;
-    vertical-align: middle;
-  }
-}
-.modal-form {
-  .ivu-form-item-label {
-    font-size: 16px;
-    padding-top: 12px;
-    padding-bottom: 12px;
-  }
-}
-// ivu-select
-.ivu-select {
-  min-width: 140px;
-  &-disabled {
-    .ivu-select-selection {
-      color: @btn-disable-color;
-      background-color: @btn-disable-bg;
-    }
-  }
-}
-
-// input
-.ivu-input {
-  &-wrapper {
-    min-width: 140px;
-  }
-}
-.input-huge {
-  > .ivu-icon {
-    line-height: 50px;
-    right: 5px;
-  }
-  .ivu-input {
-    height: 50px;
-    border-radius: @box-border-radius-large;
-
-    &-with-prefix {
-      padding-left: 40px;
-      padding-right: 20px;
-    }
-    &-prefix {
-      width: 40px;
-      padding-left: 10px;
-      i {
-        line-height: 50px;
-      }
-    }
-  }
-}
-// ivu-input-number
-.ivu-input-number {
-  min-width: 140px;
-}
-
-// table
-.ivu-table {
-  background-color: transparent;
-  color: @dark-color;
-  .ivu-table-header {
-    border-radius: @box-border-radius-small;
-    background-color: @white;
-  }
-  .ivu-table-row {
-    background-color: @white;
-    color: @dark-color-light;
-    td {
-      &:first-child {
-        border-radius: @box-border-radius-small 0 0 @box-border-radius-small;
-      }
-      &:last-child {
-        border-radius: 0 @box-border-radius-small @box-border-radius-small 0;
-      }
-    }
-  }
-  table {
-    border-spacing: 0 4px;
-    border-collapse: separate;
-  }
-}
-.ivu-table-wrapper {
-  border: 0;
-}
-.ivu-table:after,
-.ivu-table:before {
-  background: transparent;
-}
-.ivu-table td,
-.ivu-table th {
-  font-size: 14px;
-  background: transparent;
-  border: 0;
-  letter-spacing: 1px;
-}
-.ivu-table-body {
-  min-height: 200px;
-}
-.ivu-table-tip td {
-  font-size: 20px;
-  height: 200px;
-  color: @dark-color-lighter;
-}
-
-.ivu-tree-children > li {
-  font-size: 14px;
-}
-
-.table-action {
-  .ivu-icon {
-    color: @dark-color-light;
-    margin: 0 6px;
-    transition: transform 0.1s linear;
-    cursor: pointer;
-
-    &:hover {
-      color: @primary-color;
-      transform: scale(1.3, 1.3);
-    }
-  }
-  .icon-act {
-    color: @info-color;
-  }
-  .icon-danger {
-    &:hover {
-      color: @error-color;
-    }
-  }
-}
-// ivu-page
-.ivu-page {
-  &-item {
-    border-radius: @box-border-radius-small;
-    height: 32px;
-    width: 32px;
-    line-height: 30px;
-    min-width: 32px;
-    a {
-      color: @dark-color-lighter;
-    }
-
-    &-active {
-      background-color: @primary-color;
-      a {
-        color: @white;
-        &:hover {
-          color: @white;
-        }
-      }
-    }
-  }
-
-  &-prev,
-  &-next {
-    border-radius: @box-border-radius-small;
-    height: 32px;
-    width: 32px;
-    line-height: 30px;
-    min-width: 32px;
-  }
-
-  &-options-sizer {
-    width: 80px;
-    .ivu-select {
-      min-width: auto;
-      width: 100%;
-    }
-  }
-}
-
-/* button */
-.ivu-btn + .ivu-btn {
-  margin-left: 10px;
-}
-.ivu-btn-default {
-  .ivu-icon {
-    font-size: 16px;
-    color: @primary-color;
-  }
-}
-
-// ivu-modal
-.ivu-modal {
-  &-content {
-    border-radius: @box-border-radius;
-  }
-  &-header {
-    &-inner {
-      font-weight: 600;
-      font-size: 18px;
-      text-align: center;
-    }
-  }
-  &-body {
-    padding: 32px 20px 0;
-  }
-  &-mask {
-    background: rgba(53, 61, 87, 0.65);
-  }
-  &-footer {
-    border: none;
-    text-align: center;
-    .ivu-btn {
-      min-width: 80px;
-      &:not(:first-child) {
-        margin-left: 20px;
-      }
-    }
-  }
-  // $Modal.confirm
-  &-confirm {
-    padding: 16px 0 48px 0;
-    text-align: center;
-    &-body {
-      padding: 0 0 40px;
-      font-size: 18px;
-      color: @dark-color;
-      font-weight: 600;
-    }
-    &-footer {
-      text-align: center;
-
-      .ivu-btn {
-        border-radius: @box-border-radius;
-        margin: 0 10px;
-        width: 80px;
-      }
-    }
-  }
-}
-// ivu-notice
-.ivu-notice {
-  left: 10px !important;
-}
+/* form */
+.ivu-form {
+  .ivu-form-item-error-tip {
+    font-size: 14px;
+    margin-top: 3px;
+    padding-left: 20px;
+    padding-top: 0;
+    line-height: 20px;
+    white-space: nowrap;
+    background-image: url(../images/icon-error-tips.png);
+    background-size: 16px 16px;
+    background-repeat: no-repeat;
+    background-position: 0 2px;
+  }
+  .ivu-form-item-label {
+    font-weight: 600;
+    color: @dark-color;
+  }
+}
+.ivu-form-inline {
+  .ivu-form-item {
+    margin-bottom: 10px;
+    margin-right: 20px;
+  }
+  .ivu-form-item-label,
+  .ivu-form-item-content {
+    display: inline-block;
+    vertical-align: middle;
+  }
+}
+.modal-form {
+  .ivu-form-item-label {
+    font-size: 16px;
+    padding-top: 12px;
+    padding-bottom: 12px;
+  }
+}
+// ivu-select
+.ivu-select {
+  min-width: 140px;
+  &-disabled {
+    .ivu-select-selection {
+      color: @btn-disable-color;
+      background-color: @btn-disable-bg;
+    }
+  }
+}
+
+// input
+.ivu-input {
+  &-wrapper {
+    min-width: 140px;
+  }
+}
+.input-huge {
+  > .ivu-icon {
+    line-height: 50px;
+    right: 5px;
+  }
+  .ivu-input {
+    height: 50px;
+    border-radius: @box-border-radius-large;
+
+    &-with-prefix {
+      padding-left: 40px;
+      padding-right: 20px;
+    }
+    &-prefix {
+      width: 40px;
+      padding-left: 10px;
+      i {
+        line-height: 50px;
+      }
+    }
+  }
+}
+// ivu-input-number
+.ivu-input-number {
+  min-width: 140px;
+}
+
+// table
+.ivu-table {
+  background-color: transparent;
+  color: @dark-color;
+  .ivu-table-header {
+    border-radius: @box-border-radius-small;
+    background-color: @white;
+  }
+  .ivu-table-row {
+    background-color: @white;
+    color: @dark-color-light;
+    td {
+      &:first-child {
+        border-radius: @box-border-radius-small 0 0 @box-border-radius-small;
+      }
+      &:last-child {
+        border-radius: 0 @box-border-radius-small @box-border-radius-small 0;
+      }
+    }
+  }
+  table {
+    border-spacing: 0 4px;
+    border-collapse: separate;
+  }
+}
+.ivu-table-wrapper {
+  border: 0;
+}
+.ivu-table:after,
+.ivu-table:before {
+  background: transparent;
+}
+.ivu-table td,
+.ivu-table th {
+  font-size: 14px;
+  background: transparent;
+  border: 0;
+  letter-spacing: 1px;
+}
+.ivu-table-body {
+  min-height: 200px;
+}
+.ivu-table-tip td {
+  font-size: 20px;
+  height: 200px;
+  color: @dark-color-lighter;
+}
+
+.ivu-tree-children > li {
+  font-size: 14px;
+}
+
+.table-action {
+  .ivu-icon {
+    color: @dark-color-light;
+    margin: 0 6px;
+    transition: transform 0.1s linear;
+    cursor: pointer;
+
+    &:hover {
+      color: @primary-color;
+      transform: scale(1.3, 1.3);
+    }
+  }
+  .icon-act {
+    color: @info-color;
+  }
+  .icon-danger {
+    &:hover {
+      color: @error-color;
+    }
+  }
+}
+// ivu-page
+.ivu-page {
+  &-item {
+    border-radius: @box-border-radius-small;
+    height: 32px;
+    width: 32px;
+    line-height: 30px;
+    min-width: 32px;
+    a {
+      color: @dark-color-lighter;
+    }
+
+    &-active {
+      background-color: @primary-color;
+      a {
+        color: @white;
+        &:hover {
+          color: @white;
+        }
+      }
+    }
+  }
+
+  &-prev,
+  &-next {
+    border-radius: @box-border-radius-small;
+    height: 32px;
+    width: 32px;
+    line-height: 30px;
+    min-width: 32px;
+  }
+
+  &-options-sizer {
+    width: 80px;
+    .ivu-select {
+      min-width: auto;
+      width: 100%;
+    }
+  }
+}
+
+/* button */
+.ivu-btn + .ivu-btn {
+  margin-left: 10px;
+}
+.ivu-btn-default {
+  .ivu-icon {
+    font-size: 16px;
+    color: @primary-color;
+  }
+}
+.btn-primary {
+  &.ivu-btn-text:not([disabled]) {
+    color: @primary-color;
+    padding: 0;
+    &:hover {
+      font-weight: 600;
+      color: @info-color;
+    }
+  }
+}
+
+// ivu-modal
+.ivu-modal {
+  &-content {
+    border-radius: @box-border-radius;
+  }
+  &-header {
+    &-inner {
+      font-weight: 600;
+      font-size: 18px;
+      text-align: center;
+    }
+  }
+  &-body {
+    padding: 32px 20px 0;
+  }
+  &-mask {
+    background: rgba(53, 61, 87, 0.65);
+  }
+  &-footer {
+    border: none;
+    text-align: center;
+    .ivu-btn {
+      min-width: 80px;
+      &:not(:first-child) {
+        margin-left: 20px;
+      }
+    }
+  }
+  // $Modal.confirm
+  &-confirm {
+    padding: 16px 0 48px 0;
+    text-align: center;
+    &-body {
+      padding: 0 0 40px;
+      font-size: 18px;
+      color: @dark-color;
+      font-weight: 600;
+    }
+    &-footer {
+      text-align: center;
+
+      .ivu-btn {
+        border-radius: @box-border-radius;
+        margin: 0 10px;
+        width: 80px;
+      }
+    }
+  }
+}
+// ivu-notice
+.ivu-notice {
+  left: 10px !important;
+}

+ 1094 - 1094
src/assets/styles/mark.less

@@ -1,1094 +1,1094 @@
-// grading-group-manage
-.grading-group-manage {
-  .ivu-tag {
-    cursor: move;
-  }
-  .group-user {
-    min-height: 76px;
-    padding: 20px 20px 10px;
-    position: relative;
-  }
-  .group-user-list {
-    margin-right: 130px;
-    .ivu-btn {
-      margin-bottom: 10px;
-    }
-  }
-  .group-user-action {
-    position: absolute;
-    top: 20px;
-    right: 20px;
-    z-index: auto;
-  }
-}
-.group-list {
-  font-size: 0;
-  margin: -10px;
-
-  .group-box {
-    display: inline-block;
-    vertical-align: top;
-    font-size: 14px;
-    width: 25%;
-    padding: 10px;
-  }
-
-  &-1 {
-    .group-box {
-      width: 100%;
-    }
-  }
-  &-2 {
-    .group-box {
-      width: 50%;
-    }
-  }
-  &-3 {
-    .group-box {
-      width: 33.33%;
-    }
-  }
-  .group-container {
-    position: relative;
-    border-radius: @box-border-radius;
-    background-color: @white;
-  }
-  .group-head {
-    height: 56px;
-    padding: 15px;
-    border-bottom: 1px solid #f3f3f3;
-    font-size: 18px;
-    font-weight: 600;
-    line-height: 25px;
-    text-align: center;
-    position: relative;
-  }
-  .group-del {
-    position: absolute;
-    top: 15px;
-    right: 10px;
-    height: 24px;
-    width: 24px;
-    line-height: 24px;
-    font-size: 18px;
-    text-align: center;
-    color: @dark-color-lighter;
-    background-color: @background-color;
-    border-radius: @box-border-radius;
-    cursor: pointer;
-
-    &:hover {
-      background-color: @error-color;
-      color: @white;
-    }
-  }
-  .group-body {
-    padding: 15px 15px 60px 15px;
-    height: 245px;
-  }
-  .group-drag {
-    height: 100%;
-  }
-
-  .group-footer {
-    position: absolute;
-    bottom: 15px;
-    right: 15px;
-    left: 15px;
-    text-align: right;
-    z-index: 8;
-  }
-}
-.group-action {
-  text-align: center;
-  margin-top: 20px;
-  .ivu-btn {
-    width: 100px;
-  }
-}
-
-// grading
-.grading-subnav {
-  display: flex;
-  justify-content: space-between;
-  .grading-title {
-    padding: 0 10px;
-
-    > h1 {
-      display: inline-block;
-      vertical-align: middle;
-      font-size: 20px;
-      font-weight: 600;
-      margin-right: 20px;
-    }
-    > span {
-      display: inline-block;
-      vertical-align: middle;
-      margin-right: 15px;
-      color: @dark-color-light;
-    }
-  }
-}
-
-// grading-progress
-.progress-table {
-  height: 100%;
-  .progress-line {
-    max-width: 230px;
-    min-width: 100px;
-  }
-  .kzz-table {
-    margin-bottom: 10px;
-    padding-bottom: 10px;
-    border-bottom: 1px dashed #e1dfe0;
-  }
-  td:first-child {
-    font-weight: 600;
-    color: @dark-color;
-    width: 100px;
-  }
-}
-// progress-line
-.progress-line {
-  position: relative;
-  display: inline-block;
-  width: 100%;
-  height: 12px;
-  text-align: center;
-  border-radius: 6px;
-  background-color: @background-color;
-  font-size: 12px;
-  color: @dark-color;
-  line-height: 1;
-  .progress-part {
-    position: absolute;
-    height: 100%;
-    > span {
-      display: inline-block;
-      vertical-align: middle;
-      line-height: 1;
-    }
-  }
-  .progress-rate {
-    position: absolute;
-    height: 100%;
-    left: 0;
-    background-color: @info-color;
-    border-radius: 6px;
-    text-align: center;
-  }
-  .progress-current {
-    display: inline-block;
-    vertical-align: middle;
-  }
-
-  .progress-remain {
-    display: block;
-    position: absolute;
-    height: 100%;
-    right: 5px;
-    z-index: 9;
-  }
-}
-// modify-formal-grading-task
-.modify-formal-grading-task {
-  .tips-info {
-    margin-bottom: 15px;
-    text-align: center;
-  }
-}
-// modify-unformal-grading-task
-.modify-unformal-grading-task {
-  .task-body {
-    min-height: 90px;
-    text-align: center;
-  }
-  .task-tips {
-    font-size: 18px;
-    color: @dark-color-light;
-  }
-  .task-action {
-    overflow: hidden;
-    > button {
-      float: right;
-
-      &:first-child {
-        float: left;
-      }
-    }
-  }
-}
-
-// grade-step
-.grade-step {
-  font-size: 0;
-  margin-bottom: 4px;
-  &-level {
-    white-space: nowrap;
-    overflow-x: scroll;
-    overflow-y: visible;
-    padding: 0 0 10px;
-  }
-  &-other {
-    float: right;
-    padding: 0 0 10px 20px;
-  }
-  .step-item {
-    display: inline-block;
-    vertical-align: top;
-    padding: 10px;
-    min-width: 90px;
-    background-color: @white;
-    border-radius: @box-border-radius-small;
-    color: @dark-color-light;
-    text-align: center;
-    cursor: pointer;
-    &:not(:last-child) {
-      margin-right: 10px;
-    }
-    &:hover {
-      box-shadow: 0px 10px 15px 0px rgba(34, 192, 255, 0.4);
-    }
-    p {
-      font-size: 12px;
-      height: 17px;
-      line-height: 17px;
-    }
-    .step-name {
-      color: @dark-color;
-      font-size: 24px;
-      font-weight: 600;
-      height: 32px;
-      line-height: 32px;
-    }
-
-    &.step-analysis {
-      width: 72px;
-      min-width: auto;
-      margin-right: 20px;
-      .step-name {
-        font-size: 20px;
-      }
-    }
-    &.step-other {
-      min-width: 72px;
-      .step-name {
-        font-size: 20px;
-      }
-    }
-
-    &.step-act {
-      background-color: @info-color;
-      color: @white;
-      box-shadow: 0px 10px 15px 0px rgba(34, 192, 255, 0.4);
-      .step-name {
-        color: @white;
-      }
-    }
-  }
-}
-.mark-step {
-  .step-item {
-    min-width: 60px;
-  }
-}
-
-// grading-detail
-.grading-detail {
-  .grade-filter {
-    position: fixed;
-    left: 0;
-    top: 50%;
-    z-index: 199;
-    width: 20px;
-    transform: translateY(-50%);
-    transition: width 0.2s ease-in;
-    overflow: hidden;
-
-    .ivu-form {
-      white-space: nowrap;
-    }
-    .ivu-form-item {
-      margin-right: 10px;
-    }
-    .ivu-form-item:last-child {
-      margin-right: 0;
-    }
-
-    &-form {
-      display: none;
-    }
-    .detail-area {
-      background-color: @success-color;
-      border-radius: 3px;
-      color: @dark-color-light;
-      font-size: 12px;
-      line-height: 16px;
-      width: 20px;
-      padding: 5px 3px;
-      text-align: center;
-      color: #fff;
-      cursor: pointer;
-
-      &:hover {
-        background-color: fade(@success-color, 80%);
-      }
-    }
-
-    &-select {
-      width: 290px;
-      background-color: #fff;
-      padding: 10px 10px 0;
-      border-top-right-radius: 5px;
-      border-bottom-right-radius: 5px;
-      box-shadow: 0 0 15px #c0c0c0;
-      .grade-filter-form {
-        display: block;
-      }
-      .detail-area {
-        display: none;
-      }
-    }
-  }
-  .grade-step {
-    flex-grow: 0;
-  }
-
-  .detail-body {
-    flex-grow: 2;
-    min-height: 400px;
-    display: flex;
-    justify-content: space-between;
-
-    &-2 {
-      .detail-papers-list {
-        width: 100%;
-      }
-    }
-  }
-  .detail-action {
-    width: 280px;
-    padding: 20px;
-    margin-left: 20px;
-    background-color: @white;
-    border-radius: @box-border-radius;
-    overflow-x: hidden;
-    overflow-y: auto;
-    flex-grow: 0;
-  }
-  .detail-action-fullscreen {
-    position: fixed;
-    width: 280px;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    z-index: 98;
-    border-radius: 0;
-    min-height: auto;
-    margin: 0;
-    overflow-y: auto;
-    overflow-x: hidden;
-    z-index: 999;
-  }
-  .detail-papers {
-    padding: 0 20px;
-    background-color: @white;
-    border-radius: @box-border-radius;
-    font-size: 0;
-    flex-grow: 2;
-    display: flex;
-    justify-content: space-between;
-    min-height: 400px;
-
-    &-carousel {
-      position: relative;
-      padding: 10px 0 70px;
-      font-size: 14px;
-      &-split {
-        height: 40px;
-      }
-      &::after {
-        content: "";
-        position: absolute;
-        height: 100%;
-        border-left: 1px solid #eff0f5;
-        right: 0;
-        top: 0;
-        z-index: auto;
-      }
-    }
-    &-list {
-      width: 100%;
-      font-size: 14px;
-      position: relative;
-      padding: 10px 0 70px;
-      .image-view-list {
-        margin: 0;
-        height: 100%;
-      }
-      .part-page {
-        position: absolute;
-        bottom: 20px;
-        width: 100%;
-        z-index: auto;
-        margin: 0;
-      }
-    }
-    &-none {
-      padding-top: 200px;
-      text-align: center;
-      font-size: 24px;
-      color: @dark-color-lighter;
-    }
-
-    &-col-3 {
-      .detail-papers-carousel {
-        width: 33.33%;
-      }
-      .detail-papers-list {
-        width: 66.66%;
-      }
-    }
-    &-col-4 {
-      .detail-papers-carousel {
-        width: 25%;
-      }
-      .detail-papers-list {
-        width: 75%;
-      }
-    }
-    &-col-5 {
-      .detail-papers-carousel {
-        width: 20%;
-      }
-      .detail-papers-list {
-        width: 80%;
-      }
-    }
-    &-col-6 {
-      .detail-papers-carousel {
-        width: 16.66%;
-      }
-      .detail-papers-list {
-        width: 83.33%;
-      }
-    }
-
-    .ivu-page {
-      text-align: center;
-    }
-  }
-  &-image-preview {
-    .ivu-modal-mask,
-    .ivu-modal-wrap {
-      left: 0;
-      bottom: 0;
-      top: 0;
-      right: 280px;
-    }
-  }
-}
-// mark-detail
-
-// grading-operation
-.grading-operation {
-  .detail-action-fullscreen {
-    top: 0;
-  }
-  &-image-preview {
-    .ivu-modal-mask,
-    .ivu-modal-wrap {
-      left: 0;
-      bottom: 0;
-      top: 0;
-      right: 280px;
-    }
-  }
-}
-
-/* paper-carousel */
-.paper-carousel {
-  position: absolute;
-  top: 48px;
-  bottom: 62px;
-  left: 10px;
-  right: 10px;
-
-  .carousel-body > img {
-    position: absolute;
-    max-width: 100%;
-    max-height: 100%;
-    width: auto;
-    height: auto;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    margin: auto;
-    cursor: pointer;
-  }
-  .carousel-none {
-    color: @dark-color-lighter;
-    font-size: @font-size-base;
-    text-align: center;
-    position: absolute;
-    width: 100%;
-    top: 50%;
-    left: 0;
-    transform: translateY(-50%);
-    z-index: 8;
-    > i {
-      font-size: 30px;
-    }
-  }
-  .carousel-btn {
-    position: absolute;
-    width: 40px;
-    height: 40px;
-    top: 50%;
-    z-index: 9;
-    margin-top: -20px;
-    text-align: center;
-    line-height: 40px;
-    font-size: 36px;
-    color: #ccc;
-    cursor: pointer;
-
-    &:hover {
-      color: @main-color;
-    }
-
-    &-left {
-      left: 0;
-    }
-    &-right {
-      right: 0;
-    }
-  }
-}
-
-// .grade-history-paper
-.grade-history-paper {
-  position: relative;
-  padding: 10px;
-  width: 100%;
-  height: 50%;
-
-  .carousel-title {
-    text-align: center;
-    height: 32px;
-    line-height: 32px;
-    margin-bottom: 6px;
-    > h3 {
-      font-size: 16px;
-    }
-  }
-}
-// grade-standard-paper
-.grade-standard-paper {
-  position: relative;
-  padding: 10px;
-  height: 50%;
-  // margin
-  .carousel-title {
-    text-align: center;
-    height: 38px;
-
-    > h3 {
-      display: inline-block;
-      vertical-align: middle;
-      margin-right: 15px;
-      font-weight: 600;
-      font-size: 20px;
-      line-height: 32px;
-    }
-    .ivu-select {
-      width: 60px;
-      min-width: auto;
-    }
-  }
-  .carousel-loading {
-    position: absolute;
-    top: 38px;
-    left: 10px;
-    right: 10px;
-    bottom: 10px;
-    z-index: 99;
-    background-color: rgba(255, 255, 255, 0.3);
-    text-align: center;
-
-    > i {
-      font-size: 24px;
-      position: relative;
-      top: 50%;
-      margin-top: -15px;
-    }
-  }
-}
-
-// .grade-action
-.grade-action {
-  font-size: 14px;
-  text-align: center;
-  .grade-info-deviation {
-    margin-left: 10px;
-    color: @dark-color-lighter;
-
-    &-error {
-      color: @error-color;
-    }
-  }
-  .action-search {
-    margin-top: 20px;
-    padding-top: 20px;
-    border-top: 1px dashed #e0e0e0;
-    text-align: left;
-
-    .search-select {
-      display: block;
-      width: 100px;
-      min-width: auto;
-      margin-bottom: 8px;
-    }
-    .search-input {
-      display: inline-block;
-      vertical-align: top;
-      margin-right: 10px;
-      width: 150px;
-    }
-    .search-btn {
-      display: inline-block;
-      vertical-align: top;
-      width: 60px;
-    }
-  }
-  .action-paper-state {
-    position: relative;
-    display: inline-block;
-    color: @dark-color-light;
-    margin-bottom: 30px;
-    .paper-state-cont {
-      background: @background-color;
-      border-radius: @box-border-radius-small;
-      font-size: 20px;
-      line-height: 26px;
-      padding: 6px 12px;
-    }
-    .paper-state-intro {
-      position: absolute;
-      bottom: -22px;
-      width: 100%;
-      height: 20px;
-      text-align: center;
-    }
-  }
-
-  .action-paper-info {
-    font-size: 14px;
-    margin-bottom: 20px;
-    color: @dark-color-light;
-    line-height: 24px;
-    text-align: left;
-
-    p:not(:last-child) {
-      margin-bottom: 4px;
-    }
-
-    span:last-child {
-      color: @dark-color;
-      font-size: 18px;
-    }
-  }
-  .action-grade-change {
-    margin-bottom: 20px;
-    background-color: #e7eaf1;
-    color: @dark-color-light;
-    padding: 20px;
-    font-size: 20px;
-    border-radius: @box-border-radius-small;
-    line-height: 28px;
-    text-align: left;
-
-    > p:first-child {
-      margin-bottom: 10px;
-    }
-  }
-  .action-grade-change-status {
-    text-align: center;
-    padding: 8px;
-    line-height: 28px;
-    font-size: 20px;
-    font-weight: 600;
-    background: rgba(247, 247, 250, 1);
-    color: rgba(194, 199, 213, 1);
-    border-radius: @box-border-radius-small;
-
-    &-error {
-      background: rgba(255, 112, 129, 0.1);
-      color: @error-color;
-    }
-  }
-
-  .action-grade-info {
-    margin-bottom: 20px;
-    background-color: @success-color;
-    color: @white;
-    padding: 8px;
-    border-radius: @box-border-radius-small;
-    text-align: center;
-
-    + .action-grade-info {
-      margin-top: -10px;
-    }
-    + .action-mark-info {
-      margin-top: -10px;
-    }
-    &-title {
-      color: @dark-color;
-      font-size: 18px;
-      font-weight: 600;
-      line-height: 1;
-      margin-bottom: 10px;
-      text-align: left;
-    }
-
-    .grade-info-name {
-      display: inline-block;
-      vertical-align: top;
-      width: 60px;
-      height: 60px;
-      line-height: 60px;
-      font-size: 54px;
-      text-align: center;
-      border-radius: 50%;
-      color: #fff;
-    }
-    .grade-info-none {
-      font-size: 34px;
-      width: 100%;
-      margin: 0;
-    }
-    .grade-info-range {
-      display: inline-block;
-      vertical-align: top;
-      margin-left: 20px;
-      font-size: 12px;
-      text-align: left;
-      padding: 5px 0;
-      p {
-        margin: 0;
-      }
-      p:first-child {
-        line-height: 20px;
-      }
-
-      p:last-child {
-        font-size: 20px;
-        line-height: 30px;
-        > span {
-          margin-right: 2px;
-        }
-      }
-    }
-  }
-  .action-grade-list {
-    font-size: 0;
-    margin: -5px -5px 20px;
-  }
-  .action-grade-item {
-    display: inline-block;
-    vertical-align: top;
-    width: 33.33%;
-    padding: 5px;
-    font-size: 12px;
-    color: @dark-color-light;
-
-    &-content {
-      padding: 8px;
-      background: @background-color;
-      border-radius: @box-border-radius-small;
-      cursor: pointer;
-
-      &:hover {
-        background-color: @info-color;
-        color: @white;
-      }
-    }
-
-    p {
-      line-height: 1;
-
-      &:first-child {
-        font-size: 24px;
-        line-height: 28px;
-      }
-    }
-  }
-  .action-item-content-disabled {
-    background: #eee !important;
-    color: @btn-disable-color!important;
-    cursor: not-allowed !important;
-  }
-  .action-grade-history {
-    text-align: left;
-    > h3 {
-      font-size: 18px;
-      font-weight: 600;
-      line-height: 1;
-      margin-bottom: 10px;
-    }
-    .grade-history-item {
-      margin: 0 0 5px 0;
-      padding: 4px 4px 4px 10px;
-      background-color: @background-color;
-      color: @dark-color-light;
-      border-radius: 5px;
-      height: 34px;
-      font-size: 14px;
-      line-height: 26px;
-
-      p:first-child {
-        white-space: nowrap;
-        word-break: keep-all;
-        float: left;
-      }
-      p:last-child {
-        padding: 0 8px;
-        border-radius: 8px;
-        background-color: @white;
-        font-size: 14px;
-        float: right;
-      }
-    }
-  }
-  .action-grade-pass {
-    height: 60px;
-    background-color: #f7f7fa;
-    border-radius: @box-border-radius-small;
-    padding: 14px;
-    color: @dark-color-light;
-    font-weight: 600;
-    line-height: 32px;
-    font-size: 20px;
-    cursor: pointer;
-
-    &:hover {
-      background-color: shade(#f7f7fa, 5%);
-    }
-  }
-}
-.mark-action {
-  .mark-info {
-    font-size: 30px;
-  }
-  .action-mark-list {
-    font-size: 0;
-    margin: -5px -5px 20px;
-  }
-  .action-mark-item {
-    display: inline-block;
-    vertical-align: top;
-    padding: 5px;
-    width: 20%;
-
-    &-content {
-      height: 40px;
-      padding: 5px 2px;
-      font-size: 16px;
-      line-height: 30px;
-      color: @dark-color-light;
-      background: @background-color;
-      border-radius: @box-border-radius;
-      text-align: center;
-      cursor: pointer;
-
-      &:hover {
-        background-color: @info-color;
-        color: @white;
-      }
-    }
-  }
-  .action-mark-input {
-    margin-bottom: 20px;
-    text-align: left;
-    .tips-info {
-      line-height: 20px;
-      text-align: left;
-    }
-    .ivu-icon {
-      margin-right: 3px;
-    }
-    .ivu-input-number {
-      width: 90px;
-      min-width: 0;
-    }
-    .ivu-form-item.mark-input-confirm {
-      margin-right: 0;
-    }
-    .ivu-form-item-error + .mark-input-confirm + .tips-info {
-      color: @error-color;
-    }
-  }
-}
-
-// .grade-analysis
-.grade-analysis {
-  .analysis-chart {
-    margin-top: 20px;
-    padding: 10px;
-  }
-}
-
-// leader-grading
-.leader-grading {
-  text-align: center;
-  padding-bottom: 40px;
-  color: @dark-color-light;
-  .leader-level {
-    h3 {
-      padding: 10px;
-      width: 150px;
-      font-size: 28px;
-      background-color: @background-color;
-      color: @dark-color;
-      font-weight: 600;
-      border-radius: @box-border-radius;
-      margin: 5px auto 20px;
-    }
-  }
-  .leader-aciton {
-    display: inline-block;
-    vertical-align: top;
-    margin: 0 10px;
-    color: @dark-color;
-  }
-  .leader-markers {
-    margin-top: 20px;
-    background-color: @background-color;
-    border-radius: @box-border-radius;
-    padding: 20px;
-    .ivu-checkbox-wrapper {
-      margin-right: 20px;
-    }
-  }
-}
-// .mark-task-manage
-.mark-task {
-  &-total {
-    display: inline-block;
-    vertical-align: middle;
-    font-weight: 600;
-    margin-right: 20px;
-    span {
-      display: inline-block;
-      vertical-align: middle;
-      line-height: 36px;
-    }
-
-    span:last-child {
-      font-size: 18px;
-    }
-  }
-}
-.task-confirm-modal {
-  .ivu-modal-header {
-    padding: 20px 32px;
-    border: 0;
-  }
-  .ivu-modal-body {
-    padding: 10px 32px;
-  }
-  .ivu-modal-footer {
-    padding: 0 32px 32px;
-  }
-  .ivu-modal-header-inner {
-    text-align: left;
-  }
-  .ivu-modal-content {
-    background-color: @background-color;
-  }
-}
-
-// grading-standard-paper-manage
-.grading-standard-paper-manage {
-  .level-list {
-    font-size: 0;
-    white-space: nowrap;
-  }
-  .level-item {
-    display: inline-block;
-    vertical-align: top;
-    height: 32px;
-    line-height: 32px;
-    padding: 0 12px;
-    border-radius: @box-border-radius-small;
-    background-color: @white;
-    color: @dark-color-light;
-    font-size: 16px;
-    cursor: pointer;
-    &:not(:last-child) {
-      margin-right: 10px;
-    }
-    &:hover {
-      box-shadow: 0px 10px 10px 0px rgba(34, 192, 255, 0.4);
-    }
-
-    &-act {
-      background-color: @info-color;
-      color: @white;
-      box-shadow: 0px 10px 10px 0px rgba(34, 192, 255, 0.4);
-    }
-  }
-
-  .standard-papers-none {
-    padding-top: 200px;
-    text-align: center;
-    font-size: 24px;
-    color: @dark-color-lighter;
-  }
-  .standard-papers-list {
-    min-height: 400px;
-
-    .image-view-list .image-view {
-      height: 400px;
-    }
-  }
-}
-.change-standard-paper-dialog {
-  .level-list {
-    font-size: 0;
-    padding-bottom: 50px;
-  }
-  .level-item {
-    display: inline-block;
-    vertical-align: top;
-    height: 32px;
-    width: 40px;
-    line-height: 32px;
-    text-align: center;
-    border-radius: @box-border-radius-small;
-    color: @dark-color-lighter;
-    border: 1px solid @dark-color-lighter;
-    font-size: 16px;
-    margin: 10px;
-    cursor: pointer;
-
-    &:hover {
-      color: @main-color;
-      border-color: @main-color;
-    }
-
-    &-act {
-      border-color: rgba(34, 192, 255, 0.4) !important;
-      background-color: @info-color;
-      color: @white!important;
-      box-shadow: 0px 10px 10px 0px rgba(34, 192, 255, 0.4);
-    }
-
-    &-disabled {
-      border-color: @disabled-color !important;
-      color: @disabled-color!important;
-      cursor: not-allowed;
-    }
-  }
-}
+// grading-group-manage
+.grading-group-manage {
+  .ivu-tag {
+    cursor: move;
+  }
+  .group-user {
+    min-height: 76px;
+    padding: 20px 20px 10px;
+    position: relative;
+  }
+  .group-user-list {
+    margin-right: 130px;
+    .ivu-btn {
+      margin-bottom: 10px;
+    }
+  }
+  .group-user-action {
+    position: absolute;
+    top: 20px;
+    right: 20px;
+    z-index: auto;
+  }
+}
+.group-list {
+  font-size: 0;
+  margin: -10px;
+
+  .group-box {
+    display: inline-block;
+    vertical-align: top;
+    font-size: 14px;
+    width: 25%;
+    padding: 10px;
+  }
+
+  &-1 {
+    .group-box {
+      width: 100%;
+    }
+  }
+  &-2 {
+    .group-box {
+      width: 50%;
+    }
+  }
+  &-3 {
+    .group-box {
+      width: 33.33%;
+    }
+  }
+  .group-container {
+    position: relative;
+    border-radius: @box-border-radius;
+    background-color: @white;
+  }
+  .group-head {
+    height: 56px;
+    padding: 15px;
+    border-bottom: 1px solid #f3f3f3;
+    font-size: 18px;
+    font-weight: 600;
+    line-height: 25px;
+    text-align: center;
+    position: relative;
+  }
+  .group-del {
+    position: absolute;
+    top: 15px;
+    right: 10px;
+    height: 24px;
+    width: 24px;
+    line-height: 24px;
+    font-size: 18px;
+    text-align: center;
+    color: @dark-color-lighter;
+    background-color: @background-color;
+    border-radius: @box-border-radius;
+    cursor: pointer;
+
+    &:hover {
+      background-color: @error-color;
+      color: @white;
+    }
+  }
+  .group-body {
+    padding: 15px 15px 60px 15px;
+    height: 245px;
+  }
+  .group-drag {
+    height: 100%;
+  }
+
+  .group-footer {
+    position: absolute;
+    bottom: 15px;
+    right: 15px;
+    left: 15px;
+    text-align: right;
+    z-index: 8;
+  }
+}
+.group-action {
+  text-align: center;
+  margin-top: 20px;
+  .ivu-btn {
+    width: 100px;
+  }
+}
+
+// grading
+.grading-subnav {
+  display: flex;
+  justify-content: space-between;
+  .grading-title {
+    padding: 0 10px;
+
+    > h1 {
+      display: inline-block;
+      vertical-align: middle;
+      font-size: 20px;
+      font-weight: 600;
+      margin-right: 20px;
+    }
+    > span {
+      display: inline-block;
+      vertical-align: middle;
+      margin-right: 15px;
+      color: @dark-color-light;
+    }
+  }
+}
+
+// grading-progress
+.progress-table {
+  height: 100%;
+  .progress-line {
+    max-width: 230px;
+    min-width: 100px;
+  }
+  .kzz-table {
+    margin-bottom: 10px;
+    padding-bottom: 10px;
+    border-bottom: 1px dashed #e1dfe0;
+  }
+  td:first-child {
+    font-weight: 600;
+    color: @dark-color;
+    width: 100px;
+  }
+}
+// progress-line
+.progress-line {
+  position: relative;
+  display: inline-block;
+  width: 100%;
+  height: 12px;
+  text-align: center;
+  border-radius: 6px;
+  background-color: @background-color;
+  font-size: 12px;
+  color: @dark-color;
+  line-height: 1;
+  .progress-part {
+    position: absolute;
+    height: 100%;
+    > span {
+      display: inline-block;
+      vertical-align: middle;
+      line-height: 1;
+    }
+  }
+  .progress-rate {
+    position: absolute;
+    height: 100%;
+    left: 0;
+    background-color: @info-color;
+    border-radius: 6px;
+    text-align: center;
+  }
+  .progress-current {
+    display: inline-block;
+    vertical-align: middle;
+  }
+
+  .progress-remain {
+    display: block;
+    position: absolute;
+    height: 100%;
+    right: 5px;
+    z-index: 9;
+  }
+}
+// modify-formal-grading-task
+.modify-formal-grading-task {
+  .tips-info {
+    margin-bottom: 15px;
+    text-align: center;
+  }
+}
+// modify-unformal-grading-task
+.modify-unformal-grading-task {
+  .task-body {
+    min-height: 90px;
+    text-align: center;
+  }
+  .task-tips {
+    font-size: 18px;
+    color: @dark-color-light;
+  }
+  .task-action {
+    overflow: hidden;
+    > button {
+      float: right;
+
+      &:first-child {
+        float: left;
+      }
+    }
+  }
+}
+
+// grade-step
+.grade-step {
+  font-size: 0;
+  margin-bottom: 4px;
+  &-level {
+    white-space: nowrap;
+    overflow-x: scroll;
+    overflow-y: visible;
+    padding: 0 0 10px;
+  }
+  &-other {
+    float: right;
+    padding: 0 0 10px 20px;
+  }
+  .step-item {
+    display: inline-block;
+    vertical-align: top;
+    padding: 10px;
+    min-width: 90px;
+    background-color: @white;
+    border-radius: @box-border-radius-small;
+    color: @dark-color-light;
+    text-align: center;
+    cursor: pointer;
+    &:not(:last-child) {
+      margin-right: 10px;
+    }
+    &:hover {
+      box-shadow: 0px 10px 15px 0px rgba(34, 192, 255, 0.4);
+    }
+    p {
+      font-size: 12px;
+      height: 17px;
+      line-height: 17px;
+    }
+    .step-name {
+      color: @dark-color;
+      font-size: 24px;
+      font-weight: 600;
+      height: 32px;
+      line-height: 32px;
+    }
+
+    &.step-analysis {
+      width: 72px;
+      min-width: auto;
+      margin-right: 20px;
+      .step-name {
+        font-size: 20px;
+      }
+    }
+    &.step-other {
+      min-width: 72px;
+      .step-name {
+        font-size: 20px;
+      }
+    }
+
+    &.step-act {
+      background-color: @info-color;
+      color: @white;
+      box-shadow: 0px 10px 15px 0px rgba(34, 192, 255, 0.4);
+      .step-name {
+        color: @white;
+      }
+    }
+  }
+}
+.mark-step {
+  .step-item {
+    min-width: 60px;
+  }
+}
+
+// grading-detail
+.grading-detail {
+  .grade-filter {
+    position: fixed;
+    left: 0;
+    top: 50%;
+    z-index: 199;
+    width: 20px;
+    transform: translateY(-50%);
+    transition: width 0.2s ease-in;
+    overflow: hidden;
+
+    .ivu-form {
+      white-space: nowrap;
+    }
+    .ivu-form-item {
+      margin-right: 10px;
+    }
+    .ivu-form-item:last-child {
+      margin-right: 0;
+    }
+
+    &-form {
+      display: none;
+    }
+    .detail-area {
+      background-color: @success-color;
+      border-radius: 3px;
+      color: @dark-color-light;
+      font-size: 12px;
+      line-height: 16px;
+      width: 20px;
+      padding: 5px 3px;
+      text-align: center;
+      color: #fff;
+      cursor: pointer;
+
+      &:hover {
+        background-color: fade(@success-color, 80%);
+      }
+    }
+
+    &-select {
+      width: 290px;
+      background-color: #fff;
+      padding: 10px 10px 0;
+      border-top-right-radius: 5px;
+      border-bottom-right-radius: 5px;
+      box-shadow: 0 0 15px #c0c0c0;
+      .grade-filter-form {
+        display: block;
+      }
+      .detail-area {
+        display: none;
+      }
+    }
+  }
+  .grade-step {
+    flex-grow: 0;
+  }
+
+  .detail-body {
+    flex-grow: 2;
+    min-height: 400px;
+    display: flex;
+    justify-content: space-between;
+
+    &-2 {
+      .detail-papers-list {
+        width: 100%;
+      }
+    }
+  }
+  .detail-action {
+    width: 280px;
+    padding: 20px;
+    margin-left: 20px;
+    background-color: @white;
+    border-radius: @box-border-radius;
+    overflow-x: hidden;
+    overflow-y: auto;
+    flex-grow: 0;
+  }
+  .detail-action-fullscreen {
+    position: fixed;
+    width: 280px;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 98;
+    border-radius: 0;
+    min-height: auto;
+    margin: 0;
+    overflow-y: auto;
+    overflow-x: hidden;
+    z-index: 999;
+  }
+  .detail-papers {
+    padding: 0 20px;
+    background-color: @white;
+    border-radius: @box-border-radius;
+    font-size: 0;
+    flex-grow: 2;
+    display: flex;
+    justify-content: space-between;
+    min-height: 400px;
+
+    &-carousel {
+      position: relative;
+      padding: 10px 0 70px;
+      font-size: 14px;
+      &-split {
+        height: 40px;
+      }
+      &::after {
+        content: "";
+        position: absolute;
+        height: 100%;
+        border-left: 1px solid #eff0f5;
+        right: 0;
+        top: 0;
+        z-index: auto;
+      }
+    }
+    &-list {
+      width: 100%;
+      font-size: 14px;
+      position: relative;
+      padding: 10px 0 70px;
+      .image-view-list {
+        margin: 0;
+        height: 100%;
+      }
+      .part-page {
+        position: absolute;
+        bottom: 20px;
+        width: 100%;
+        z-index: auto;
+        margin: 0;
+      }
+    }
+    &-none {
+      padding-top: 200px;
+      text-align: center;
+      font-size: 24px;
+      color: @dark-color-lighter;
+    }
+
+    &-col-3 {
+      .detail-papers-carousel {
+        width: 33.33%;
+      }
+      .detail-papers-list {
+        width: 66.66%;
+      }
+    }
+    &-col-4 {
+      .detail-papers-carousel {
+        width: 25%;
+      }
+      .detail-papers-list {
+        width: 75%;
+      }
+    }
+    &-col-5 {
+      .detail-papers-carousel {
+        width: 20%;
+      }
+      .detail-papers-list {
+        width: 80%;
+      }
+    }
+    &-col-6 {
+      .detail-papers-carousel {
+        width: 16.66%;
+      }
+      .detail-papers-list {
+        width: 83.33%;
+      }
+    }
+
+    .ivu-page {
+      text-align: center;
+    }
+  }
+  &-image-preview {
+    .ivu-modal-mask,
+    .ivu-modal-wrap {
+      left: 0;
+      bottom: 0;
+      top: 0;
+      right: 280px;
+    }
+  }
+}
+// mark-detail
+
+// grading-operation
+.grading-operation {
+  .detail-action-fullscreen {
+    top: 0;
+  }
+  &-image-preview {
+    .ivu-modal-mask,
+    .ivu-modal-wrap {
+      left: 0;
+      bottom: 0;
+      top: 0;
+      right: 280px;
+    }
+  }
+}
+
+/* paper-carousel */
+.paper-carousel {
+  position: absolute;
+  top: 48px;
+  bottom: 62px;
+  left: 10px;
+  right: 10px;
+
+  .carousel-body > img {
+    position: absolute;
+    max-width: 100%;
+    max-height: 100%;
+    width: auto;
+    height: auto;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    margin: auto;
+    cursor: pointer;
+  }
+  .carousel-none {
+    color: @dark-color-lighter;
+    font-size: @font-size-base;
+    text-align: center;
+    position: absolute;
+    width: 100%;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    z-index: 8;
+    > i {
+      font-size: 30px;
+    }
+  }
+  .carousel-btn {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 50%;
+    z-index: 9;
+    margin-top: -20px;
+    text-align: center;
+    line-height: 40px;
+    font-size: 36px;
+    color: #ccc;
+    cursor: pointer;
+
+    &:hover {
+      color: @main-color;
+    }
+
+    &-left {
+      left: 0;
+    }
+    &-right {
+      right: 0;
+    }
+  }
+}
+
+// .grade-history-paper
+.grade-history-paper {
+  position: relative;
+  padding: 10px;
+  width: 100%;
+  height: 50%;
+
+  .carousel-title {
+    text-align: center;
+    height: 32px;
+    line-height: 32px;
+    margin-bottom: 6px;
+    > h3 {
+      font-size: 16px;
+    }
+  }
+}
+// grade-standard-paper
+.grade-standard-paper {
+  position: relative;
+  padding: 10px;
+  height: 50%;
+  // margin
+  .carousel-title {
+    text-align: center;
+    height: 38px;
+
+    > h3 {
+      display: inline-block;
+      vertical-align: middle;
+      margin-right: 15px;
+      font-weight: 600;
+      font-size: 20px;
+      line-height: 32px;
+    }
+    .ivu-select {
+      width: 60px;
+      min-width: auto;
+    }
+  }
+  .carousel-loading {
+    position: absolute;
+    top: 38px;
+    left: 10px;
+    right: 10px;
+    bottom: 10px;
+    z-index: 99;
+    background-color: rgba(255, 255, 255, 0.3);
+    text-align: center;
+
+    > i {
+      font-size: 24px;
+      position: relative;
+      top: 50%;
+      margin-top: -15px;
+    }
+  }
+}
+
+// .grade-action
+.grade-action {
+  font-size: 14px;
+  text-align: center;
+  .grade-info-deviation {
+    margin-left: 10px;
+    color: @dark-color-lighter;
+
+    &-error {
+      color: @error-color;
+    }
+  }
+  .action-search {
+    margin-top: 20px;
+    padding-top: 20px;
+    border-top: 1px dashed #e0e0e0;
+    text-align: left;
+
+    .search-select {
+      display: block;
+      width: 100px;
+      min-width: auto;
+      margin-bottom: 8px;
+    }
+    .search-input {
+      display: inline-block;
+      vertical-align: top;
+      margin-right: 10px;
+      width: 150px;
+    }
+    .search-btn {
+      display: inline-block;
+      vertical-align: top;
+      width: 60px;
+    }
+  }
+  .action-paper-state {
+    position: relative;
+    display: inline-block;
+    color: @dark-color-light;
+    margin-bottom: 30px;
+    .paper-state-cont {
+      background: @background-color;
+      border-radius: @box-border-radius-small;
+      font-size: 20px;
+      line-height: 26px;
+      padding: 6px 12px;
+    }
+    .paper-state-intro {
+      position: absolute;
+      bottom: -22px;
+      width: 100%;
+      height: 20px;
+      text-align: center;
+    }
+  }
+
+  .action-paper-info {
+    font-size: 14px;
+    margin-bottom: 20px;
+    color: @dark-color-light;
+    line-height: 24px;
+    text-align: left;
+
+    p:not(:last-child) {
+      margin-bottom: 4px;
+    }
+
+    span:last-child {
+      color: @dark-color;
+      font-size: 18px;
+    }
+  }
+  .action-grade-change {
+    margin-bottom: 20px;
+    background-color: #e7eaf1;
+    color: @dark-color-light;
+    padding: 20px;
+    font-size: 20px;
+    border-radius: @box-border-radius-small;
+    line-height: 28px;
+    text-align: left;
+
+    > p:first-child {
+      margin-bottom: 10px;
+    }
+  }
+  .action-grade-change-status {
+    text-align: center;
+    padding: 8px;
+    line-height: 28px;
+    font-size: 20px;
+    font-weight: 600;
+    background: rgba(247, 247, 250, 1);
+    color: rgba(194, 199, 213, 1);
+    border-radius: @box-border-radius-small;
+
+    &-error {
+      background: rgba(255, 112, 129, 0.1);
+      color: @error-color;
+    }
+  }
+
+  .action-grade-info {
+    margin-bottom: 20px;
+    background-color: @success-color;
+    color: @white;
+    padding: 8px;
+    border-radius: @box-border-radius-small;
+    text-align: center;
+
+    + .action-grade-info {
+      margin-top: -10px;
+    }
+    + .action-mark-info {
+      margin-top: -10px;
+    }
+    &-title {
+      color: @dark-color;
+      font-size: 18px;
+      font-weight: 600;
+      line-height: 1;
+      margin-bottom: 10px;
+      text-align: left;
+    }
+
+    .grade-info-name {
+      display: inline-block;
+      vertical-align: top;
+      width: 60px;
+      height: 60px;
+      line-height: 60px;
+      font-size: 54px;
+      text-align: center;
+      border-radius: 50%;
+      color: #fff;
+    }
+    .grade-info-none {
+      font-size: 34px;
+      width: 100%;
+      margin: 0;
+    }
+    .grade-info-range {
+      display: inline-block;
+      vertical-align: top;
+      margin-left: 20px;
+      font-size: 12px;
+      text-align: left;
+      padding: 5px 0;
+      p {
+        margin: 0;
+      }
+      p:first-child {
+        line-height: 20px;
+      }
+
+      p:last-child {
+        font-size: 20px;
+        line-height: 30px;
+        > span {
+          margin-right: 2px;
+        }
+      }
+    }
+  }
+  .action-grade-list {
+    font-size: 0;
+    margin: -5px -5px 20px;
+  }
+  .action-grade-item {
+    display: inline-block;
+    vertical-align: top;
+    width: 33.33%;
+    padding: 5px;
+    font-size: 12px;
+    color: @dark-color-light;
+
+    &-content {
+      padding: 8px;
+      background: @background-color;
+      border-radius: @box-border-radius-small;
+      cursor: pointer;
+
+      &:hover {
+        background-color: @info-color;
+        color: @white;
+      }
+    }
+
+    p {
+      line-height: 1;
+
+      &:first-child {
+        font-size: 24px;
+        line-height: 28px;
+      }
+    }
+  }
+  .action-item-content-disabled {
+    background: #eee !important;
+    color: @btn-disable-color!important;
+    cursor: not-allowed !important;
+  }
+  .action-grade-history {
+    text-align: left;
+    > h3 {
+      font-size: 18px;
+      font-weight: 600;
+      line-height: 1;
+      margin-bottom: 10px;
+    }
+    .grade-history-item {
+      margin: 0 0 5px 0;
+      padding: 4px 4px 4px 10px;
+      background-color: @background-color;
+      color: @dark-color-light;
+      border-radius: 5px;
+      height: 34px;
+      font-size: 14px;
+      line-height: 26px;
+
+      p:first-child {
+        white-space: nowrap;
+        word-break: keep-all;
+        float: left;
+      }
+      p:last-child {
+        padding: 0 8px;
+        border-radius: 8px;
+        background-color: @white;
+        font-size: 14px;
+        float: right;
+      }
+    }
+  }
+  .action-grade-pass {
+    height: 60px;
+    background-color: #f7f7fa;
+    border-radius: @box-border-radius-small;
+    padding: 14px;
+    color: @dark-color-light;
+    font-weight: 600;
+    line-height: 32px;
+    font-size: 20px;
+    cursor: pointer;
+
+    &:hover {
+      background-color: shade(#f7f7fa, 5%);
+    }
+  }
+}
+.mark-action {
+  .mark-info {
+    font-size: 30px;
+  }
+  .action-mark-list {
+    font-size: 0;
+    margin: -5px -5px 20px;
+  }
+  .action-mark-item {
+    display: inline-block;
+    vertical-align: top;
+    padding: 5px;
+    width: 20%;
+
+    &-content {
+      height: 40px;
+      padding: 5px 2px;
+      font-size: 16px;
+      line-height: 30px;
+      color: @dark-color-light;
+      background: @background-color;
+      border-radius: @box-border-radius;
+      text-align: center;
+      cursor: pointer;
+
+      &:hover {
+        background-color: @info-color;
+        color: @white;
+      }
+    }
+  }
+  .action-mark-input {
+    margin-bottom: 20px;
+    text-align: left;
+    .tips-info {
+      line-height: 20px;
+      text-align: left;
+    }
+    .ivu-icon {
+      margin-right: 3px;
+    }
+    .ivu-input-number {
+      width: 90px;
+      min-width: 0;
+    }
+    .ivu-form-item.mark-input-confirm {
+      margin-right: 0;
+    }
+    .ivu-form-item-error + .mark-input-confirm + .tips-info {
+      color: @error-color;
+    }
+  }
+}
+
+// .grade-analysis
+.grade-analysis {
+  .analysis-chart {
+    margin-top: 20px;
+    padding: 10px;
+  }
+}
+
+// leader-grading
+.leader-grading {
+  text-align: center;
+  padding-bottom: 40px;
+  color: @dark-color-light;
+  .leader-level {
+    h3 {
+      padding: 10px;
+      width: 150px;
+      font-size: 28px;
+      background-color: @background-color;
+      color: @dark-color;
+      font-weight: 600;
+      border-radius: @box-border-radius;
+      margin: 5px auto 20px;
+    }
+  }
+  .leader-aciton {
+    display: inline-block;
+    vertical-align: top;
+    margin: 0 10px;
+    color: @dark-color;
+  }
+  .leader-markers {
+    margin-top: 20px;
+    background-color: @background-color;
+    border-radius: @box-border-radius;
+    padding: 20px;
+    .ivu-checkbox-wrapper {
+      margin-right: 20px;
+    }
+  }
+}
+// .mark-task-manage
+.mark-task {
+  &-total {
+    display: inline-block;
+    vertical-align: middle;
+    font-weight: 600;
+    margin-right: 20px;
+    span {
+      display: inline-block;
+      vertical-align: middle;
+      line-height: 36px;
+    }
+
+    span:last-child {
+      font-size: 18px;
+    }
+  }
+}
+.task-confirm-modal {
+  .ivu-modal-header {
+    padding: 20px 32px;
+    border: 0;
+  }
+  .ivu-modal-body {
+    padding: 10px 32px;
+  }
+  .ivu-modal-footer {
+    padding: 0 32px 32px;
+  }
+  .ivu-modal-header-inner {
+    text-align: left;
+  }
+  .ivu-modal-content {
+    background-color: @background-color;
+  }
+}
+
+// grading-standard-paper-manage
+.grading-standard-paper-manage {
+  .level-list {
+    font-size: 0;
+    white-space: nowrap;
+  }
+  .level-item {
+    display: inline-block;
+    vertical-align: top;
+    height: 32px;
+    line-height: 32px;
+    padding: 0 12px;
+    border-radius: @box-border-radius-small;
+    background-color: @white;
+    color: @dark-color-light;
+    font-size: 16px;
+    cursor: pointer;
+    &:not(:last-child) {
+      margin-right: 10px;
+    }
+    &:hover {
+      box-shadow: 0px 10px 10px 0px rgba(34, 192, 255, 0.4);
+    }
+
+    &-act {
+      background-color: @info-color;
+      color: @white;
+      box-shadow: 0px 10px 10px 0px rgba(34, 192, 255, 0.4);
+    }
+  }
+
+  .standard-papers-none {
+    padding-top: 200px;
+    text-align: center;
+    font-size: 24px;
+    color: @dark-color-lighter;
+  }
+  .standard-papers-list {
+    min-height: 400px;
+
+    .image-view-list .image-view {
+      height: 400px;
+    }
+  }
+}
+.change-standard-paper-dialog {
+  .level-list {
+    font-size: 0;
+    padding-bottom: 50px;
+  }
+  .level-item {
+    display: inline-block;
+    vertical-align: top;
+    height: 32px;
+    width: 40px;
+    line-height: 32px;
+    text-align: center;
+    border-radius: @box-border-radius-small;
+    color: @dark-color-lighter;
+    border: 1px solid @dark-color-lighter;
+    font-size: 16px;
+    margin: 10px;
+    cursor: pointer;
+
+    &:hover {
+      color: @main-color;
+      border-color: @main-color;
+    }
+
+    &-act {
+      border-color: rgba(34, 192, 255, 0.4) !important;
+      background-color: @info-color;
+      color: @white!important;
+      box-shadow: 0px 10px 10px 0px rgba(34, 192, 255, 0.4);
+    }
+
+    &-disabled {
+      border-color: @disabled-color !important;
+      color: @disabled-color!important;
+      cursor: not-allowed;
+    }
+  }
+}

+ 166 - 1
src/assets/styles/marker.less

@@ -124,7 +124,7 @@
       cursor: pointer;
       > i {
         color: #bec3d1;
-        &:last-child {
+        &:nth-of-type(2) {
           display: block;
           float: right;
           margin-top: 8px;
@@ -1128,3 +1128,168 @@
     max-width: 80%;
   }
 }
+
+// task-detail
+.task-detail {
+  .header-user {
+    border: none;
+    width: 223px;
+  }
+  .marker-menu {
+    position: absolute;
+    width: 240px;
+    top: 40px;
+    bottom: 0;
+    left: 0;
+    background-color: @color-background-light;
+    color: @color-text;
+
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+
+    .menu-head {
+      flex-grow: 0;
+      flex-shrink: 0;
+      height: 40px;
+      padding: 0 5px 10px 5px;
+      font-size: 0;
+
+      &-box {
+        margin: 0 -5px;
+      }
+
+      .menu-item {
+        display: inline-block;
+        vertical-align: middle;
+        font-size: 14px;
+        width: 50%;
+        text-align: center;
+        cursor: pointer;
+        line-height: 30px;
+        padding: 0 5px;
+
+        > div {
+          background-color: @color-background;
+          color: @color-text;
+          border-radius: 3px;
+          &:hover {
+            opacity: 0.8;
+          }
+        }
+
+        &.is-active {
+          > div {
+            background-color: @color-act1;
+            color: @color-text-act;
+          }
+        }
+      }
+    }
+    .menu-body {
+      flex-grow: 2;
+      overflow-x: hidden;
+      overflow-y: auto;
+      padding: 0 5px;
+
+      li {
+        line-height: 24px;
+        border-radius: 3px;
+        padding: 0 5px;
+        cursor: pointer;
+
+        &:hover {
+          opacity: 0.8;
+        }
+
+        &.is-active {
+          background-color: @color-act1;
+          color: @color-text-act;
+        }
+      }
+    }
+    .menu-foot {
+      flex-grow: 0;
+      flex-shrink: 0;
+      height: 40px;
+      padding: 5px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      overflow: hidden;
+    }
+  }
+  .marker-body {
+    left: 240px;
+    overflow: hidden;
+  }
+}
+
+.task-page {
+  .page-total {
+    display: inline-block;
+    vertical-align: middle;
+    margin: 0 5px;
+  }
+
+  .page-item {
+    display: inline-block;
+    vertical-align: middle;
+    margin: 0 2px;
+    min-width: 24px;
+    height: 24px;
+    line-height: 24px;
+    text-align: center;
+    background-color: @color-background;
+    border-radius: 2px;
+    cursor: pointer;
+    &:not(.page-cpage):hover {
+      background-color: shade(@color-background, 20%);
+    }
+  }
+  .page-cpage {
+    padding: 0;
+    background-color: transparent;
+    font-size: 0;
+    span {
+      margin: 0 3px;
+      display: inline-block;
+      vertical-align: middle;
+      font-size: 14px;
+    }
+  }
+  .page-size {
+    padding: 0 10px;
+  }
+  .page-input {
+    width: 30px;
+    text-align: center;
+    min-width: 0;
+    margin-right: 3px;
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 14px;
+
+    &.ivu-input-number {
+      height: 24px;
+      background-color: @color-background;
+      border: none;
+      border-radius: 0;
+    }
+    .ivu-input-number-handler-wrap {
+      display: none;
+    }
+    .ivu-input-number-input-wrap {
+      height: 24px;
+    }
+    .ivu-input-number-input {
+      display: block;
+      height: 24px;
+      line-height: 24px;
+      background-color: @color-background;
+      border-radius: 0;
+      padding: 0 2px;
+      text-align: center;
+    }
+  }
+}

+ 257 - 0
src/components/ImageView.vue

@@ -0,0 +1,257 @@
+<template>
+  <div class="task-body">
+    <div :class="[`${prefixCls}-body`]" ref="ReviewBody">
+      <div
+        :class="[`${prefixCls}-guide`, `${prefixCls}-guide-prev`]"
+        @click.stop="showPrev"
+      >
+        <Icon type="ios-arrow-back" />
+      </div>
+      <div
+        :class="[`${prefixCls}-guide`, `${prefixCls}-guide-next`]"
+        @click.stop="showNext"
+      >
+        <Icon type="ios-arrow-forward" />
+      </div>
+      <div
+        :class="[
+          `${prefixCls}-imgs`,
+          { [`${prefixCls}-imgs-nosition`]: nosition },
+        ]"
+        :style="styles"
+        v-move-ele.prevent.stop="{ mouseMove }"
+      >
+        <img
+          :key="imgSrc"
+          :src="imgSrc"
+          ref="PreviewImgDetail"
+          @load="resizeImage"
+        />
+      </div>
+      <div :class="[`${prefixCls}-none`]" v-if="!imgSrc">
+        <Icon type="md-image" />
+        <p>暂无数据</p>
+      </div>
+
+      <div :class="[`${prefixCls}-loading`]" v-show="loading">
+        <Icon class="ivu-load-loop" type="ios-loading" />
+      </div>
+    </div>
+
+    <div :class="[`${prefixCls}-footer`]">
+      <ul>
+        <li title="合适大小" @click="toOrigin">
+          <Icon type="md-expand" />
+        </li>
+        <li
+          title="放大"
+          @click="toMagnify"
+          :class="{
+            'li-disabled': transform.scale === maxScale,
+          }"
+        >
+          <Icon type="md-add-circle" />
+        </li>
+        <li
+          title="缩小"
+          @click="toShrink"
+          :class="{
+            'li-disabled': transform.scale === minScale,
+          }"
+        >
+          <Icon type="md-remove-circle" />
+        </li>
+        <li title="旋转" @click.stop="toRotate">
+          <Icon type="ios-refresh-circle" />
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+import MoveEle from "./common/ImagePreview/move-ele";
+
+export default {
+  name: "image-view",
+  directives: { MoveEle },
+  props: {
+    imgSrc: {
+      type: String,
+      default() {
+        return "";
+      },
+    },
+  },
+  data() {
+    return {
+      prefixCls: "cc-image-preview",
+      styles: { width: "", height: "", top: "", left: "", transform: "" },
+      initWidth: 500,
+      minScale: 0.2,
+      maxScale: 5,
+      transform: {
+        scale: 1,
+        rotate: 0,
+      },
+      loading: false,
+      nosition: false,
+    };
+  },
+  mounted() {
+    this.registWheelHandle();
+  },
+  methods: {
+    resizeImage() {
+      const imgDom = this.$refs.PreviewImgDetail;
+      const { naturalWidth, naturalHeight } = imgDom;
+      const rotate = 0;
+      const imageSize = this.getImageSizePos({
+        win: {
+          width: this.$refs.ReviewBody.clientWidth,
+          height: this.$refs.ReviewBody.clientHeight,
+        },
+        img: {
+          width: naturalWidth,
+          height: naturalHeight,
+        },
+        rotate,
+      });
+      this.transform = {
+        scale: 1,
+        rotate,
+      };
+
+      this.styles = Object.assign(this.styles, {
+        width: imageSize.width + "px",
+        height: imageSize.height + "px",
+        top: imageSize.top + "px",
+        left: imageSize.left + "px",
+        marginLeft: "auto",
+        transform: "none",
+      });
+      this.setStyleTransform();
+      this.nosition = true;
+
+      this.loading = false;
+      setTimeout(() => {
+        this.nosition = false;
+      }, 100);
+    },
+    getImageSizePos({ win, img, rotate }) {
+      const imageSize = {
+        width: 0,
+        height: 0,
+        top: 0,
+        left: 0,
+      };
+      const isHorizontal = !!(rotate % 180);
+
+      const rateWin = isHorizontal
+        ? win.height / win.width
+        : win.width / win.height;
+      const hwin = isHorizontal
+        ? {
+            width: win.height,
+            height: win.width,
+          }
+        : win;
+
+      const rateImg = img.width / img.height;
+
+      if (rateImg <= rateWin) {
+        imageSize.height = Math.min(hwin.height, img.height);
+        imageSize.width = Math.floor(
+          (imageSize.height * img.width) / img.height
+        );
+      } else {
+        imageSize.width = Math.min(hwin.width, img.width);
+        imageSize.height = Math.floor(
+          (imageSize.width * img.height) / img.width
+        );
+      }
+      imageSize.left = (win.width - imageSize.width) / 2;
+      imageSize.top = (win.height - imageSize.height) / 2;
+      return imageSize;
+    },
+    showPrev() {
+      this.$emit("on-prev");
+    },
+    showNext() {
+      this.$emit("on-next");
+    },
+    // dome-move
+    registWheelHandle() {
+      this.$refs.ReviewBody.addEventListener("wheel", (e) => {
+        e.preventDefault();
+        this.mouseWheel(e.wheelDeltaY);
+      });
+    },
+    mouseMove({ left, top }) {
+      this.styles.left = left + "px";
+      this.styles.top = top + "px";
+    },
+    mouseWheel(delta) {
+      if (delta > 0) {
+        this.toMagnify();
+      } else {
+        this.toShrink();
+      }
+    },
+    setStyleTransform() {
+      const { scale, rotate } = this.transform;
+      this.styles.transform = `scale(${scale}, ${scale}) rotate(${rotate}deg)`;
+    },
+    toOrigin() {
+      this.transform.scale = 1;
+      this.setStyleTransform();
+    },
+    toMagnify() {
+      const scale = (this.transform.scale * 1.2).toFixed(2);
+      this.transform.scale = scale >= this.maxScale ? this.maxScale : scale;
+      this.setStyleTransform();
+    },
+    toShrink() {
+      const scale = (this.transform.scale * 0.75).toFixed(2);
+      this.transform.scale = scale <= this.minScale ? this.minScale : scale;
+      this.setStyleTransform();
+    },
+    toRotate() {
+      this.transform.rotate = this.transform.rotate + 90;
+      this.setStyleTransform();
+      // 调整图片尺寸
+      const { naturalWidth, naturalHeight } = this.$refs.PreviewImgDetail;
+      const imageSize = this.getImageSizePos({
+        win: {
+          width: this.$refs.ReviewBody.clientWidth,
+          height: this.$refs.ReviewBody.clientHeight,
+        },
+        img: {
+          width: naturalWidth,
+          height: naturalHeight,
+        },
+        rotate: this.transform.rotate,
+      });
+
+      this.styles = Object.assign(this.styles, {
+        width: imageSize.width + "px",
+        height: imageSize.height + "px",
+        top: imageSize.top + "px",
+        left: imageSize.left + "px",
+      });
+      // 360度无缝切换到0度
+      if (this.transform.rotate >= 360) {
+        setTimeout(() => {
+          this.nosition = true;
+          this.transform.rotate = 0;
+          this.setStyleTransform();
+          setTimeout(() => {
+            this.nosition = false;
+          }, 100);
+        }, 200);
+        // 200ms当次旋转动画持续时间
+      }
+    },
+  },
+};
+</script>

+ 9 - 1
src/constants/authority.js

@@ -189,6 +189,11 @@ export const inspection = [
     title: "成绩查询",
     icon: "ivu-icon-score",
   },
+  {
+    name: "InspectionPaperCheck",
+    title: "试卷抽查",
+    icon: "ivu-icon-paper",
+  },
 ];
 
 // const getLeadRouter = () => {
@@ -223,7 +228,10 @@ export const checkRouterValid = (roleCode, routerName) => {
       "MarkerMarking",
     ],
     MARK_LEADER: () => ["LeaderGrading", "LeaderMarking"],
-    INSPECTION: () => inspection.map((item) => item.name),
+    INSPECTION: () => [
+      ...inspection.map((item) => item.name),
+      "InspectionPaperCheckDetail",
+    ],
     QC: () => ["Quality"],
   };
 

+ 157 - 0
src/modules/inspection/paperCheck/ModifyTask.vue

@@ -0,0 +1,157 @@
+<template>
+  <Modal
+    class="modify-grading-user"
+    v-model="modalIsShow"
+    :title="title"
+    width="540"
+    :mask-closable="false"
+    @on-visible-change="visibleChange"
+  >
+    <Form
+      ref="modalFormComp"
+      class="modal-form"
+      :model="modalForm"
+      :rules="rules"
+      :key="modalForm.id"
+      :label-width="100"
+    >
+      <FormItem prop="name" label="名称">
+        <Input
+          v-model.trim="modalForm.name"
+          placeholder="请输入名称"
+          clearable
+        ></Input>
+      </FormItem>
+      <FormItem prop="subject" label="科目">
+        <Select v-model="modalForm.subject" placeholder="科目" clearable>
+          <Option
+            v-for="(item, index) in subjects"
+            :key="index"
+            :value="item.subject"
+            :label="item.name"
+          ></Option>
+        </Select>
+      </FormItem>
+
+      <FormItem label="备注">
+        <Input
+          v-model.trim="modalForm.remark"
+          type="textarea"
+          placeholder="请输入备注"
+          :maxlength="99"
+          :autosize="{ minRows: 2, maxRows: 6 }"
+        ></Input>
+      </FormItem>
+    </Form>
+    <div slot="footer">
+      <Button shape="circle" type="primary" :disabled="isSubmit" @click="submit"
+        >保存</Button
+      >
+      <Button shape="circle" @click="cancel">取消</Button>
+    </div>
+  </Modal>
+</template>
+
+<script>
+import { subjectList, paperCheckSave } from "@/api";
+
+const initModalForm = {
+  id: "",
+  workId: "",
+  subject: "",
+  name: "",
+  remark: "",
+};
+
+export default {
+  name: "modify-task",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "抽查任务";
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      subjects: [],
+      modalForm: { ...initModalForm },
+      rules: {
+        name: [
+          {
+            required: true,
+            message: "请输入名称",
+            trigger: "change",
+          },
+          {
+            max: 50,
+            message: "名称长度不能超过50字符",
+            trigger: "change",
+          },
+        ],
+        subject: [
+          {
+            required: true,
+            message: "请选择科目",
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    initData(val) {
+      this.$refs.modalFormComp.resetFields();
+      this.modalForm = this.$objAssign(initModalForm, val);
+    },
+    visibleChange(visible) {
+      if (visible) {
+        this.initData(this.instance);
+        if (!this.subjects.length) {
+          this.getSubjects();
+        }
+      }
+    },
+    async getSubjects() {
+      const data = await subjectList(this.instance.workId);
+      this.subjects = data.filter((item) => item.enable);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate();
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      let result = true;
+      const datas = { ...this.modalForm };
+      await paperCheckSave(datas).catch(() => {
+        result = false;
+      });
+      this.isSubmit = false;
+
+      if (!result) return;
+
+      this.$Message.success(this.title + "成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
+  },
+};
+</script>

+ 246 - 0
src/modules/inspection/paperCheck/TaskAction.vue

@@ -0,0 +1,246 @@
+<template>
+  <div class="mark-action grade-action">
+    <!-- 试卷状态 -->
+    <!-- 状态:已评,改档 -->
+    <div v-if="rights.stepLabel" class="action-paper-state">
+      <p class="paper-state-cont">{{ stepLabel }}</p>
+    </div>
+    <!-- 试卷信息 -->
+    <div v-if="curPaperOrTask.sn" class="action-paper-info">
+      <p>
+        <span>试卷密号:</span>
+        <span>NO.{{ curPaperOrTask.sn }}</span>
+      </p>
+    </div>
+    <!-- 改档信息 -->
+    <div class="action-grade-change" v-if="rights.gradeChange">
+      <p>
+        <span>原始档位:</span><span>{{ curPaperOrTask.originLevel }}</span>
+      </p>
+      <p>
+        <span>申请档位:</span>
+        <span>{{ curPaperOrTask.redoLevel }}</span>
+      </p>
+    </div>
+
+    <!-- 档位信息 -->
+    <!-- 已评/待评(已评档位),改档打分(已评档位) -->
+    <div class="action-grade-info" v-if="rights.gradeInfo">
+      <h3 class="grade-info-name">
+        {{ curPaperLevel }}
+      </h3>
+    </div>
+    <!-- 打分信息 -->
+    <div class="action-grade-info action-mark-info" v-if="rights.markInfo">
+      <p class="grade-info-name" v-if="curPaperScore">
+        {{ curPaperScore }}
+      </p>
+      <p class="grade-info-name grade-info-none" v-else>未打分</p>
+    </div>
+    <!-- 选择档位 -->
+    <div class="action-grade-list" v-if="rights.gradeList">
+      <div
+        class="action-grade-item"
+        v-for="(level, index) in levels"
+        :key="index"
+      >
+        <div
+          :class="[
+            'action-grade-item-content',
+            {
+              'action-item-content-disabled': btnClicked,
+            },
+          ]"
+          @click="selectLevel(level)"
+        >
+          <p>{{ level.name }}</p>
+          <p>{{ level.minScore }}~{{ level.maxScore }}</p>
+        </div>
+      </div>
+    </div>
+
+    <!-- 评卷记录 -->
+    <div class="action-grade-history" v-if="rights.markHis">
+      <h3>评卷记录</h3>
+      <div class="grade-history-list">
+        <div
+          v-for="(his, hindex) in gradingHistory"
+          :key="hindex"
+          class="grade-history-item"
+        >
+          <p>{{ his.loginName }}</p>
+          <p>{{ his.value }}</p>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { markHistoryList } from "@/api";
+
+/*
+[paper template]
+{
+  "id": 2,
+  "sn": "1117542991",
+  "examNumber": "400030",
+  "level": "G",
+  "roughLevel": "3",
+  "originLevel": "",
+  "score": 62,
+  "redoLevel": null,
+  "updatedOn": "2022-10-27 16:16:56",
+  "imgSrc": "http://192.168.10.165:9000/upload/images/1/SC/1/400030.jpg?random=ead2b4b5-5908-4206-a174-bc7d4ef9670a",
+  "thumbSrc": "http://192.168.10.165:9000/upload/thumbs/1/SC/1/400030.jpg?random=4120b23e-3652-4f8b-ae1e-3e6d7a2cfc9f",
+  "markByLeader": false,
+  "markedLogic": false,
+  "areaCode": "1",
+  "subjectName": "色彩",
+  "inspectScore": null,
+  "inspectLevel": null,
+  "inspector": null,
+  "sheetSrc": "http://192.168.10.165:9000/upload/sheet/1/SC/1/400030.jpg?random=05423d49-02a1-4900-87df-76e536871e24",
+  "stage": "SCORE",
+  "test": 0,
+  "paperTest": 0,
+  "shift": false,
+  "shiftScore": false,
+  "paperId": 2,
+  "isRejectedByLeader": false,
+  "sortSum": 62,
+  "studentName": null,
+  "secretNumber": "1117542991",
+  "scanUserId": 3,
+  "markResults": [],
+  "adminMark": false,
+  "manual": false,
+  "rejected": false,
+  "arbitrated": false,
+  "roughSample": false,
+  "roughOneClick": false,
+  "oneClick": false,
+  "tagged": false,
+  "sample": false,
+  "missing": false,
+  "mark": false
+  "dataType":'task', // task or history
+}
+*/
+
+const initRights = {
+  stepLabel: false,
+  gradeChange: false,
+  gradeInfo: false,
+  markInfo: false,
+  gradeList: false,
+  markHis: false,
+};
+
+export default {
+  name: "task-action",
+  props: {
+    curPaperOrTask: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+    levels: {
+      type: Array,
+      default() {
+        return [];
+      },
+    },
+  },
+  data() {
+    return {
+      rights: {
+        ...initRights,
+      },
+      roleRight: {
+        task: ["gradeInfo", "markInfo", "gradeList", "markHis"],
+        history: ["stepLabel", "gradeChange", "gradeList"],
+      },
+      stepDict: {
+        task: "待评",
+        history: "改档",
+      },
+      stepType: "",
+      stepLabel: "",
+      curPaperLevel: "",
+      curPaperScore: "",
+      gradingHistory: [],
+      curLevel: {},
+      setT: null,
+      btnClicked: false,
+    };
+  },
+  watch: {
+    curPaperOrTask(val, oldval) {
+      if (val !== oldval) this.rebuildRight();
+    },
+  },
+  mounted() {
+    this.rebuildRight();
+  },
+  methods: {
+    rebuildRight() {
+      if (!this.curPaperOrTask || !this.curPaperOrTask.id) return;
+
+      const curPaperScore = this.curPaperOrTask.score;
+      this.curPaperScore = curPaperScore !== null ? curPaperScore + "" : "";
+      this.stepType = this.curPaperOrTask.dataType || "task";
+      this.stepLabel = this.stepDict[this.stepType];
+      this.rights = { ...initRights };
+      const roleRights = this.roleRight[this.stepType] || [];
+      roleRights.map((key) => {
+        this.rights[key] = true;
+      });
+
+      if (this.curPaperOrTask.level) {
+        this.curLevel = this.levels.find(
+          (level) => level.name === this.curPaperOrTask.level
+        );
+        this.curPaperLevel = this.curLevel.name;
+      }
+
+      if (this.rights.markHis) {
+        this.getMarkHistory();
+      }
+      this.btnClicked = false;
+    },
+    async getMarkHistory() {
+      const data = await markHistoryList(this.curPaperOrTask.id, "SCORE");
+      this.gradingHistory = data.map((item) => {
+        return {
+          id: item.markerId,
+          name: item.marker,
+          loginName: item.loginName,
+          value: item.result || "未评",
+        };
+      });
+    },
+    selectLevel(level, actionType = null) {
+      if (this.curPaperOrTask.level === level.name && !actionType) return;
+
+      if (this.btnClicked) return;
+      this.btnClicked = true;
+
+      this.setT = setTimeout(() => {
+        this.btnClicked = false;
+      }, 500);
+
+      // 科组长改档
+      this.$emit("on-leader-level", {
+        paperId: this.curPaperOrTask.paperId,
+        curLevel: this.curPaperOrTask.level,
+        selectedLevel: level.name,
+      });
+    },
+  },
+  beforeDestroy() {
+    if (this.setT) clearTimeout(this.setT);
+  },
+};
+</script>

+ 268 - 0
src/modules/inspection/paperCheck/TaskDetail.vue

@@ -0,0 +1,268 @@
+<template>
+  <div class="task-detail marker-grading">
+    <div class="marker-header">
+      <div class="header-main">
+        <div class="header-group">
+          <div class="header-part">
+            <p>试卷抽查 > 批量处理</p>
+          </div>
+        </div>
+        <div class="header-group">
+          <div class="header-user">
+            <div class="user-name">
+              <Icon type="md-person" size="16" /> {{ username }}
+            </div>
+          </div>
+          <div class="header-part header-back" @click="toBack">
+            <p>返回 <Icon type="ios-arrow-right"></Icon></p>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="marker-menu">
+      <div class="menu-head">
+        <div class="menu-head-box">
+          <div
+            v-for="menu in menus"
+            :key="menu.value"
+            :class="['menu-item', { 'is-active': menu.value === curMenu }]"
+            @click="toSwitchMenu(menu)"
+          >
+            <div>{{ menu.label }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="menu-body">
+        <ul>
+          <li
+            v-for="(paper, pidnex) in papers"
+            :key="paper.id"
+            :class="{ 'is-active': paper.id === curPaper.id }"
+            @click="selectPaper(pidnex)"
+          >
+            {{ paper.sn }}
+          </li>
+        </ul>
+      </div>
+      <div class="menu-foot">
+        <div class="page-total">共{{ total }}条</div>
+
+        <div class="task-page">
+          <div class="page-item" @click="toPage(1)" title="首页">
+            <Icon type="ios-skip-backward" />
+          </div>
+          <div class="page-item" @click="toPrevPage" title="上一页">
+            <Icon type="md-arrow-dropleft" />
+          </div>
+          <div class="page-item page-cpage" @keydown.enter="changePage">
+            <InputNumber
+              v-model="pageNo"
+              class="page-input"
+              :min="1"
+              :max="totalPage"
+              :step="1"
+              :precision="0"
+            ></InputNumber>
+            <span>/</span>
+            <span>{{ totalPage }}</span>
+          </div>
+          <div class="page-item" @click="toNextPage" title="下一页">
+            <Icon type="md-arrow-dropright" />
+          </div>
+          <div class="page-item" @click="toPage(totalPage)" title="尾页">
+            <Icon type="ios-skip-forward" />
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="marker-body">
+      <ImageView
+        :img-src="curPaper.imgSrc"
+        @on-prev="toPrevPaper"
+        @on-next="toNextPaper"
+      />
+    </div>
+    <div class="marker-action">
+      <TaskAction
+        :levels="levels"
+        :cur-paper-or-task="curPaper"
+        @on-leader-level="leaderSelectLevel"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  paperCheckListStudent,
+  markStepChangeLevel,
+  workLevelList,
+  paperCheckUpdateProgress,
+  paperCheckProgress,
+} from "@/api";
+import TaskAction from "./TaskAction.vue";
+import ImageView from "@/components/ImageView.vue";
+
+export default {
+  name: "task-detail",
+  components: { TaskAction, ImageView },
+  data() {
+    return {
+      username: this.$ls.get("user", { loginName: "" }).loginName,
+      taskInfo: this.$ls.get("taskInfo", {}),
+      pageNo: 1,
+      current: 1,
+      size: 25,
+      total: 0,
+      totalPage: 0,
+      papers: [],
+      curPaper: {},
+      curPaperIndex: -1,
+      paperKey: "",
+      menus: [
+        {
+          label: "试卷抽查",
+          value: "task",
+        },
+        {
+          label: "历史记录",
+          value: "history",
+        },
+      ],
+      curMenu: "task",
+      levels: [],
+    };
+  },
+  mounted() {
+    this.initData();
+  },
+  methods: {
+    async initData() {
+      this.getWorkLevels();
+      const res = await paperCheckProgress({ paperCheckId: this.taskInfo.id });
+      if (res && res.secretNumber) {
+        await this.toPage(res.pageNumber + 1);
+        const index = this.papers.findIndex(
+          (item) => item.sn === res.secretNumber
+        );
+        this.selectPaper(index !== -1 ? index : 0);
+      } else {
+        await this.toPage(1);
+        this.selectPaper(0);
+      }
+    },
+    async getWorkLevels() {
+      const data = await workLevelList(this.taskInfo.workId);
+      this.levels = data || [];
+    },
+    async getList() {
+      const res = await paperCheckListStudent({
+        paperCheckId: this.taskInfo.id,
+        pageNumber: this.current - 1,
+        pageSize: this.size,
+      });
+      this.papers = res.data;
+      this.total = res.totalCount;
+      this.totalPage = res.pageCount;
+    },
+    async toPage(page) {
+      this.current = page;
+      await this.getList();
+      this.pageNo = this.current;
+    },
+    changePage() {
+      if (!this.pageNo) return;
+      this.toPage(this.pageNo);
+    },
+    async toPrevPage() {
+      if (this.current <= 1) return;
+      await this.toPage(this.current - 1);
+    },
+    async toNextPage() {
+      if (this.current >= this.totalPage) return;
+      await this.toPage(this.current + 1);
+    },
+    // menu
+    toSwitchMenu(item) {
+      this.curMenu = item.value;
+    },
+    // paper
+    selectPaper(index) {
+      this.paperKey = this.$randomCode();
+      let nindex = index;
+      if (!this.papers.length) {
+        nindex = 0;
+      } else if (index > this.papers.length - 1) {
+        nindex = this.papers.length - 1;
+      } else if (index < 0) {
+        nindex = 0;
+      }
+      this.curPaperIndex = nindex;
+      this.curPaper = this.papers[nindex] ? { ...this.papers[nindex] } : {};
+
+      this.updateProgress();
+    },
+    async toPrevPaper() {
+      if (this.curPaperIndex === 0) {
+        if (this.current <= 1) {
+          this.$Message.warning("当前已经是第一条数据了");
+          return;
+        }
+
+        await this.toPage(this.current - 1);
+        this.curPaperIndex = this.papers.length - 1;
+      } else {
+        this.curPaperIndex--;
+      }
+
+      this.selectPaper(this.curPaperIndex);
+    },
+    async toNextPaper() {
+      if (this.curPaperIndex === this.papers.length - 1) {
+        if (this.current === this.totalPage) {
+          this.$Message.warning("当前已经是最后一条数据了");
+          return;
+        } else {
+          this.setPage({ current: this.page.current + 1 });
+          this.curPaperIndex = 0;
+          await this.getList();
+        }
+      } else {
+        this.curPaperIndex++;
+      }
+
+      this.selectPaper(this.curPaperIndex);
+    },
+    async updateProgress() {
+      await paperCheckUpdateProgress({
+        paperCheckId: this.taskInfo.id,
+        pageNumber: this.current,
+        secretNumber: this.curPaper.sn,
+      });
+    },
+    // change level
+    leaderSelectLevel(levelInfo) {
+      const content = `确定申请由${levelInfo.curLevel}档改为${levelInfo.selectedLevel}并打回给所有老师吗?`;
+      this.$Modal.confirm({
+        content,
+        width: 450,
+        onOk: async () => {
+          await markStepChangeLevel({
+            subjectId: `${this.taskInfo.workId}-${this.taskInfo.subject}`,
+            paperId: levelInfo.paperId,
+            level: levelInfo.selectedLevel,
+            userId: this.$ls.get("user", { id: "" }).id,
+            paperCheckId: this.curPaper.id,
+          });
+          this.$Message.success("申请改档成功!");
+          await this.toNextPaper();
+        },
+      });
+    },
+    // toBack
+    toBack() {
+      this.$router.back();
+    },
+  },
+};
+</script>

+ 212 - 0
src/modules/inspection/paperCheck/index.vue

@@ -0,0 +1,212 @@
+<template>
+  <div class="paper-check">
+    <div class="part-box part-box-filter">
+      <Form ref="FilterForm" label-position="left" inline>
+        <FormItem>
+          <Select
+            v-model="filter.workId"
+            placeholder="工作文件夹"
+            style="width: 150px"
+          >
+            <Option
+              v-for="(work, windex) in works"
+              :key="windex"
+              :value="work.id"
+              :label="work.name"
+            ></Option>
+          </Select>
+        </FormItem>
+        <FormItem>
+          <Button
+            class="btn-form-search"
+            size="small"
+            type="primary"
+            @click="toPage(1)"
+            >查询</Button
+          >
+        </FormItem>
+      </Form>
+    </div>
+    <div class="part-box-head">
+      <Button
+        type="success"
+        icon="recode-white icon"
+        shape="circle"
+        @click="toAdd"
+        >新增</Button
+      >
+    </div>
+
+    <Table
+      ref="TableList"
+      :columns="columns"
+      :data="dataList"
+      disabled-hover
+      border
+    ></Table>
+
+    <!-- ModifyTask -->
+    <ModifyTask ref="ModifyTaskRef" :instance="curRow" @modified="getList" />
+    <!-- import student  -->
+    <import-file
+      ref="ExportStudentRef"
+      title="导入考生"
+      :upload-url="uploadStudentUrl"
+      :upload-data="{ paperCheckId: curRow.id }"
+      :download-url="downloadStudentTemplateUrl"
+      :download-filename="downloadStudentTemplateFilename"
+      :headers="headers"
+      :format="['xls', 'xlsx']"
+      @upload-success="uploadSuccess"
+    >
+    </import-file>
+  </div>
+</template>
+
+<script>
+import { workList, paperCheckList } from "@/api";
+import ModifyTask from "./ModifyTask.vue";
+import ImportFile from "@/components/common/ImportFile/ImportFile.vue";
+
+import { download } from "@/plugins/utils";
+
+export default {
+  name: "inspection-paper-check",
+  components: { ModifyTask, ImportFile },
+  data() {
+    return {
+      filter: {
+        workId: "",
+      },
+      works: [],
+      dataList: [],
+      curRow: {},
+      columns: [
+        {
+          type: "index",
+          title: "序号",
+          width: 80,
+          align: "center",
+        },
+        {
+          title: "名称",
+          key: "name",
+        },
+        {
+          title: "科目",
+          key: "subject",
+        },
+        {
+          title: "备注",
+          key: "remark",
+        },
+        {
+          title: "操作",
+          key: "action",
+          width: 240,
+          align: "center",
+          className: "table-action",
+          render: (h, param) => {
+            const actions = [
+              {
+                name: "导入考生",
+                type: "text",
+                disabled: param.row.startDeal,
+                attrs: {
+                  class: "ivu-btn ivu-btn-text btn-primary",
+                },
+                action: () => {
+                  this.toImport(param.row);
+                },
+              },
+              {
+                name: "批量处理",
+                type: "text",
+                attrs: {
+                  class: "ivu-btn ivu-btn-text btn-primary",
+                },
+                action: () => {
+                  this.toDone(param.row);
+                },
+              },
+              {
+                name: "导出信息",
+                type: "text",
+                attrs: {
+                  class: "ivu-btn ivu-btn-text btn-primary",
+                },
+                action: () => {
+                  this.toExport(param.row);
+                },
+              },
+            ];
+
+            return h("div", this.$tableAction(h, actions));
+          },
+        },
+      ],
+      // import
+      headers: {
+        Authorization: this.$ls.get("user", { token: "" }).token,
+        userId: this.$ls.get("user", { id: "" }).id,
+      },
+      uploadStudentUrl: this.GLOBAL.domain + "/api/paperCheck/importStudent",
+      downloadStudentTemplateUrl: "/templates/试卷抽查-模板.xlsx",
+      downloadStudentTemplateFilename: "试卷抽查-模板.xlsx",
+    };
+  },
+  async mounted() {
+    await this.getWorkList();
+    await this.getList();
+  },
+  methods: {
+    async getWorkList() {
+      this.works = await workList();
+      this.filter.workId = this.works[0].id;
+    },
+    async getList() {
+      const res = await paperCheckList(this.filter);
+      this.dataList = res || [];
+    },
+    toAdd() {
+      this.curRow = { workId: this.filter.workId };
+      this.$refs.ModifyTaskRef.open();
+    },
+    toImport(row) {
+      this.curRow = row;
+      this.$refs.ExportStudentRef.open();
+    },
+    uploadSuccess() {
+      this.$Message.success("导入成功!");
+      this.getList();
+    },
+    toDone(row) {
+      this.$ls.set("taskInfo", {
+        ...row,
+        workId: this.filter.workId,
+      });
+      this.$router.push({
+        name: "InspectionPaperCheckDetail",
+      });
+    },
+    async toExport(row) {
+      let result = true;
+      const user = this.$ls.get("user", { token: "", id: "" });
+
+      await download({
+        type: "post",
+        url: `${this.GLOBAL.domain}/api/paperCheck/export?paperCheckId=${row.id}`,
+        header: { Authorization: user.token, userId: user.id },
+        data: {},
+        fileName: `${row.name}-试卷抽查信息.xlsx`,
+      }).catch(() => {
+        result = false;
+      });
+
+      if (!result) return;
+
+      this.$Message.success("导出成功!");
+    },
+  },
+};
+</script>

+ 18 - 0
src/routers/inspection.js

@@ -2,6 +2,8 @@ import Inspection from "../modules/inspection/Inspection";
 import InspectionActionLogs from "../modules/inspection/InspectionActionLogs";
 import InspectionCollectLogs from "../modules/inspection/InspectionCollectLogs";
 import InspectionGrading from "../modules/inspection/InspectionGrading";
+import InspectionPaperCheck from "../modules/inspection/paperCheck/index.vue";
+import InspectionPaperCheckDetail from "../modules/inspection/paperCheck/TaskDetail.vue";
 // 纪检成绩查询页面,直接使用管理员中的成绩查询页面,页面做了权限控制
 import StudentScore from "../modules/main/StudentScore";
 
@@ -38,6 +40,14 @@ const inspectionRoutes = [
       title: "成绩查询",
     },
   },
+  {
+    path: "inspection-paper-check",
+    name: "InspectionPaperCheck",
+    component: InspectionPaperCheck,
+    meta: {
+      title: "试卷抽查",
+    },
+  },
 ];
 
 export default [
@@ -48,4 +58,12 @@ export default [
     redirect: { name: "InspectionActionLogs" },
     children: inspectionRoutes,
   },
+  {
+    path: "/inspection-paper-check-detail",
+    name: "InspectionPaperCheckDetail",
+    component: InspectionPaperCheckDetail,
+    meta: {
+      title: "试卷抽查批量处理",
+    },
+  },
 ];