zhangjie 4 år sedan
förälder
incheckning
a3cf60ad6a

+ 12 - 5
card/assets/styles/card-preview.scss

@@ -1151,15 +1151,22 @@
       }
       &.elem-fill-no {
         position: absolute;
-        top: 0;
+        top: 2px;
+        bottom: 2px;
         left: 1px;
         z-index: 9;
-        transform: translateY(-100%);
-        width: 20px;
-        padding-bottom: 4px;
-        text-align: center;
+        min-width: 20px;
+        text-align: left;
         background-color: #fff;
         border: none;
+
+        span {
+          display: block;
+          position: relative;
+          padding-bottom: 5px;
+          padding-right: 3px;
+          transform: translateY(-100%);
+        }
       }
       &.elem-fill-comma {
         position: absolute;

+ 1 - 1
card/elements/card-head/CardHead.vue

@@ -22,7 +22,7 @@
           type="textarea"
           resize="none"
           :rows="2"
-          placeholder="请输入题卡描述信息"
+          placeholder="请输入题卡描述信息,最多只展示两行内容"
           @blur="nameChange"
         >
         </el-input>

+ 1 - 0
card/elements/fill-line/EditFillLine.vue

@@ -67,6 +67,7 @@
         <el-input
           style="width:125px;"
           v-model.trim="modalForm.numberPre"
+          :maxlength="6"
           clearable
         ></el-input>
       </el-form-item>

+ 9 - 5
card/elements/fill-line/ElemFillLine.vue

@@ -10,8 +10,10 @@
         :key="question.no"
         :style="groupStyles"
       >
-        <li class="elem-fill-no" :style="lineNoStyles">
-          {{ data.numberPre }}{{ question.no }}.
+        <li class="elem-fill-no">
+          <span :style="lineNoStyles"
+            >{{ data.numberPre }}{{ question.no }}.</span
+          >
         </li>
         <li
           class="elem-fill-line"
@@ -28,8 +30,10 @@
         :key="line"
         :style="groupStyles"
       >
-        <li v-if="line === 1" class="elem-fill-no" :style="lineNoStyles">
-          {{ data.numberPre }}{{ data.questionLineNums[0].no }}.
+        <li v-if="line === 1" class="elem-fill-no">
+          <span :style="lineNoStyles">
+            {{ data.numberPre }}{{ data.questionLineNums[0].no }}.
+          </span>
         </li>
         <li
           v-if="line !== data.questionLineNums[0].count"
@@ -65,7 +69,7 @@ export default {
     },
     lineNoStyles() {
       return {
-        top: this.data.lineSpacing - 2 + "px"
+        top: this.data.lineSpacing - 4 + "px"
       };
     },
     groupStyles() {

+ 2 - 2
card/elements/fill-question/EditFillQuestion.vue

@@ -98,14 +98,14 @@
         <span>是:</span>
         <el-input
           v-model.trim="booleanTypes.yes"
-          :maxlength="2"
+          :maxlength="1"
           placeholder="是"
           style="margin-right: 20px;width:60px;"
         ></el-input>
         <span>否:</span>
         <el-input
           v-model.trim="booleanTypes.no"
-          :maxlength="2"
+          :maxlength="1"
           placeholder="否"
           style="margin-right: 20px;width:60px;"
         ></el-input>

BIN
public/temps/命题任务导入模板.xlsx


+ 77 - 22
src/assets/styles/common-comp.scss

@@ -200,7 +200,7 @@ $--cc-list-upload-pre: cc-list-upload;
     padding: 15px;
     top: 0;
     left: 0;
-    line-height: 22px;
+    line-height: 20px;
     text-align: center;
     font-size: 16px;
     z-index: 99;
@@ -215,16 +215,18 @@ $--cc-list-upload-pre: cc-list-upload;
     position: absolute;
     width: 30px;
     height: 30px;
-    right: 10px;
-    z-index: auto;
+    top: 5px;
+    right: 15px;
+    z-index: 100;
     line-height: 30px;
     text-align: center;
-    font-size: 26px;
-    color: #c0c0c0;
+    font-size: 40px;
+    color: #fff;
+    text-shadow: 0 0 2px #333;
     cursor: pointer;
 
     &:hover {
-      color: #fff;
+      color: $--color-danger;
     }
   }
   &-body {
@@ -238,14 +240,19 @@ $--cc-list-upload-pre: cc-list-upload;
   }
   &-imgs {
     position: absolute;
+    top: 0;
+    left: 50%;
     width: 600px;
-    box-shadow: 0px 24px 36px 0px rgba(0, 0, 0, 0.3);
-    cursor: move;
-    transition: transform 0.2s linear;
+    margin-left: -300px;
+    // box-shadow: 0px 24px 36px 0px rgba(0, 0, 0, 0.3);
+    transition: width, height, transform 0.2s linear;
     z-index: 8;
     &-nosition {
       transition: none;
     }
+    &-move {
+      cursor: move;
+    }
     > img {
       display: block;
       width: 100%;
@@ -259,14 +266,14 @@ $--cc-list-upload-pre: cc-list-upload;
     top: 50%;
     margin-top: -80px;
     text-align: center;
-    color: #999;
+    color: #d0d0d0;
     z-index: 9;
-    cursor: pointer;
     font-size: 60px;
+    text-shadow: 0 0 2px #333;
+    cursor: pointer;
 
     &:hover {
-      color: #fff;
-      border-color: #b0b0b0;
+      color: #eee;
     }
     > i {
       margin-top: -5px;
@@ -280,14 +287,12 @@ $--cc-list-upload-pre: cc-list-upload;
   }
   &-footer {
     position: absolute;
-    width: 100%;
     height: 60px;
     bottom: 0;
-    left: 0;
+    right: 0;
     padding: 10px;
-    text-align: center;
     font-size: 30px;
-    color: #b0b0b0;
+    color: #d0d0d0;
     z-index: 99;
     li {
       display: inline-block;
@@ -296,23 +301,73 @@ $--cc-list-upload-pre: cc-list-upload;
       width: 40px;
       line-height: 40px;
       margin: 0 5px;
+      text-align: center;
       cursor: pointer;
       transition: transform 0.2s linear;
     }
     li:hover {
-      color: #fff;
+      // color: #000;
       transform: scale(1.1, 1.1);
     }
     li.li-disabled {
       cursor: not-allowed;
-      color: #b0b0b0 !important;
+      color: #d0d0d0 !important;
       transform: none !important;
     }
   }
 
-  /* element-dialog */
-  .el-dialog {
-    background: rgba(0, 0, 0, 0.3);
+  &-loading {
+    position: absolute;
+    width: 60px;
+    height: 60px;
+    top: 0;
+    left: 50%;
+    margin: 0 0 0 -30px;
+    color: $--border-color-base;
+    font-size: 50px;
+    text-align: center;
+    line-height: 60px;
+    z-index: 99;
+  }
+
+  &-preload {
+    position: absolute;
+    z-index: 9;
+    width: 100px;
+    height: 100px;
+    overflow: hidden;
+    top: -1000px;
+    left: -1000px;
+  }
+
+  &-none {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    color: #e0e0e0;
+    text-align: center;
+    font-size: 20px;
+    > i {
+      font-size: 30px;
+    }
+  }
+
+  // view-ui
+  .ivu-modal-content {
+    background: transparent;
+  }
+  .ivu-modal-header {
+    display: none;
+  }
+  .ivu-modal-body {
+    top: 0;
+  }
+  .ivu-modal-close {
+    display: none;
+  }
+  .ivu-modal-mask {
+    background: rgba(55, 55, 55, 0.8);
   }
 }
 

+ 18 - 0
src/assets/styles/element-ui-costom.scss

@@ -66,6 +66,24 @@
     @extend .el-popup-close;
   }
 }
+// .opacity-dialog
+.opacity-dialog {
+  .el-dialog {
+    background-color: transparent;
+  }
+  .el-dialog__header,
+  .el-dialog__footer {
+    display: none;
+  }
+  .el-dialog__body {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+    background-color: transparent;
+  }
+}
 // form
 .el-form {
   &-item {

+ 1 - 0
src/assets/styles/pages.scss

@@ -60,6 +60,7 @@
       right: 0;
       bottom: 0;
       z-index: auto;
+      cursor: pointer;
     }
 
     .image-delete {

+ 241 - 0
src/components/SimpleImagePreview.vue

@@ -0,0 +1,241 @@
+<template>
+  <el-dialog
+    :class="[prefixCls, 'opacity-dialog']"
+    :visible.sync="modalIsShow"
+    title="图片预览"
+    fullscreen
+    append-to-body
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+  >
+    <div slot="title"></div>
+    <div slot="footer"></div>
+    <div :class="[`${prefixCls}-close`]" @click="cancel">
+      <i class="el-icon-circle-close"></i>
+    </div>
+
+    <div :class="[`${prefixCls}-body`]" ref="ReviewBody">
+      <div
+        :class="[`${prefixCls}-guide`, `${prefixCls}-guide-prev`]"
+        @click.stop="showPrev"
+      >
+        <i class="el-icon-arrow-left"></i>
+      </div>
+      <div
+        :class="[`${prefixCls}-guide`, `${prefixCls}-guide-next`]"
+        @click.stop="showNext"
+      >
+        <i class="el-icon-arrow-right"></i>
+      </div>
+      <div
+        :class="[
+          `${prefixCls}-imgs`,
+          { [`${prefixCls}-imgs-nosition`]: nosition }
+        ]"
+        :style="styles"
+        v-if="modalIsShow"
+      >
+        <img
+          :key="curImage.url"
+          :src="curImage.url"
+          :alt="curImage.filename"
+          ref="PreviewImgDetail"
+          @load="reizeImage"
+        />
+      </div>
+      <div :class="[`${prefixCls}-none`]" v-if="!curImage.url">
+        <i class="el-icon-picture"></i>
+        <p>暂无数据</p>
+      </div>
+
+      <div :class="[`${prefixCls}-loading`]" v-show="loading">
+        <i class="el-icon-loading"></i>
+      </div>
+    </div>
+
+    <div :class="[`${prefixCls}-footer`]">
+      <ul>
+        <li title="旋转" @click.stop="toRotate">
+          <i class="el-icon-refresh-right"></i>
+        </li>
+      </ul>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+const prefixCls = "cc-image-preview";
+
+export default {
+  name: "simple-image-preview",
+  props: {
+    curImage: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      prefixCls,
+      modalIsShow: false,
+      styles: { width: "", height: "", top: "", left: "", transform: "" },
+      initWidth: 500,
+      transform: {
+        scale: 1,
+        rotate: 0
+      },
+      loading: false,
+      loadingSetT: null,
+      nosition: false
+    };
+  },
+  watch: {
+    "curImage.url": {
+      handler(val) {
+        if (val) {
+          this.loadingSetT = setTimeout(() => {
+            this.loading = true;
+          }, 300);
+          this.styles = {
+            width: "",
+            height: "",
+            top: "",
+            left: "",
+            transform: ""
+          };
+        }
+      }
+    }
+  },
+  methods: {
+    reizeImage() {
+      if (this.loadingSetT) clearTimeout(this.loadingSetT);
+
+      const imgDom = this.$refs.PreviewImgDetail;
+      const { naturalWidth, naturalHeight } = imgDom;
+      const imageSize = this.getImageSizePos({
+        win: {
+          width: this.$refs.ReviewBody.clientWidth,
+          height: this.$refs.ReviewBody.clientHeight
+        },
+        img: {
+          width: naturalWidth,
+          height: naturalHeight
+        },
+        rotate: 0
+      });
+
+      this.styles = Object.assign(this.styles, {
+        width: imageSize.width + "px",
+        height: imageSize.height + "px",
+        top: imageSize.top + "px",
+        left: imageSize.left + "px",
+        marginLeft: "auto",
+        transform: "none"
+      });
+      this.transform = {
+        scale: 1,
+        rotate: 0
+      };
+      this.loading = false;
+      setTimeout(() => {
+        this.nosition = false;
+      }, 100);
+    },
+    getImageSizePos({ win, img, rotate }) {
+      const imageSize = {
+        width: 0,
+        height: 0,
+        top: 0,
+        left: 0
+      };
+      const isHorizontal = !!(rotate % 180);
+
+      const rateWin = isHorizontal
+        ? win.height / win.width
+        : win.width / win.height;
+      const hwin = isHorizontal
+        ? {
+            width: win.height,
+            height: win.width
+          }
+        : win;
+
+      const rateImg = img.width / img.height;
+
+      if (rateImg <= rateWin) {
+        imageSize.height = Math.min(hwin.height, img.height);
+        imageSize.width = Math.floor(
+          (imageSize.height * img.width) / img.height
+        );
+      } else {
+        imageSize.width = Math.min(hwin.width, img.width);
+        imageSize.height = Math.floor(
+          (imageSize.width * img.height) / img.width
+        );
+      }
+      imageSize.left = (win.width - imageSize.width) / 2;
+      imageSize.top = (win.height - imageSize.height) / 2;
+      return imageSize;
+    },
+    cancel() {
+      this.modalIsShow = false;
+      this.$emit("on-close");
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    showPrev() {
+      this.$emit("on-prev");
+      // this.initData();
+    },
+    showNext() {
+      this.$emit("on-next");
+      // this.initData();
+    },
+    // dome-move
+    setStyleTransform() {
+      const { scale, rotate } = this.transform;
+      this.styles.transform = `scale(${scale}, ${scale}) rotate(${rotate}deg)`;
+    },
+    toRotate() {
+      this.transform.rotate = this.transform.rotate + 90;
+      this.setStyleTransform();
+      // 调整图片尺寸
+      const { naturalWidth, naturalHeight } = this.$refs.PreviewImgDetail;
+      const imageSize = this.getImageSizePos({
+        win: {
+          width: this.$refs.ReviewBody.clientWidth,
+          height: this.$refs.ReviewBody.clientHeight
+        },
+        img: {
+          width: naturalWidth,
+          height: naturalHeight
+        },
+        rotate: this.transform.rotate
+      });
+
+      this.styles = Object.assign(this.styles, {
+        width: imageSize.width + "px",
+        height: imageSize.height + "px",
+        top: imageSize.top + "px",
+        left: imageSize.left + "px"
+      });
+      // 360度无缝切换到0度
+      if (this.transform.rotate >= 360) {
+        setTimeout(() => {
+          this.nosition = true;
+          this.transform.rotate = 0;
+          this.setStyleTransform();
+          setTimeout(() => {
+            this.nosition = false;
+          }, 100);
+        }, 200);
+        // 200ms当次旋转动画持续时间
+      }
+    }
+  }
+};
+</script>

+ 47 - 3
src/modules/exam/components/ApplyContent.vue

@@ -94,7 +94,7 @@
           v-for="(img, index) in paperConfirmAttachments"
           :key="index"
         >
-          <img :src="img.url" :alt="img.filename" />
+          <img :src="img.url" :alt="img.filename" @click="toPreview(index)" />
           <div v-if="IS_APPLY" class="image-delete">
             <i
               class="el-icon-delete-solid"
@@ -177,6 +177,13 @@
       @draft-task="silentSave"
       @confirm="cardConfirm"
     ></card-option-dialog>
+    <!-- image-preview -->
+    <simple-image-preview
+      :cur-image="curImage"
+      @on-prev="toPrevImage"
+      @on-next="toNextImage"
+      ref="SimpleImagePreview"
+    ></simple-image-preview>
   </div>
 </template>
 
@@ -185,6 +192,7 @@ import UploadPaperDialog from "./UploadPaperDialog";
 import CardOptionDialog from "./CardOptionDialog";
 import { taskApplyDetail, updateTaskApply, updateTaskReview } from "../api";
 import { attachmentPreview } from "../../login/api";
+import SimpleImagePreview from "@/components/SimpleImagePreview";
 
 const initTaskApply = {
   examTaskId: "",
@@ -207,7 +215,7 @@ const initTaskApply = {
 
 export default {
   name: "apply-content",
-  components: { UploadPaperDialog, CardOptionDialog },
+  components: { UploadPaperDialog, CardOptionDialog, SimpleImagePreview },
   props: {
     examTask: {
       type: Object,
@@ -219,6 +227,12 @@ export default {
       type: String,
       default: "APPLY",
       validator: val => ["APPLY", "PREVIEW", "AUDIT"].includes(val)
+    },
+    examRule: {
+      type: Object,
+      default() {
+        return {};
+      }
     }
   },
   data() {
@@ -233,7 +247,10 @@ export default {
       attachmentLimitCount: 26,
       abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
       task: {},
-      reason: ""
+      reason: "",
+      // image-preview
+      curImage: {},
+      curImageIndex: 0
     };
   },
   computed: {
@@ -492,6 +509,33 @@ export default {
       if (!data) return;
       this.$message.success("审核成功!");
       this.$emit("modified");
+    },
+    // image-preview
+    toPreview(index) {
+      this.curImageIndex = index;
+      this.selectImage(index);
+      this.$refs.SimpleImagePreview.open();
+    },
+    selectImage(index) {
+      this.curImage = this.paperConfirmAttachments[index];
+    },
+    toPrevImage() {
+      if (this.curImageIndex === 0) {
+        this.curImageIndex = this.paperConfirmAttachments.length - 1;
+      } else {
+        this.curImageIndex--;
+      }
+
+      this.selectImage(this.curImageIndex);
+    },
+    toNextImage() {
+      if (this.curImageIndex === this.paperConfirmAttachments.length - 1) {
+        this.curImageIndex = 0;
+      } else {
+        this.curImageIndex++;
+      }
+
+      this.selectImage(this.curImageIndex);
     }
   }
 };