zhangjie %!s(int64=5) %!d(string=hai) anos
pai
achega
85d39d50d8

+ 10 - 0
src/assets/styles/icons.scss

@@ -156,6 +156,16 @@
     width: 18px;
     height: 14px;
   }
+  &-upload {
+    background-image: url(../images/icon-upload.png);
+    width: 18px;
+    height: 14px;
+  }
+  &-upload-act {
+    background-image: url(../images/icon-upload-act.png);
+    width: 18px;
+    height: 14px;
+  }
 
   // card
   &-help {

+ 19 - 2
src/components/UploadButton.vue

@@ -12,7 +12,10 @@
     style="display:inline-block;margin: 0 18px;"
     ref="UploadComp"
   >
-    <slot></slot>
+    <!-- <slot></slot> -->
+    <el-button :type="btnType" :icon="btnIcon" :loading="loading">{{
+      btnContent
+    }}</el-button>
   </el-upload>
 </template>
 
@@ -22,6 +25,16 @@ import { fileMD5 } from "../plugins/md5";
 export default {
   name: "import-file",
   props: {
+    btnIcon: {
+      type: String
+    },
+    btnType: {
+      type: String,
+      default: "default"
+    },
+    btnContent: {
+      type: String
+    },
     format: {
       type: Array,
       default() {
@@ -50,7 +63,8 @@ export default {
   data() {
     return {
       headers: {},
-      res: {}
+      res: {},
+      loading: false
     };
   },
   created() {
@@ -85,10 +99,12 @@ export default {
 
       const md5 = await fileMD5(file);
       this.headers["md5"] = md5;
+      this.loading = true;
 
       return true;
     },
     handleError(error) {
+      this.loading = false;
       this.res = {
         success: false,
         msg: error.message
@@ -96,6 +112,7 @@ export default {
       this.$emit("upload-error", error);
     },
     handleSuccess(response) {
+      this.loading = false;
       if (response.code === "200") {
         this.res = {
           success: true,

+ 6 - 0
src/constants/enumerate.js

@@ -77,3 +77,9 @@ export const RESERVE_TYPE = {
   0: "考试任务备用方式",
   1: "考场备用方式"
 };
+
+export const CARD_SOURCE_TYPE = {
+  0: "选择已有答题卡",
+  1: "自组创建",
+  2: "申请客服制卡"
+};

+ 6 - 1
src/main.js

@@ -53,7 +53,12 @@ var queue = [];
 // 解决js处理超过16位number时精度丢失的问题
 axios.defaults.transformResponse = [
   data => {
-    return JSON.parse(data.replace(/([0-9]{16,19})/g, `"$1"`));
+    return JSON.parse(
+      data
+        .replace(/([0-9]{16,19})/g, '"$1"')
+        .replace(/\\""/g, '\\"')
+        .replace(/"\\"/g, '\\"')
+    );
   }
 ];
 axios.interceptors.request.use(

+ 2 - 3
src/modules/base/components/BusinessFields.vue

@@ -20,15 +20,14 @@
       </el-form-item>
       <el-form-item>
         <upload-button
+          btn-icon="icon icon-share-gray"
+          btn-content="导入考务扩展字段"
           :upload-url="uploadUrl"
           :format="['xls', 'xlsx']"
           @upload-error="uplaodError"
           @upload-success="uploadSuccess"
           style="margin:10px 0 0;"
         >
-          <el-button class="btn-table-icon" icon="icon icon-share-gray"
-            >导入考务扩展字段</el-button
-          >
         </upload-button>
       </el-form-item>
     </el-form>

+ 3 - 1
src/modules/base/views/UserManage.vue

@@ -46,13 +46,15 @@
             >查询</el-button
           >
           <upload-button
+            btn-icon="icon icon-share"
+            btn-type="warning"
+            btn-content="导入"
             :upload-url="uploadUrl"
             :format="['xls', 'xlsx']"
             :upload-data="uploadData"
             @upload-error="uplaodError"
             @upload-success="uploadSuccess"
           >
-            <el-button type="warning" icon="icon icon-share">导入</el-button>
           </upload-button>
         </el-form-item>
       </el-form>

+ 40 - 43
src/modules/card/api.js

@@ -1,54 +1,51 @@
 import { $get, $post } from "@/plugins/axios";
 
-export const cardInfosById = id => {
-  return $post("/backend/login", id);
+export const cardDetail = id => {
+  return $get("/api/print/card/card/detailEdit", id);
 };
-export const cardConfigInfos = datas => {
-  // return $get("/backend/sysuser/resetPwd", datas);
-  return Promise.resolve({
-    missAndFill: true,
-    writeSign: true,
-    examNumberStyle: "auto", // auto:自动条码, empty:手动条码, fill:手动涂填
-    aOrBSystem: true, // 后台附带的aOrB设置,如果有则使用这个值,如果没有则前台自动设置
-    aOrBType: "auto", // fill:手动涂填,auto:自动条码
-    schoolName: "河南财经政法大学",
-    businessParams: [
-      {
-        name: "学号",
-        field: "studentNo"
-      },
-      {
-        name: "姓名",
-        field: "username"
-      },
-      {
-        name: "科目名称",
-        field: "courseName"
-      },
-      {
-        name: "课程名称",
-        field: "subjectName"
-      }
-    ],
-    noticeHead: [
-      "答题前,请考生认真核对姓名、学号、教学班号、课程名称等信息,确认无误后签名。",
-      "客观题部分必须使用2B铅笔填涂,主观题部分请使用黑色签字笔写在指定的答题区内。",
-      "保持卡面清洁,不破损。"
-    ],
-    objectiveNotice:
-      "注意:必须使用2B铅笔填涂;在答题区内作答,超出涂填边框限定区域的答案无效。",
-    subjectiveNotice:
-      "注意:必须使用黑色字迹签字笔书写;在答题区内作答,超出以下黑色矩形边框限定区域的答案无效。"
-  });
+export const cardConfigInfos = () => {
+  return $get("/api/print/basic/cardRule/selectBySchoolId", {});
+  // return Promise.resolve({
+  //   missAndFill: true,
+  //   writeSign: true,
+  //   examNumberStyle: "auto", // auto:自动条码, empty:手动条码, fill:手动涂填
+  //   aOrBSystem: true, // 后台附带的aOrB设置,如果有则使用这个值,如果没有则前台自动设置
+  //   aOrBType: "auto", // fill:手动涂填,auto:自动条码
+  //   schoolName: "河南财经政法大学",
+  //   businessParams: [
+  //     {
+  //       name: "学号",
+  //       field: "studentNo"
+  //     },
+  //     {
+  //       name: "姓名",
+  //       field: "username"
+  //     },
+  //     {
+  //       name: "科目名称",
+  //       field: "courseName"
+  //     },
+  //     {
+  //       name: "课程名称",
+  //       field: "subjectName"
+  //     }
+  //   ],
+  //   noticeHead: [
+  //     "答题前,请考生认真核对姓名、学号、教学班号、课程名称等信息,确认无误后签名。",
+  //     "客观题部分必须使用2B铅笔填涂,主观题部分请使用黑色签字笔写在指定的答题区内。",
+  //     "保持卡面清洁,不破损。"
+  //   ],
+  //   objectiveNotice:
+  //     "注意:必须使用2B铅笔填涂;在答题区内作答,超出涂填边框限定区域的答案无效。",
+  //   subjectiveNotice:
+  //     "注意:必须使用黑色字迹签字笔书写;在答题区内作答,超出以下黑色矩形边框限定区域的答案无效。"
+  // });
 };
 
 export const saveCard = datas => {
-  return $post("/backend/sysuser/resetPwd", datas);
+  return $post("/api/print/card/card/add", datas);
 };
 
-export const cardDetail = cardId => {
-  return $get("/backend/sysuser/resetPwd", cardId);
-};
 export const cardStudentInfo = ({ cardId, studentNo }) => {
   return $get("/backend/sysuser/resetPwd", { cardId, studentNo });
 };

+ 17 - 2
src/modules/exam-center/api.js

@@ -33,6 +33,9 @@ export const examListPage = datas => {
 export const examList = () => {
   return $get("/api/print/exam/exam/list", {});
 };
+export const examSiteRoomList = () => {
+  return $get("/api/print/exam/exam/listRooms", {});
+};
 export const examDetail = examId => {
   return $get("/api/print/exam/exam/preEdit", { examId });
 };
@@ -62,8 +65,17 @@ export const courseList = () => {
 };
 
 // card-manage
-export const allCardList = datas => {
-  return $get("/api/print/exam/notDone/listCards", datas);
+export const cardList = datas => {
+  return $get("/api/print/card/card/list", datas);
+};
+export const cardListPage = datas => {
+  return $get("/api/print/card/card/listPage", datas);
+};
+export const CopyCard = cardId => {
+  return $post("/api/print/card/card/copy", { cardId });
+};
+export const deleteCard = cardId => {
+  return $post("/api/print/card/card/delete", { cardId });
 };
 
 // print-manage
@@ -72,6 +84,9 @@ export const printTaskListPage = datas => {
 };
 
 // card-audit
+export const createCardAudit = (datas, headers) => {
+  return $post("/api/print/exam/exam/listPrintPage", datas, { headers });
+};
 
 // custom upload-file
 export const customUpload = options => {

+ 154 - 0
src/modules/exam-center/components/CardOptionDialog.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="card-option-dialog">
+    <el-dialog
+      class="card-option-dialog"
+      :visible.sync="modalIsShow"
+      title="选择制卡方式"
+      top="10vh"
+      width="559px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      @opened="visibleChange"
+    >
+      <div class="card-option-body">
+        <p>请您选择创建题卡方式:</p>
+        <p>1.自助创建:使用题卡工具自助设计题卡,操作简单,即刻生成;</p>
+        <p>
+          2.申请客服制卡:需提交试卷,由客服后台统一处理,处理完毕后您可查看或微调。
+        </p>
+        <div class="card-type">
+          <el-radio-group v-model="modalForm.cardSource">
+            <el-radio
+              v-for="(val, key) in CARD_SOURCE_TYPE"
+              :key="key"
+              :label="key"
+              >{{ val }}</el-radio
+            >
+          </el-radio-group>
+        </div>
+        <!-- card-select -->
+        <div class="card-select" v-if="modalForm.cardSource === '0'">
+          <el-select
+            v-model="modalForm.refCardId"
+            style="width: 193px;"
+            placeholder="请选择"
+            clearable
+          >
+            <el-option
+              v-for="item in cards"
+              :key="item.id"
+              :value="item.id"
+              :label="item.title"
+            ></el-option>
+          </el-select>
+          <span class="card-view" @click="toPreview">预览</span>
+        </div>
+      </div>
+      <div slot="footer" style="text-align: right;">
+        <el-button type="primary" @click="confirm">保存</el-button>
+        <el-button @click="cancel">返回</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- upload-sample-paper-dialog -->
+    <upload-sample-paper-dialog
+      ref="UploadSamplePaperDialog"
+    ></upload-sample-paper-dialog>
+  </div>
+</template>
+
+<script>
+import { CARD_SOURCE_TYPE } from "@/constants/enumerate";
+import { cardList } from "../api";
+import UploadSamplePaperDialog from "./UploadSamplePaperDialog";
+
+export default {
+  name: "card-option-dialog-view",
+  props: {
+    data: {
+      type: Object
+    },
+    noExam: {
+      type: Boolean,
+      default: false
+    }
+  },
+  components: { UploadSamplePaperDialog },
+  data() {
+    return {
+      modalIsShow: false,
+      modalForm: {
+        cardSource: "",
+        refCardId: ""
+      },
+      cards: [],
+      CARD_SOURCE_TYPE
+    };
+  },
+  methods: {
+    visibleChange() {
+      this.modalForm.cardSource = this.data.cardSource || "0";
+      this.getCardList();
+    },
+    async getCardList() {
+      this.cards = await cardList();
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    confirm() {
+      if (this.modalForm.cardSource === "2") {
+        this.$refs.UploadSamplePaperDialog.open();
+        return;
+      }
+
+      if (this.modalForm.cardSource === "1") {
+        // 打开题卡编辑页,创建题卡,并预设需要绑定的任务
+        this.$ls.set("prepareBindTask", this.data);
+        this.$router.push({
+          name: "CardDesign"
+        });
+        return;
+      }
+
+      if (this.modalForm.cardSource === "0" && !this.modalForm.refCardId) {
+        this.$message.error("请选择已有的题卡!");
+        return;
+      }
+
+      const data = { ...this.modalForm };
+      if (data.cardSource !== "0") data.refCardId = "";
+      this.$emit("confirm", data);
+      this.cancel();
+    },
+    toPreview() {
+      window.open(`/card/preview/${this.modalForm.refCardId}/view`);
+    }
+  }
+};
+</script>
+
+<style scoped>
+.card-option-body {
+  color: #878787;
+}
+.card-type {
+  margin: 32px 0;
+}
+.card-select {
+  margin-bottom: 10px;
+}
+.card-view {
+  display: inline-block;
+  margin-left: 10px;
+  color: rgba(35, 196, 185, 1);
+  cursor: pointer;
+}
+.card-view:hover {
+  color: rgba(28, 208, 161, 1);
+}
+</style>

+ 0 - 172
src/modules/exam-center/components/FileUploadView.vue

@@ -1,172 +0,0 @@
-<template>
-  <el-dialog
-    class="file-upload-view"
-    :visible.sync="modalIsShow"
-    title="上传试卷文件"
-    top="10vh"
-    width="580px"
-    :close-on-click-modal="false"
-    :close-on-press-escape="false"
-    append-to-body
-    @open="visibleChange"
-  >
-    <div class="file-upload-body">
-      <el-form label-width="75px" label-position="left">
-        <el-form-item label="试卷文件:">
-          <el-input
-            v-model="file.name"
-            style="width: 270px;"
-            readonly
-          ></el-input>
-          <el-upload
-            style="display:inline-block;margin: 0 26px 0 10px;"
-            :action="uploadUrl"
-            :headers="headers"
-            :max-size="maxSize"
-            :format="format"
-            :accept="accept"
-            :data="uploadData"
-            :before-upload="handleBeforeUpload"
-            :on-error="handleError"
-            :on-success="handleSuccess"
-            :on-remove="handleRemove"
-            ref="UploadComp"
-          >
-            <el-button type="primary">选择</el-button>
-          </el-upload>
-          <el-button @click="toPreview">预览</el-button>
-        </el-form-item>
-      </el-form>
-      <p
-        slot="tip"
-        :class="[
-          `cc-tips`,
-          {
-            'cc-tips-success': res.success,
-            'cc-tips-error': !res.success
-          }
-        ]"
-        v-if="res.msg"
-      >
-        {{ res.msg }}
-      </p>
-    </div>
-    <div slot="footer" style="text-align: right">
-      <el-button type="primary" @click="confirm">保存</el-button>
-      <el-button @click="cancel">返回</el-button>
-    </div>
-  </el-dialog>
-</template>
-
-<script>
-export default {
-  name: "file-upload-view",
-  data() {
-    return {
-      modalIsShow: false,
-      file: {},
-      uploadUrl: this.GLOBAL.domain + "/api/print/basic/sys/saveAttachment",
-      maxSize: 10 * 1024 * 1024,
-      addFilenameParam: "file",
-      headers: {},
-      uploadData: {},
-      format: ["doc", "docx"],
-      res: {
-        success: true,
-        msg: ""
-      }
-    };
-  },
-  computed: {
-    accept() {
-      return this.format.map(el => `.${el}`).join();
-    }
-  },
-  methods: {
-    visibleChange() {
-      this.res = {
-        success: true,
-        msg: ""
-      };
-    },
-    checkFileFormat(fileType) {
-      const _file_format = fileType
-        .split("/")
-        .pop()
-        .toLocaleLowerCase();
-      return this.format.some(
-        item => item.toLocaleLowerCase() === _file_format
-      );
-    },
-    handleBeforeUpload(file) {
-      this.file = {
-        id: "",
-        name: file.name
-      };
-
-      if (this.addFilenameParam)
-        this.uploadData[this.addFilenameParam] = file.name;
-
-      if (file.size > this.maxSize) {
-        this.handleExceededSize();
-        return Promise.reject();
-      }
-
-      if (!this.checkFileFormat(file.type)) {
-        this.handleFormatError();
-        return Promise.reject();
-      }
-
-      return true;
-    },
-    handleError(error) {
-      this.res = {
-        success: false,
-        msg: error.message
-      };
-      this.$emit("upload-error", error);
-    },
-    handleSuccess(response) {
-      this.res = {
-        success: true,
-        msg: "导入成功!"
-      };
-      this.$emit("upload-success", response);
-    },
-    handleFormatError() {
-      this.res = {
-        success: false,
-        msg: "只支持文件格式为" + this.format.join("/")
-      };
-      this.$refs.UploadComp.clearFiles();
-    },
-    handleExceededSize() {
-      this.res = {
-        success: false,
-        msg: "文件大小不能超过" + Math.floor(this.maxSize / 1024) + "M"
-      };
-      this.$refs.UploadComp.clearFiles();
-    },
-    handleRemove() {
-      this.$refs.UploadComp.abort();
-      this.$refs.UploadComp.clearFiles();
-    },
-    cancel() {
-      this.modalIsShow = false;
-    },
-    open() {
-      this.modalIsShow = true;
-    },
-    confirm() {
-      this.$emit("confirm", this.file);
-    },
-    toPreview() {}
-  }
-};
-</script>
-
-<style lang="css" scoped>
-.file-upload-body {
-  min-height: 150px;
-}
-</style>

+ 17 - 8
src/modules/exam-center/components/ExamBusinessUpload.vue → src/modules/exam-center/components/UploadFileView.vue

@@ -1,9 +1,9 @@
 <template>
-  <div class="exam-business-upload">
+  <div class="upload-file-view">
     <el-input
-      style="width: 439px;"
+      :style="{ width: inputWidth }"
       v-model.trim="attachmentName"
-      placeholder="考务文件"
+      placeholder="文件名称"
       readonly
     ></el-input>
     <el-upload
@@ -11,7 +11,7 @@
       :headers="headers"
       :max-size="maxSize"
       :format="format"
-      :data="uploadData"
+      :data="uploadDataDict"
       :on-change="handleFileChange"
       :before-upload="handleBeforeUpload"
       :on-error="handleError"
@@ -40,8 +40,12 @@ import { fileMD5 } from "@/plugins/md5";
 import ajax from "@/plugins/ajax";
 
 export default {
-  name: "exam-business-upload",
+  name: "upload-file-view",
   props: {
+    inputWidth: {
+      type: String,
+      default: "439px"
+    },
     format: {
       type: Array,
       default() {
@@ -72,6 +76,7 @@ export default {
       attachmentName: "",
       canUpload: false,
       loading: false,
+      uploadDataDict: {},
       headers: {
         token: this.$ls.get("token"),
         md5: ""
@@ -98,8 +103,12 @@ export default {
       this.canUpload = file.status === "ready";
     },
     async handleBeforeUpload(file) {
-      if (this.addFilenameParam)
-        this.uploadData[this.addFilenameParam] = file.name;
+      this.uploadDataDict = {
+        ...this.uploadData,
+        schoolId: this.$ls.get("schoolId"),
+        userId: this.$ls.get("user", { id: "" }).id
+      };
+      this.uploadDataDict[this.addFilenameParam] = file.name;
 
       if (file.size > this.maxSize) {
         this.handleExceededSize();
@@ -166,7 +175,7 @@ export default {
 </script>
 
 <style scoped>
-.exam-business-upload {
+.upload-file-view {
   display: inline-block;
 }
 </style>

+ 101 - 0
src/modules/exam-center/components/UploadPaperDialog.vue

@@ -0,0 +1,101 @@
+<template>
+  <el-dialog
+    class="file-upload-view"
+    :visible.sync="modalIsShow"
+    title="上传试卷文件"
+    top="10vh"
+    width="685px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <div class="file-upload-body">
+      <el-form label-width="75px" label-position="left">
+        <el-form-item label="试卷文件:">
+          <upload-file-view
+            input-width="270px"
+            :format="['doc', 'docx']"
+            :upload-url="uploadUrl"
+            @upload-error="uplaodError"
+            @upload-success="uploadSuccess"
+            ref="UploadFileView"
+          ></upload-file-view>
+          <el-button @click="toPreview" style="margin-left: 10px;"
+            >预览</el-button
+          >
+        </el-form-item>
+      </el-form>
+    </div>
+    <div slot="footer" style="text-align: right">
+      <el-button type="primary" @click="confirm">保存</el-button>
+      <el-button @click="cancel">返回</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import UploadFileView from "../components/UploadFileView";
+import { attachmentPreview } from "../../login/api";
+
+export default {
+  name: "file-upload-view",
+  components: { UploadFileView },
+  props: {
+    paperAttachment: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      attachment: {},
+      // import
+      uploadUrl: "/api/print/basic/sys/saveAttachment"
+    };
+  },
+  methods: {
+    visibleChange() {
+      this.$refs.UploadFileView.setAttachmentName(
+        `${this.paperAttachment.filename || ""}`
+      );
+      this.attachment = { ...this.paperAttachment };
+    },
+    // upload-handler
+    uplaodError(msg) {
+      this.$message.error(msg);
+    },
+    uploadSuccess(res) {
+      this.$message.success("上传成功!");
+      this.attachment = Object.assign(this.attachment, {
+        id: res.data.id,
+        filename: `${res.data.name}${res.data.type}`
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    confirm() {
+      this.$emit("confirm", this.attachment);
+      this.cancel();
+    },
+    async toPreview() {
+      if (!this.attachment.id) {
+        this.$message.error("请先上传附件!");
+        return;
+      }
+      const data = await attachmentPreview(this.attachment.id);
+      window.open(data.path);
+    }
+  }
+};
+</script>
+
+<style lang="css" scoped>
+.file-upload-body {
+  min-height: 150px;
+}
+</style>

+ 149 - 0
src/modules/exam-center/components/UploadSamplePaperDialog.vue

@@ -0,0 +1,149 @@
+<template>
+  <el-dialog
+    class="upload-sample-paper-dialog"
+    :visible.sync="modalIsShow"
+    title="上传样卷或试卷结构文件"
+    top="10vh"
+    width="560px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="visibleChange"
+  >
+    <div class="file-upload-body">
+      <el-form
+        ref="ModalForm"
+        :model="modalForm"
+        :rules="rules"
+        label-width="85px"
+        label-position="left"
+      >
+        <el-form-item prop="title" label="文件标题:">
+          <el-input
+            style="width:386px"
+            v-model.trim="modalForm.title"
+            placeholder="请输入文件标题"
+          ></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button icon="icon icon-upload" @click="handleClick"
+            >选择上传文件</el-button
+          >
+          <span style="margin-left: 10px;"
+            >上传的单个试卷文件大小不超过20M</span
+          >
+          <input
+            ref="fileInput"
+            type="file"
+            style="visibility:hidden;"
+            @change="handleChange"
+          />
+        </el-form-item>
+      </el-form>
+    </div>
+    <div slot="footer" style="text-align: right">
+      <el-button type="primary" @click="confirm">保存</el-button>
+      <el-button @click="cancel">返回</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { fileMD5 } from "@/plugins/md5";
+import { createCardAudit } from "../api";
+
+export default {
+  name: "upload-sample-paper-dialog",
+  props: {},
+  data() {
+    return {
+      modalIsShow: false,
+      attachmentName: "",
+      format: ["doc", "docx"],
+      modalForm: {
+        title: "",
+        schoolId: this.$ls.get("schoolId"),
+        userId: this.$ls.get("user", { id: "" }).id
+      },
+      maxSize: 20 * 1024,
+      addFilenameParam: "filename",
+      loading: false,
+      uploadUrl: "/api/print/basic/sys/saveAttachment",
+      headers: {
+        token: this.$ls.get("token"),
+        md5: ""
+      },
+      rules: {
+        title: [
+          {
+            required: true,
+            message: "请输入文件标题",
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    visibleChange() {
+      this.modalForm.title = "";
+      this.$refs.fileInput.value = "";
+    },
+    handleClick() {
+      if (this.loading) return;
+      this.$refs.fileInput.value = "";
+      this.$refs.fileInput.click();
+    },
+    async handleChange(e) {
+      let file = e.target.files[0];
+      this.modalForm[this.addFilenameParam] = file.name;
+
+      if (file.size > this.maxSize) {
+        this.handleExceededSize();
+      }
+
+      if (!this.checkFileFormat(file.name)) {
+        this.handleFormatError();
+      }
+
+      const md5 = await fileMD5(file);
+      this.headers["md5"] = md5;
+    },
+    checkFileFormat(fileType) {
+      const _file_format = fileType
+        .split(".")
+        .pop()
+        .toLocaleLowerCase();
+      return this.format.some(
+        item => item.toLocaleLowerCase() === _file_format
+      );
+    },
+    handleFormatError() {
+      const content = "只支持文件格式为" + this.format.join("/");
+      this.$message.error(content);
+    },
+    handleExceededSize() {
+      const content =
+        "文件大小不能超过" + Math.floor(this.maxSize / 1024) + "M";
+      this.$message.error(content);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async confirm() {
+      const valid = await this.$refs["ModalForm"].validate().catch(() => {});
+      if (!valid) return;
+
+      this.loading = true;
+      await createCardAudit(this.modalForm, this.headers).catch(() => {});
+      this.loading = false;
+      this.$message.success("申请客户制作题卡成功!");
+      this.$emit("confirm");
+      this.cancel();
+    }
+  }
+};
+</script>

+ 2 - 2
src/modules/exam-center/router.js

@@ -51,7 +51,7 @@ export default [
     }
   },
   {
-    path: "/exam-center/exam-room-detail/:examId",
+    path: "/exam-center/exam-room-detail/:examId?",
     name: "ExamRomeDetail",
     component: ExamRomeDetail,
     meta: {
@@ -59,7 +59,7 @@ export default [
     }
   },
   {
-    path: "/exam-center/exam-room-student-detail/:examRoomId",
+    path: "/exam-center/exam-room-student-detail/:examRoomInfo?",
     name: "ExamRomeStudentDetail",
     component: ExamRomeStudentDetail,
     meta: {

+ 7 - 5
src/modules/exam-center/views/CardManage.vue

@@ -46,7 +46,7 @@
     </div>
 
     <div class="part-box">
-      <el-table ref="TableList" :data="examPages" border stripe>
+      <el-table ref="TableList" :data="cards" border stripe>
         <el-table-column prop="id" label="题目ID"></el-table-column>
         <el-table-column label="科目(代码)">
           <template slot-scope="scope">
@@ -78,7 +78,7 @@
               class="btn-table-icon"
               type="text"
               icon="icon icon-delete"
-              @click="toEdit(scope.row)"
+              @click="toDelete(scope.row)"
               title="确认"
             ></el-button>
             <el-button
@@ -132,7 +132,7 @@ export default {
       visible: false,
       AUDITING_STATUS,
       exams: [],
-      examPages: [{ id: "" }],
+      cards: [],
       curExam: {}
     };
   },
@@ -147,7 +147,7 @@ export default {
         pageSize: this.size
       };
       const data = await printTaskListPage(datas);
-      this.examPages = data.records;
+      this.cards = data.records;
       this.total = data.total;
     },
     toPage(page) {
@@ -170,7 +170,9 @@ export default {
     },
     toEdit(row) {
       this.curExam = row;
-      this.$refs.ModifyData.open();
+    },
+    toDelete(row) {
+      this.curExam = row;
     }
   }
 };

+ 7 - 13
src/modules/exam-center/views/ExamModify.vue

@@ -16,13 +16,12 @@
         ></el-input>
       </el-form-item>
       <el-form-item prop="examCodeTemp" label="考务文件:">
-        <exam-business-upload
+        <upload-file-view
           :upload-url="uploadUrl"
-          :upload-data="uploadData"
           @upload-error="uplaodError"
           @upload-success="uploadSuccess"
-          ref="ExamBusinessUpload"
-        ></exam-business-upload>
+          ref="UploadFileView"
+        ></upload-file-view>
         <el-button @click="toPreview" style="margin-left:16px;">预览</el-button>
       </el-form-item>
       <el-form-item label="考试开始时间:">
@@ -105,11 +104,11 @@
 import { RESERVE_TYPE } from "@/constants/enumerate";
 import { uploadExam, examDetail } from "../api";
 import BusinessData from "../components/BusinessData";
-import ExamBusinessUpload from "../components/ExamBusinessUpload";
+import UploadFileView from "../components/UploadFileView";
 
 export default {
   name: "exam-modify",
-  components: { BusinessData, ExamBusinessUpload },
+  components: { BusinessData, UploadFileView },
   data() {
     const printTimeValidator = (rule, value, callback) => {
       if (!this.checkDateRangeValid(value, this.modalForm.beginTime)) {
@@ -184,11 +183,7 @@ export default {
       courses: [],
       isSubmit: false,
       // import
-      uploadUrl: "/api/print/exam/exam/impExamData",
-      uploadData: {
-        schoolId: this.$ls.get("schoolId"),
-        userId: this.$ls.get("user", { id: "" }).id
-      }
+      uploadUrl: "/api/print/exam/exam/impExamData"
     };
   },
   computed: {
@@ -207,7 +202,7 @@ export default {
       this.modalForm = Object.assign({}, this.modalForm, data.tcPExam);
       this.modalForm.backup += "";
       this.courses = data.userCourses;
-      this.$refs.ExamBusinessUpload.setAttachmentName(
+      this.$refs.UploadFileView.setAttachmentName(
         `${data.tcPAttachment.name}${data.tcPAttachment.type}`
       );
     },
@@ -263,7 +258,6 @@ export default {
       this.modalForm.beginTime = data.startTime;
       this.modalForm.examCodeTemp = data.examCode;
       this.modalForm.attachmentId = data.attachmentId;
-      console.log(`data.attachmentId=${data.attachmentId}`);
       this.$refs["ModalForm"].validateField("examCodeTemp");
 
       this.courses = data.userCourses.map(item => {

+ 44 - 26
src/modules/exam-center/views/ExamRomeDetail.vue

@@ -7,42 +7,44 @@
             v-model="filter.examId"
             style="width: 193px;"
             placeholder="请选择"
+            @change="examChange"
             clearable
           >
             <el-option
               v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="场次ID:" label-width="75px">
           <el-select
-            v-model="filter.examId"
+            v-model="filter.sceneNumberId"
             style="width: 193px;"
             placeholder="请选择"
+            @change="sceneChange"
             clearable
           >
             <el-option
-              v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              v-for="item in scenes"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="考点:" label-width="55px">
           <el-select
-            v-model="filter.examId"
+            v-model="filter.examSite"
             style="width: 193px;"
             placeholder="请选择"
             clearable
           >
             <el-option
-              v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              v-for="item in sites"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
@@ -58,14 +60,14 @@
 
     <div class="part-box">
       <el-table ref="TableList" :data="examPages" border stripe>
-        <el-table-column prop="id" label="场次ID"></el-table-column>
+        <el-table-column prop="sceneNumberId" label="场次ID"></el-table-column>
         <el-table-column prop="examName" label="考试名称"></el-table-column>
-        <el-table-column prop="paperStatus" label="考场名称"></el-table-column>
+        <el-table-column prop="examRoom" label="考场名称"></el-table-column>
         <el-table-column
-          prop="cardStatus"
+          prop="courseCodeAndName"
           label="科目名称(ID)"
         ></el-table-column>
-        <el-table-column prop="createTime" label="应考科次"></el-table-column>
+        <el-table-column prop="examTotal" label="应考科次"></el-table-column>
         <el-table-column label="操作" align="center">
           <template slot-scope="scope">
             <el-button
@@ -95,7 +97,7 @@
 
 <script>
 import { PRINT_STATUS } from "@/constants/enumerate";
-import { examRoomDetail, examList } from "../api";
+import { examRoomDetail, examSiteRoomList } from "../api";
 
 export default {
   name: "exam-room-detail",
@@ -112,14 +114,19 @@ export default {
       visible: false,
       PRINT_STATUS,
       exams: [],
+      scenes: [],
+      sites: [],
       examPages: []
     };
   },
   created() {
-    this.getList();
-    this.getExamList();
+    this.init();
   },
   methods: {
+    init() {
+      this.getList();
+      this.getExamSiteRoomList();
+    },
     async getList() {
       const datas = {
         ...this.filter,
@@ -134,20 +141,31 @@ export default {
       this.current = page;
       this.getList();
     },
-    async getExamList() {
-      const data = await examList();
-      this.exams = data.map(item => {
-        return {
-          id: item.id,
-          name: item.examName
-        };
-      });
+    async getExamSiteRoomList() {
+      this.exams = await examSiteRoomList();
+      this.examChange();
+    },
+    examChange() {
+      const curExam = this.exams.find(exam => exam.code === this.filter.examId);
+      if (!curExam) return;
+      this.scenes = curExam.sceneNumbers;
+      this.filter.sceneNumberId = "";
+      this.sites = [];
+      this.filter.examSite = "";
+    },
+    sceneChange() {
+      const curScene = this.scenes.find(
+        scene => scene.code === this.filter.sceneNumberId
+      );
+      if (!curScene) return;
+      this.sites = curScene.examSites;
+      this.filter.examSite = "";
     },
     toDetail(row) {
       this.$router.push({
         name: "ExamRomeStudentDetail",
         params: {
-          examRoomId: "1"
+          examRoomInfo: `${row.examId}-${row.sceneNumberId}-${row.examSite}-${row.examRoomId}`
         }
       });
     }

+ 109 - 46
src/modules/exam-center/views/ExamRomeStudentDetail.vue

@@ -7,75 +7,84 @@
             v-model="filter.examId"
             style="width: 193px;"
             placeholder="请选择"
+            @change="examChange"
             clearable
           >
             <el-option
               v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="场次ID:" label-width="75px">
           <el-select
-            v-model="filter.examId"
+            v-model="filter.sceneNumberId"
             style="width: 193px;"
             placeholder="请选择"
+            @change="sceneChange"
             clearable
           >
             <el-option
-              v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              v-for="item in scenes"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="考点:" label-width="55px">
           <el-select
-            v-model="filter.examId"
+            v-model="filter.examSite"
             style="width: 193px;"
             placeholder="请选择"
+            @change="siteChange"
             clearable
           >
             <el-option
-              v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              v-for="item in sites"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="考场:" label-width="55px">
           <el-select
-            v-model="filter.examId"
+            v-model="filter.examRoomId"
             style="width: 193px;"
             placeholder="请选择"
             clearable
           >
             <el-option
-              v-for="item in exams"
-              :key="item.id"
-              :value="item.id"
+              v-for="item in rooms"
+              :key="item.code"
+              :value="item.code"
               :label="item.name"
             ></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="学号:" label-width="55px">
-          <el-select
-            v-model="filter.examId"
+          <el-input
+            v-model="filter.studentCode"
+            placeholder="请输入"
+            style="width: 193px;"
+            clearable
+          ></el-input>
+          <!-- <el-select
+            v-model="filter.studentCode"
             style="width: 193px;"
             placeholder="请选择"
             clearable
           >
             <el-option
-              v-for="item in exams"
+              v-for="item in students"
               :key="item.id"
               :value="item.id"
               :label="item.name"
             ></el-option>
-          </el-select>
+          </el-select> -->
         </el-form-item>
         <el-form-item label-width="0px">
           <el-button type="primary" icon="icon icon-search" @click="toPage(1)"
@@ -87,21 +96,30 @@
     </div>
 
     <div class="part-box">
-      <el-table ref="TableList" :data="examPages" border stripe>
-        <el-table-column prop="id" label="场次ID"></el-table-column>
-        <el-table-column prop="examName" label="考点名称"></el-table-column>
+      <el-table ref="TableList" :data="studentList" border stripe>
+        <el-table-column
+          prop="sceneNumberId"
+          label="场次ID"
+          width="80"
+        ></el-table-column>
+        <el-table-column prop="examSite" label="考点名称"></el-table-column>
         <el-table-column prop="examName" label="考试名称"></el-table-column>
-        <el-table-column prop="paperStatus" label="考场名称"></el-table-column>
+        <el-table-column prop="examRoom" label="考场名称"></el-table-column>
+        <el-table-column label="科目名称(ID)" min-width="100">
+          <template slot-scope="scope">
+            {{ scope.row.courseName }}({{ scope.row.courseCode }})
+          </template>
+        </el-table-column>
+        <el-table-column prop="examNumber" label="考号"></el-table-column>
+        <el-table-column prop="name" label="姓名"></el-table-column>
+        <el-table-column prop="studentCode" label="学号"></el-table-column>
         <el-table-column
-          prop="cardStatus"
-          label="科目名称(ID)"
+          prop="gender"
+          label="性别"
+          width="60"
         ></el-table-column>
-        <el-table-column prop="createTime" label="考号"></el-table-column>
-        <el-table-column prop="createTime" label="姓名"></el-table-column>
-        <el-table-column prop="createTime" label="学号"></el-table-column>
-        <el-table-column prop="createTime" label="性别"></el-table-column>
-        <el-table-column prop="createTime" label="教学班号"></el-table-column>
-        <el-table-column prop="createTime" label="座位号"></el-table-column>
+        <el-table-column label="教学班号"></el-table-column>
+        <el-table-column prop="siteNumber" label="座位号"></el-table-column>
       </el-table>
       <div class="part-page">
         <el-pagination
@@ -120,7 +138,7 @@
 
 <script>
 import { PRINT_STATUS } from "@/constants/enumerate";
-import { examListPage, examList } from "../api";
+import { studentDetail, examSiteRoomList } from "../api";
 
 export default {
   name: "exam-room-detail",
@@ -128,8 +146,10 @@ export default {
     return {
       filter: {
         examId: "",
-        printStatus: "",
-        printTime: ""
+        sceneNumberId: "",
+        examSite: "",
+        examRoomId: "",
+        studentCode: ""
       },
       current: 1,
       size: this.GLOBAL.pageSize,
@@ -137,36 +157,79 @@ export default {
       visible: false,
       PRINT_STATUS,
       exams: [],
-      examPages: [{ id: "" }],
-      curExam: {}
+      scenes: [],
+      sites: [],
+      rooms: [],
+      studentList: []
     };
   },
   created() {
-    // this.getList();
+    this.init();
   },
   methods: {
+    async init() {
+      const examRoomInfo = this.$route.params.examRoomInfo;
+      if (!examRoomInfo) return;
+
+      const [examId, sceneNumberId, examSite, examRoomId] = examRoomInfo.split(
+        "-"
+      );
+
+      this.getList();
+      // review selected
+      await this.getExamSiteRoomList();
+      this.filter.examId = examId;
+      this.examChange();
+      this.filter.sceneNumberId = sceneNumberId;
+      this.sceneChange();
+      this.filter.examSite = examSite;
+      this.siteChange();
+      this.filter.examRoomId = examRoomId;
+    },
     async getList() {
       const datas = {
         ...this.filter,
         pageNumber: this.current,
         pageSize: this.size
       };
-      const data = await examListPage(datas);
-      this.examPages = data.records;
+      const data = await studentDetail(datas);
+      this.studentList = data.records;
       this.total = data.total;
     },
     toPage(page) {
       this.current = page;
       this.getList();
     },
-    async getExamList() {
-      const data = await examList();
-      this.exams = data.map(item => {
-        return {
-          id: item.id,
-          name: item.examName
-        };
-      });
+    async getExamSiteRoomList() {
+      this.exams = await examSiteRoomList();
+    },
+    examChange() {
+      const curExam = this.exams.find(exam => exam.code === this.filter.examId);
+      if (!curExam) return;
+      this.scenes = curExam.sceneNumbers;
+      this.filter.sceneNumberId = "";
+      this.sites = [];
+      this.filter.examSite = "";
+      this.rooms = [];
+      this.filter.examRoomId = "";
+    },
+    sceneChange() {
+      const curScene = this.scenes.find(
+        scene => scene.code === this.filter.sceneNumberId
+      );
+      if (!curScene) return;
+      this.sites = curScene.examSites;
+      this.filter.examSite = "";
+      this.rooms = [];
+      this.filter.examRoomId = "";
+    },
+    siteChange() {
+      const curSite = this.sites.find(
+        site => site.code === this.filter.examSite
+      );
+      if (!curSite) return;
+      this.rooms = curSite.examRooms;
+      this.filter.examRoomId = "";
     },
     toDetail(row) {
       this.$router.push({

+ 96 - 27
src/modules/exam-center/views/WaitTaskDetail.vue

@@ -3,7 +3,7 @@
     <div class="task-title">
       <h2>
         <span>考试名称: {{ task.examName }} </span>
-        <span>科目名称:{{ task.courseName }}</span>
+        <span>科目名称:{{ task.courseNameCode }}</span>
       </h2>
       <div class="task-title-infos">
         <el-checkbox v-model="pTypeEnable" @change="pTypeEnableChange"
@@ -21,14 +21,14 @@
         <tr v-for="(attachment, index) in curPaperAttachments" :key="index">
           <td>{{ attachment.name }}卷</td>
           <td class="td-link">
-            <span @click="toUpload(attachment)">
+            <span @click="toUpload(attachment)" title="点击上传试卷">
               <i
                 :class="[
                   'icon',
                   attachment.id ? 'icon-files-act' : 'icon-files'
                 ]"
               ></i
-              >点击上传试卷文件
+              >{{ attachment.id ? attachment.filename : "点击上传试卷文件" }}
             </span>
           </td>
           <td
@@ -36,37 +36,62 @@
             :rowspan="pTypeEnable ? curPaperAttachments.length : 1"
             v-if="index === 0"
           >
-            <span><i class="icon icon-plus-act"></i>创建答题卡</span>
+            <span @click="toCreateCard"
+              ><i class="icon icon-plus-act"></i
+              >{{ task.cardId ? "预览题卡" : "创建答题卡" }}</span
+            >
           </td>
         </tr>
       </table>
 
       <div class="task-action">
-        <el-button type="primary" style="width:105px;">确认提交</el-button>
-        <el-button style="width:88px;">暂存</el-button>
+        <el-button type="primary" style="width:105px;" @click="toSubmit"
+          >确认提交</el-button
+        >
+        <el-button style="width:88px;" @click="toSave">暂存</el-button>
         <el-button @click="goback" style="width:88px;">取消</el-button>
       </div>
     </div>
 
-    <!-- file-upload-view -->
-    <file-upload-view ref="FileUploadView"></file-upload-view>
+    <!-- upload-paper-dialog -->
+    <upload-paper-dialog
+      :paper-attachment="curAttachment"
+      @confirm="uploadConfirm"
+      ref="UploadPaperDialog"
+    ></upload-paper-dialog>
+    <!-- card-option-dialog -->
+    <card-option-dialog
+      :data="task"
+      ref="CardOptionDialog"
+      @confirm="cardConfirm"
+    ></card-option-dialog>
   </div>
 </template>
 
 <script>
-import { waitTaskDetail, saveWaitTask } from "../api";
-import FileUploadView from "../components/FileUploadView";
+import { waitTaskDetail, saveWaitTask, submitWaitTask } from "../api";
+import UploadPaperDialog from "../components/UploadPaperDialog";
+import CardOptionDialog from "../components/CardOptionDialog";
 
 export default {
   name: "wait-task-detail",
   components: {
-    FileUploadView
+    UploadPaperDialog,
+    CardOptionDialog
   },
   data() {
     return {
       taskId: this.$route.params.taskId,
       PAPER_TYPE_FIELDS: ["A", "B"],
-      task: {},
+      task: {
+        id: "",
+        taskId: "",
+        enablePaperType: "A",
+        paperAttachmentId: "",
+        cardId: "",
+        cardSource: "",
+        refCardId: ""
+      },
       pTypeEnable: false,
       paperAttachments: [],
       curPaperAttachments: [],
@@ -83,26 +108,27 @@ export default {
   },
   methods: {
     async getData() {
-      this.task = await waitTaskDetail(this.taskId);
+      const data = await waitTaskDetail(this.taskId);
+      this.task = Object.assign(this.task, data);
       this.pTypeEnable = this.task.enablePaperType.split(",").length > 1;
       this.parsePaperAttachment();
+      this.pTypeEnableChange(this.pTypeEnable);
     },
     parsePaperAttachment() {
       const paperAttachment =
         this.task.paperAttachmentId && JSON.parse(this.task.paperAttachmentId);
-      const pagers = paperAttachment && paperAttachment.paper;
-      let pagerDict = {};
-      if (pagers) {
-        pagers.map(paper => {
-          pagerDict[paper.name] = paper;
+      const papers = paperAttachment && paperAttachment.paper;
+      let paperDict = {};
+      if (papers) {
+        papers.map(paper => {
+          paperDict[paper.name] = paper;
         });
       }
       this.paperAttachments = this.PAPER_TYPE_FIELDS.map(paperType => {
-        const paperInfo = pagerDict[paperType];
+        const paperInfo = paperDict[paperType];
         let paper = {
           id: "",
-          name: paperType,
-          path: ""
+          name: paperType
         };
         return paperInfo ? Object.assign({}, paper, paperInfo) : paper;
       });
@@ -113,14 +139,57 @@ export default {
         : [this.paperAttachments[0]];
     },
     toUpload(attachment) {
-      this.curAttachment = attachment;
-      this.$refs.FileUploadView.open();
+      this.curAttachment = { ...attachment };
+      this.$refs.UploadPaperDialog.open();
+    },
+    uploadConfirm(attachment) {
+      this.curAttachment = Object.assign(this.curAttachment, attachment);
+      const index = this.paperAttachments.findIndex(
+        item => item.name === attachment.name
+      );
+      this.paperAttachments.splice(index, 1, { ...this.curAttachment });
+      this.pTypeEnableChange(this.pTypeEnable);
+    },
+    toCreateCard() {
+      if (this.task.cardId) {
+        window.open(`/card/preview/${this.task.cardId}/view`);
+        return;
+      }
+      this.$refs.CardOptionDialog.open();
+    },
+    cardConfirm(options) {
+      this.task = Object.assign(this.task, options);
     },
-    async save() {
+    getTaskData() {
       let datas = { ...this.task };
-      if (this.pTypeEnable)
-        datas.enablePaperType = this.PAGE_TYPE_FIELDS.join();
-      await saveWaitTask(datas);
+      datas.taskId = this.taskId;
+      datas.paperAttachmentId = JSON.stringify({
+        paper: this.curPaperAttachments
+      });
+      datas.enablePaperType = this.curPaperAttachments
+        .map(item => item.name)
+        .join(",");
+      return datas;
+    },
+    toSubmit() {
+      this.$confirm(
+        "任务确定提交后,则不可更改试卷及答题卡内容,确定提交该任务?",
+        "提示",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      ).then(async () => {
+        await submitWaitTask(this.getTaskData());
+        this.$message.success("提交成功!");
+        this.goback();
+      });
+    },
+    async toSave() {
+      await saveWaitTask(this.getTaskData());
+      this.$message.success("保存成功!");
+      this.goback();
     }
   }
 };

+ 3 - 0
src/modules/login/api.js

@@ -9,3 +9,6 @@ export const logout = userId => {
 export const sysMenu = datas => {
   return $post("/api/print/basic/sys/getMenu", datas);
 };
+export const attachmentPreview = attachmentId => {
+  return $get("/api/print/basic/sys/attachmentPreview", { attachmentId });
+};

+ 4 - 1
src/plugins/ajax.js

@@ -16,7 +16,10 @@ function getError(action, option, xhr) {
 }
 // 解决后台返回的数据中number位数超过16位的情况
 function bigNumberToString(text) {
-  return text.replace(/([0-9]{16,19})/g, '"$1"');
+  return text
+    .replace(/([0-9]{16,19})/g, '"$1"')
+    .replace(/\\""/g, '\\"')
+    .replace(/"\\"/g, '\\"');
 }
 
 function getBody(xhr) {