瀏覽代碼

离线文件上传

lideyin 5 年之前
父節點
當前提交
ef237ec606
共有 4 個文件被更改,包括 460 次插入23 次删除
  1. 1 0
      package.json
  2. 3 0
      src/modules/examwork/view/offlineExam.vue
  3. 40 4
      src/modules/oe/views/examDetail.vue
  4. 416 19
      src/modules/oe/views/examScheduling.vue

+ 1 - 0
package.json

@@ -23,6 +23,7 @@
     "randomcolor": "^0.5.4",
     "rasterizehtml": "^1.3.0",
     "register-service-worker": "^1.6.2",
+    "spark-md5": "^3.0.1",
     "viewerjs": "^1.3.6",
     "vue": "^2.6.10",
     "vue-awesome": "^3.5.4",

+ 3 - 0
src/modules/examwork/view/offlineExam.vue

@@ -201,6 +201,9 @@
                     <el-checkbox-group v-model="uploadFileType" class="input">
                       <el-checkbox label="ZIP" key="ZIP"></el-checkbox>
                       <el-checkbox label="PDF" key="PDF"></el-checkbox>
+                      <el-checkbox label="JPG" key="JPG"></el-checkbox>
+                      <el-checkbox label="JPEG" key="JPEG"></el-checkbox>
+                      <el-checkbox label="PNG" key="PNG"></el-checkbox>
                     </el-checkbox-group>
                   </el-form-item>
                 </el-row>

+ 40 - 4
src/modules/oe/views/examDetail.vue

@@ -301,7 +301,7 @@
                   class="operateRow"
                   v-if="
                     scope.row.examType == 'OFFLINE' &&
-                      scope.row.offlineFileUrl &&
+                      scope.row.offlineFiles &&
                       currentPagePrivileges.EXAM_QUERY_GETPAPER
                   "
                 >
@@ -311,7 +311,7 @@
                       type="primary"
                       icon="el-icon-view"
                       plain
-                      @click="downloadOfflineFile(scope.row.offlineFileUrl)"
+                      @click="downloadOfflineFile(scope.row.offlineFiles)"
                       >调卷</el-button
                     >
                   </el-col>
@@ -379,6 +379,27 @@
           </div>
         </el-form>
       </el-dialog>
+      <el-dialog
+        title="下载图片"
+        :visible.sync="downloadImageDialogVisible"
+        @closed="closeDownloadImageDialog"
+      >
+        <div style="max-width:350px;">
+          <div
+            class="block"
+            v-for="cof in currentOfflineFiles"
+            :key="'cof_' + cof.id"
+          >
+            <span class="demonstration">{{ cof.offlineFileName }}</span>
+            <el-image
+              @click="window.open(cof.offlineFileUrl)"
+              style="width: 100px; height: 100px"
+              :src="cof.offlineFileUrl"
+              fit="fill"
+            ></el-image>
+          </div>
+        </div>
+      </el-dialog>
     </el-main>
   </el-container>
 </template>
@@ -398,6 +419,8 @@ export default {
       tableLoading: false,
       showAllCondition: false,
       startExamDatetimeRange: [],
+      downloadImageDialogVisible: false,
+      currentOfflineFiles: [],
       form: {
         examRecordDataId: null,
         hasStranger: null,
@@ -565,8 +588,18 @@ export default {
         path: "/oe/captureDetail/" + examRecordDataId + "/examDetail"
       });
     },
