zhangjie 2 سال پیش
والد
کامیت
fd26de2aa9

+ 877 - 789
src/assets/styles/marker.less

@@ -1,789 +1,877 @@
-.marker-grading {
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  z-index: auto;
-  color: @color-text;
-}
-// marker-header
-.marker-header {
-  position: fixed;
-  height: 40px;
-  padding: 5px 0;
-  top: 0;
-  left: 0;
-  width: 100%;
-  z-index: 9;
-  background-color: @color-background-light;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  line-height: 30px;
-
-  .header-part {
-    display: inline-block;
-    vertical-align: top;
-    padding: 0 10px;
-    margin-left: 5px;
-    background: @color-background;
-    border-radius: 5px;
-    cursor: pointer;
-    &:hover {
-      background-color: shade(@color-background, 20%);
-      color: @color-text-act;
-    }
-  }
-  .header-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;
-      &:hover {
-        background-color: shade(@color-background, 20%);
-      }
-    }
-    .page-cpage {
-      padding: 0 5px;
-      span {
-        margin: 0 1px;
-      }
-    }
-    .page-size {
-      padding: 0 10px;
-    }
-  }
-  .header-step {
-    color: @color-text-act;
-  }
-  .header-selection {
-    padding: 0;
-    background-color: transparent;
-
-    &:hover {
-      background-color: transparent;
-    }
-
-    .image-checkbox {
-      display: inline-block;
-      vertical-align: middle;
-      height: 20px;
-      width: 20px;
-      margin-right: 2px;
-      border-radius: 5px;
-      background-color: @color-background;
-      color: @color-text-act;
-      font-size: 14px;
-      text-align: center;
-      line-height: 20px;
-      cursor: pointer;
-
-      &:hover,
-      &.image-selected {
-        box-shadow: 0 0 3px inset @color-background-light;
-      }
-    }
-  }
-  .header-history {
-    margin-right: 5px;
-  }
-  .header-user {
-    display: inline-block;
-    vertical-align: top;
-    width: 280px;
-    border-left: 1px solid @color-background;
-    margin: -5px 0;
-    padding: 5px 10px;
-
-    .ivu-dropdown {
-      display: block;
-    }
-
-    .user-name {
-      background: @color-background;
-      border-radius: 15px;
-      padding: 0 15px;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-      cursor: pointer;
-      > i {
-        color: #bec3d1;
-        &:last-child {
-          display: block;
-          float: right;
-          margin-top: 8px;
-        }
-      }
-      &:hover {
-        background-color: shade(@color-background, 20%);
-        color: @color-text-act;
-      }
-    }
-  }
-}
-.header-step-dropdown {
-  .header-step-item {
-    > i {
-      color: @color-text-act;
-      &:last-child {
-        color: @color-text;
-      }
-    }
-  }
-}
-.header-filter-body {
-  .filter-part {
-    padding: 15px 0 7px;
-
-    &:not(:last-child) {
-      border-bottom: 1px dashed @color-text;
-    }
-
-    &-title {
-      line-height: 1;
-      margin-bottom: 10px;
-    }
-  }
-
-  .filter-select {
-    display: inline-block;
-    vertical-align: top;
-    width: 100px;
-    min-width: auto;
-    margin-right: 10px;
-    margin-bottom: 8px;
-  }
-  .filter-input {
-    display: inline-block;
-    vertical-align: top;
-    width: 150px;
-    margin-right: 10px;
-    margin-bottom: 8px;
-  }
-  .filter-btn {
-    display: inline-block;
-    vertical-align: top;
-    width: 60px;
-    height: 30px;
-  }
-  .filter-label {
-    display: inline-block;
-    vertical-align: top;
-    line-height: 32px;
-  }
-}
-
-// .marker-body
-.marker-body {
-  position: absolute;
-  left: 0;
-  top: 40px;
-  right: 280px;
-  bottom: 0;
-  overflow: auto;
-  padding: 5px;
-  background: @color-background;
-  z-index: 7;
-}
-.marker-image-list {
-  height: 100%;
-
-  .marker-image-item {
-    display: inline-block;
-    vertical-align: top;
-    width: 25%;
-    height: 50%;
-    padding: 5px;
-    font-size: 0;
-
-    &-act {
-      .marker-image-content::before {
-        content: "";
-        display: block;
-        position: absolute;
-        width: 20px;
-        height: 20px;
-        top: 0;
-        right: 0;
-        border-top-right-radius: 5px;
-        border-bottom-left-radius: 20px;
-        background-color: @color-act1;
-      }
-    }
-  }
-  .marker-image-content {
-    position: relative;
-    background-color: @color-background-light;
-    height: 100%;
-    padding: 10px;
-    border-radius: 5px;
-  }
-
-  &-1 {
-    .marker-image-item {
-      width: 100%;
-      height: 100%;
-    }
-  }
-  &-2 {
-    .marker-image-item {
-      width: 50%;
-      height: 100%;
-    }
-  }
-  &-3 {
-    .marker-image-item {
-      width: 33.33%;
-      height: 100%;
-    }
-  }
-  &-4 {
-    .marker-image-item {
-      width: 50%;
-      height: 50%;
-    }
-  }
-  &-6 {
-    .marker-image-item {
-      width: 33.33%;
-      height: 50%;
-    }
-  }
-  &-8 {
-    .marker-image-item {
-      width: 25%;
-      height: 50%;
-    }
-  }
-  &-9 {
-    .marker-image-item {
-      width: 33.33%;
-      height: 33.33%;
-    }
-  }
-  &-10 {
-    .marker-image-item {
-      width: 20%;
-      height: 50%;
-    }
-  }
-  &-12 {
-    .marker-image-item {
-      width: 25%;
-      height: 33.33%;
-    }
-  }
-  &-15 {
-    .marker-image-item {
-      width: 20%;
-      height: 33.33%;
-    }
-  }
-  &-16 {
-    .marker-image-item {
-      width: 25%;
-      height: 25%;
-    }
-  }
-  &-20 {
-    .marker-image-item {
-      width: 20%;
-      height: 25%;
-    }
-  }
-  &-24 {
-    .marker-image-item {
-      width: 16.66%;
-      height: 25%;
-    }
-  }
-  &-25 {
-    .marker-image-item {
-      width: 20%;
-      height: 20%;
-    }
-  }
-}
-.marker-image-view {
-  position: relative;
-  height: 100%;
-  font-size: 14px;
-
-  .image-view-contain {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 36px;
-  }
-  .image-view-footer {
-    position: absolute;
-    width: 100%;
-    bottom: 0;
-    left: 0;
-    height: 26px;
-    line-height: 26px;
-    padding: 0;
-    display: flex;
-    justify-content: space-between;
-  }
-  .image-info {
-    white-space: nowrap;
-    overflow: hidden;
-    > div {
-      display: inline-block;
-      vertical-align: top;
-    }
-  }
-  .image-sample {
-    height: 26px;
-    width: 26px;
-    border-radius: 5px;
-    background-color: @color-act1;
-    color: @color-text;
-    font-size: 16px;
-    text-align: center;
-    line-height: 26px;
-  }
-  .image-checkbox {
-    height: 26px;
-    width: 26px;
-
-    border-radius: 5px;
-    background-color: @color-background;
-    color: @color-text-act;
-    font-size: 20px;
-    text-align: center;
-    line-height: 26px;
-    cursor: pointer;
-
-    &:hover,
-    &.image-selected {
-      box-shadow: 0 0 3px inset @color-background-light;
-    }
-  }
-  .image-level {
-    height: 26px;
-    min-width: 26px;
-    margin-right: 5px;
-    border-radius: 5px;
-    background-color: @color-background;
-    font-size: 18px;
-    text-align: center;
-  }
-  .image-title {
-    height: 26px;
-    padding-left: 5px;
-    cursor: pointer;
-    &:hover {
-      color: @color-text-act;
-    }
-  }
-  .image-action {
-    .ivu-btn {
-      width: 26px;
-      height: 26px;
-      padding: 0;
-      font-size: 12px;
-      border-radius: 50%;
-      border: 0;
-      .ivu-icon {
-        color: @color-text-act;
-      }
-    }
-
-    &-li {
-      display: inline-block;
-      vertical-align: top;
-      margin-left: 5px;
-      height: 26px;
-      font-size: 26px;
-      cursor: pointer;
-
-      &:hover {
-        color: @color-text-act;
-      }
-    }
-    .mark-act {
-      color: @warning-color;
-    }
-  }
-}
-.marker-image-none {
-  padding-top: 150px;
-  font-size: 16px;
-  text-align: center;
-  color: @color-text;
-}
-
-// marker-action
-.marker-action {
-  position: fixed;
-  width: 280px;
-  right: 0;
-  top: 0;
-  height: 100%;
-  z-index: 8;
-  padding: 60px 10px 20px;
-  background-color: @color-background-light;
-  color: @color-text;
-  overflow-y: auto;
-  overflow-x: hidden;
-
-  &-fullscreen {
-    z-index: 2000;
-  }
-
-  .action-search {
-    border-top: 1px dashed @color-text;
-  }
-  .action-paper-state {
-    color: @color-text;
-    .paper-state-cont {
-      background: @color-background;
-    }
-  }
-
-  .action-paper-info {
-    color: @color-text;
-    span:last-child {
-      color: @color-text-act;
-    }
-  }
-  .action-grade-change {
-    background-color: @color-background;
-    color: @color-text;
-  }
-  .action-grade-info {
-    background-color: @color-act1;
-    color: @color-text;
-    &-title {
-      color: @color-text;
-    }
-    .grade-info-name {
-      color: @color-text-act;
-    }
-  }
-  .action-grade-item {
-    color: @color-text;
-
-    &-content {
-      background: @color-background;
-
-      &:hover {
-        background-color: @color-act1;
-        color: @color-text-act;
-      }
-    }
-  }
-  .action-item-content-disabled {
-    background: shade(@color-background-light, 30%) !important;
-    color: @color-background-light!important;
-  }
-  .action-grade-history {
-    .grade-history-item {
-      background-color: @color-background;
-      color: @color-text;
-
-      p:last-child {
-        background-color: @color-act1;
-        color: @color-text-act;
-      }
-    }
-  }
-  .action-grade-pass {
-    background: @color-background;
-    color: @color-text;
-
-    &:hover {
-      background-color: shade(@color-background, 20%);
-    }
-  }
-
-  // marking
-  .action-mark-item {
-    color: @color-text;
-
-    &-content {
-      background: @color-background;
-
-      &:hover {
-        background-color: @color-act1;
-        color: @color-text-act;
-      }
-    }
-  }
-}
-.dark-mark {
-  // iview-ui
-  .ivu-btn-primary {
-    color: @color-text-act;
-    background-color: @color-act1;
-    border-color: @color-act1;
-
-    &:hover {
-      background-color: shade(@color-act1, 10%);
-      border-color: shade(@color-act1, 10%);
-    }
-  }
-  .ivu-input {
-    background-color: @color-background!important;
-    border-color: @color-background;
-    color: @color-text;
-    box-shadow: none !important;
-  }
-  .ivu-select-selection {
-    background-color: @color-background;
-    color: @color-text;
-    border-color: @color-background;
-  }
-  .ivu-select-dropdown {
-    background-color: @color-background;
-    color: @color-text;
-
-    .ivu-select-item {
-      color: @color-text;
-      border-top: 1px solid @color-background-light;
-      &:hover,
-      &-focus {
-        background-color: @color-act1;
-      }
-    }
-  }
-  .ivu-form .ivu-form-item-label {
-    color: @color-text;
-  }
-}
-
-// marker-history
-.marker-history {
-  .image-view-footer {
-    color: @color-text;
-  }
-  .image-action-name {
-    height: 26px;
-    padding-left: 5px;
-  }
-  .ivu-modal {
-    width: 100% !important;
-    top: 0 !important;
-  }
-}
-.history-image-list {
-  height: 360px;
-
-  .marker-image-item {
-    width: 20%;
-    height: 100%;
-  }
-}
-// marker-standard
-.marker-standard {
-  .level-list {
-    text-align: center;
-    margin-bottom: 30px;
-  }
-  .level-item {
-    display: inline-block;
-    vertical-align: top;
-    width: 40px;
-    height: 26px;
-    line-height: 26px;
-    padding: 0 5px;
-    margin: 0 10px;
-    border-radius: 5px;
-    background-color: @color-background-light;
-    color: @color-text;
-    text-align: center;
-    cursor: pointer;
-    &:hover,
-    &-act {
-      color: @color-text-act;
-      background-color: @color-act1;
-    }
-  }
-  .standard-image-list {
-    height: auto;
-  }
-
-  .image-view-footer {
-    color: @color-text;
-  }
-  .marker-image-item {
-    width: 20%;
-    height: 300px;
-  }
-  .standard-image-none {
-    padding-top: 150px;
-    font-size: 16px;
-    text-align: center;
-    color: @color-text;
-  }
-}
-.change-standard {
-  .level-list {
-    margin-bottom: 50px;
-  }
-  .level-item {
-    display: inline-block;
-    vertical-align: top;
-    margin: 5px;
-    height: 30px;
-    line-height: 30px;
-    width: 40px;
-    text-align: center;
-    border-radius: 5px;
-    color: @color-text;
-    background-color: @color-background-light;
-    border-color: @color-background-light;
-    cursor: pointer;
-
-    &:hover,
-    &-act {
-      background-color: @color-act1;
-      border-color: @color-act1;
-    }
-
-    &-disabled {
-      cursor: not-allowed;
-      color: @color-text;
-      background-color: shade(@color-background-light, 20%) !important;
-    }
-  }
-}
-// marker-statistics
-.marker-statistics {
-  color: @color-text;
-  &-chart {
-    > h3 {
-      font-size: 16px;
-    }
-    .chart-box {
-      background-color: @color-background;
-    }
-  }
-}
-
-// leader-progress
-.leader-progress {
-  .ivu-modal {
-    width: 600px !important;
-  }
-  .progress-line {
-    color: @color-text;
-    background-color: tint(@color-background, 5%);
-
-    .progress-rate {
-      background-color: @color-act1;
-      color: @color-text-act;
-    }
-  }
-
-  &-part {
-    margin-bottom: 20px;
-  }
-}
-// modify-leader-grading
-.marker-modal {
-  .leader-grading {
-    color: @color-text;
-    .leader-level {
-      h3 {
-        background-color: @color-background-light;
-        color: @color-text-act;
-      }
-    }
-    .leader-aciton {
-      color: @color-text;
-    }
-    .leader-markers {
-      background-color: @color-background-light;
-    }
-  }
-  .ivu-btn-primary {
-    .marker-btn-primary;
-  }
-  .ivu-radio-inner:after,
-  .ivu-checkbox-checked .ivu-checkbox-inner {
-    background-color: @color-act1;
-  }
-}
-
-// custom iview ui ----------------->
-// marker-modal
-.marker-modal {
-  color: @color-text;
-  .ivu-modal-mask {
-    background-color: rgba(55, 55, 55, 0.7);
-  }
-
-  .ivu-modal-content {
-    background-color: @color-background;
-    border-radius: 0;
-  }
-  .ivu-modal-header {
-    border-color: @color-background-light;
-    &-inner {
-      color: @color-text;
-      text-align: left;
-    }
-  }
-  .ivu-modal-body {
-    padding: 15px;
-  }
-}
-// marker-dropdown
-.marker-dropdown {
-  background-color: @color-background;
-  box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
-
-  .ivu-dropdown-item {
-    margin-top: 0;
-    color: @color-text;
-    border-top: 1px solid @color-background-light;
-    &:hover {
-      background-color: @color-act1;
-    }
-  }
-}
-// marker-popper
-.marker-popper {
-  &.ivu-poptip-popper {
-    .ivu-poptip-arrow {
-      border-bottom-color: @color-act1;
-      &::after {
-        border-bottom-color: @color-act1;
-      }
-    }
-  }
-  .ivu-poptip-inner {
-    background-color: @color-background-light2;
-    color: @color-text;
-
-    box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
-  }
-}
-// btn
-.marker-btn-primary {
-  color: @color-text-act;
-  background-color: @color-act1;
-  border-color: @color-act1;
-
-  &:hover {
-    background-color: shade(@color-act1, 10%);
-    border-color: shade(@color-act1, 10%);
-  }
-}
+.marker-grading {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  z-index: auto;
+  color: @color-text;
+}
+// marker-header
+.marker-header {
+  position: fixed;
+  height: 40px;
+  padding: 5px 0;
+  top: 0;
+  left: 0;
+  width: 100%;
+  z-index: 9;
+  background-color: @color-background-light;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  line-height: 30px;
+
+  .header-part {
+    display: inline-block;
+    vertical-align: top;
+    padding: 0 10px;
+    margin-left: 5px;
+    background: @color-background;
+    border-radius: 5px;
+    cursor: pointer;
+    &:hover {
+      background-color: shade(@color-background, 20%);
+      color: @color-text-act;
+    }
+  }
+  .header-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;
+      &:hover {
+        background-color: shade(@color-background, 20%);
+      }
+    }
+    .page-cpage {
+      padding: 0 5px;
+      span {
+        margin: 0 1px;
+      }
+    }
+    .page-size {
+      padding: 0 10px;
+    }
+  }
+  .header-step {
+    color: @color-text-act;
+  }
+  .header-selection {
+    padding: 0;
+    background-color: transparent;
+
+    &:hover {
+      background-color: transparent;
+    }
+
+    .image-checkbox {
+      display: inline-block;
+      vertical-align: middle;
+      height: 20px;
+      width: 20px;
+      margin-right: 2px;
+      border-radius: 5px;
+      background-color: @color-background;
+      color: @color-text-act;
+      font-size: 14px;
+      text-align: center;
+      line-height: 20px;
+      cursor: pointer;
+
+      &:hover,
+      &.image-selected {
+        box-shadow: 0 0 3px inset @color-background-light;
+      }
+    }
+  }
+  .header-history {
+    margin-right: 5px;
+  }
+  .header-user {
+    display: inline-block;
+    vertical-align: top;
+    width: 280px;
+    border-left: 1px solid @color-background;
+    margin: -5px 0;
+    padding: 5px 10px;
+
+    .ivu-dropdown {
+      display: block;
+    }
+
+    .user-name {
+      background: @color-background;
+      border-radius: 15px;
+      padding: 0 15px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      cursor: pointer;
+      > i {
+        color: #bec3d1;
+        &:last-child {
+          display: block;
+          float: right;
+          margin-top: 8px;
+        }
+      }
+      &:hover {
+        background-color: shade(@color-background, 20%);
+        color: @color-text-act;
+      }
+    }
+  }
+}
+.header-step-dropdown {
+  .header-step-item {
+    > i {
+      color: @color-text-act;
+      &:last-child {
+        color: @color-text;
+      }
+    }
+  }
+}
+.header-filter-body {
+  .filter-part {
+    padding: 15px 0 7px;
+
+    &:not(:last-child) {
+      border-bottom: 1px dashed @color-text;
+    }
+
+    &-title {
+      line-height: 1;
+      margin-bottom: 10px;
+    }
+  }
+
+  .filter-select {
+    display: inline-block;
+    vertical-align: top;
+    width: 100px;
+    min-width: auto;
+    margin-right: 10px;
+    margin-bottom: 8px;
+  }
+  .filter-input {
+    display: inline-block;
+    vertical-align: top;
+    width: 150px;
+    margin-right: 10px;
+    margin-bottom: 8px;
+  }
+  .filter-btn {
+    display: inline-block;
+    vertical-align: top;
+    width: 60px;
+    height: 30px;
+  }
+  .filter-label {
+    display: inline-block;
+    vertical-align: top;
+    line-height: 32px;
+  }
+}
+
+// .marker-body
+.marker-body {
+  position: absolute;
+  left: 0;
+  top: 40px;
+  right: 280px;
+  bottom: 0;
+  overflow: auto;
+  padding: 5px;
+  background: @color-background;
+  z-index: 7;
+}
+.marker-image-list {
+  height: 100%;
+
+  .marker-image-item {
+    display: inline-block;
+    vertical-align: top;
+    width: 25%;
+    height: 50%;
+    padding: 5px;
+    font-size: 0;
+
+    &-act {
+      .marker-image-content::before {
+        content: "";
+        display: block;
+        position: absolute;
+        width: 20px;
+        height: 20px;
+        top: 0;
+        right: 0;
+        border-top-right-radius: 5px;
+        border-bottom-left-radius: 20px;
+        background-color: @color-act1;
+      }
+    }
+  }
+  .marker-image-content {
+    position: relative;
+    background-color: @color-background-light;
+    height: 100%;
+    padding: 10px;
+    border-radius: 5px;
+  }
+
+  &-1 {
+    .marker-image-item {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  &-2 {
+    .marker-image-item {
+      width: 50%;
+      height: 100%;
+    }
+  }
+  &-3 {
+    .marker-image-item {
+      width: 33.33%;
+      height: 100%;
+    }
+  }
+  &-4 {
+    .marker-image-item {
+      width: 50%;
+      height: 50%;
+    }
+  }
+  &-6 {
+    .marker-image-item {
+      width: 33.33%;
+      height: 50%;
+    }
+  }
+  &-8 {
+    .marker-image-item {
+      width: 25%;
+      height: 50%;
+    }
+  }
+  &-9 {
+    .marker-image-item {
+      width: 33.33%;
+      height: 33.33%;
+    }
+  }
+  &-10 {
+    .marker-image-item {
+      width: 20%;
+      height: 50%;
+    }
+  }
+  &-12 {
+    .marker-image-item {
+      width: 25%;
+      height: 33.33%;
+    }
+  }
+  &-15 {
+    .marker-image-item {
+      width: 20%;
+      height: 33.33%;
+    }
+  }
+  &-16 {
+    .marker-image-item {
+      width: 25%;
+      height: 25%;
+    }
+  }
+  &-20 {
+    .marker-image-item {
+      width: 20%;
+      height: 25%;
+    }
+  }
+  &-24 {
+    .marker-image-item {
+      width: 16.66%;
+      height: 25%;
+    }
+  }
+  &-25 {
+    .marker-image-item {
+      width: 20%;
+      height: 20%;
+    }
+  }
+}
+.marker-image-view {
+  position: relative;
+  height: 100%;
+  font-size: 14px;
+
+  .image-view-contain {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 36px;
+  }
+  .image-view-footer {
+    position: absolute;
+    width: 100%;
+    bottom: 0;
+    left: 0;
+    height: 26px;
+    line-height: 26px;
+    padding: 0;
+    display: flex;
+    justify-content: space-between;
+  }
+  .image-info {
+    white-space: nowrap;
+    overflow: hidden;
+    > div {
+      display: inline-block;
+      vertical-align: top;
+    }
+  }
+  .image-sample {
+    height: 26px;
+    width: 26px;
+    border-radius: 5px;
+    background-color: @color-act1;
+    color: @color-text;
+    font-size: 16px;
+    text-align: center;
+    line-height: 26px;
+  }
+  .image-checkbox {
+    height: 26px;
+    width: 26px;
+
+    border-radius: 5px;
+    background-color: @color-background;
+    color: @color-text-act;
+    font-size: 20px;
+    text-align: center;
+    line-height: 26px;
+    cursor: pointer;
+
+    &:hover,
+    &.image-selected {
+      box-shadow: 0 0 3px inset @color-background-light;
+    }
+  }
+  .image-level {
+    height: 26px;
+    min-width: 26px;
+    margin-right: 5px;
+    border-radius: 5px;
+    background-color: @color-background;
+    font-size: 18px;
+    text-align: center;
+  }
+  .image-title {
+    height: 26px;
+    padding-left: 5px;
+    cursor: pointer;
+    &:hover {
+      color: @color-text-act;
+    }
+  }
+  .image-action {
+    .ivu-btn {
+      width: 26px;
+      height: 26px;
+      padding: 0;
+      font-size: 12px;
+      border-radius: 50%;
+      border: 0;
+      .ivu-icon {
+        color: @color-text-act;
+      }
+    }
+
+    &-li {
+      display: inline-block;
+      vertical-align: top;
+      margin-left: 5px;
+      height: 26px;
+      font-size: 26px;
+      cursor: pointer;
+
+      &:hover {
+        color: @color-text-act;
+      }
+    }
+    .mark-act {
+      color: @warning-color;
+    }
+  }
+}
+.marker-image-none {
+  padding-top: 150px;
+  font-size: 16px;
+  text-align: center;
+  color: @color-text;
+}
+
+// marker-action
+.marker-action {
+  position: fixed;
+  width: 280px;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  z-index: 8;
+  padding: 60px 0 50px;
+  background-color: @color-background-light;
+  color: @color-text;
+
+  &-fullscreen {
+    z-index: 2000;
+  }
+
+  .grade-action {
+    padding: 0 10px;
+    height: 100%;
+    overflow-y: auto;
+    overflow-x: hidden;
+  }
+
+  .action-search {
+    border-top: 1px dashed @color-text;
+  }
+  .action-paper-state {
+    color: @color-text;
+    .paper-state-cont {
+      background: @color-background;
+    }
+  }
+
+  .action-paper-info {
+    color: @color-text;
+    span:last-child {
+      color: @color-text-act;
+    }
+  }
+  .action-grade-change {
+    background-color: @color-background;
+    color: @color-text;
+  }
+  .action-grade-info {
+    background-color: @color-act1;
+    color: @color-text;
+    &-title {
+      color: @color-text;
+    }
+    .grade-info-name {
+      color: @color-text-act;
+    }
+  }
+  .action-grade-item {
+    color: @color-text;
+
+    &-content {
+      background: @color-background;
+
+      &.is-active,
+      &:hover {
+        background-color: @color-act1;
+        color: @color-text-act;
+      }
+    }
+  }
+  .action-item-content-disabled {
+    background: shade(@color-background-light, 30%) !important;
+    color: @color-background-light!important;
+  }
+
+  .action-grade-keyboard {
+    margin-bottom: 20px;
+    color: @color-text-act;
+    .keyboard-input {
+      display: inline-block;
+      vertical-align: top;
+      border: 1px solid @color-act1;
+      background-color: @color-background;
+      line-height: 28px;
+      height: 30px;
+      text-align: center;
+      width: 80%;
+      border-top-left-radius: 5px;
+      border-bottom-left-radius: 5px;
+    }
+    .keyboard-clear {
+      display: inline-block;
+      vertical-align: top;
+      background-color: @color-act1;
+      height: 30px;
+      line-height: 30px;
+      text-align: center;
+      font-size: 20px;
+      width: 20%;
+      cursor: pointer;
+      border-top-right-radius: 5px;
+      border-bottom-right-radius: 5px;
+
+      &:hover {
+        background-color: shade(@color-act1, 10%);
+      }
+    }
+  }
+  .action-grade-history {
+    .grade-history-item {
+      background-color: @color-background;
+      color: @color-text;
+
+      p:last-child {
+        background-color: @color-act1;
+        color: @color-text-act;
+      }
+    }
+  }
+  .action-grade-pass {
+    background: @color-background;
+    color: @color-text;
+
+    &:hover {
+      background-color: shade(@color-background, 20%);
+    }
+  }
+
+  // marking
+  .action-mark-item {
+    color: @color-text;
+
+    &-content {
+      background: @color-background;
+
+      &:hover {
+        background-color: @color-act1;
+        color: @color-text-act;
+      }
+    }
+  }
+}
+.grade-ribbon {
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  left: 0;
+  z-index: 8;
+  padding: 10px;
+  background-color: #3d3f55;
+
+  .ribbon-list {
+    font-size: 0;
+    text-align: right;
+    height: 30px;
+  }
+
+  .ribbon-item {
+    display: inline-block;
+    vertical-align: middle;
+    text-align: center;
+    width: 30px;
+    height: 30px;
+    line-height: 30px;
+    font-size: 20px;
+    cursor: pointer;
+    transition: all linear 0.1s;
+
+    &:hover {
+      color: #bec3d1;
+      transform: scale(1.1, 1.1);
+    }
+  }
+}
+.dark-mark {
+  // iview-ui
+  .ivu-btn-primary {
+    color: @color-text-act;
+    background-color: @color-act1;
+    border-color: @color-act1;
+
+    &:hover {
+      background-color: shade(@color-act1, 10%);
+      border-color: shade(@color-act1, 10%);
+    }
+  }
+  .ivu-input {
+    background-color: @color-background!important;
+    border-color: @color-background;
+    color: @color-text;
+    box-shadow: none !important;
+  }
+  .ivu-select-selection {
+    background-color: @color-background;
+    color: @color-text;
+    border-color: @color-background;
+  }
+  .ivu-select-dropdown {
+    background-color: @color-background;
+    color: @color-text;
+
+    .ivu-select-item {
+      color: @color-text;
+      border-top: 1px solid @color-background-light;
+      &:hover,
+      &-focus {
+        background-color: @color-act1;
+      }
+    }
+  }
+  .ivu-form .ivu-form-item-label {
+    color: @color-text;
+  }
+}
+
+// marker-history
+.marker-history {
+  .image-view-footer {
+    color: @color-text;
+  }
+  .image-action-name {
+    height: 26px;
+    padding-left: 5px;
+  }
+  .ivu-modal {
+    width: 100% !important;
+    top: 0 !important;
+  }
+}
+.history-image-list {
+  height: 360px;
+
+  .marker-image-item {
+    width: 20%;
+    height: 100%;
+  }
+}
+// marker-standard
+.marker-standard {
+  .level-list {
+    text-align: center;
+    margin-bottom: 30px;
+  }
+  .level-item {
+    display: inline-block;
+    vertical-align: top;
+    width: 40px;
+    height: 26px;
+    line-height: 26px;
+    padding: 0 5px;
+    margin: 0 10px;
+    border-radius: 5px;
+    background-color: @color-background-light;
+    color: @color-text;
+    text-align: center;
+    cursor: pointer;
+    &:hover,
+    &-act {
+      color: @color-text-act;
+      background-color: @color-act1;
+    }
+  }
+  .standard-image-list {
+    height: auto;
+  }
+
+  .image-view-footer {
+    color: @color-text;
+  }
+  .marker-image-item {
+    width: 20%;
+    height: 300px;
+  }
+  .standard-image-none {
+    padding-top: 150px;
+    font-size: 16px;
+    text-align: center;
+    color: @color-text;
+  }
+}
+.change-standard {
+  .level-list {
+    margin-bottom: 50px;
+  }
+  .level-item {
+    display: inline-block;
+    vertical-align: top;
+    margin: 5px;
+    height: 30px;
+    line-height: 30px;
+    width: 40px;
+    text-align: center;
+    border-radius: 5px;
+    color: @color-text;
+    background-color: @color-background-light;
+    border-color: @color-background-light;
+    cursor: pointer;
+
+    &:hover,
+    &-act {
+      background-color: @color-act1;
+      border-color: @color-act1;
+    }
+
+    &-disabled {
+      cursor: not-allowed;
+      color: @color-text;
+      background-color: shade(@color-background-light, 20%) !important;
+    }
+  }
+}
+// marker-statistics
+.marker-statistics {
+  color: @color-text;
+  &-chart {
+    > h3 {
+      font-size: 16px;
+    }
+    .chart-box {
+      background-color: @color-background;
+    }
+  }
+}
+
+// leader-progress
+.leader-progress {
+  .ivu-modal {
+    width: 600px !important;
+  }
+  .progress-line {
+    color: @color-text;
+    background-color: tint(@color-background, 5%);
+
+    .progress-rate {
+      background-color: @color-act1;
+      color: @color-text-act;
+    }
+  }
+
+  &-part {
+    margin-bottom: 20px;
+  }
+}
+// modify-leader-grading
+.marker-modal {
+  .leader-grading {
+    color: @color-text;
+    .leader-level {
+      h3 {
+        background-color: @color-background-light;
+        color: @color-text-act;
+      }
+    }
+    .leader-aciton {
+      color: @color-text;
+    }
+    .leader-markers {
+      background-color: @color-background-light;
+    }
+  }
+  .ivu-btn-primary {
+    .marker-btn-primary;
+  }
+  .ivu-radio-inner:after,
+  .ivu-checkbox-checked .ivu-checkbox-inner {
+    background-color: @color-act1;
+  }
+}
+
+// custom iview ui ----------------->
+// marker-modal
+.marker-modal {
+  color: @color-text;
+  .ivu-modal-mask {
+    background-color: rgba(55, 55, 55, 0.7);
+  }
+
+  .ivu-modal-content {
+    background-color: @color-background;
+    border-radius: 0;
+  }
+  .ivu-modal-header {
+    border-color: @color-background-light;
+    &-inner {
+      color: @color-text;
+      text-align: left;
+    }
+  }
+  .ivu-modal-body {
+    padding: 15px;
+  }
+}
+// marker-dropdown
+.marker-dropdown {
+  background-color: @color-background;
+  box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
+
+  .ivu-dropdown-item {
+    margin-top: 0;
+    color: @color-text;
+    border-top: 1px solid @color-background-light;
+    &:hover {
+      background-color: @color-act1;
+    }
+  }
+}
+// marker-popper
+.marker-popper {
+  &.ivu-poptip-popper {
+    .ivu-poptip-arrow {
+      border-bottom-color: @color-act1;
+      &::after {
+        border-bottom-color: @color-act1;
+      }
+    }
+  }
+  .ivu-poptip-inner {
+    background-color: @color-background-light2;
+    color: @color-text;
+
+    box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
+  }
+}
+// btn
+.marker-btn-primary {
+  color: @color-text-act;
+  background-color: @color-act1;
+  border-color: @color-act1;
+
+  &:hover {
+    background-color: shade(@color-act1, 10%);
+    border-color: shade(@color-act1, 10%);
+  }
+}
+
+.ribbon-set-dialog {
+  .ribbon-set-form {
+    padding-bottom: 30px;
+  }
+  .ivu-form-item {
+    margin-bottom: 5px;
+  }
+  .ivu-form-item-label {
+    color: #9d9c9c;
+  }
+  .ivu-switch-checked {
+    border-color: @color-act1;
+    background-color: @color-act1;
+  }
+}

+ 493 - 426
src/modules/grading/components/GradeAction.vue

@@ -1,426 +1,493 @@
-<template>
-  <div class="grade-action">
-    <!-- 头部信息 ------ -->
-    <!-- 试卷状态 -->
-    <!-- 状态:已评,待评,打回,仲裁 -->
-    <div class="action-paper-state" v-if="stepType === 'reject'">
-      <p class="paper-state-cont">
-        {{ curPaperOrTask.isRejectedByLeader ? "科组长打回" : "自动打回" }}
-      </p>
-      <p class="paper-state-intro">
-        <span v-if="curPaperOrTask.rejectedCount"
-          >共打回{{ curPaperOrTask.rejectedCount }}次</span
-        >
-      </p>
-    </div>
-    <div class="action-paper-state" v-else>
-      <p class="paper-state-cont">{{ stepLabel }}</p>
-    </div>
-
-    <!-- 试卷信息 -->
-    <div class="action-paper-info">
-      <!-- <p v-if="IS_ADMIN">
-        <span>试卷考号:</span><span>{{ curPaperOrTask.examNumber }}</span>
-      </p> -->
-      <p>
-        <span v-if="IS_MARKER">任务密号:</span>
-        <span v-else>试卷密号:</span>
-        <span>NO.{{ curPaperOrTask.sn }}</span>
-      </p>
-    </div>
-
-    <!-- 选择档位 -->
-    <h3
-      class="action-grade-info-title"
-      v-if="IS_MARK_LEADER && markLeaderOnlyRight && rights.gradeList"
-    >
-      当前操作:{{ markLeaderOnlyRight.name }}
-    </h3>
-    <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>
-
-    <!-- 档位信息 -->
-    <!-- 已评(已评档位),打回(建议档位) -->
-    <h3
-      class="action-grade-info-title"
-      v-if="IS_MARKER && stepType === 'reject'"
-    >
-      <span>原分档档位:{{ curPaperOrTask.originLevel || "" }}</span>
-      <span
-        v-if="
-          paramsSet.autoCallbackShowDeviation &&
-            curPaperOrTask.deviationDirection &&
-            curPaperOrTask.deviationDirection !== '0'
-        "
-        :class="[
-          'grade-info-deviation',
-          {
-            'grade-info-deviation-error':
-              curPaperOrTask.deviationDirection * 1 > 0
-          }
-        ]"
-        >{{ curPaperOrTask.deviationDirection * 1 > 0 ? "偏高" : "偏低" }}</span
-      >
-    </h3>
-    <h3
-      class="action-grade-info-title"
-      v-if="curPaperOrTask.rejected && curPaperOrTask.isRejectedByLeader"
-    >
-      建议档位:
-    </h3>
-    <div class="action-grade-info" v-if="rights.gradeInfo && curLevel.name">
-      <h3 class="grade-info-name">{{ curLevel.name }}</h3>
-      <div class="grade-info-range">
-        <p>分数范围</p>
-        <p>
-          <span>{{ curLevel.minScore }}</span>
-          <span>~</span>
-          <span>{{ curLevel.maxScore }}</span>
-        </p>
-      </div>
-    </div>
-
-    <!-- 跳过 -->
-    <div
-      class="action-grade-pass"
-      v-if="rights.gradeList && IS_MARKER"
-      @click="toPass"
-    >
-      跳过
-    </div>
-
-    <!-- 评卷记录 -->
-    <div class="action-grade-history" v-if="rights.gradeHis">
-      <h3>评卷记录</h3>
-      <div class="grade-history-list">
-        <div
-          class="grade-history-item"
-          v-for="his in gradingHistory"
-          :key="his.id"
-        >
-          <p>{{ his.loginName }}</p>
-          <p>{{ his.value }}</p>
-        </div>
-      </div>
-    </div>
-
-    <!-- 查询 -->
-    <div class="action-search" v-if="rights.search">
-      <Select
-        class="search-select"
-        v-model="filter.codeType"
-        placeholder="密号类型"
-      >
-        <Option
-          v-for="item in codeTypes"
-          :key="item.key"
-          :value="item.key"
-          :label="item.val"
-        ></Option>
-      </Select>
-      <Input
-        class="search-input"
-        v-model.trim="filter.code"
-        placeholder="输入密号"
-        clearable
-      >
-      </Input>
-      <Button size="small" type="primary" class="search-btn" @click="searchCode"
-        >查询</Button
-      >
-    </div>
-  </div>
-</template>
-
-<script>
-import { markHistoryList } from "@/api";
-import { CODE_TYPE } from "@/constants/enumerate";
-// 三种情况:
-// 管理员(ADMIN),科组长(MARK_LEADER),评卷员(MARKER)
-// 管理员:查询,头部信息,评卷记录
-// 科组长:查询,头部信息,选择档位,评卷记录
-// 评卷员:头部信息,选择档位
-
-// MARK_LEADER / ADMIN: curPaperOrTask => paper
-// MARKER: curPaperOrTask => task
-//
-/*
-[paper template]
-{
-  "id": 165,
-  "sn": "029947536",
-  "examNumber": "1901040084",
-  "level": "A",
-  "score": null,
-  "redoLevel": null,
-  "updatedOn": 1591767742000,
-  "imgSrc": "",
-  "thumbSrc": "",
-  "markByLeader": false,
-  "markedLogic": true,
-  "areaCode": "2",
-  "inspectScore": null,
-  "inspectLevel": null,
-  "inspector": null,
-  "sheetSrc": null,
-  "stage": "LEVEL",
-  "test": 0,
-  "paperTest": 0,
-  "markResults": [],
-  "rejected": false,
-  "arbitrated": false,
-  "sample": false,
-  "tagged": false,
-  "missing": false,
-  "manual": false
-}
-[marktask template]
-{
-  "id": 511,
-  "sn": "4929446110",
-  "redoLevel": null,
-  "level": "A",
-  "score": null,
-  "result": "100",
-  "originLevel": null,
-  "markerId": 49,
-  "marker": "pj061001",
-  "updatedOn": 1594775592000,
-  "imgSrc": "",
-  "thumbSrc": "",
-  "markByLeader": true,
-  "oldRejected": false,
-  "paperId": 168,
-  "randomSeqNew": 9446110,
-  "randomSeq": null,
-  "rejected": false,
-  "sample": true
-}
-*/
-
-const initRights = {
-  search: false,
-  gradeInfo: false,
-  gradeList: false,
-  gradeHis: false
-};
-
-export default {
-  name: "grade-action",
-  props: {
-    curPaperOrTask: {
-      type: Object,
-      default() {
-        return {};
-      }
-    },
-    levels: {
-      type: Array,
-      default() {
-        return [];
-      }
-    },
-    paramsSet: {
-      type: Object,
-      default() {
-        return {};
-      }
-    }
-  },
-  data() {
-    return {
-      curUserRoleType: this.$ls.get("user", { role: "" }).role,
-      rights: {
-        ...initRights
-      },
-      roleRight: {
-        ADMIN: {
-          done: ["search", "gradeHis", "gradeInfo"],
-          reject: ["search", "gradeInfo", "gradeHis"],
-          arbitrate: ["search", "gradeHis"]
-        },
-        MARK_LEADER: {
-          undo: ["gradeList", "gradeInfo"],
-          done: ["gradeList", "gradeHis", "gradeInfo"],
-          reject: ["gradeList", "gradeInfo", "gradeHis"],
-          arbitrate: ["gradeList", "gradeHis"]
-        },
-        MARKER: {
-          done: ["gradeList", "gradeInfo"],
-          undo: ["gradeList"],
-          reject: ["gradeList", "gradeInfo"]
-        },
-        STANDARD: ["gradeInfo"]
-      },
-      filter: {
-        codeType: "examNumber",
-        code: ""
-      },
-      codeTypes: [],
-      stepDict: {
-        undo: "待评",
-        done: "已评",
-        reject: "打回",
-        arbitrate: "待仲裁",
-        sample: "标准卷"
-      },
-      stepType: "",
-      stepLabel: "",
-      gradingHistory: [],
-      curLevel: {},
-      setT: null,
-      btnClicked: false,
-      // 科组长权限
-      markLeaderOnlyRight: null
-    };
-  },
-  computed: {
-    IS_ADMIN() {
-      return this.curUserRoleType === "ADMIN";
-    },
-    IS_MARKER() {
-      return this.curUserRoleType === "MARKER";
-    },
-    IS_MARK_LEADER() {
-      return this.curUserRoleType === "MARK_LEADER";
-    }
-  },
-  watch: {
-    curPaperOrTask(val) {
-      this.rebuildRight();
-    }
-  },
-  mounted() {
-    this.markLeaderOnlyRight = this.$ls.get("user", {
-      markLeaderOnlyRight: null
-    }).markLeaderOnlyRight;
-
-    this.codeTypes = Object.entries(CODE_TYPE)
-      .map(([key, val]) => {
-        return {
-          key,
-          val
-        };
-      })
-      .filter(item => item.key !== "examNumber");
-    // .filter(item => this.IS_ADMIN || item.key !== "examNumber");
-    this.rebuildRight();
-  },
-  methods: {
-    getStepType() {
-      const info = this.curPaperOrTask;
-      if (info.sample) return "sample";
-      if (info.level) return "done";
-      if (info.arbitrated) return "arbitrate";
-      if (info.rejected) return "reject";
-      if (!info.rejected && !info.arbitrated && !info.level) return "undo";
-      return;
-    },
-    rebuildRight() {
-      let roleRights = [];
-      this.stepType = this.getStepType();
-      this.stepLabel = this.stepDict[this.stepType];
-      if (this.stepType === "sample") {
-        roleRights = this.roleRight.STANDARD;
-      } else {
-        roleRights = this.roleRight[this.curUserRoleType][this.stepType] || [];
-      }
-      this.rights = { ...initRights };
-      roleRights.map(key => {
-        this.rights[key] = true;
-      });
-      this.getCurLevel();
-      if (this.rights.gradeHis) {
-        this.getMarkHistory();
-      }
-      this.btnClicked = false;
-    },
-    getCurLevel() {
-      const levelName = this.curPaperOrTask.rejected
-        ? this.curPaperOrTask.redoLevel
-        : this.curPaperOrTask.level;
-      if (levelName) {
-        this.curLevel = this.levels.find(item => item.name === levelName);
-      } else {
-        this.curLevel = {};
-      }
-    },
-    async getMarkHistory() {
-      // 只有科组长和超管才会展示评卷记录
-      const data = await markHistoryList(this.curPaperOrTask.id, "LEVEL");
-      this.gradingHistory = data.map(item => {
-        let level = item.result || "未评";
-        if (this.stepType === "reject" && !item.result) {
-          level = `${level}(${item.originLevel})`;
-        }
-        return {
-          id: item.id,
-          markerId: item.markerId,
-          name: item.marker,
-          loginName: item.loginName,
-          value: level
-        };
-      });
-    },
-    selectLevel(level) {
-      if (this.IS_MARKER && this.curPaperOrTask.level === level.name) return;
-      if (this.btnClicked) return;
-      this.btnClicked = true;
-
-      if (this.IS_MARK_LEADER) {
-        this.setT = setTimeout(() => {
-          this.btnClicked = false;
-        }, 500);
-
-        this.$emit(
-          "on-leader-level",
-          {
-            paperIds: this.curPaperOrTask.id + "",
-            curLevel: this.curPaperOrTask.level,
-            selectedLevel: level.name,
-            markLeaderOnlyRight: this.markLeaderOnlyRight
-          },
-          this.gradingHistory.map(item => {
-            return {
-              id: item.markerId,
-              name: item.loginName
-            };
-          })
-        );
-        return;
-      }
-
-      this.$emit("on-select-level", level);
-    },
-    toPass() {
-      this.$emit("on-pass");
-    },
-    searchCode() {
-      if (!this.filter.code || !this.filter.codeType) {
-        this.$Message.error("请设置密号类型和密号!");
-        return;
-      }
-      this.$emit("on-code-search", this.filter);
-    }
-  },
-  beforeDestroy() {
-    if (this.setT) clearTimeout(this.setT);
-  }
-};
-</script>
+<template>
+  <div class="grade-action">
+    <!-- 头部信息 ------ -->
+    <!-- 试卷状态 -->
+    <!-- 状态:已评,待评,打回,仲裁 -->
+    <div class="action-paper-state" v-if="stepType === 'reject'">
+      <p class="paper-state-cont">
+        {{ curPaperOrTask.isRejectedByLeader ? "科组长打回" : "自动打回" }}
+      </p>
+      <p class="paper-state-intro">
+        <span v-if="curPaperOrTask.rejectedCount"
+          >共打回{{ curPaperOrTask.rejectedCount }}次</span
+        >
+      </p>
+    </div>
+    <div class="action-paper-state" v-else>
+      <p class="paper-state-cont">{{ stepLabel }}</p>
+    </div>
+
+    <!-- 试卷信息 -->
+    <div class="action-paper-info">
+      <!-- <p v-if="IS_ADMIN">
+        <span>试卷考号:</span><span>{{ curPaperOrTask.examNumber }}</span>
+      </p> -->
+      <p>
+        <span v-if="IS_MARKER">任务密号:</span>
+        <span v-else>试卷密号:</span>
+        <span>NO.{{ curPaperOrTask.sn }}</span>
+      </p>
+    </div>
+
+    <!-- 选择档位 -->
+    <h3
+      class="action-grade-info-title"
+      v-if="IS_MARK_LEADER && markLeaderOnlyRight && rights.gradeList"
+    >
+      当前操作:{{ markLeaderOnlyRight.name }}
+    </h3>
+    <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,
+              'is-active': keyInput == level.name
+            }
+          ]"
+          @click="selectLevel(level)"
+        >
+          <p>{{ level.name }}</p>
+          <p>{{ level.minScore }}~{{ level.maxScore }}</p>
+        </div>
+      </div>
+    </div>
+    <div v-if="ribbonSet.keyboardMark" class="action-grade-keyboard">
+      <div class="keyboard-input">{{ keyInput }}</div>
+      <div class="keyboard-clear" @click="clearKeyInput">
+        <Icon type="md-trash" />
+      </div>
+    </div>
+
+    <!-- 档位信息 -->
+    <!-- 已评(已评档位),打回(建议档位) -->
+    <h3
+      class="action-grade-info-title"
+      v-if="IS_MARKER && stepType === 'reject'"
+    >
+      <span>原分档档位:{{ curPaperOrTask.originLevel || "" }}</span>
+      <span
+        v-if="
+          paramsSet.autoCallbackShowDeviation &&
+            curPaperOrTask.deviationDirection &&
+            curPaperOrTask.deviationDirection !== '0'
+        "
+        :class="[
+          'grade-info-deviation',
+          {
+            'grade-info-deviation-error':
+              curPaperOrTask.deviationDirection * 1 > 0
+          }
+        ]"
+        >{{ curPaperOrTask.deviationDirection * 1 > 0 ? "偏高" : "偏低" }}</span
+      >
+    </h3>
+    <h3
+      class="action-grade-info-title"
+      v-if="curPaperOrTask.rejected && curPaperOrTask.isRejectedByLeader"
+    >
+      建议档位:
+    </h3>
+    <div class="action-grade-info" v-if="rights.gradeInfo && curLevel.name">
+      <h3 class="grade-info-name">{{ curLevel.name }}</h3>
+      <div class="grade-info-range">
+        <p>分数范围</p>
+        <p>
+          <span>{{ curLevel.minScore }}</span>
+          <span>~</span>
+          <span>{{ curLevel.maxScore }}</span>
+        </p>
+      </div>
+    </div>
+
+    <!-- 跳过 -->
+    <div
+      class="action-grade-pass"
+      v-if="rights.gradeList && IS_MARKER"
+      @click="toPass"
+    >
+      跳过
+    </div>
+
+    <!-- 评卷记录 -->
+    <div class="action-grade-history" v-if="rights.gradeHis">
+      <h3>评卷记录</h3>
+      <div class="grade-history-list">
+        <div
+          class="grade-history-item"
+          v-for="his in gradingHistory"
+          :key="his.id"
+        >
+          <p>{{ his.loginName }}</p>
+          <p>{{ his.value }}</p>
+        </div>
+      </div>
+    </div>
+
+    <!-- 查询 -->
+    <div class="action-search" v-if="rights.search">
+      <Select
+        class="search-select"
+        v-model="filter.codeType"
+        placeholder="密号类型"
+      >
+        <Option
+          v-for="item in codeTypes"
+          :key="item.key"
+          :value="item.key"
+          :label="item.val"
+        ></Option>
+      </Select>
+      <Input
+        class="search-input"
+        v-model.trim="filter.code"
+        placeholder="输入密号"
+        clearable
+      >
+      </Input>
+      <Button size="small" type="primary" class="search-btn" @click="searchCode"
+        >查询</Button
+      >
+    </div>
+  </div>
+</template>
+
+<script>
+import { markHistoryList } from "@/api";
+import { CODE_TYPE } from "@/constants/enumerate";
+import { mapState } from "vuex";
+
+// 三种情况:
+// 管理员(ADMIN),科组长(MARK_LEADER),评卷员(MARKER)
+// 管理员:查询,头部信息,评卷记录
+// 科组长:查询,头部信息,选择档位,评卷记录
+// 评卷员:头部信息,选择档位
+
+// MARK_LEADER / ADMIN: curPaperOrTask => paper
+// MARKER: curPaperOrTask => task
+//
+/*
+[paper template]
+{
+  "id": 165,
+  "sn": "029947536",
+  "examNumber": "1901040084",
+  "level": "A",
+  "score": null,
+  "redoLevel": null,
+  "updatedOn": 1591767742000,
+  "imgSrc": "",
+  "thumbSrc": "",
+  "markByLeader": false,
+  "markedLogic": true,
+  "areaCode": "2",
+  "inspectScore": null,
+  "inspectLevel": null,
+  "inspector": null,
+  "sheetSrc": null,
+  "stage": "LEVEL",
+  "test": 0,
+  "paperTest": 0,
+  "markResults": [],
+  "rejected": false,
+  "arbitrated": false,
+  "sample": false,
+  "tagged": false,
+  "missing": false,
+  "manual": false
+}
+[marktask template]
+{
+  "id": 511,
+  "sn": "4929446110",
+  "redoLevel": null,
+  "level": "A",
+  "score": null,
+  "result": "100",
+  "originLevel": null,
+  "markerId": 49,
+  "marker": "pj061001",
+  "updatedOn": 1594775592000,
+  "imgSrc": "",
+  "thumbSrc": "",
+  "markByLeader": true,
+  "oldRejected": false,
+  "paperId": 168,
+  "randomSeqNew": 9446110,
+  "randomSeq": null,
+  "rejected": false,
+  "sample": true
+}
+*/
+
+const initRights = {
+  search: false,
+  gradeInfo: false,
+  gradeList: false,
+  gradeHis: false
+};
+
+export default {
+  name: "grade-action",
+  props: {
+    curPaperOrTask: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    levels: {
+      type: Array,
+      default() {
+        return [];
+      }
+    },
+    paramsSet: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    // 是否处于
+    isCoarseLevel: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      curUserRoleType: this.$ls.get("user", { role: "" }).role,
+      rights: {
+        ...initRights
+      },
+      roleRight: {
+        ADMIN: {
+          done: ["search", "gradeHis", "gradeInfo"],
+          reject: ["search", "gradeInfo", "gradeHis"],
+          arbitrate: ["search", "gradeHis"]
+        },
+        MARK_LEADER: {
+          undo: ["gradeList", "gradeInfo"],
+          done: ["gradeList", "gradeHis", "gradeInfo"],
+          reject: ["gradeList", "gradeInfo", "gradeHis"],
+          arbitrate: ["gradeList", "gradeHis"]
+        },
+        MARKER: {
+          done: ["gradeList", "gradeInfo"],
+          undo: ["gradeList"],
+          reject: ["gradeList", "gradeInfo"]
+        },
+        STANDARD: ["gradeInfo"]
+      },
+      filter: {
+        codeType: "examNumber",
+        code: ""
+      },
+      codeTypes: [],
+      stepDict: {
+        undo: "待评",
+        done: "已评",
+        reject: "打回",
+        arbitrate: "待仲裁",
+        sample: "标准卷"
+      },
+      stepType: "",
+      stepLabel: "",
+      gradingHistory: [],
+      curLevel: {},
+      setT: null,
+      btnClicked: false,
+      keyInput: null,
+      // 科组长权限
+      markLeaderOnlyRight: null
+    };
+  },
+  computed: {
+    ...mapState("marker", ["ribbonSet"]),
+    IS_ADMIN() {
+      return this.curUserRoleType === "ADMIN";
+    },
+    IS_MARKER() {
+      return this.curUserRoleType === "MARKER";
+    },
+    IS_MARK_LEADER() {
+      return this.curUserRoleType === "MARK_LEADER";
+    }
+  },
+  watch: {
+    curPaperOrTask(val) {
+      this.rebuildRight();
+    },
+    "ribbonSet.keyboardMark": {
+      immediate: true,
+      handler(val) {
+        console.log(val);
+        if (val) {
+          document.addEventListener("keydown", this.keyEvent);
+        } else {
+          this.keyInput = null;
+          document.removeEventListener("keydown", this.keyEvent);
+        }
+      }
+    }
+  },
+  mounted() {
+    this.markLeaderOnlyRight = this.$ls.get("user", {
+      markLeaderOnlyRight: null
+    }).markLeaderOnlyRight;
+
+    this.codeTypes = Object.entries(CODE_TYPE)
+      .map(([key, val]) => {
+        return {
+          key,
+          val
+        };
+      })
+      .filter(item => item.key !== "examNumber");
+    // .filter(item => this.IS_ADMIN || item.key !== "examNumber");
+    this.rebuildRight();
+  },
+  methods: {
+    getStepType() {
+      const info = this.curPaperOrTask;
+      if (info.sample) return "sample";
+      if (info.level) return "done";
+      if (info.arbitrated) return "arbitrate";
+      if (info.rejected) return "reject";
+      if (!info.rejected && !info.arbitrated && !info.level) return "undo";
+      return;
+    },
+    rebuildRight() {
+      let roleRights = [];
+      this.stepType = this.getStepType();
+      this.stepLabel = this.stepDict[this.stepType];
+      if (this.stepType === "sample") {
+        roleRights = this.roleRight.STANDARD;
+      } else {
+        roleRights = this.roleRight[this.curUserRoleType][this.stepType] || [];
+      }
+      this.rights = { ...initRights };
+      roleRights.map(key => {
+        this.rights[key] = true;
+      });
+      this.getCurLevel();
+      if (this.rights.gradeHis) {
+        this.getMarkHistory();
+      }
+      this.btnClicked = false;
+    },
+    getCurLevel() {
+      const levelName = this.curPaperOrTask.rejected
+        ? this.curPaperOrTask.redoLevel
+        : this.curPaperOrTask.level;
+      if (levelName) {
+        this.curLevel = this.levels.find(item => item.name === levelName);
+      } else {
+        this.curLevel = {};
+      }
+    },
+    async getMarkHistory() {
+      // 只有科组长和超管才会展示评卷记录
+      const data = await markHistoryList(this.curPaperOrTask.id, "LEVEL");
+      this.gradingHistory = data.map(item => {
+        let level = item.result || "未评";
+        if (this.stepType === "reject" && !item.result) {
+          level = `${level}(${item.originLevel})`;
+        }
+        return {
+          id: item.id,
+          markerId: item.markerId,
+          name: item.marker,
+          loginName: item.loginName,
+          value: level
+        };
+      });
+    },
+    selectLevel(level) {
+      if (this.IS_MARKER && this.curPaperOrTask.level === level.name) return;
+      if (this.btnClicked) return;
+      this.btnClicked = true;
+
+      if (this.IS_MARK_LEADER) {
+        this.setT = setTimeout(() => {
+          this.btnClicked = false;
+        }, 500);
+
+        this.$emit(
+          "on-leader-level",
+          {
+            paperIds: this.curPaperOrTask.id + "",
+            curLevel: this.curPaperOrTask.level,
+            selectedLevel: level.name,
+            markLeaderOnlyRight: this.markLeaderOnlyRight
+          },
+          this.gradingHistory.map(item => {
+            return {
+              id: item.markerId,
+              name: item.loginName
+            };
+          })
+        );
+        return;
+      }
+
+      this.$emit("on-select-level", level);
+    },
+    toPass() {
+      this.$emit("on-pass");
+    },
+    searchCode() {
+      if (!this.filter.code || !this.filter.codeType) {
+        this.$Message.error("请设置密号类型和密号!");
+        return;
+      }
+      this.$emit("on-code-search", this.filter);
+    },
+    // keyboard submit
+    keyEvent(e) {
+      if (this.btnClicked) return;
+      // if (!this.ribbonSet.keyboardMark) return;
+      if (!e.altKey && !e.shiftKey && !e.ctrlKey) {
+        if (e.key === "F5") return;
+        this.$Message.destroy();
+
+        if (e.key === "Enter" && this.ribbonSet.needEnterSubmit) {
+          e.preventDefault();
+          this.toKeySubmit();
+          return;
+        }
+        const keyInput = e.key.toUpperCase();
+        if (this.getKeyInputLevel(keyInput)) {
+          e.preventDefault();
+          this.keyInput = keyInput;
+
+          if (!this.ribbonSet.needEnterSubmit) {
+            this.toKeySubmit();
+          }
+        } else {
+          this.$Message.error("按键无效");
+        }
+      }
+    },
+    getKeyInputLevel(key) {
+      return this.levels.find(item => item.name === key);
+    },
+    toKeySubmit() {
+      if (!this.keyInput) return;
+      const level = this.getKeyInputLevel(this.keyInput);
+      this.selectLevel(level);
+    },
+    clearKeyInput() {
+      this.keyInput = null;
+    }
+  },
+  beforeDestroy() {
+    if (this.setT) clearTimeout(this.setT);
+  }
+};
+</script>