-    downloadOfflineFile(url) {
-      window.open(url);
+    downloadOfflineFile(files) {
+      if (files && files.length > 0) {
+        for (let f of files) {
+          if (f.fileType != "image") {
+            window.open(files[0].offlineFileUrl);
+          } else {
+            this.currentOfflineFiles = files;
+            this.downloadImageDialogVisible = true;
+            break;
+          }
+        }
+      }
     },
     redoAudit(examRecordDataId, isPass) {
       if (isPass != "pass") {
@@ -684,6 +717,9 @@ export default {
         p2 = 0;
       }
       return p1 - p2;
+    },
+    closeDownloadImageDialog() {
+      this.downloadImageDialogVisible = false;
     }
   },
   created() {

+ 416 - 19
src/modules/oe/views/examScheduling.vue

@@ -229,10 +229,10 @@
                       type="primary"
                       size="mini"
                       icon="el-icon-download"
-                      @click="downloadAnswer(scope.row.offlineFileUrl)"
+                      @click="downloadAnswer(scope.row.offlineFiles)"
                       v-if="
                         scope.row.examType == 'OFFLINE' &&
-                          scope.row.offlineFileUrl
+                          scope.row.offlineFiles
                       "
                       >下载作答</el-button
                     >
@@ -259,30 +259,142 @@
           title="上传作答"
           v-loading="uploadAnswerDialogLoading"
           :visible.sync="uploadAnswerDialogVisible"
-          @closed="cleanOfflineFile"
         >
           <el-form>
+            <el-form-item label="选择文件类型">
+              <el-radio-group v-model="fileType" @change="handleFileTypeChange">
+                <el-radio label="zip">ZIP</el-radio>
+                <el-radio label="pdf">PDF</el-radio>
+                <el-radio label="image">图片(*.jpg|*.jpeg|*.png)</el-radio>
+              </el-radio-group>
+            </el-form-item>
             <el-form-item label="选择文件">
-              <input
-                type="file"
-                accept="application/pdf, application/zip"
-                id="importFile"
-                ref="offlineFileInput"
-                @change="uploadAnswerChange"
-                v-bind:class="{ offline_file: offlineAnswerFile }"
-              />
-              <div>温馨提示:仅支持pdf和zip文件,文件大小请不要超过30M!</div>
+              <div
+                v-show="fileType == 'image'"
+                style="width:580px;padding-left:80px;"
+              >
+                <el-upload
+                  class="upload-demo"
+                  ref="upload"
+                  action
+                  :limit="6"
+                  :http-request="customUpload"
+                  :before-upload="beforeFileUpload"
+                  :on-success="handleSuccess"
+                  :file-list="fileList"
+                  :auto-upload="false"
+                  :accept="accept"
+                  :on-change="handleChange"
+                  multiple
+                  list-type="picture-card"
+                >
+                  <i slot="default" class="el-icon-plus"></i>
+                  <div slot="file" slot-scope="{ file }">
+                    <img
+                      class="el-upload-list__item-thumbnail"
+                      :src="file.url"
+                      alt
+                    />
+                    <span class="el-upload-list__item-actions">
+                      <span
+                        class="el-upload-list__item-preview"
+                        @click="handlePictureCardPreview(file)"
+                      >
+                        <i class="el-icon-zoom-in"></i>
+                      </span>
+                      <span
+                        v-if="!disabled"
+                        class="el-upload-list__item-delete"
+                        @click="handleRemove(file)"
+                      >
+                        <i class="el-icon-delete"></i>
+                      </span>
+                    </span>
+                  </div>
+                </el-upload>
+
+                <div style="width:580px;">
+                  温馨提示:仅支持JPG,JPEG和PNG文件,单个图片大小请不要超过5M,图片数量最多6张!
+                </div>
+              </div>
+              <div v-show="fileType != 'image'">
+                <input
+                  type="file"
+                  accept="application/pdf, application/zip"
+                  id="importFile"
+                  ref="offlineFileInput"
+                  @change="uploadAnswerChange"
+                  v-bind:class="{ offline_file: offlineAnswerFile }"
+                />
+                <div>温馨提示:仅支持pdf和zip文件,文件大小请不要超过30M!</div>
+              </div>
             </el-form-item>
             <div class="dialog-footer">
-              <el-button @click="uploadAnswerDialogVisible = false"
-                >取 消</el-button
-              >
+              <el-button @click="cancelUpload">取 消</el-button>
               <el-button
+                v-show="fileType != 'image'"
                 :disabled="!offlineAnswerFile"
                 type="primary"
                 @click="doUploadAnswer"
                 >确 定</el-button
               >
+              <el-button
+                v-show="fileType == 'image'"
+                :disabled="batchSubmitUploadDisabled"
+                type="primary"
+                @click="batchSubmitUpload"
+                >确 定</el-button
+              >
+            </div>
+          </el-form>
+        </el-dialog>
+        <el-dialog :append-to-body="true" :visible.sync="dialogVisible">
+          <img width="100%" :src="dialogImageUrl" alt="" />
+        </el-dialog>
+        <el-dialog title="图片作答" :visible.sync="downloadImageDialogVisible">
+          <el-form>
+            <el-form-item label="作答结果">
+              <div style="width:580px;padding-left:80px;">
+                <el-upload
+                  class="upload-demo"
+                  action
+                  :limit="6"
+                  :file-list="imageAnswerFileList"
+                  multiple
+                  list-type="picture-card"
+                  :disabled="true"
+                >
+                  <i slot="default" class="el-icon-plus"></i>
+                  <div slot="file" slot-scope="{ file }">
+                    <img
+                      class="el-upload-list__item-thumbnail"
+                      :src="file.url"
+                      :alt="file.name"
+                    />
+                    <span class="el-upload-list__item-actions">
+                      <span
+                        class="el-upload-list__item-preview"
+                        @click="handlePictureCardPreview(file)"
+                      >
+                        <i class="el-icon-zoom-in"></i>
+                      </span>
+                      <span
+                        class="el-upload-list__item-delete"
+                        @click="handleDownload(file)"
+                      >
+                        <i class="el-icon-download"></i>
+                      </span>
+                    </span>
+                  </div>
+                </el-upload>
+              </div>
+            </el-form-item>
+            <div class="dialog-footer">
+              <el-button
+                type="primary"
+                @click="downloadImageDialogVisible = false"
+                >确 定</el-button
+              >
             </div>
           </el-form>
         </el-dialog>
@@ -295,17 +407,29 @@ import { mapState } from "vuex";
 import commonFormVue from "../component/commonForm.vue";
 import commonExportVue from "../component/commonExport.vue";
 import pagePrivilege from "../mixin/pagePrivilege.js";
+// import MD5 from "js-md5";
+import SparkMD5 from "spark-md5";
 export default {
   components: { commonFormVue, commonExportVue },
   mixins: [pagePrivilege],
   data() {
     return {
+      dialogImageUrl: "",
+      dialogVisible: false,
+      disabled: false,
       loading: false,
       uploadAnswerDialogLoading: false,
       uploadAnswerDialogVisible: false,
       total: 0,
       tableLoading: false,
       showAllCondition: false,
+      currentOfflineFiles: [],
+      fileType: "zip",
+      accept: "application/zip",
+      fileList: [],
+      offlineFiles: [],
+      downloadImageDialogVisible: false,
+      imageAnswerFileList: [],
       form: {
         examRecordDataId: null,
         hasStranger: null,
@@ -340,13 +464,74 @@ export default {
       offlineAnswerFile: "",
       currentPagePrivileges: {
         EXAM_PARTICULARS_EXPORT: false //导出
-      }
+      },
+      summary: "",
+      summaryList: [],
+      md5Size: 0
     };
   },
   computed: {
-    ...mapState({ user: state => state.user })
+    ...mapState({ user: state => state.user }),
+    batchSubmitUploadDisabled() {
+      return this.fileList.length != this.md5Size;
+    }
   },
   methods: {
+    cancelUpload() {
+      this.uploadAnswerDialogVisible = false;
+      this.removeImgs();
+    },
+    handleChange(file, fileList) {
+      this.fileList = fileList;
+      this.calcSummary(this.fileList);
+    },
+    getFileMD5(dataFile, callback) {
+      var fileReader = new FileReader();
+      var spark = new SparkMD5(); //创建md5对象(基于SparkMD5)
+      if (dataFile.size > 1024 * 1024 * 10) {
+        var data1 = dataFile.slice(0, 1024 * 1024 * 10); //将文件进行分块 file.slice(start,length)
+        fileReader.readAsBinaryString(data1); //将文件读取为二进制码
+      } else {
+        fileReader.readAsBinaryString(dataFile);
+      }
+
+      //文件读取完毕之后的处理
+      //a639e28526d1809745b46bf1189594fe  6d9efe0c593b1383482feb229318e03a
+      fileReader.onload = function(e) {
+        spark.appendBinary(e.target.result);
+        var md5 = spark.end();
+        console.log(md5);
+        callback(md5);
+      };
+    },
+    handleRemove(file) {
+      debugger;
+      let index = this.fileList.findIndex(p => p.uid == file.uid);
+      this.fileList.splice(index, 1);
+      this.calcSummary(this.fileList);
+    },
+    calcSummary(fileList) {
+      this.summaryList = [];
+      this.md5Size = 0;
+      for (let i = 0; i < fileList.length; i++) {
+        let f = fileList[i];
+        this.getFileMD5(f.raw, md5 => {
+          this.summaryList.push({ index: i, summary: md5 });
+          this.md5Size++;
+        });
+      }
+    },
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    handleDownload(file) {
+      window.open(file.url);
+      console.log(file);
+    },
+    removeImgs() {
+      this.$refs.upload.clearFiles();
+    },
     resetForm() {
       this.form = {
         examRecordDataId: null,
@@ -541,6 +726,7 @@ export default {
     },
     uploadAnswerChange(event) {
       if (event.target.files.length > 0) {
+        debugger;
         this.offlineAnswerFile = event.target.files[0];
       } else {
         this.offlineAnswerFile = "";
@@ -584,6 +770,7 @@ export default {
             headers: { "Content-Type": "multipart/form-data" }
           };
           let param = new FormData();
+          debugger;
           param.append("file", this.offlineAnswerFile);
           param.append("examRecordDataId", this.currentOfflineExamRecordDataId);
           this.$http
@@ -614,12 +801,222 @@ export default {
             });
         });
     },
+    beforeUpload(file) {
+      debugger;
+      var index = file.name.lastIndexOf(".");
+      var fileNameLength = file.name.length;
+      var fileSuffix = file.name
+        .substring(index + 1, fileNameLength)
+        .toUpperCase();
+      this.$http
+        .get(
+          "/api/ecs_exam_work/exam/property/" +
+            this.form.examId +
+            "/OFFLINE_UPLOAD_FILE_TYPE"
+        )
+        .then(response => {
+          var allowfileSuffixs = response.data;
+          if (!allowfileSuffixs || allowfileSuffixs.length == 0) {
+            this.$notify({
+              title: "提示",
+              message: "当前考试设置不允许上传附件",
+              type: "error",
+              duration: 2000
+            });
+            return false;
+          }
+          if (allowfileSuffixs.toString().indexOf(fileSuffix) < 0) {
+            this.$notify({
+              title: "提示",
+              message:
+                "当前考试允许上传文件格式为:" + allowfileSuffixs.toString(),
+              type: "error",
+              duration: 2000
+            });
+            return false;
+          }
+          this.offlineAnswerFile = file;
+        });
+
+      // function blobToArray(blob) {
+      //   return new Promise((resolve) => {
+      //     var reader = new FileReader();
+      //     reader.addEventListener("loadend", function() {
+      //       // reader.result contains the contents of blob as a typed array
+      //       resolve(reader.result);
+      //     });
+      //     reader.readAsArrayBuffer(blob);
+      //   });
+      // }
+      // const buffer = blobToArray(file);
+      // const fileMd5 = MD5(buffer);
+      // console.log(fileMd5);
+      // this.summary = fileMd5;
+
+      this.uploadData = {
+        examRecordDataId: this.currentOfflineExamRecordDataId,
+        summary: this.summary
+      };
+      console.log(this.uploadData);
+      let promise = new Promise(resolve => {
+        this.$nextTick(function() {
+          resolve(true);
+        });
+      });
+      return promise; //通过返回一个promis对象解决
+    },
+    blobToArray(blob) {
+      return new Promise(resolve => {
+        var reader = new FileReader();
+        reader.addEventListener("loadend", function() {
+          // reader.result contains the contents of blob as a typed array
+          resolve(reader.result);
+        });
+        reader.readAsArrayBuffer(blob);
+      });
+    },
+    submitUpload() {
+      debugger;
+      this.uploadAnswerDialogLoading = true;
+      let config = {
+        headers: { "Content-Type": "multipart/form-data" }
+      };
+      let param = new FormData();
+      param.append("file", this.offlineAnswerFile);
+      param.append("examRecordDataId", this.currentOfflineExamRecordDataId);
+      param.append("fileType", this.fileType);
+
+      // const buffer = this.blobToArray(this.offlineAnswerFile);
+      // const fileMd5 = MD5(buffer);
+      // console.log(fileMd5);
+      // this.summary = fileMd5;
+      // param.append("summary", this.summary);
+      this.$http
+        .post("/api/ecs_oe_admin/offlineExam/submitPaper", param, config)
+        .then(() => {
+          this.$notify({
+            title: "提示",
+            message: "上传成功",
+            type: "success",
+            duration: 2000
+          });
+          this.uploadAnswerDialogVisible = false;
+          this.$refs.offlineFileInput.value = "";
+          this.offlineAnswerFile = "";
+          this.search();
+        })
+        .catch(() => {
+          this.$notify({
+            title: "提示",
+            message: "上传失败",
+            type: "error",
+            duration: 2000
+          });
+          this.uploadAnswerDialogLoading = false;
+          this.$refs.offlineFileInput.value = "";
+          this.offlineAnswerFile = "";
+        });
+    },
     cleanOfflineFile() {
       this.$refs.offlineFileInput.value = "";
       this.offlineAnswerFile = "";
     },
-    downloadAnswer(offlineFileUrl) {
-      window.open(offlineFileUrl);
+    downloadAnswer(files) {
+      debugger;
+      if (files && files.length > 0) {
+        if (files[0].fileType != "image") {
+          window.open(files[0].offlineFileUrl);
+          return;
+        }
+
+        this.imageAnswerFileList = [];
+        for (let f of files) {
+          this.imageAnswerFileList.push({
+            url: f.offlineFileUrl,
+            name: f.offlineFileName
+          });
+        }
+        this.downloadImageDialogVisible = true;
+      }
+    },
+    handleFileTypeChange(ft) {
+      switch (ft) {
+        case "zip":
+          this.accept = "application/zip";
+          break;
+        case "pdf":
+          this.accept = "application/pdf";
+          break;
+        case "image":
+          this.accept = "image/jpeg,image/png";
+          break;
+      }
+    },
+    batchSubmitUpload() {
+      this.$refs.upload.submit();
+      debugger;
+      let params = new FormData();
+      params.append("examRecordDataId", this.currentOfflineExamRecordDataId);
+      params.append("fileType", this.fileType);
+      for (let f of this.fileList) {
+        params.append("files", f.raw);
+      }
+
+      //先对文件md5进行排序(按索引正序排列)
+      this.summaryList.sort((a, b) => a.index - b.index);
+      let summaries = [];
+      for (let s of this.summaryList) {
+        summaries.push(s.summary);
+      }
+      params.append("summaries", summaries);
+
+      let config = {
+        headers: { "Content-Type": "multipart/form-data" }
+      };
+      this.$http
+        .post("/api/ecs_oe_admin/offlineExam/batchSubmitPaper", params, config)
+        .then(() => {
+          this.$notify({
+            title: "提示",
+            message: "上传成功",
+            type: "success",
+            duration: 2000
+          });
+
+          this.uploadAnswerDialogVisible = false;
+          this.removeImgs();
+          this.offlineAnswerFile = "";
+          this.search();
+        })
+        .catch(() => {
+          this.$notify({
+            title: "提示",
+            message: "上传失败",
+            type: "error",
+            duration: 2000
+          });
+          this.uploadAnswerDialogLoading = false;
+          this.offlineAnswerFile = "";
+        });
+    },
+    beforeFileUpload(file) {
+      debugger;
+      const isLt5M = file.size / 1024 / 1024 <= 5;
+      if (!isLt5M) {
+        this.$message.error("上传的单个数据文件大小不能超过5MB!");
+      }
+      return isLt5M;
+    },
+    handleSuccess(response, file, fileList) {
+      console.log(response);
+      console.log(file);
+      console.log(fileList);
+      this.$message.success("上传成功");
+    },
+    customUpload(file) {
+      debugger;
+      this.offlineFiles.push(file.file);
+      return false;
     }
   },
   created() {}