+ 35 - 0
src/modules/grading/components/GradeRibbon.vue

@@ -0,0 +1,35 @@
+<template>
+  <div class="grade-ribbon">
+    <div class="ribbon-list">
+      <div class="ribbon-item" title="消息" @click="toNotice">
+        <Icon type="md-notifications" />
+      </div>
+      <div class="ribbon-item" title="设置" @click="toSet">
+        <Icon type="md-settings" />
+      </div>
+    </div>
+
+    <!-- RibbonSetDialog -->
+    <ribbon-set-dialog ref="RibbonSetDialog"></ribbon-set-dialog>
+  </div>
+</template>
+
+<script>
+import RibbonSetDialog from "./RibbonSetDialog";
+
+export default {
+  name: "grade-ribbon",
+  components: {
+    RibbonSetDialog
+  },
+  data() {
+    return {};
+  },
+  methods: {
+    toNotice() {},
+    toSet() {
+      this.$refs.RibbonSetDialog.open();
+    }
+  }
+};
+</script>

+ 66 - 0
src/modules/grading/components/RibbonSetDialog.vue

@@ -0,0 +1,66 @@
+<template>
+  <Modal
+    class="ribbon-set-dialog marker-modal"
+    v-model="modalIsShow"
+    title="设置"
+    :mask-closable="false"
+    @on-visible-change="visibleChange"
+  >
+    <Form
+      ref="modalFormComp"
+      class="ribbon-set-form"
+      :model="ribbonSetModal"
+      :label-width="120"
+    >
+      <FormItem label="启用键盘">
+        <i-switch v-model="ribbonSetModal.keyboardMark"></i-switch>
+      </FormItem>
+      <FormItem v-if="ribbonSetModal.keyboardMark" label="需要回车提交">
+        <i-switch v-model="ribbonSetModal.needEnterSubmit"></i-switch>
+      </FormItem>
+    </Form>
+
+    <div slot="footer">
+      <Button shape="circle" type="primary" @click="submit">确认</Button>
+      <Button shape="circle" @click="cancel">取消</Button>
+    </div>
+  </Modal>
+</template>
+
+<script>
+import { mapState, mapMutations } from "vuex";
+
+export default {
+  name: "ribbon-set-dialog",
+  data() {
+    return {
+      modalIsShow: false,
+      ribbonSetModal: {}
+    };
+  },
+  computed: {
+    ...mapState("marker", ["ribbonSet"])
+  },
+  methods: {
+    ...mapMutations("marker", ["setRibbonSet"]),
+    initData() {
+      this.ribbonSetModal = { ...this.ribbonSet };
+    },
+    visibleChange(visible) {
+      if (visible) {
+        this.initData();
+      }
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    submit() {
+      this.setRibbonSet(this.ribbonSetModal);
+      this.cancel();
+    }
+  }
+};
+</script>

+ 4 - 0
src/modules/grading/leader/LeaderGrading.vue

@@ -32,6 +32,7 @@
         ref="GradeAction"
         v-if="curPaper.id"
       ></grade-action>
+      <grade-ribbon ref="GradeRibbon"></grade-ribbon>
     </div>
     <!-- multiple grading action -->
     <div class="marker-action" v-show="multipleGradingList.length">
@@ -64,6 +65,7 @@
           </div>
         </div>
       </div>
+      <grade-ribbon ref="GradeRibbon"></grade-ribbon>
     </div>
 
     <div class="marker-body">
@@ -161,6 +163,7 @@ import LeaderStatistics from "./LeaderStatistics";
 import GradeAction from "../components/GradeAction";
 import SimpleImagePreview from "@/components/SimpleImagePreview";
 import ModifyLeaderGrading from "../components/ModifyLeaderGrading";
+import GradeRibbon from "../components/GradeRibbon";
 
 import {
   paperList,
@@ -184,6 +187,7 @@ export default {
     LeaderProgress,
     LeaderStatistics,
     GradeAction,
+    GradeRibbon,
     SimpleImagePreview,
     ModifyLeaderGrading
   },

+ 555 - 551
src/modules/grading/marker/MarkerGrading.vue

@@ -1,551 +1,555 @@
-<template>
-  <div class="marker-grading">
-    <marker-header
-      @area-change="areaChange"
-      @step-change="stepChange"
-      @page-set-change="pageSetChange"
-      @to-history="toHistory"
-      @to-standard="toStandard"
-      @to-statistics="toStatistics"
-    ></marker-header>
-
-    <div
-      :class="[
-        'marker-action',
-        'dark-mark',
-        { 'marker-action-fullscreen': isFullscreenMarking }
-      ]"
-      v-show="!multipleGradingList.length"
-    >
-      <grade-action
-        :cur-paper-or-task="curPaper"
-        :levels="levels"
-        :params-set="paramsSet"
-        :key="curPaper.key"
-        @on-select-level="gradeCurPaper"
-        @on-pass="passCurPaper"
-        ref="GradeAction"
-        v-if="curPaper.id"
-      ></grade-action>
-    </div>
-    <!-- multiple grading action -->
-    <div class="marker-action" v-show="multipleGradingList.length">
-      <div class="grade-action">
-        <div class="action-paper-state">
-          <p class="paper-state-cont">批量分档</p>
-        </div>
-        <div class="action-paper-info">
-          <p><span>任务密号:</span><span>--</span></p>
-        </div>
-        <div class="action-grade-list">
-          <div
-            class="action-grade-item"
-            v-for="(level, index) in levels"
-            :key="index"
-          >
-            <div
-              :class="[
-                'action-grade-item-content',
-                { 'action-item-content-disabled': multiplebtnClicked }
-              ]"
-              @click="multipleSelectLevel(level)"
-            >
-              <p>{{ level.name }}</p>
-              <p>{{ level.minScore }}~{{ level.maxScore }}</p>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <div class="marker-body">
-      <div :class="markerImageListClasses" v-if="papers.length">
-        <div
-          v-for="(paper, index) in papers"
-          :key="paper.key"
-          :class="[
-            'marker-image-item',
-            {
-              'marker-image-item-act': curPaperIndex === index
-            }
-          ]"
-        >
-          <div class="marker-image-content">
-            <marker-image-view
-              :data="paper"
-              @to-review="toReview(index)"
-              @to-select="selectMultiplePaper"
-            ></marker-image-view>
-          </div>
-        </div>
-      </div>
-      <div v-else class="marker-image-none">暂无数据</div>
-    </div>
-
-    <!-- MarkerHistory -->
-    <marker-history
-      :question-id="filter.questionId"
-      @on-paper-click="
-        (index, papers) => {
-          toViewCarouselPaper(index, papers, 'history');
-        }
-      "
-      ref="MarkerHistory"
-    ></marker-history>
-    <!-- MarkerStandard -->
-    <marker-standard
-      :question-id="filter.questionId"
-      :levels="levels"
-      @on-paper-click="
-        (index, papers) => {
-          toViewCarouselPaper(index, papers, 'sample');
-        }
-      "
-      ref="MarkerStandard"
-      v-if="levels.length && filter.questionId"
-    ></marker-standard>
-    <!-- MarkerStatistics -->
-    <marker-statistics ref="MarkerStatistics"></marker-statistics>
-    <!-- image-preview -->
-    <simple-image-preview
-      class="grading-operation-image-preview"
-      :cur-image="curPaper"
-      @on-prev="toPrevPaper"
-      @on-next="toNextPaper"
-      @on-close="isFullscreenMarking = false"
-      ref="SimpleImagePreview"
-    ></simple-image-preview>
-
-    <!-- carousel paper review -->
-    <simple-image-preview
-      class="grading-operation-image-preview"
-      :cur-image="curPaper"
-      @on-prev="toCarousePaper('prev')"
-      @on-next="toCarousePaper('next')"
-      @on-close="carouseImagePreviewClose"
-      ref="CarouselPapersPreview"
-    ></simple-image-preview>
-  </div>
-</template>
-
-<script>
-import { mapState, mapMutations } from "vuex";
-import MarkerHeader from "./MarkerHeader";
-import MarkerImageView from "./MarkerImageView";
-import MarkerHistory from "./MarkerHistory";
-import MarkerStandard from "./MarkerStandard";
-import MarkerStatistics from "./MarkerStatistics";
-import GradeAction from "../components/GradeAction";
-import SimpleImagePreview from "@/components/SimpleImagePreview";
-
-import {
-  markerTaskList,
-  markerLevelTotalStatData,
-  workLevelList,
-  paperSelectLevelOrScore,
-  paperSelectLevelBatch,
-  paperTaskPass,
-  getParamsSet
-} from "@/api";
-
-export default {
-  name: "marker-grading",
-  components: {
-    MarkerHeader,
-    MarkerImageView,
-    MarkerHistory,
-    MarkerStandard,
-    MarkerStatistics,
-    GradeAction,
-    SimpleImagePreview
-  },
-  data() {
-    return {
-      filter: {
-        markerId: this.$ls.get("user").id,
-        questionId: "",
-        sort: "randomSeq,asc",
-        stage: "LEVEL"
-      },
-      typeFilter: {
-        done: {
-          level: ""
-        },
-        undo: {},
-        reject: {
-          reject: true
-        }
-      },
-      workId: this.$route.params.workId,
-      subjectId: this.$route.params.subjectId,
-      subject: "",
-      workSubject: {},
-      curStandardGradeId: "",
-      levels: [],
-      papers: [],
-      curPaper: {},
-      curPaperIndex: 0,
-      // multiple grading
-      multiplebtnClicked: false,
-      multipleGradingList: [],
-      // carousel paper review,
-      carouselType: "",
-      carouselPapers: [],
-      curCarouselPaperIndex: 0,
-      isFullscreenMarking: false
-    };
-  },
-  computed: {
-    ...mapState("marker", ["paramsSet", "page", "steps", "curStep", "curArea"]),
-    markerImageListClasses() {
-      return ["marker-image-list", `marker-image-list-${this.page.size}`];
-    }
-  },
-  created() {
-    this.subject = this.subjectId.split("-")[1];
-    this.workSubject = {
-      workId: this.workId,
-      subject: this.subject
-    };
-    const curUserRoleType = this.$ls.get("user", { role: "" }).role;
-    this.setCurUserRoleType(curUserRoleType);
-    this.initData();
-  },
-  methods: {
-    ...mapMutations("marker", [
-      "setParamSet",
-      "setPage",
-      "setSteps",
-      "setCurArea",
-      "setCurStep",
-      "setCurUserRoleType",
-      "clearState"
-    ]),
-    async initData() {
-      await this.getParamsSetInfo();
-      await this.getWorkLevels();
-    },
-    async getParamsSetInfo() {
-      const data = await getParamsSet(this.workId);
-      this.setParamSet(data || {});
-    },
-    async getList() {
-      this.multipleGradingList = [];
-      const datas = {
-        ...this.filter,
-        ...this.typeFilter[this.curStep.type],
-        workId: this.workId,
-        page: this.page.current - 1,
-        size: this.page.size
-      };
-      if (this.curStep.type === "done") {
-        datas.level = this.curStep.name;
-        datas.sort = "updatedOn,desc";
-      }
-
-      const data = await markerTaskList(datas);
-      this.papers = data.data.map(paper => {
-        paper.key = this.$randomCode();
-        paper.title = `NO.${paper.sn}`;
-        paper.selected = false;
-        return paper;
-      });
-      this.setPage({
-        total: data.totalCount,
-        totalPage: data.pageCount
-      });
-    },
-    async toPage(page) {
-      this.setPage({
-        current: page
-      });
-      await this.getList();
-      this.selectPaper(this.curPaperIndex);
-    },
-    async getStepLevels() {
-      const data = await markerLevelTotalStatData(
-        this.filter.markerId,
-        this.filter.questionId
-      );
-      const undoIndex = data.findIndex(item => item.id === null);
-      let otherStep = [];
-      let undo = {
-        count: 0,
-        rejected: 0
-      };
-      if (undoIndex !== -1) {
-        undo = { ...data[undoIndex] };
-        data.splice(undoIndex, 1);
-      }
-
-      otherStep.push({
-        name: "待评",
-        count: undo.count,
-        type: "undo"
-      });
-      otherStep.push({
-        name: "打回",
-        count: undo.rejected,
-        type: "reject"
-      });
-      let levelStep = data.map(item => {
-        // 评卷员不展示kdpt
-        item.kdpt = null;
-        return {
-          ...item,
-          name: item.id,
-          type: "done"
-        };
-      });
-      this.setSteps({ levelStep, otherStep });
-
-      if (!this.curStep.name) {
-        let curStep = {};
-        if (undoIndex === -1) {
-          curStep = levelStep[0];
-        } else {
-          const firstStep = otherStep.find(item => item.count);
-          curStep = firstStep || levelStep[0];
-        }
-        this.setCurStep(curStep);
-      } else {
-        const curStep = [...levelStep, ...otherStep].find(
-          item => item.name === this.curStep.name
-        );
-        this.setCurStep(curStep);
-      }
-    },
-    updateStepLevel(curStep, curLevel, count) {
-      if (curStep.type === "done") {
-        const lpos = this.steps.levelStep.findIndex(
-          item => item.name === curStep.name
-        );
-        this.steps.levelStep[lpos].count -= count;
-      } else {
-        const opos = this.steps.otherStep.findIndex(
-          item => item.type === curStep.type
-        );
-        this.steps.otherStep[opos].count -= count;
-      }
-
-      const pos = this.steps.levelStep.findIndex(
-        item => item.name === curLevel
-      );
-      this.steps.levelStep[pos].count += count;
-
-      this.steps.levelStep.forEach(item => {
-        item.percent =
-          item.finalKdTotal && item.count
-            ? ((100 * item.count) / item.finalKdTotal).toFixed(3)
-            : 0;
-      });
-      this.setSteps(this.steps);
-    },
-    async getWorkLevels() {
-      const data = await workLevelList(this.workId);
-      this.levels = data.map(item => {
-        return {
-          id: item.id,
-          name: item.code,
-          minScore: item.minScore,
-          maxScore: item.maxScore
-        };
-      });
-    },
-    async pageSetChange() {
-      await this.getList();
-      this.selectPaper(this.curPaperIndex);
-    },
-    async stepChange(step) {
-      this.setCurStep(step);
-      this.setPage({ current: 1 });
-      this.isFullscreenMarking = false;
-      await this.getList();
-      this.getStepLevels();
-      if (this.papers.length) {
-        this.selectPaper(0);
-      } else {
-        this.curPaper = {};
-      }
-    },
-    async areaChange(curArea) {
-      this.setCurArea(curArea);
-      this.filter.questionId = curArea.id;
-      await this.getStepLevels();
-      this.toPage(1);
-    },
-    // selectMultiplePaper
-    selectMultiplePaper(paper) {
-      if (paper.sample) return;
-      const curPaper = this.papers.find(p => p.id === paper.id);
-      curPaper.selected = paper.selected;
-      this.multipleGradingList = this.papers.filter(paper => paper.selected);
-      console.log(this.multipleGradingList);
-    },
-    async multipleSelectLevel(level) {
-      if (!this.multipleGradingList.length) return;
-      if (this.multiplebtnClicked) return;
-      this.multiplebtnClicked = true;
-      const multipleGradingListCount = this.multipleGradingList.length;
-
-      let result = true;
-      await paperSelectLevelBatch(
-        this.multipleGradingList.map(item => item.id).join(), // is taskId
-        level.name,
-        "LEVEL"
-      ).catch(() => {
-        result = false;
-      });
-
-      this.multiplebtnClicked = false;
-      if (!result) return;
-
-      this.multipleGradingList = [];
-      // this.getStepLevels();
-      this.updateStepLevel(this.curStep, level.name, multipleGradingListCount);
-
-      // update paper list
-      if (
-        this.page.current > 1 &&
-        this.page.current === this.page.totalPage &&
-        this.papers.length === multipleGradingListCount
-      ) {
-        this.setPage({ current: this.page.current - 1 });
-      }
-
-      await this.getList();
-      this.selectPaper(this.curPaperIndex);
-    },
-    // paper view action
-    toReview(index) {
-      this.isFullscreenMarking = true;
-      this.multipleGradingList = [];
-      this.selectPaper(index);
-      this.$refs.SimpleImagePreview.open();
-    },
-    selectPaper(index) {
-      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] } : {};
-    },
-    async toPrevPaper() {
-      if (this.curPaperIndex === 0) {
-        if (this.page.current > 1) {
-          this.setPage({ current: this.page.current - 1 });
-          this.curPaperIndex = this.page.size - 1;
-          await this.getList();
-        } else {
-          this.$Message.warning("当前已经是第一条数据了");
-          return;
-        }
-      } else {
-        this.curPaperIndex--;
-      }
-
-      this.selectPaper(this.curPaperIndex);
-    },
-    async toNextPaper() {
-      if (this.curPaperIndex === this.papers.length - 1) {
-        if (this.page.current === this.page.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 toActionNextPaper() {
-      if (this.page.current > 1 && this.papers.length === 1) {
-        this.setPage({ current: this.page.current - 1 });
-        this.curPaperIndex = this.page.size;
-      }
-
-      await this.getList();
-      if (!this.papers.length) this.$refs.SimpleImagePreview.cancel();
-      this.selectPaper(this.curPaperIndex);
-    },
-    async gradeCurPaper(level) {
-      const paper = await paperSelectLevelOrScore(
-        this.curPaper.id, // is taskId
-        level.name,
-        "LEVEL"
-      );
-      if (!paper) return;
-      this.updateStepLevel(this.curStep, level.name, 1);
-      this.toActionNextPaper();
-    },
-    async passCurPaper() {
-      await paperTaskPass(this.curPaper.id);
-      this.toActionNextPaper();
-    },
-    // paper carousel
-    toViewCarouselPaper(paperIndex, papers, type) {
-      this.carouselType = type;
-      this.isFullscreenMarking = true;
-      this.carouselPapers = papers;
-      this.selectCarouselPaper(paperIndex);
-      this.$nextTick(() => {
-        this.$refs.CarouselPapersPreview.open();
-      });
-    },
-    selectCarouselPaper(index) {
-      this.curCarouselPaperIndex = index;
-      this.curPaper = { ...this.carouselPapers[index] };
-    },
-    toCarousePaper(type) {
-      // if (this.carouselType === "sample") {
-      //   this.toSampleCarousePaper(type);
-      //   return;
-      // }
-      if (type === "prev" && this.curCarouselPaperIndex > 0) {
-        this.curCarouselPaperIndex--;
-      } else if (
-        type === "next" &&
-        this.curCarouselPaperIndex < this.carouselPapers.length - 1
-      ) {
-        this.curCarouselPaperIndex++;
-      }
-      this.selectCarouselPaper(this.curCarouselPaperIndex);
-    },
-    toSampleCarousePaper(type) {
-      if (type === "prev") {
-        this.$refs.GradeStandardPaper.$refs.PaperCarousel.handleLeft();
-      } else if (type === "next") {
-        this.$refs.GradeStandardPaper.$refs.PaperCarousel.handleRight();
-      }
-    },
-    carouseImagePreviewClose() {
-      this.isFullscreenMarking = false;
-      this.carouselType = "";
-      this.selectPaper(this.curPaperIndex);
-    },
-    // header
-    toHistory() {
-      this.$refs.MarkerHistory.open();
-    },
-    toStandard() {
-      this.$refs.MarkerStandard.open();
-    },
-    async toStatistics() {
-      await this.getStepLevels();
-      this.$refs.MarkerStatistics.open();
-    }
-  },
-  beforeDestroy() {
-    this.clearState();
-  }
-};
-</script>
+<template>
+  <div class="marker-grading">
+    <marker-header
+      @area-change="areaChange"
+      @step-change="stepChange"
+      @page-set-change="pageSetChange"
+      @to-history="toHistory"
+      @to-standard="toStandard"
+      @to-statistics="toStatistics"
+    ></marker-header>
+
+    <div
+      :class="[
+        'marker-action',
+        'dark-mark',
+        { 'marker-action-fullscreen': isFullscreenMarking }
+      ]"
+      v-show="!multipleGradingList.length"
+    >
+      <grade-action
+        :cur-paper-or-task="curPaper"
+        :levels="levels"
+        :params-set="paramsSet"
+        :key="curPaper.key"
+        @on-select-level="gradeCurPaper"
+        @on-pass="passCurPaper"
+        ref="GradeAction"
+        v-if="curPaper.id"
+      ></grade-action>
+      <grade-ribbon ref="GradeRibbon"></grade-ribbon>
+    </div>
+    <!-- multiple grading action -->
+    <div class="marker-action" v-show="multipleGradingList.length">
+      <div class="grade-action">
+        <div class="action-paper-state">
+          <p class="paper-state-cont">批量分档</p>
+        </div>
+        <div class="action-paper-info">
+          <p><span>任务密号:</span><span>--</span></p>
+        </div>
+        <div class="action-grade-list">
+          <div
+            class="action-grade-item"
+            v-for="(level, index) in levels"
+            :key="index"
+          >
+            <div
+              :class="[
+                'action-grade-item-content',
+                { 'action-item-content-disabled': multiplebtnClicked }
+              ]"
+              @click="multipleSelectLevel(level)"
+            >
+              <p>{{ level.name }}</p>
+              <p>{{ level.minScore }}~{{ level.maxScore }}</p>
+            </div>
+          </div>
+        </div>
+      </div>
+      <grade-ribbon ref="GradeRibbon"></grade-ribbon>
+    </div>
+
+    <div class="marker-body">
+      <div :class="markerImageListClasses" v-if="papers.length">
+        <div
+          v-for="(paper, index) in papers"
+          :key="paper.key"
+          :class="[
+            'marker-image-item',
+            {
+              'marker-image-item-act': curPaperIndex === index
+            }
+          ]"
+        >
+          <div class="marker-image-content">
+            <marker-image-view
+              :data="paper"
+              @to-review="toReview(index)"
+              @to-select="selectMultiplePaper"
+            ></marker-image-view>
+          </div>
+        </div>
+      </div>
+      <div v-else class="marker-image-none">暂无数据</div>
+    </div>
+
+    <!-- MarkerHistory -->
+    <marker-history
+      :question-id="filter.questionId"
+      @on-paper-click="
+        (index, papers) => {
+          toViewCarouselPaper(index, papers, 'history');
+        }
+      "
+      ref="MarkerHistory"
+    ></marker-history>
+    <!-- MarkerStandard -->
+    <marker-standard
+      :question-id="filter.questionId"
+      :levels="levels"
+      @on-paper-click="
+        (index, papers) => {
+          toViewCarouselPaper(index, papers, 'sample');
+        }
+      "
+      ref="MarkerStandard"
+      v-if="levels.length && filter.questionId"
+    ></marker-standard>
+    <!-- MarkerStatistics -->
+    <marker-statistics ref="MarkerStatistics"></marker-statistics>
+    <!-- image-preview -->
+    <simple-image-preview
+      class="grading-operation-image-preview"
+      :cur-image="curPaper"
+      @on-prev="toPrevPaper"
+      @on-next="toNextPaper"
+      @on-close="isFullscreenMarking = false"
+      ref="SimpleImagePreview"
+    ></simple-image-preview>
+
+    <!-- carousel paper review -->
+    <simple-image-preview
+      class="grading-operation-image-preview"
+      :cur-image="curPaper"
+      @on-prev="toCarousePaper('prev')"
+      @on-next="toCarousePaper('next')"
+      @on-close="carouseImagePreviewClose"
+      ref="CarouselPapersPreview"
+    ></simple-image-preview>
+  </div>
+</template>
+
+<script>
+import { mapState, mapMutations } from "vuex";
+import MarkerHeader from "./MarkerHeader";
+import MarkerImageView from "./MarkerImageView";
+import MarkerHistory from "./MarkerHistory";
+import MarkerStandard from "./MarkerStandard";
+import MarkerStatistics from "./MarkerStatistics";
+import GradeAction from "../components/GradeAction";
+import SimpleImagePreview from "@/components/SimpleImagePreview";
+import GradeRibbon from "../components/GradeRibbon";
+
+import {
+  markerTaskList,
+  markerLevelTotalStatData,
+  workLevelList,
+  paperSelectLevelOrScore,
+  paperSelectLevelBatch,
+  paperTaskPass,
+  getParamsSet
+} from "@/api";
+
+export default {
+  name: "marker-grading",
+  components: {
+    MarkerHeader,
+    MarkerImageView,
+    MarkerHistory,
+    MarkerStandard,
+    MarkerStatistics,
+    GradeAction,
+    GradeRibbon,
+    SimpleImagePreview
+  },
+  data() {
+    return {
+      filter: {
+        markerId: this.$ls.get("user").id,
+        questionId: "",
+        sort: "randomSeq,asc",
+        stage: "LEVEL"
+      },
+      typeFilter: {
+        done: {
+          level: ""
+        },
+        undo: {},
+        reject: {
+          reject: true
+        }
+      },
+      workId: this.$route.params.workId,
+      subjectId: this.$route.params.subjectId,
+      subject: "",
+      workSubject: {},
+      curStandardGradeId: "",
+      levels: [],
+      papers: [],
+      curPaper: {},
+      curPaperIndex: 0,
+      // multiple grading
+      multiplebtnClicked: false,
+      multipleGradingList: [],
+      // carousel paper review,
+      carouselType: "",
+      carouselPapers: [],
+      curCarouselPaperIndex: 0,
+      isFullscreenMarking: false
+    };
+  },
+  computed: {
+    ...mapState("marker", ["paramsSet", "page", "steps", "curStep", "curArea"]),
+    markerImageListClasses() {
+      return ["marker-image-list", `marker-image-list-${this.page.size}`];
+    }
+  },
+  created() {
+    this.subject = this.subjectId.split("-")[1];
+    this.workSubject = {
+      workId: this.workId,
+      subject: this.subject
+    };
+    const curUserRoleType = this.$ls.get("user", { role: "" }).role;
+    this.setCurUserRoleType(curUserRoleType);
+    this.initData();
+  },
+  methods: {
+    ...mapMutations("marker", [
+      "setParamSet",
+      "setPage",
+      "setSteps",
+      "setCurArea",
+      "setCurStep",
+      "setCurUserRoleType",
+      "clearState"
+    ]),
+    async initData() {
+      await this.getParamsSetInfo();
+      await this.getWorkLevels();
+    },
+    async getParamsSetInfo() {
+      const data = await getParamsSet(this.workId);
+      this.setParamSet(data || {});
+    },
+    async getList() {
+      this.multipleGradingList = [];
+      const datas = {
+        ...this.filter,
+        ...this.typeFilter[this.curStep.type],
+        workId: this.workId,
+        page: this.page.current - 1,
+        size: this.page.size
+      };
+      if (this.curStep.type === "done") {
+        datas.level = this.curStep.name;
+        datas.sort = "updatedOn,desc";
+      }
+
+      const data = await markerTaskList(datas);
+      this.papers = data.data.map(paper => {
+        paper.key = this.$randomCode();
+        paper.title = `NO.${paper.sn}`;
+        paper.selected = false;
+        return paper;
+      });
+      this.setPage({
+        total: data.totalCount,
+        totalPage: data.pageCount
+      });
+    },
+    async toPage(page) {
+      this.setPage({
+        current: page
+      });
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async getStepLevels() {
+      const data = await markerLevelTotalStatData(
+        this.filter.markerId,
+        this.filter.questionId
+      );
+      const undoIndex = data.findIndex(item => item.id === null);
+      let otherStep = [];
+      let undo = {
+        count: 0,
+        rejected: 0
+      };
+      if (undoIndex !== -1) {
+        undo = { ...data[undoIndex] };
+        data.splice(undoIndex, 1);
+      }
+
+      otherStep.push({
+        name: "待评",
+        count: undo.count,
+        type: "undo"
+      });
+      otherStep.push({
+        name: "打回",
+        count: undo.rejected,
+        type: "reject"
+      });
+      let levelStep = data.map(item => {
+        // 评卷员不展示kdpt
+        item.kdpt = null;
+        return {
+          ...item,
+          name: item.id,
+          type: "done"
+        };
+      });
+      this.setSteps({ levelStep, otherStep });
+
+      if (!this.curStep.name) {
+        let curStep = {};
+        if (undoIndex === -1) {
+          curStep = levelStep[0];
+        } else {
+          const firstStep = otherStep.find(item => item.count);
+          curStep = firstStep || levelStep[0];
+        }
+        this.setCurStep(curStep);
+      } else {
+        const curStep = [...levelStep, ...otherStep].find(
+          item => item.name === this.curStep.name
+        );
+        this.setCurStep(curStep);
+      }
+    },
+    updateStepLevel(curStep, curLevel, count) {
+      if (curStep.type === "done") {
+        const lpos = this.steps.levelStep.findIndex(
+          item => item.name === curStep.name
+        );
+        this.steps.levelStep[lpos].count -= count;
+      } else {
+        const opos = this.steps.otherStep.findIndex(
+          item => item.type === curStep.type
+        );
+        this.steps.otherStep[opos].count -= count;
+      }
+
+      const pos = this.steps.levelStep.findIndex(
+        item => item.name === curLevel
+      );
+      this.steps.levelStep[pos].count += count;
+
+      this.steps.levelStep.forEach(item => {
+        item.percent =
+          item.finalKdTotal && item.count
+            ? ((100 * item.count) / item.finalKdTotal).toFixed(3)
+            : 0;
+      });
+      this.setSteps(this.steps);
+    },
+    async getWorkLevels() {
+      const data = await workLevelList(this.workId);
+      this.levels = data.map(item => {
+        return {
+          id: item.id,
+          name: item.code,
+          minScore: item.minScore,
+          maxScore: item.maxScore
+        };
+      });
+    },
+    async pageSetChange() {
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async stepChange(step) {
+      this.setCurStep(step);
+      this.setPage({ current: 1 });
+      this.isFullscreenMarking = false;
+      await this.getList();
+      this.getStepLevels();
+      if (this.papers.length) {
+        this.selectPaper(0);
+      } else {
+        this.curPaper = {};
+      }
+    },
+    async areaChange(curArea) {
+      this.setCurArea(curArea);
+      this.filter.questionId = curArea.id;
+      await this.getStepLevels();
+      this.toPage(1);
+    },
+    // selectMultiplePaper
+    selectMultiplePaper(paper) {
+      if (paper.sample) return;
+      const curPaper = this.papers.find(p => p.id === paper.id);
+      curPaper.selected = paper.selected;
+      this.multipleGradingList = this.papers.filter(paper => paper.selected);
+      console.log(this.multipleGradingList);
+    },
+    async multipleSelectLevel(level) {
+      if (!this.multipleGradingList.length) return;
+      if (this.multiplebtnClicked) return;
+      this.multiplebtnClicked = true;
+      const multipleGradingListCount = this.multipleGradingList.length;
+
+      let result = true;
+      await paperSelectLevelBatch(
+        this.multipleGradingList.map(item => item.id).join(), // is taskId
+        level.name,
+        "LEVEL"
+      ).catch(() => {
+        result = false;
+      });
+
+      this.multiplebtnClicked = false;
+      if (!result) return;
+
+      this.multipleGradingList = [];
+      // this.getStepLevels();
+      this.updateStepLevel(this.curStep, level.name, multipleGradingListCount);
+
+      // update paper list
+      if (
+        this.page.current > 1 &&
+        this.page.current === this.page.totalPage &&
+        this.papers.length === multipleGradingListCount
+      ) {
+        this.setPage({ current: this.page.current - 1 });
+      }
+
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+    },
+    // paper view action
+    toReview(index) {
+      this.isFullscreenMarking = true;
+      this.multipleGradingList = [];
+      this.selectPaper(index);
+      this.$refs.SimpleImagePreview.open();
+    },
+    selectPaper(index) {
+      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] } : {};
+    },
+    async toPrevPaper() {
+      if (this.curPaperIndex === 0) {
+        if (this.page.current > 1) {
+          this.setPage({ current: this.page.current - 1 });
+          this.curPaperIndex = this.page.size - 1;
+          await this.getList();
+        } else {
+          this.$Message.warning("当前已经是第一条数据了");
+          return;
+        }
+      } else {
+        this.curPaperIndex--;
+      }
+
+      this.selectPaper(this.curPaperIndex);
+    },
+    async toNextPaper() {
+      if (this.curPaperIndex === this.papers.length - 1) {
+        if (this.page.current === this.page.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 toActionNextPaper() {
+      if (this.page.current > 1 && this.papers.length === 1) {
+        this.setPage({ current: this.page.current - 1 });
+        this.curPaperIndex = this.page.size;
+      }
+
+      await this.getList();
+      if (!this.papers.length) this.$refs.SimpleImagePreview.cancel();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async gradeCurPaper(level) {
+      const paper = await paperSelectLevelOrScore(
+        this.curPaper.id, // is taskId
+        level.name,
+        "LEVEL"
+      );
+      if (!paper) return;
+      this.updateStepLevel(this.curStep, level.name, 1);
+      this.toActionNextPaper();
+    },
+    async passCurPaper() {
+      await paperTaskPass(this.curPaper.id);
+      this.toActionNextPaper();
+    },
+    // paper carousel
+    toViewCarouselPaper(paperIndex, papers, type) {
+      this.carouselType = type;
+      this.isFullscreenMarking = true;
+      this.carouselPapers = papers;
+      this.selectCarouselPaper(paperIndex);
+      this.$nextTick(() => {
+        this.$refs.CarouselPapersPreview.open();
+      });
+    },
+    selectCarouselPaper(index) {
+      this.curCarouselPaperIndex = index;
+      this.curPaper = { ...this.carouselPapers[index] };
+    },
+    toCarousePaper(type) {
+      // if (this.carouselType === "sample") {
+      //   this.toSampleCarousePaper(type);
+      //   return;
+      // }
+      if (type === "prev" && this.curCarouselPaperIndex > 0) {
+        this.curCarouselPaperIndex--;
+      } else if (
+        type === "next" &&
+        this.curCarouselPaperIndex < this.carouselPapers.length - 1
+      ) {
+        this.curCarouselPaperIndex++;
+      }
+      this.selectCarouselPaper(this.curCarouselPaperIndex);
+    },
+    toSampleCarousePaper(type) {
+      if (type === "prev") {
+        this.$refs.GradeStandardPaper.$refs.PaperCarousel.handleLeft();
+      } else if (type === "next") {
+        this.$refs.GradeStandardPaper.$refs.PaperCarousel.handleRight();
+      }
+    },
+    carouseImagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.carouselType = "";
+      this.selectPaper(this.curPaperIndex);
+    },
+    // header
+    toHistory() {
+      this.$refs.MarkerHistory.open();
+    },
+    toStandard() {
+      this.$refs.MarkerStandard.open();
+    },
+    async toStatistics() {
+      await this.getStepLevels();
+      this.$refs.MarkerStatistics.open();
+    }
+  },
+  beforeDestroy() {
+    this.clearState();
+  }
+};
+</script>

+ 77 - 67
src/modules/grading/marker/store.js

@@ -1,67 +1,77 @@
-const state = {
-  paramsSet: {},
-  page: {
-    current: 1,
-    size: 12,
-    total: 0,
-    totalPage: 1
-  },
-  steps: {},
-  curStep: { name: "", count: 0 },
-  areas: [],
-  curArea: {},
-  curSubject: {},
-  curUserRoleType: "",
-  IS_MARKER: false,
-  IS_MARK_LEADER: false
-};
-const mutations = {
-  setParamSet(state, paramsSet) {
-    state.paramsSet = paramsSet;
-  },
-  setPage(state, page) {
-    state.page = Object.assign({}, state.page, page);
-  },
-  setSteps(state, steps) {
-    state.steps = steps;
-  },
-  setCurStep(state, curStep) {
-    state.curStep = curStep;
-  },
-  setAreas(state, areas) {
-    state.areas = areas;
-  },
-  setCurArea(state, curArea) {
-    state.curArea = curArea;
-  },
-  setCurSubject(state, curSubject) {
-    state.curSubject = curSubject;
-  },
-  setCurUserRoleType(state, curUserRoleType) {
-    state.curUserRoleType = curUserRoleType;
-    state.IS_MARKER = curUserRoleType === "MARKER";
-    state.IS_MARK_LEADER = curUserRoleType === "MARK_LEADER";
-  },
-  clearState(state) {
-    state.paramsSet = {};
-    state.page = {
-      current: 1,
-      size: 12,
-      total: 0,
-      totalPage: 1
-    };
-    state.steps = {};
-    state.curStep = { name: "", count: 0 };
-    state.curArea = {};
-    state.curSubject = {};
-    state.curUserRoleType = "";
-    state.IS_MARKER = false;
-    state.IS_MARK_LEADER = false;
-  }
-};
-
-export default {
-  namespaced: true,
-  state,
-  mutations
-};
+let ribbonSet = window.localStorage.getItem("ribbonSet");
+ribbonSet = ribbonSet
+  ? JSON.parse(ribbonSet)
+  : { keyboardMark: false, needEnterSubmit: true };
+
+const state = {
+  paramsSet: {},
+  page: {
+    current: 1,
+    size: 12,
+    total: 0,
+    totalPage: 1
+  },
+  steps: {},
+  curStep: { name: "", count: 0 },
+  areas: [],
+  curArea: {},
+  curSubject: {},
+  ribbonSet,
+  curUserRoleType: "",
+  IS_MARKER: false,
+  IS_MARK_LEADER: false
+};
+const mutations = {
+  setParamSet(state, paramsSet) {
+    state.paramsSet = paramsSet;
+  },
+  setPage(state, page) {
+    state.page = Object.assign({}, state.page, page);
+  },
+  setSteps(state, steps) {
+    state.steps = steps;
+  },
+  setCurStep(state, curStep) {
+    state.curStep = curStep;
+  },
+  setAreas(state, areas) {
+    state.areas = areas;
+  },
+  setCurArea(state, curArea) {
+    state.curArea = curArea;
+  },
+  setCurSubject(state, curSubject) {
+    state.curSubject = curSubject;
+  },
+  setCurUserRoleType(state, curUserRoleType) {
+    state.curUserRoleType = curUserRoleType;
+    state.IS_MARKER = curUserRoleType === "MARKER";
+    state.IS_MARK_LEADER = curUserRoleType === "MARK_LEADER";
+  },
+  setRibbonSet(state, ribbonSet) {
+    state.ribbonSet = ribbonSet;
+    window.localStorage.setItem("ribbonSet", JSON.stringify(ribbonSet));
+  },
+  clearState(state) {
+    state.paramsSet = {};
+    state.page = {
+      current: 1,
+      size: 12,
+      total: 0,
+      totalPage: 1
+    };
+    state.steps = {};
+    state.curStep = { name: "", count: 0 };
+    state.curArea = {};
+    state.curSubject = {};
+    state.curUserRoleType = "";
+    state.IS_MARKER = false;
+    state.IS_MARK_LEADER = false;
+  }
+};
+
+export default {
+  namespaced: true,
+  state,
+  mutations
+};

+ 521 - 456
src/modules/mark/components/MarkAction.vue

@@ -1,456 +1,521 @@
-<template>
-  <div class="mark-action grade-action">
-    <!-- 头部信息 ------ -->
-    <!-- 试卷状态 -->
-    <!-- 状态:已评,待评,改档,改档打分 -->
-    <div class="action-paper-state">
-      <p class="paper-state-cont">{{ stepLabel }}</p>
-    </div>
-    <!-- 试卷信息 -->
-    <div class="action-paper-info">
-      <!-- <p v-if="IS_ADMIN">
-        <span>试卷考号:</span><span>{{ curPaperOrTask.examNumber }}</span>
-      </p> -->
-      <p>
-        <span v-if="IS_MARKER">任务密号:</span>
-        <span v-else>试卷密号:</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 v-if="IS_MARKER">建议档位:</span>
-        <span v-else>申请档位:</span>
-        <span>{{ curPaperOrTask.redoLevel }}</span>
-      </p>
-    </div>
-    <div
-      :class="[
-        'action-grade-change-status',
-        { 'action-grade-change-status-error': curPaperOrTask.auditStatus === 0 }
-      ]"
-      v-if="rights.gradeChange && IS_ADMIN"
-    >
-      <p>{{ curPaperOrTask.auditStatus === 1 ? "同意改档" : "不同意改档" }}</p>
-    </div>
-
-    <!-- 档位信息 -->
-    <!-- 已评/待评(已评档位),改档打分(已评档位) -->
-    <div class="action-grade-info" v-if="rights.gradeInfo">
-      <h3 class="grade-info-name">
-        {{ curPaperLevel }}
-      </h3>
-      <!-- <div class="grade-info-range">
-        <p>分数范围</p>
-        <p>
-          <span>{{ curLevel.minScore }}</span>
-          <span>~</span>
-          <span>{{ curLevel.maxScore }}</span>
-        </p>
-      </div> -->
-    </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-mark-list" v-if="rights.levelList">
-      <div
-        class="action-mark-item"
-        v-for="(score, index) in scores"
-        :key="index"
-      >
-        <div
-          :class="[
-            'action-mark-item-content',
-            { 'action-item-content-disabled': btnClicked }
-          ]"
-          @click="selectScore(score)"
-        >
-          <p>{{ score }}</p>
-        </div>
-      </div>
-    </div>
-    <div class="action-grade-pass" v-if="rights.levelList" @click="toPass">
-      跳过
-    </div>
-    <!-- mark confirm grade change -->
-    <div
-      class="action-grade-change-confirm"
-      v-if="IS_MARKER && stepType === 'shift'"
-    >
-      <Button type="primary" @click="gradeChangeConfirm">确认改档</Button>
-    </div>
-
-    <!-- 评卷记录 -->
-    <div class="action-grade-history" v-if="rights.markHis">
-      <h3>评卷记录</h3>
-      <div class="grade-history-list">
-        <div
-          class="grade-history-item"
-          v-for="(his, hindex) in gradingHistory"
-          :key="hindex"
-        >
-          <p>{{ his.loginName }}</p>
-          <p>{{ his.value }}</p>
-        </div>
-      </div>
-    </div>
-    <!-- 查询 -->
-    <div class="action-search" v-if="rights.search">
-      <Select
-        class="search-select"
-        v-model="filter.codeType"
-        placeholder="密号类型"
-      >
-        <Option
-          v-for="item in codeTypes"
-          :key="item.key"
-          :value="item.key"
-          :label="item.val"
-        ></Option>
-      </Select>
-      <Input
-        class="search-input"
-        v-model.trim="filter.code"
-        placeholder="输入密号"
-        clearable
-      >
-      </Input>
-      <Button size="small" type="primary" class="search-btn" @click="searchCode"
-        >查询</Button
-      >
-    </div>
-    <!-- 改档处理状态查询 -->
-    <div class="action-search" v-if="rights.gradeChangeSearch">
-      <Select
-        class="search-input"
-        v-model="applyChangeLevelStatus"
-        placeholder="类型"
-      >
-        <Option
-          v-for="(val, key) in CHANGE_LEVEL_STATUS"
-          :key="key"
-          :value="key * 1"
-          :label="val"
-        ></Option>
-      </Select>
-      <Button
-        size="small"
-        type="primary"
-        class="search-btn"
-        @click="searchGradeChange"
-        >查询</Button
-      >
-    </div>
-  </div>
-</template>
-
-<script>
-import { markHistoryList } from "@/api";
-import { CODE_TYPE, CHANGE_LEVEL_STATUS } from "@/constants/enumerate";
-// 三种情况:
-// 管理员(ADMIN),科组长(MARK_LEADER),评卷员(MARKER)
-// 管理员:查询,头部信息,评卷记录
-// 科组长:查询,头部信息,选择档位,评卷记录
-// 评卷员:头部信息,选择分数
-/*
-[paper template]
-{
-  "id": 42,
-  "sn": "5314987744",
-  "redoLevel": null,
-  "level": "B",
-  "score": null,
-  "result": "88",
-  "originLevel": null,
-  "markerId": 52,
-  "marker": "zj-pj-01",
-  "updatedOn": 1595812145000,
-  "imgSrc": "http://192.168.10.145:9000/images/34/SC/1/1901130046.jpg?random=f5549bb0-ba58-4cd3-a88e-0559be4e06e5",
-  "thumbSrc": "http://192.168.10.145:9000/thumbs/34/SC/1/1901130046.jpg?random=e7f880b8-4cb6-4963-8e66-532f0f8bdeb0",
-  "markByLeader": false,
-  "oldRejected": false,
-  "paperId": 116,
-  "randomSeqNew": 4987744,
-  "randomSeq": null,
-  "serialNumber": "B1",
-  "displayNumber": true,
-  "shift": false,
-  "shiftScore": false,
-  "rejected": false,
-  "sample": false
-}
-[marktask template]
-{
-  "id": 38,
-  "sn": "5314266469",
-  "redoLevel": null,
-  "level": "A",
-  "score": null,
-  "result": "96",
-  "originLevel": null,
-  "markerId": 52,
-  "marker": "zj-pj-01",
-  "updatedOn": 1595812012000,
-  "imgSrc": "http://192.168.10.145:9000/images/34/SC/1/1901130043.jpg?random=bffc061c-7a80-42a4-ad56-36ec6eba0d45",
-  "thumbSrc": "http://192.168.10.145:9000/thumbs/34/SC/1/1901130043.jpg?random=da743f9d-8d46-4499-bb6f-b9c26e003ba2",
-  "markByLeader": true,
-  "oldRejected": false,
-  "paperId": 113,
-  "randomSeqNew": 4266469,
-  "randomSeq": null,
-  "serialNumber": "A1",
-  "displayNumber": true,
-  "shift": false,
-  "shiftScore": false,
-  "rejected": false,
-  "sample": true
-}
-*/
-
-const initRights = {
-  search: false,
-  gradeChangeSearch: false,
-  gradeChange: false,
-  gradeInfo: false,
-  markInfo: false,
-  gradeList: false,
-  levelList: false,
-  markHis: false
-};
-
-export default {
-  name: "mark-action",
-  props: {
-    curPaperOrTask: {
-      type: Object,
-      default() {
-        return {};
-      }
-    },
-    levels: {
-      type: Array,
-      default() {
-        return [];
-      }
-    }
-  },
-  data() {
-    return {
-      curUserRoleType: this.$ls.get("user", { role: "" }).role,
-      rights: {
-        ...initRights
-      },
-      roleRight: {
-        ADMIN: {
-          done: ["search", "markHis", "gradeInfo", "markInfo"],
-          shift: ["search", "gradeChangeSearch", "gradeChange"]
-        },
-        MARK_LEADER: {
-          undo: ["gradeList", "gradeInfo", "markInfo"],
-          done: ["gradeList", "markHis", "gradeInfo", "markInfo"],
-          shift: ["gradeList", "gradeChange"]
-        },
-        MARKER: {
-          done: ["levelList", "gradeInfo", "markInfo"],
-          undo: ["levelList", "gradeInfo"],
-          shift: ["gradeChange"],
-          shiftScore: ["levelList", "gradeInfo"]
-        }
-      },
-      filter: {
-        codeType: "examNumber",
-        code: ""
-      },
-      codeTypes: [],
-      CHANGE_LEVEL_STATUS,
-      applyChangeLevelStatus: null,
-      stepDict: {
-        undo: "待评",
-        done: "已评",
-        shift: "改档",
-        shiftScore: "改档打分"
-      },
-      stepType: "",
-      stepLabel: "",
-      curPaperLevel: "",
-      curPaperScore: "",
-      scores: [],
-      gradingHistory: [],
-      curLevel: {},
-      setT: null,
-      btnClicked: false
-    };
-  },
-  computed: {
-    IS_ADMIN() {
-      return this.curUserRoleType === "ADMIN";
-    },
-    IS_MARKER() {
-      return this.curUserRoleType === "MARKER";
-    },
-    IS_MARK_LEADER() {
-      return this.curUserRoleType === "MARK_LEADER";
-    }
-  },
-  watch: {
-    curPaperOrTask(val) {
-      this.rebuildRight();
-    }
-  },
-  mounted() {
-    this.codeTypes = Object.entries(CODE_TYPE)
-      .map(([key, val]) => {
-        return {
-          key,
-          val
-        };
-      })
-      .filter(item => item.key !== "examNumber");
-    // .filter(item => this.IS_ADMIN || item.key !== "examNumber");
-    this.rebuildRight();
-  },
-  methods: {
-    getStepType() {
-      const paper = this.curPaperOrTask;
-      if (paper.shift && paper.shiftScore && !paper.level && !paper.result)
-        return "shift";
-      if (!paper.shift && paper.shiftScore && !paper.result)
-        return "shiftScore";
-      if (this.IS_MARKER) {
-        if (!paper.result) return "undo";
-        if (paper.result) return "done";
-      } else {
-        if (paper.score !== null) return "done";
-        if (paper.score === null) return "undo";
-      }
-    },
-    rebuildRight() {
-      const curPaperScore = this.IS_MARKER
-        ? this.curPaperOrTask.result
-        : this.curPaperOrTask.score;
-      this.curPaperScore = curPaperScore !== null ? curPaperScore + "" : "";
-      this.stepType = this.getStepType();
-      this.stepLabel = this.stepDict[this.stepType];
-      this.rights = { ...initRights };
-      const roleRights =
-        this.roleRight[this.curUserRoleType][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.curPaperOrTask["displayNumber"] && this.stepType !== "shiftScore"
-            ? this.curPaperOrTask["serialNumber"]
-            : this.curLevel.name;
-        this.updateScoreList();
-      }
-      if (this.rights.markHis) {
-        this.getMarkHistory();
-      }
-      this.btnClicked = false;
-    },
-    updateScoreList() {
-      let scores = [];
-      if (this.curLevel.levelType === "ADMITED") {
-        const { minScore, maxScore, intervalScore } = this.curLevel;
-        for (let i = minScore; i <= maxScore; i += intervalScore) {
-          scores.push(i);
-        }
-      } else {
-        scores = this.curLevel.scoreList.split(",").map(item => item * 1);
-      }
-
-      this.scores = scores;
-    },
-    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) {
-      if (this.curPaperOrTask.level === level.name) return;
-
-      if (this.btnClicked) return;
-      this.btnClicked = true;
-
-      this.setT = setTimeout(() => {
-        this.btnClicked = false;
-      }, 500);
-
-      // 科组长改档 / 评卷同意改档:只使用selectedLevel
-      this.$emit("on-leader-level", {
-        paperId: this.curPaperOrTask.paperId,
-        curLevel:
-          this.stepType === "shift"
-            ? this.curPaperOrTask.redoLevel
-            : this.curPaperOrTask.level,
-        selectedLevel: level.name
-      });
-    },
-    gradeChangeConfirm() {
-      this.selectLevel({ name: this.curPaperOrTask.redoLevel });
-    },
-    selectScore(score) {
-      if (this.btnClicked) return;
-      this.btnClicked = true;
-
-      this.setT = setTimeout(() => {
-        this.btnClicked = false;
-      }, 500);
-      // 评卷员打分
-      this.$emit("on-select-score", score * 1);
-    },
-    toPass() {
-      this.$emit("on-pass");
-    },
-    searchCode() {
-      if (!this.filter.code || !this.filter.codeType) {
-        this.$Message.error("请设置密号类型和密号!");
-        return;
-      }
-      this.$emit("on-code-search", this.filter);
-    },
-    searchGradeChange() {
-      this.$emit("on-grade-change-search", this.applyChangeLevelStatus);
-    }
-  }
-};
-</script>
+<template>
+  <div class="mark-action grade-action">
+    <!-- 头部信息 ------ -->
+    <!-- 试卷状态 -->
+    <!-- 状态:已评,待评,改档,改档打分 -->
+    <div class="action-paper-state">
+      <p class="paper-state-cont">{{ stepLabel }}</p>
+    </div>
+    <!-- 试卷信息 -->
+    <div class="action-paper-info">
+      <!-- <p v-if="IS_ADMIN">
+        <span>试卷考号:</span><span>{{ curPaperOrTask.examNumber }}</span>
+      </p> -->
+      <p>
+        <span v-if="IS_MARKER">任务密号:</span>
+        <span v-else>试卷密号:</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 v-if="IS_MARKER">建议档位:</span>
+        <span v-else>申请档位:</span>
+        <span>{{ curPaperOrTask.redoLevel }}</span>
+      </p>
+    </div>
+    <div
+      :class="[
+        'action-grade-change-status',
+        { 'action-grade-change-status-error': curPaperOrTask.auditStatus === 0 }
+      ]"
+      v-if="rights.gradeChange && IS_ADMIN"
+    >
+      <p>{{ curPaperOrTask.auditStatus === 1 ? "同意改档" : "不同意改档" }}</p>
+    </div>
+
+    <!-- 档位信息 -->
+    <!-- 已评/待评(已评档位),改档打分(已评档位) -->
+    <div class="action-grade-info" v-if="rights.gradeInfo">
+      <h3 class="grade-info-name">
+        {{ curPaperLevel }}
+      </h3>
+      <!-- <div class="grade-info-range">
+        <p>分数范围</p>
+        <p>
+          <span>{{ curLevel.minScore }}</span>
+          <span>~</span>
+          <span>{{ curLevel.maxScore }}</span>
+        </p>
+      </div> -->
+    </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-mark-list" v-if="rights.levelList">
+      <div
+        class="action-mark-item"
+        v-for="(score, index) in scores"
+        :key="index"
+      >
+        <div
+          :class="[
+            'action-mark-item-content',
+            {
+              'action-item-content-disabled': btnClicked,
+              'is-active': keyInput == score
+            }
+          ]"
+          @click="selectScore(score)"
+        >
+          <p>{{ score }}</p>
+        </div>
+      </div>
+    </div>
+    <div class="action-grade-pass" v-if="rights.levelList" @click="toPass">
+      跳过
+    </div>
+    <!-- mark confirm grade change -->
+    <div
+      class="action-grade-change-confirm"
+      v-if="IS_MARKER && stepType === 'shift'"
+    >
+      <Button type="primary" @click="gradeChangeConfirm">确认改档</Button>
+    </div>
+
+    <!-- 评卷记录 -->
+    <div class="action-grade-history" v-if="rights.markHis">
+      <h3>评卷记录</h3>
+      <div class="grade-history-list">
+        <div
+          class="grade-history-item"
+          v-for="(his, hindex) in gradingHistory"
+          :key="hindex"
+        >
+          <p>{{ his.loginName }}</p>
+          <p>{{ his.value }}</p>
+        </div>
+      </div>
+    </div>
+    <!-- 查询 -->
+    <div class="action-search" v-if="rights.search">
+      <Select
+        class="search-select"
+        v-model="filter.codeType"
+        placeholder="密号类型"
+      >
+        <Option
+          v-for="item in codeTypes"
+          :key="item.key"
+          :value="item.key"
+          :label="item.val"
+        ></Option>
+      </Select>
+      <Input
+        class="search-input"
+        v-model.trim="filter.code"
+        placeholder="输入密号"
+        clearable
+      >
+      </Input>
+      <Button size="small" type="primary" class="search-btn" @click="searchCode"
+        >查询</Button
+      >
+    </div>
+    <!-- 改档处理状态查询 -->
+    <div class="action-search" v-if="rights.gradeChangeSearch">
+      <Select
+        class="search-input"
+        v-model="applyChangeLevelStatus"
+        placeholder="类型"
+      >
+        <Option
+          v-for="(val, key) in CHANGE_LEVEL_STATUS"
+          :key="key"
+          :value="key * 1"
+          :label="val"
+        ></Option>
+      </Select>
+      <Button
+        size="small"
+        type="primary"
+        class="search-btn"
+        @click="searchGradeChange"
+        >查询</Button
+      >
+    </div>
+  </div>
+</template>
+
+<script>
+import { markHistoryList } from "@/api";
+import { CODE_TYPE, CHANGE_LEVEL_STATUS } from "@/constants/enumerate";
+import { mapState } from "vuex";
+
+// 三种情况:
+// 管理员(ADMIN),科组长(MARK_LEADER),评卷员(MARKER)
+// 管理员:查询,头部信息,评卷记录
+// 科组长:查询,头部信息,选择档位,评卷记录
+// 评卷员:头部信息,选择分数
+/*
+[paper template]
+{
+  "id": 42,
+  "sn": "5314987744",
+  "redoLevel": null,
+  "level": "B",
+  "score": null,
+  "result": "88",
+  "originLevel": null,
+  "markerId": 52,
+  "marker": "zj-pj-01",
+  "updatedOn": 1595812145000,
+  "imgSrc": "http://192.168.10.145:9000/images/34/SC/1/1901130046.jpg?random=f5549bb0-ba58-4cd3-a88e-0559be4e06e5",
+  "thumbSrc": "http://192.168.10.145:9000/thumbs/34/SC/1/1901130046.jpg?random=e7f880b8-4cb6-4963-8e66-532f0f8bdeb0",
+  "markByLeader": false,
+  "oldRejected": false,
+  "paperId": 116,
+  "randomSeqNew": 4987744,
+  "randomSeq": null,
+  "serialNumber": "B1",
+  "displayNumber": true,
+  "shift": false,
+  "shiftScore": false,
+  "rejected": false,
+  "sample": false
+}
+[marktask template]
+{
+  "id": 38,
+  "sn": "5314266469",
+  "redoLevel": null,
+  "level": "A",
+  "score": null,
+  "result": "96",
+  "originLevel": null,
+  "markerId": 52,
+  "marker": "zj-pj-01",
+  "updatedOn": 1595812012000,
+  "imgSrc": "http://192.168.10.145:9000/images/34/SC/1/1901130043.jpg?random=bffc061c-7a80-42a4-ad56-36ec6eba0d45",
+  "thumbSrc": "http://192.168.10.145:9000/thumbs/34/SC/1/1901130043.jpg?random=da743f9d-8d46-4499-bb6f-b9c26e003ba2",
+  "markByLeader": true,
+  "oldRejected": false,
+  "paperId": 113,
+  "randomSeqNew": 4266469,
+  "randomSeq": null,
+  "serialNumber": "A1",
+  "displayNumber": true,
+  "shift": false,
+  "shiftScore": false,
+  "rejected": false,
+  "sample": true
+}
+*/
+
+const initRights = {
+  search: false,
+  gradeChangeSearch: false,
+  gradeChange: false,
+  gradeInfo: false,
+  markInfo: false,
+  gradeList: false,
+  levelList: false,
+  markHis: false
+};
+
+export default {
+  name: "mark-action",
+  props: {
+    curPaperOrTask: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    levels: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  data() {
+    return {
+      curUserRoleType: this.$ls.get("user", { role: "" }).role,
+      rights: {
+        ...initRights
+      },
+      roleRight: {
+        ADMIN: {
+          done: ["search", "markHis", "gradeInfo", "markInfo"],
+          shift: ["search", "gradeChangeSearch", "gradeChange"]
+        },
+        MARK_LEADER: {
+          undo: ["gradeList", "gradeInfo", "markInfo"],
+          done: ["gradeList", "markHis", "gradeInfo", "markInfo"],
+          shift: ["gradeList", "gradeChange"]
+        },
+        MARKER: {
+          done: ["levelList", "gradeInfo", "markInfo"],
+          undo: ["levelList", "gradeInfo"],
+          shift: ["gradeChange"],
+          shiftScore: ["levelList", "gradeInfo"]
+        }
+      },
+      filter: {
+        codeType: "examNumber",
+        code: ""
+      },
+      codeTypes: [],
+      CHANGE_LEVEL_STATUS,
+      applyChangeLevelStatus: null,
+      stepDict: {
+        undo: "待评",
+        done: "已评",
+        shift: "改档",
+        shiftScore: "改档打分"
+      },
+      stepType: "",
+      stepLabel: "",
+      curPaperLevel: "",
+      curPaperScore: "",
+      scores: [],
+      gradingHistory: [],
+      curLevel: {},
+      setT: null,
+      btnClicked: false,
+      keyInput: null
+    };
+  },
+  computed: {
+    ...mapState("marker", ["ribbonSet"]),
+    IS_ADMIN() {
+      return this.curUserRoleType === "ADMIN";
+    },
+    IS_MARKER() {
+      return this.curUserRoleType === "MARKER";
+    },
+    IS_MARK_LEADER() {
+      return this.curUserRoleType === "MARK_LEADER";
+    }
+  },
+  watch: {
+    curPaperOrTask(val) {
+      this.rebuildRight();
+    },
+    "ribbonSet.keyboardMark": {
+      immediate: true,
+      handler(val) {
+        console.log(val);
+        if (val) {
+          document.addEventListener("keydown", this.keyEvent);
+        } else {
+          this.keyInput = null;
+          document.removeEventListener("keydown", this.keyEvent);
+        }
+      }
+    }
+  },
+  mounted() {
+    this.codeTypes = Object.entries(CODE_TYPE)
+      .map(([key, val]) => {
+        return {
+          key,
+          val
+        };
+      })
+      .filter(item => item.key !== "examNumber");
+    // .filter(item => this.IS_ADMIN || item.key !== "examNumber");
+    this.rebuildRight();
+  },
+  methods: {
+    getStepType() {
+      const paper = this.curPaperOrTask;
+      if (paper.shift && paper.shiftScore && !paper.level && !paper.result)
+        return "shift";
+      if (!paper.shift && paper.shiftScore && !paper.result)
+        return "shiftScore";
+      if (this.IS_MARKER) {
+        if (!paper.result) return "undo";
+        if (paper.result) return "done";
+      } else {
+        if (paper.score !== null) return "done";
+        if (paper.score === null) return "undo";
+      }
+    },
+    rebuildRight() {
+      const curPaperScore = this.IS_MARKER
+        ? this.curPaperOrTask.result
+        : this.curPaperOrTask.score;
+      this.curPaperScore = curPaperScore !== null ? curPaperScore + "" : "";
+      this.stepType = this.getStepType();
+      this.stepLabel = this.stepDict[this.stepType];
+      this.rights = { ...initRights };
+      const roleRights =
+        this.roleRight[this.curUserRoleType][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.curPaperOrTask["displayNumber"] && this.stepType !== "shiftScore"
+            ? this.curPaperOrTask["serialNumber"]
+            : this.curLevel.name;
+        this.updateScoreList();
+      }
+      if (this.rights.markHis) {
+        this.getMarkHistory();
+      }
+      this.btnClicked = false;
+    },
+    updateScoreList() {
+      let scores = [];
+      if (this.curLevel.levelType === "ADMITED") {
+        const { minScore, maxScore, intervalScore } = this.curLevel;
+        for (let i = minScore; i <= maxScore; i += intervalScore) {
+          scores.push(i);
+        }
+      } else {
+        scores = this.curLevel.scoreList.split(",").map(item => item * 1);
+      }
+
+      this.scores = scores;
+    },
+    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) {
+      if (this.curPaperOrTask.level === level.name) return;
+
+      if (this.btnClicked) return;
+      this.btnClicked = true;
+
+      this.setT = setTimeout(() => {
+        this.btnClicked = false;
+      }, 500);
+
+      // 科组长改档 / 评卷同意改档:只使用selectedLevel
+      this.$emit("on-leader-level", {
+        paperId: this.curPaperOrTask.paperId,
+        curLevel:
+          this.stepType === "shift"
+            ? this.curPaperOrTask.redoLevel
+            : this.curPaperOrTask.level,
+        selectedLevel: level.name
+      });
+    },
+    gradeChangeConfirm() {
+      this.selectLevel({ name: this.curPaperOrTask.redoLevel });
+    },
+    selectScore(score) {
+      if (this.btnClicked) return;
+      this.btnClicked = true;
+
+      this.setT = setTimeout(() => {
+        this.btnClicked = false;
+      }, 500);
+      // 评卷员打分
+      this.$emit("on-select-score", score * 1);
+    },
+    toPass() {
+      this.$emit("on-pass");
+    },
+    searchCode() {
+      if (!this.filter.code || !this.filter.codeType) {
+        this.$Message.error("请设置密号类型和密号!");
+        return;
+      }
+      this.$emit("on-code-search", this.filter);
+    },
+    searchGradeChange() {
+      this.$emit("on-grade-change-search", this.applyChangeLevelStatus);
+    },
+    // keyboard submit
+    keyEvent(e) {
+      if (this.btnClicked) return;
+      // if (!this.ribbonSet.keyboardMark) return;
+      if (!e.altKey && !e.shiftKey && !e.ctrlKey) {
+        if (e.key === "F5") return;
+        this.$Message.destroy();
+
+        if (e.key === "Enter" && this.ribbonSet.needEnterSubmit) {
+          e.preventDefault();
+          this.toKeySubmit();
+          return;
+        }
+        if (this.checkKeyCodeValid(e.keyCode)) {
+          e.preventDefault();
+          this.keyInput += e.key;
+          this.keyInput = this.keyInput.slice(-3);
+
+          if (!this.ribbonSet.needEnterSubmit) {
+            this.toKeySubmit();
+          }
+        } else {
+          this.$Message.error("按键无效");
+        }
+      }
+    },
+    checkKeyCodeValid(keyCode) {
+      return keyCode >= 49 && keyCode <= 58;
+    },
+    checkScoreValid(score) {
+      const minScore = this.scores[0];
+      const maxScore = this.scores.slice(-1)[0];
+      return score >= minScore && score <= maxScore;
+    },
+    toKeySubmit() {
+      if (!this.keyInput) return;
+      if (!this.checkScoreValid()) {
+        this.$Message.destroy();
+        this.$Message.error("输入分数无效");
+        return;
+      }
+      this.selectScore(this.keyInput);
+    },
+    clearKeyInput() {
+      this.keyInput = null;
+    }
+  }
+};
+</script>

+ 3 - 0
src/modules/mark/leader/LeaderMarking.vue

@@ -29,6 +29,7 @@
         v-if="curPaper.id"
         ref="GradeAction"
       ></mark-action>
+      <grade-ribbon ref="GradeRibbon"></grade-ribbon>
     </div>
 
     <div class="marker-body">
@@ -97,6 +98,7 @@ import SimpleImagePreview from "@/components/SimpleImagePreview";
 import LeaderProgress from "../../grading/leader/LeaderProgress";
 import MarkerImageView from "../../grading/marker/MarkerImageView";
 import MarkerHistory from "../../grading/marker/MarkerHistory";
+import GradeRibbon from "../../grading/components/GradeRibbon";
 
 import {
   paperList,
@@ -119,6 +121,7 @@ export default {
     // MarkerStatistics,
     LeaderProgress,
     MarkAction,
+    GradeRibbon,
     SimpleImagePreview
   },
   data() {

+ 518 - 515
src/modules/mark/marker/MarkerMarking.vue

@@ -1,515 +1,518 @@
-<template>
-  <div class="marker-marking marker-grading">
-    <marker-header
-      v-if="paramsSetReady"
-      :show-standard="false"
-      :show-statistics="false"
-      @area-change="areaChange"
-      @step-change="stepChange"
-      @page-set-change="pageSetChange"
-      @to-history="toHistory"
-      @to-statistics="toStatistics"
-    ></marker-header>
-
-    <div
-      :class="[
-        'marker-action',
-        'dark-mark',
-        { 'marker-action-fullscreen': isFullscreenMarking }
-      ]"
-    >
-      <mark-action
-        :cur-paper-or-task="curPaper"
-        :levels="levels"
-        :params-set="paramsSet"
-        :key="curPaper.key"
-        @on-leader-level="gradingCurPaper"
-        @on-select-score="scoreCurPaper"
-        @on-pass="passCurPaper"
-        ref="GradeAction"
-        v-if="curPaper.id"
-      ></mark-action>
-    </div>
-
-    <div class="marker-body">
-      <div :class="markerImageListClasses" v-if="papers.length">
-        <div
-          v-for="(paper, index) in papers"
-          :key="`${paper.key}-${paper.result}`"
-          :class="[
-            'marker-image-item',
-            {
-              'marker-image-item-act': curPaperIndex === index
-            }
-          ]"
-        >
-          <div class="marker-image-content">
-            <marker-image-view
-              :data="paper"
-              :stage="stage"
-              @to-review="toReview(index)"
-            ></marker-image-view>
-          </div>
-        </div>
-      </div>
-      <div v-else class="marker-image-none">暂无数据</div>
-    </div>
-
-    <!-- MarkerHistory -->
-    <marker-history
-      :question-id="filter.questionId"
-      :stage="stage"
-      @on-paper-click="
-        (index, papers) => {
-          toViewCarouselPaper(index, papers, 'history');
-        }
-      "
-      ref="MarkerHistory"
-    ></marker-history>
-    <!-- image-preview -->
-    <simple-image-preview
-      class="grading-operation-image-preview"
-      :cur-image="curPaper"
-      @on-prev="toPrevPaper"
-      @on-next="toNextPaper"
-      @on-close="isFullscreenMarking = false"
-      ref="SimpleImagePreview"
-    ></simple-image-preview>
-    <!-- carousel paper review -->
-    <simple-image-preview
-      class="grading-operation-image-preview"
-      :cur-image="curPaper"
-      @on-prev="toCarousePaper('prev')"
-      @on-next="toCarousePaper('next')"
-      @on-close="carouseImagePreviewClose"
-      ref="CarouselPapersPreview"
-    ></simple-image-preview>
-    <!-- level-change-modal-info -->
-    <Modal
-      v-model="levelChangeModalIsShow"
-      width="400"
-      footer-hide
-      :z-index="2001"
-      :closable="false"
-      :mask-closable="false"
-    >
-      <div class="ivu-modal-confirm">
-        <div class="ivu-modal-confirm-body">
-          <div>{{ levelChangeTips }}</div>
-        </div>
-        <div class="ivu-modal-confirm-footer">
-          <Button type="primary" @click="levelChangeModalIsShow = false"
-            >确定</Button
-          >
-        </div>
-      </div>
-    </Modal>
-  </div>
-</template>
-
-<script>
-import { mapState, mapMutations } from "vuex";
-import MarkerHeader from "../../grading/marker/MarkerHeader";
-import MarkAction from "../components/MarkAction";
-import SimpleImagePreview from "@/components/SimpleImagePreview";
-import MarkerImageView from "../../grading/marker/MarkerImageView";
-import MarkerHistory from "../../grading/marker/MarkerHistory";
-
-import {
-  getParamsSet,
-  markerTaskList,
-  markerChangeLevelPaperList,
-  markerScoreTotalStatData,
-  workLevelList,
-  paperSelectLevelOrScore,
-  paperTaskPass
-} from "@/api";
-
-export default {
-  name: "marker-marking",
-  components: {
-    MarkerHeader,
-    MarkerImageView,
-    MarkerHistory,
-    MarkAction,
-    SimpleImagePreview
-  },
-  data() {
-    return {
-      filter: {
-        markerId: this.$ls.get("user").id,
-        questionId: ""
-      },
-      typeFilter: {
-        undo: {
-          sort: "paper.level",
-          stage: "SCORE"
-        },
-        done: {
-          level: "",
-          sort: "updatedOn,desc",
-          stage: "SCORE"
-        },
-        shift: {
-          isShift: true,
-          isShiftScore: false
-        },
-        shiftScore: {
-          isShift: false,
-          isShiftScore: true
-        },
-        manualScore: {}
-      },
-      stage: "SCORE",
-      workId: this.$route.params.workId,
-      subjectId: this.$route.params.subjectId,
-      subject: "",
-      workSubject: {},
-      curSubject: {},
-      changeStage: 0, // 是否显示改档及改档打分
-      curStandardGradeId: "",
-      levels: [],
-      papers: [],
-      curPaper: {},
-      curPaperIndex: 0,
-      paramsSetReady: false,
-      // carousel paper review,
-      carouselPapers: [],
-      curCarouselPaperIndex: 0,
-      isFullscreenMarking: false,
-      // tips-modal
-      levelChangeTips: "",
-      levelChangeModalIsShow: false
-    };
-  },
-  computed: {
-    ...mapState("marker", ["paramsSet", "page", "steps", "curStep", "curArea"]),
-    markerImageListClasses() {
-      return ["marker-image-list", `marker-image-list-${this.page.size}`];
-    }
-  },
-  created() {
-    this.subject = this.subjectId.split("-")[1];
-    this.workSubject = {
-      workId: this.workId,
-      subject: this.subject
-    };
-    const curUserRoleType = this.$ls.get("user", { role: "" }).role;
-    this.setCurUserRoleType(curUserRoleType);
-    this.initData();
-  },
-  methods: {
-    ...mapMutations("marker", [
-      "setParamSet",
-      "setPage",
-      "setSteps",
-      "setCurArea",
-      "setCurStep",
-      "setCurUserRoleType",
-      "clearState"
-    ]),
-    initData() {
-      this.getParamsSetInfo();
-      this.getWorkLevels();
-    },
-    async getParamsSetInfo() {
-      const data = await getParamsSet(this.workId);
-      this.setParamSet(data || {});
-      this.changeStage = this.paramsSet.changeStage;
-      this.paramsSetReady = true;
-    },
-    async getList() {
-      const datas = {
-        ...this.filter,
-        ...this.typeFilter[this.curStep.type],
-        subject: this.subject,
-        workId: this.workId,
-        page: this.page.current - 1,
-        size: this.page.size
-      };
-      if (this.curStep.type === "done") {
-        datas.level = this.curStep.name;
-      }
-
-      let requestAction = null;
-      if (this.curStep.type.includes("shift")) {
-        requestAction = markerChangeLevelPaperList;
-      } else {
-        requestAction = markerTaskList;
-      }
-
-      const data = await requestAction(datas);
-      this.papers = data.data.map(paper => {
-        paper.key = this.$randomCode();
-        paper.title = `NO.${paper.sn}`;
-        paper.score = paper.result;
-        return paper;
-      });
-      this.setPage({
-        total: data.totalCount,
-        totalPage: data.pageCount
-      });
-    },
-    async toPage(page) {
-      this.setPage({
-        current: page
-      });
-      await this.getList();
-      this.selectPaper(this.curPaperIndex);
-    },
-    async getStepLevels() {
-      const data = await markerScoreTotalStatData(
-        this.filter.markerId,
-        this.filter.questionId
-      );
-      const undoIndex = data.findIndex(item => item.id === null);
-      let otherStep = [];
-      let undo = {
-        count: 0,
-        shift: 0,
-        shiftScore: 0
-      };
-      if (undoIndex !== -1) {
-        undo = { ...data[undoIndex] };
-        data.splice(undoIndex, 1);
-      }
-      otherStep.push({
-        name: "待评",
-        count: undo.count,
-        type: "undo"
-      });
-
-      if (this.changeStage) {
-        otherStep.push({
-          name: "改档",
-          count: undo.shift,
-          type: "shift"
-        });
-        otherStep.push({
-          name: "改档打分",
-          count: undo.shiftScore,
-          type: "shiftScore"
-        });
-      }
-
-      let levelStep = data
-        .filter(item => item.id !== "manualScore")
-        .map(item => {
-          return {
-            ...item,
-            name: item.id,
-            type: "done"
-          };
-        });
-      const msInfo = data.find(item => item.id === "manualScore");
-      if (msInfo) {
-        otherStep.push({
-          count: msInfo.count,
-          name: "输分试卷",
-          type: "manualScore"
-        });
-      }
-
-      this.setSteps({ levelStep, otherStep });
-
-      if (!this.curStep.name) {
-        let curStep = {};
-        if (undoIndex === -1) {
-          curStep = levelStep[0];
-        } else {
-          const firstStep = otherStep.find(item => item.count);
-          curStep = firstStep || levelStep[0];
-        }
-        this.setCurStep(curStep);
-      } else {
-        const curStep = [...levelStep, ...otherStep].find(
-          item => item.name === this.curStep.name
-        );
-        this.setCurStep(curStep);
-      }
-    },
-    updateStepLevel(curStep, curLevel, count = 1) {
-      if (curStep.type === "done") return;
-
-      const opos = this.steps.otherStep.findIndex(
-        item => item.type === curStep.type
-      );
-      this.steps.otherStep[opos].count -= count;
-
-      if (curStep.type === "shift") {
-        const spos = this.steps.otherStep.findIndex(
-          item => item.type === "shiftScore"
-        );
-        this.steps.otherStep[spos].count += count;
-      } else {
-        const pos = this.steps.levelStep.findIndex(
-          item => item.name === curLevel
-        );
-        this.steps.levelStep[pos].count += count;
-      }
-    },
-    async getWorkLevels() {
-      const data = await workLevelList(this.workId);
-      this.levels = data.map(item => {
-        return {
-          ...item,
-          name: item.code
-        };
-      });
-    },
-    async pageSetChange() {
-      await this.getList();
-      this.selectPaper(this.curPaperIndex);
-    },
-    async stepChange(step) {
-      this.setCurStep(step);
-      this.setPage({ current: 1 });
-      this.isFullscreenMarking = false;
-      await this.getList();
-      this.getStepLevels();
-      if (this.papers.length) {
-        this.selectPaper(0);
-      } else {
-        this.curPaper = {};
-      }
-    },
-    async areaChange(curArea) {
-      this.setCurArea(curArea);
-      this.filter.questionId = curArea.id;
-      await this.getStepLevels();
-      this.toPage(1);
-    },
-    toReview(index) {
-      this.isFullscreenMarking = true;
-      this.selectPaper(index);
-      this.$refs.SimpleImagePreview.open();
-    },
-    selectPaper(index) {
-      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;
-      }
-      const lastPaper = { ...this.curPaper };
-      this.curPaperIndex = nindex;
-      this.curPaper = this.papers[nindex] ? { ...this.papers[nindex] } : {};
-
-      // 待评时,检查当前试卷是否已经切换档位
-      if (
-        this.curStep.type === "undo" &&
-        this.curPaper["level"] &&
-        this.curPaper["level"] !== lastPaper["level"]
-      ) {
-        this.levelChangeTips = `即将打分档位:${this.curPaper.level}`;
-        this.levelChangeModalIsShow = true;
-      }
-    },
-    async toPrevPaper() {
-      if (this.curPaperIndex === 0) {
-        if (this.page.current > 1) {
-          this.setPage({ current: this.page.current - 1 });
-          this.curPaperIndex = this.page.size - 1;
-          await this.getList();
-        } else {
-          this.$Message.warning("当前已经是第一条数据了");
-          return;
-        }
-      } else {
-        this.curPaperIndex--;
-      }
-
-      this.selectPaper(this.curPaperIndex);
-    },
-    async toNextPaper() {
-      if (this.curPaperIndex === this.papers.length - 1) {
-        if (this.page.current === this.page.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 toActionNextPaper() {
-      if (this.page.current > 1 && this.papers.length === 1) {
-        this.setPage({ current: this.page.current - 1 });
-        this.curPaperIndex = this.page.size;
-      }
-
-      await this.getList();
-      if (!this.papers.length) this.$refs.SimpleImagePreview.cancel();
-      this.selectPaper(this.curPaperIndex);
-    },
-    async gradingCurPaper({ selectedLevel }) {
-      await paperSelectLevelOrScore(
-        this.curPaper.id, // is taskId
-        selectedLevel,
-        "LEVEL"
-      );
-      this.updateStepLevel(this.curStep, "shiftScore");
-      this.toActionNextPaper();
-    },
-    async scoreCurPaper(score) {
-      const paper = await paperSelectLevelOrScore(
-        this.curPaper.id, // is taskId
-        score,
-        "SCORE"
-      );
-      if (!paper) return;
-      this.updateStepLevel(this.curStep, this.curPaper.level);
-      this.toActionNextPaper();
-    },
-    async passCurPaper(level) {
-      await paperTaskPass(this.curPaper.id);
-      this.toActionNextPaper();
-    },
-    // paper carousel
-    toViewCarouselPaper(paperIndex, papers) {
-      this.isFullscreenMarking = true;
-      this.carouselPapers = papers;
-      this.selectCarouselPaper(paperIndex);
-      this.$nextTick(() => {
-        this.$refs.CarouselPapersPreview.open();
-      });
-    },
-    selectCarouselPaper(index) {
-      this.curCarouselPaperIndex = index;
-      this.curPaper = { ...this.carouselPapers[index] };
-    },
-    toCarousePaper(type) {
-      if (type === "prev" && this.curCarouselPaperIndex > 0) {
-        this.curCarouselPaperIndex--;
-      } else if (
-        type === "next" &&
-        this.curCarouselPaperIndex < this.carouselPapers.length - 1
-      ) {
-        this.curCarouselPaperIndex++;
-      }
-      this.selectCarouselPaper(this.curCarouselPaperIndex);
-    },
-    carouseImagePreviewClose() {
-      this.isFullscreenMarking = false;
-      this.selectPaper(this.curPaperIndex);
-    },
-    // header
-    toHistory() {
-      this.$refs.MarkerHistory.open();
-    },
-    toStatistics() {
-      this.$refs.MarkerStatistics.open();
-    }
-  },
-  beforeDestroy() {
-    this.clearState();
-  }
-};
-</script>
+<template>
+  <div class="marker-marking marker-grading">
+    <marker-header
+      v-if="paramsSetReady"
+      :show-standard="false"
+      :show-statistics="false"
+      @area-change="areaChange"
+      @step-change="stepChange"
+      @page-set-change="pageSetChange"
+      @to-history="toHistory"
+      @to-statistics="toStatistics"
+    ></marker-header>
+
+    <div
+      :class="[
+        'marker-action',
+        'dark-mark',
+        { 'marker-action-fullscreen': isFullscreenMarking }
+      ]"
+    >
+      <mark-action
+        :cur-paper-or-task="curPaper"
+        :levels="levels"
+        :params-set="paramsSet"
+        :key="curPaper.key"
+        @on-leader-level="gradingCurPaper"
+        @on-select-score="scoreCurPaper"
+        @on-pass="passCurPaper"
+        ref="GradeAction"
+        v-if="curPaper.id"
+      ></mark-action>
+      <grade-ribbon ref="GradeRibbon"></grade-ribbon>
+    </div>
+
+    <div class="marker-body">
+      <div :class="markerImageListClasses" v-if="papers.length">
+        <div
+          v-for="(paper, index) in papers"
+          :key="`${paper.key}-${paper.result}`"
+          :class="[
+            'marker-image-item',
+            {
+              'marker-image-item-act': curPaperIndex === index
+            }
+          ]"
+        >
+          <div class="marker-image-content">
+            <marker-image-view
+              :data="paper"
+              :stage="stage"
+              @to-review="toReview(index)"
+            ></marker-image-view>
+          </div>
+        </div>
+      </div>
+      <div v-else class="marker-image-none">暂无数据</div>
+    </div>
+
+    <!-- MarkerHistory -->
+    <marker-history
+      :question-id="filter.questionId"
+      :stage="stage"
+      @on-paper-click="
+        (index, papers) => {
+          toViewCarouselPaper(index, papers, 'history');
+        }
+      "
+      ref="MarkerHistory"
+    ></marker-history>
+    <!-- image-preview -->
+    <simple-image-preview
+      class="grading-operation-image-preview"
+      :cur-image="curPaper"
+      @on-prev="toPrevPaper"
+      @on-next="toNextPaper"
+      @on-close="isFullscreenMarking = false"
+      ref="SimpleImagePreview"
+    ></simple-image-preview>
+    <!-- carousel paper review -->
+    <simple-image-preview
+      class="grading-operation-image-preview"
+      :cur-image="curPaper"
+      @on-prev="toCarousePaper('prev')"
+      @on-next="toCarousePaper('next')"
+      @on-close="carouseImagePreviewClose"
+      ref="CarouselPapersPreview"
+    ></simple-image-preview>
+    <!-- level-change-modal-info -->
+    <Modal
+      v-model="levelChangeModalIsShow"
+      width="400"
+      footer-hide
+      :z-index="2001"
+      :closable="false"
+      :mask-closable="false"
+    >
+      <div class="ivu-modal-confirm">
+        <div class="ivu-modal-confirm-body">
+          <div>{{ levelChangeTips }}</div>
+        </div>
+        <div class="ivu-modal-confirm-footer">
+          <Button type="primary" @click="levelChangeModalIsShow = false"
+            >确定</Button
+          >
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { mapState, mapMutations } from "vuex";
+import MarkerHeader from "../../grading/marker/MarkerHeader";
+import MarkAction from "../components/MarkAction";
+import SimpleImagePreview from "@/components/SimpleImagePreview";
+import MarkerImageView from "../../grading/marker/MarkerImageView";
+import MarkerHistory from "../../grading/marker/MarkerHistory";
+import GradeRibbon from "../../grading/components/GradeRibbon";
+
+import {
+  getParamsSet,
+  markerTaskList,
+  markerChangeLevelPaperList,
+  markerScoreTotalStatData,
+  workLevelList,
+  paperSelectLevelOrScore,
+  paperTaskPass
+} from "@/api";
+
+export default {
+  name: "marker-marking",
+  components: {
+    MarkerHeader,
+    MarkerImageView,
+    MarkerHistory,
+    MarkAction,
+    GradeRibbon,
+    SimpleImagePreview
+  },
+  data() {
+    return {
+      filter: {
+        markerId: this.$ls.get("user").id,
+        questionId: ""
+      },
+      typeFilter: {
+        undo: {
+          sort: "paper.level",
+          stage: "SCORE"
+        },
+        done: {
+          level: "",
+          sort: "updatedOn,desc",
+          stage: "SCORE"
+        },
+        shift: {
+          isShift: true,
+          isShiftScore: false
+        },
+        shiftScore: {
+          isShift: false,
+          isShiftScore: true
+        },
+        manualScore: {}
+      },
+      stage: "SCORE",
+      workId: this.$route.params.workId,
+      subjectId: this.$route.params.subjectId,
+      subject: "",
+      workSubject: {},
+      curSubject: {},
+      changeStage: 0, // 是否显示改档及改档打分
+      curStandardGradeId: "",
+      levels: [],
+      papers: [],
+      curPaper: {},
+      curPaperIndex: 0,
+      paramsSetReady: false,
+      // carousel paper review,
+      carouselPapers: [],
+      curCarouselPaperIndex: 0,
+      isFullscreenMarking: false,
+      // tips-modal
+      levelChangeTips: "",
+      levelChangeModalIsShow: false
+    };
+  },
+  computed: {
+    ...mapState("marker", ["paramsSet", "page", "steps", "curStep", "curArea"]),
+    markerImageListClasses() {
+      return ["marker-image-list", `marker-image-list-${this.page.size}`];
+    }
+  },
+  created() {
+    this.subject = this.subjectId.split("-")[1];
+    this.workSubject = {
+      workId: this.workId,
+      subject: this.subject
+    };
+    const curUserRoleType = this.$ls.get("user", { role: "" }).role;
+    this.setCurUserRoleType(curUserRoleType);
+    this.initData();
+  },
+  methods: {
+    ...mapMutations("marker", [
+      "setParamSet",
+      "setPage",
+      "setSteps",
+      "setCurArea",
+      "setCurStep",
+      "setCurUserRoleType",
+      "clearState"
+    ]),
+    initData() {
+      this.getParamsSetInfo();
+      this.getWorkLevels();
+    },
+    async getParamsSetInfo() {
+      const data = await getParamsSet(this.workId);
+      this.setParamSet(data || {});
+      this.changeStage = this.paramsSet.changeStage;
+      this.paramsSetReady = true;
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        ...this.typeFilter[this.curStep.type],
+        subject: this.subject,
+        workId: this.workId,
+        page: this.page.current - 1,
+        size: this.page.size
+      };
+      if (this.curStep.type === "done") {
+        datas.level = this.curStep.name;
+      }
+
+      let requestAction = null;
+      if (this.curStep.type.includes("shift")) {
+        requestAction = markerChangeLevelPaperList;
+      } else {
+        requestAction = markerTaskList;
+      }
+
+      const data = await requestAction(datas);
+      this.papers = data.data.map(paper => {
+        paper.key = this.$randomCode();
+        paper.title = `NO.${paper.sn}`;
+        paper.score = paper.result;
+        return paper;
+      });
+      this.setPage({
+        total: data.totalCount,
+        totalPage: data.pageCount
+      });
+    },
+    async toPage(page) {
+      this.setPage({
+        current: page
+      });
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async getStepLevels() {
+      const data = await markerScoreTotalStatData(
+        this.filter.markerId,
+        this.filter.questionId
+      );
+      const undoIndex = data.findIndex(item => item.id === null);
+      let otherStep = [];
+      let undo = {
+        count: 0,
+        shift: 0,
+        shiftScore: 0
+      };
+      if (undoIndex !== -1) {
+        undo = { ...data[undoIndex] };
+        data.splice(undoIndex, 1);
+      }
+      otherStep.push({
+        name: "待评",
+        count: undo.count,
+        type: "undo"
+      });
+
+      if (this.changeStage) {
+        otherStep.push({
+          name: "改档",
+          count: undo.shift,
+          type: "shift"
+        });
+        otherStep.push({
+          name: "改档打分",
+          count: undo.shiftScore,
+          type: "shiftScore"
+        });
+      }
+
+      let levelStep = data
+        .filter(item => item.id !== "manualScore")
+        .map(item => {
+          return {
+            ...item,
+            name: item.id,
+            type: "done"
+          };
+        });
+      const msInfo = data.find(item => item.id === "manualScore");
+      if (msInfo) {
+        otherStep.push({
+          count: msInfo.count,
+          name: "输分试卷",
+          type: "manualScore"
+        });
+      }
+
+      this.setSteps({ levelStep, otherStep });
+
+      if (!this.curStep.name) {
+        let curStep = {};
+        if (undoIndex === -1) {
+          curStep = levelStep[0];
+        } else {
+          const firstStep = otherStep.find(item => item.count);
+          curStep = firstStep || levelStep[0];
+        }
+        this.setCurStep(curStep);
+      } else {
+        const curStep = [...levelStep, ...otherStep].find(
+          item => item.name === this.curStep.name
+        );
+        this.setCurStep(curStep);
+      }
+    },
+    updateStepLevel(curStep, curLevel, count = 1) {
+      if (curStep.type === "done") return;
+
+      const opos = this.steps.otherStep.findIndex(
+        item => item.type === curStep.type
+      );
+      this.steps.otherStep[opos].count -= count;
+
+      if (curStep.type === "shift") {
+        const spos = this.steps.otherStep.findIndex(
+          item => item.type === "shiftScore"
+        );
+        this.steps.otherStep[spos].count += count;
+      } else {
+        const pos = this.steps.levelStep.findIndex(
+          item => item.name === curLevel
+        );
+        this.steps.levelStep[pos].count += count;
+      }
+    },
+    async getWorkLevels() {
+      const data = await workLevelList(this.workId);
+      this.levels = data.map(item => {
+        return {
+          ...item,
+          name: item.code
+        };
+      });
+    },
+    async pageSetChange() {
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async stepChange(step) {
+      this.setCurStep(step);
+      this.setPage({ current: 1 });
+      this.isFullscreenMarking = false;
+      await this.getList();
+      this.getStepLevels();
+      if (this.papers.length) {
+        this.selectPaper(0);
+      } else {
+        this.curPaper = {};
+      }
+    },
+    async areaChange(curArea) {
+      this.setCurArea(curArea);
+      this.filter.questionId = curArea.id;
+      await this.getStepLevels();
+      this.toPage(1);
+    },
+    toReview(index) {
+      this.isFullscreenMarking = true;
+      this.selectPaper(index);
+      this.$refs.SimpleImagePreview.open();
+    },
+    selectPaper(index) {
+      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;
+      }
+      const lastPaper = { ...this.curPaper };
+      this.curPaperIndex = nindex;
+      this.curPaper = this.papers[nindex] ? { ...this.papers[nindex] } : {};
+
+      // 待评时,检查当前试卷是否已经切换档位
+      if (
+        this.curStep.type === "undo" &&
+        this.curPaper["level"] &&
+        this.curPaper["level"] !== lastPaper["level"]
+      ) {
+        this.levelChangeTips = `即将打分档位:${this.curPaper.level}`;
+        this.levelChangeModalIsShow = true;
+      }
+    },
+    async toPrevPaper() {
+      if (this.curPaperIndex === 0) {
+        if (this.page.current > 1) {
+          this.setPage({ current: this.page.current - 1 });
+          this.curPaperIndex = this.page.size - 1;
+          await this.getList();
+        } else {
+          this.$Message.warning("当前已经是第一条数据了");
+          return;
+        }
+      } else {
+        this.curPaperIndex--;
+      }
+
+      this.selectPaper(this.curPaperIndex);
+    },
+    async toNextPaper() {
+      if (this.curPaperIndex === this.papers.length - 1) {
+        if (this.page.current === this.page.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 toActionNextPaper() {
+      if (this.page.current > 1 && this.papers.length === 1) {
+        this.setPage({ current: this.page.current - 1 });
+        this.curPaperIndex = this.page.size;
+      }
+
+      await this.getList();
+      if (!this.papers.length) this.$refs.SimpleImagePreview.cancel();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async gradingCurPaper({ selectedLevel }) {
+      await paperSelectLevelOrScore(
+        this.curPaper.id, // is taskId
+        selectedLevel,
+        "LEVEL"
+      );
+      this.updateStepLevel(this.curStep, "shiftScore");
+      this.toActionNextPaper();
+    },
+    async scoreCurPaper(score) {
+      const paper = await paperSelectLevelOrScore(
+        this.curPaper.id, // is taskId
+        score,
+        "SCORE"
+      );
+      if (!paper) return;
+      this.updateStepLevel(this.curStep, this.curPaper.level);
+      this.toActionNextPaper();
+    },
+    async passCurPaper(level) {
+      await paperTaskPass(this.curPaper.id);
+      this.toActionNextPaper();
+    },
+    // paper carousel
+    toViewCarouselPaper(paperIndex, papers) {
+      this.isFullscreenMarking = true;
+      this.carouselPapers = papers;
+      this.selectCarouselPaper(paperIndex);
+      this.$nextTick(() => {
+        this.$refs.CarouselPapersPreview.open();
+      });
+    },
+    selectCarouselPaper(index) {
+      this.curCarouselPaperIndex = index;
+      this.curPaper = { ...this.carouselPapers[index] };
+    },
+    toCarousePaper(type) {
+      if (type === "prev" && this.curCarouselPaperIndex > 0) {
+        this.curCarouselPaperIndex--;
+      } else if (
+        type === "next" &&
+        this.curCarouselPaperIndex < this.carouselPapers.length - 1
+      ) {
+        this.curCarouselPaperIndex++;
+      }
+      this.selectCarouselPaper(this.curCarouselPaperIndex);
+    },
+    carouseImagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.selectPaper(this.curPaperIndex);
+    },
+    // header
+    toHistory() {
+      this.$refs.MarkerHistory.open();
+    },
+    toStatistics() {
+      this.$refs.MarkerStatistics.open();
+    }
+  },
+  beforeDestroy() {
+    this.clearState();
+  }
+};
+</script>