zhangjie 3 سال پیش
والد
کامیت
954477f401

+ 5 - 2
src/modules/base/api.js

@@ -123,6 +123,9 @@ export const deleteCourse = idList => {
 export const updateCourse = datas => {
   return $post("/api/admin/basic/course/save", datas);
 };
+export const ableCourse = ({ id, enable }) => {
+  return $post("/api/admin/basic/course/enable", { id, enable });
+};
 // flow-manage
 export const flowListPage = datas => {
   return $postParam("/api/admin/flow/list", datas);
@@ -133,8 +136,8 @@ export const flowPublish = id => {
 export const flowEnd = flowId => {
   return $post("/api/admin/flow/end", { flowId });
 };
-export const flowDelete = () => {
-  return $post("/api/admin/flow/enable", {});
+export const flowDelete = id => {
+  return $post("/api/admin/flow/enable", { id });
 };
 export const flowRegister = (datas, headers) => {
   return $post("/api/admin/flow/register", datas, { headers });

+ 53 - 5
src/modules/base/views/CourseManage.vue

@@ -11,6 +11,21 @@
               clearable
             ></el-input>
           </el-form-item>
+          <el-form-item label="启用/禁用:" label-width="90px">
+            <el-select
+              v-model="filter.enable"
+              style="width: 120px;"
+              placeholder="启用/禁用"
+              clearable
+            >
+              <el-option
+                v-for="(val, key) in ABLE_TYPE"
+                :key="key"
+                :value="key * 1"
+                :label="val"
+              ></el-option>
+            </el-select>
+          </el-form-item>
           <el-form-item label="创建时间:">
             <el-date-picker
               v-model="createTime"
@@ -86,6 +101,11 @@
             scope.row.createTime | timestampFilter
           }}</span>
         </el-table-column>
+        <el-table-column prop="enable" label="启用/禁用" width="100">
+          <template slot-scope="scope">
+            {{ scope.row.enable | enableFilter }}
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="120px">
           <template slot-scope="scope">
             <el-button
@@ -97,11 +117,17 @@
             >
             <el-button
               v-if="checkPrivilege('link', 'delete')"
+              :class="scope.row.enable ? 'btn-danger' : 'btn-primary'"
+              type="text"
+              @click="toEnable(scope.row)"
+              >{{ scope.row.enable ? "禁用" : "启用" }}</el-button
+            >
+            <!-- <el-button
               class="btn-danger"
               type="text"
               @click="toDelete(scope.row)"
               >删除</el-button
-            >
+            > -->
           </template>
         </el-table-column>
       </el-table>
@@ -127,10 +153,11 @@
 </template>
 
 <script>
-import { courseListPage, deleteCourse } from "../api";
+import { courseListPage, deleteCourse, ableCourse } from "../api";
 import pickerOptions from "@/constants/datePickerOptions";
 import ModifyCourse from "../components/ModifyCourse";
 import UploadButton from "../../../components/UploadButton";
+import { ABLE_TYPE } from "@/constants/enumerate";
 
 export default {
   name: "course-manage",
@@ -140,20 +167,22 @@ export default {
       filter: {
         courseName: "",
         startCreateTime: "",
-        endCreateTime: ""
+        endCreateTime: "",
+        enable: ""
       },
-      pickerOptions,
+      ABLE_TYPE,
       current: 1,
       size: this.GLOBAL.pageSize,
       total: 0,
       courses: [],
+      curCourse: {},
       // import
       uploadUrl: "/api/admin/basic/course/data_import",
       downloadUrl: "/temps/courseTemplate.xlsx",
       dfilename: "课程导入模板.xlsx",
       // date-picker
       createTime: [],
-      curCourse: {}
+      pickerOptions
     };
   },
   mounted() {
@@ -172,6 +201,9 @@ export default {
         datas.startCreateTime = this.createTime[0];
         datas.endCreateTime = this.createTime[1];
       }
+      if (datas.enable !== null && datas.enable !== "")
+        datas.enable = !!datas.enable;
+
       const data = await courseListPage(datas);
       this.courses = data.records;
       this.total = data.total;
@@ -199,6 +231,22 @@ export default {
         })
         .catch(() => {});
     },
+    toEnable(row) {
+      const action = row.enable ? "禁用" : "启用";
+      this.$confirm(`确定要${action}课程【${row.courseName}】吗?`, "提示", {
+        type: "warning"
+      })
+        .then(async () => {
+          const enable = !row.enable;
+          await ableCourse({
+            id: row.id,
+            enable
+          });
+          row.enable = enable;
+          this.$message.success("操作成功!");
+        })
+        .catch(() => {});
+    },
     // import
     uplaodError(errorData) {
       this.$notify.error({ title: "错误提示", message: errorData.message });

+ 1 - 1
src/modules/base/views/FlowManage.vue

@@ -135,7 +135,7 @@ export default {
         type: "warning"
       })
         .then(async () => {
-          await flowDelete();
+          await flowDelete(row.id);
           this.$message.success("操作成功!");
           this.getList();
         })

+ 0 - 1
src/modules/exam/components/CreatePrintTask.vue

@@ -52,7 +52,6 @@
         <el-input-number
           v-model="modalForm.studentCount"
           :min="0"
-          :max="10000"
           :step="1"
           step-strictly
           disabled

+ 294 - 0
src/modules/exam/components/createTaskApply/CreateTaskApply.vue

@@ -0,0 +1,294 @@
+<template>
+  <el-dialog
+    class="create-task-apply"
+    :visible.sync="modalIsShow"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :show-close="false"
+    append-to-body
+    fullscreen
+    destroy-on-close
+    @open="visibleChange"
+  >
+    <div slot="title">
+      <span class="el-dialog__title">新增命题申请</span>
+      <button class="el-dialog__headerbtn" @click="close"></button>
+    </div>
+
+    <el-steps class="apply-step" :active="current" align-center>
+      <el-step
+        v-for="step in steps"
+        :key="step.name"
+        :title="step.name"
+        :description="step.title"
+      >
+      </el-step>
+    </el-steps>
+
+    <component
+      :is="currentComponent"
+      :ref="currentComponent"
+      @next-step="toNext"
+      @on-ready="compReady"
+    ></component>
+
+    <div slot="footer">
+      <el-button v-if="!isFirstStep" type="primary" @click="prevStep"
+        >上一步</el-button
+      >
+      <el-button
+        v-if="isLastStep"
+        type="success"
+        :disabled="isSubmit"
+        @click="submit"
+        >确认提交</el-button
+      >
+      <el-button v-else type="primary" @click="nextStep" :disabled="nextHolder"
+        >下一步</el-button
+      >
+      <el-button @click="cancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { examRuleDetail } from "../../base/api";
+import { teacherCreateTaskApply, teacherCancelTaskApply } from "../api";
+
+const STEPS_LIST = [
+  {
+    name: "exam-task",
+    title: "命题信息"
+  },
+  {
+    name: "print",
+    title: "备卷印品信息"
+  },
+  {
+    name: "exam-business",
+    title: "考务信息"
+  }
+];
+
+const initExamTask = {
+  id: null,
+  courseCode: "",
+  courseName: "",
+  paperNumber: "",
+  cardRuleId: "",
+  teachingRoomId: "",
+  teacherName: "",
+  lecturerName: ""
+};
+
+const initExamTaskDetail = {
+  operateType: "STAGE",
+  paperType: "A",
+  cardId: "",
+  paperAttachmentIds: [],
+  paperConfirmAttachmentIds: [],
+  drawCount: 2,
+  remark: "",
+  makeMethod: "",
+  // 题卡状态
+  status: "",
+  // 考务规则
+  review: false,
+  includePaper: false,
+  customCard: false
+};
+
+const initPrintPlan = {
+  id: null,
+  name: "",
+  examStartTime: "",
+  examEndTime: "",
+  printContent: [],
+  backupMethod: "ROOM",
+  backupCount: 1,
+  drawRule: "ONE",
+  variableContent: [
+    {
+      type: "SIGN",
+      templateId: [],
+      oldTemplateId: [],
+      backupMethod: "ROOM",
+      backupCount: 1
+    },
+    {
+      type: "PACKAGE",
+      templateId: [],
+      oldTemplateId: [],
+      backupMethod: "ROOM",
+      backupCount: 1
+    }
+  ],
+  ordinaryContent: [
+    {
+      type: "CHECK_IN",
+      templateId: [],
+      oldTemplateId: [],
+      backupMethod: "ROOM",
+      backupCount: 1
+    }
+  ]
+};
+
+const initPrintTask = {
+  printPlanName: "",
+  printPlanId: "",
+  examStartTime: "",
+  examEndTime: "",
+  paperNumber: "",
+  courseName: "",
+  courseCode: "",
+  list: []
+};
+
+export default {
+  name: "create-task-apply",
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      needReview: false,
+      examRule: {},
+      infos: {},
+      // step
+      steps: STEPS_LIST,
+      current: 0,
+      nextHolder: false,
+      isPaying: false,
+      dataReady: true
+    };
+  },
+  computed: {
+    currentComponent() {
+      return `info-${this.steps[this.current].name}`;
+    },
+    isFirstStep() {
+      return this.current === 0;
+    },
+    isLastStep() {
+      return this.current === this.lastStep;
+    },
+    lastStep() {
+      return this.steps.length - 1;
+    },
+    isFree() {
+      return this.infos.free || !this.infos.fee;
+    },
+    payBtnName() {
+      return this.isFree ? "确认并提交" : "确认并缴费";
+    }
+  },
+  created() {
+    this.getExamRule();
+  },
+  methods: {
+    async getExamRule() {
+      const examRule = await examRuleDetail();
+      this.examRule = examRule || {};
+      this.needReview = examRule && examRule.review;
+    },
+    initData() {
+      const examTaskDetail = Object.assign({}, initExamTaskDetail, {
+        includePaper: this.examRule.includePaper,
+        review: this.examRule.review,
+        customCard: this.examRule.customCard
+      });
+
+      this.infos = {
+        examTask: { ...initExamTask },
+        examTaskDetail,
+        printPlan: { ...initPrintPlan },
+        printTask: { ...initPrintTask }
+      };
+    },
+    visibleChange() {
+      this.initData();
+    },
+    prevStep() {
+      if (this.isFirstStep) return;
+      this.current -= 1;
+    },
+    nextStep() {
+      if (this.isLastStep) return;
+      this.$refs[this.currentComponent].checkForm();
+    },
+    toNext() {
+      if (this.isLastStep) return;
+      this.current += 1;
+      this.nextHolder = true;
+    },
+    compReady(type = false) {
+      this.nextHolder = type;
+    },
+    checkData() {
+      return this.$refs.examTaskComp.validate().catch(() => {});
+    },
+    async cancel() {
+      if (this.examTask.id) {
+        await teacherCancelTaskApply(this.examTask.id);
+        this.$message.success("取消命题申请成功!");
+      }
+      this.close();
+    },
+    close() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async toSave(silent) {
+      const valid = await this.$refs.examTaskComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      this.getTaskDetailData();
+      const datas = {
+        examTaskDetail: this.examTaskDetail,
+        examTask: this.examTask
+      };
+      const data = await teacherCreateTaskApply(datas).catch(() => {});
+      this.isSubmit = false;
+      if (!data) return;
+
+      this.examTask = this.$objAssign(this.examTask, data);
+
+      if (!silent) this.$message.success("保存成功!");
+      return true;
+    },
+    async submit() {
+      const valid = await this.$refs.examTaskComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (!this.checkDataValid()) return;
+
+      this.$confirm(
+        "任务确定提交后,则不可更改试卷及答题卡内容,确定提交该任务?",
+        "提示",
+        {
+          type: "warning"
+        }
+      )
+        .then(async () => {
+          this.getTaskDetailData();
+          this.examTaskDetail.operateType = "SUBMIT";
+          const datas = {
+            examTaskDetail: this.examTaskDetail,
+            examTask: this.examTask
+          };
+          const data = await teacherCreateTaskApply(datas).catch(() => {});
+
+          if (!data) return;
+          this.$message.success("提交成功!");
+          this.close();
+          this.$emit("modified");
+        })
+        .catch(() => {});
+    }
+  }
+};
+</script>

+ 15 - 0
src/modules/exam/components/createTaskApply/InfoExamBusiness.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="info-exam-business">
+    info-exam-business
+  </div>
+</template>
+
+<script>
+export default {
+  name: "info-exam-business",
+  data() {
+    return {};
+  },
+  methods: {}
+};
+</script>

+ 624 - 0
src/modules/exam/components/createTaskApply/InfoExamTask.vue

@@ -0,0 +1,624 @@
+<template>
+  <div class="info-exam-task">
+    <div class="part-box part-box-pad part-box-border">
+      <el-form
+        ref="examTaskComp"
+        :model="examTask"
+        :rules="rules"
+        label-width="120px"
+      >
+        <el-row>
+          <el-col :span="12">
+            <el-form-item prop="teachingRoomId" label="教研室:">
+              <teaching-room-select
+                v-model="examTask.teachingRoomId"
+                @change="teachingRoomChange"
+              ></teaching-room-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item prop="courseCode" label="课程(代码):">
+              <course-select
+                v-model="examTask.courseCode"
+                :teaching-room-id="examTask.teachingRoomId"
+                @change="courseChange"
+              ></course-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item prop="cardRuleId" label="题卡规则:">
+              <card-rule-select
+                ref="CardRuleSelect"
+                v-model.trim="examTask.cardRuleId"
+                placeholder="请选择"
+                clearable
+                @change="clearCard"
+              ></card-rule-select>
+              <p class="tips-info">
+                说明:若选择全部通卡,则命题老师只能选择通卡,若选择题卡规则,则专卡和通卡均可选择
+              </p>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="试卷编号:">
+              <el-input
+                v-model.trim="examTask.paperNumber"
+                placeholder="请输入试卷编号"
+                :maxlength="50"
+                clearable
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="拟卷教师:">
+              <el-input
+                v-model.trim="examTask.teacherName"
+                placeholder="请输入拟卷教师"
+                :maxlength="50"
+                clearable
+              ></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="主讲教师:">
+              <el-input
+                v-model.trim="examTask.lecturerName"
+                placeholder="请输入主讲教师"
+                :maxlength="50"
+                clearable
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </div>
+
+    <div class="task-apply-steps" v-if="flows.length">
+      <el-steps align-center>
+        <el-step
+          v-for="flow in flows"
+          :key="flow.taskKey"
+          :title="flow.taskName"
+          :status="flow.status"
+        >
+          <div slot="description">
+            <div class="step-info" v-if="flow.firstUser">
+              <span>{{ flow.firstUser }}</span>
+              <el-popover
+                v-if="flow.moreUser"
+                placement="top-start"
+                width="300"
+                trigger="hover"
+                :content="flow.moreUser"
+              >
+                <span class="color-primary ml-1" slot="reference">更多</span>
+              </el-popover>
+            </div>
+          </div>
+        </el-step>
+      </el-steps>
+    </div>
+
+    <div class="apply-content task-detail">
+      <div class="task-body">
+        <div class="mb-2 text-right">
+          <el-button
+            type="info"
+            icon="el-icon-circle-plus-outline"
+            @click="addAtachment"
+            >增加卷型</el-button
+          >
+        </div>
+        <table class="table mb-2">
+          <tr>
+            <th>试卷类型</th>
+            <th>试卷文件</th>
+            <th>答题卡创建方式</th>
+            <th>答题卡</th>
+            <th>操作</th>
+          </tr>
+          <tr v-for="(attachment, index) in paperAttachments" :key="index">
+            <td>{{ attachment.name }}卷</td>
+            <td>
+              <el-button
+                type="text"
+                class="btn-primary"
+                @click="toUpload(attachment)"
+              >
+                <i
+                  :class="[
+                    'icon',
+                    attachment.attachmentId ? 'icon-files-act' : 'icon-files'
+                  ]"
+                ></i
+                >{{
+                  attachment.attachmentId
+                    ? attachment.filename
+                    : "点击上传试卷文件"
+                }}
+              </el-button>
+            </td>
+            <td :rowspan="paperAttachments.length" v-if="index === 0">
+              {{ createCardTypeName }}
+            </td>
+            <td :rowspan="paperAttachments.length" v-if="index === 0">
+              <el-button
+                type="text"
+                class="btn-primary"
+                @click="toCreateOrViewCard"
+                >{{ cardTodoName }}</el-button
+              >
+              <el-button
+                v-if="examTaskDetail.makeMethod"
+                size="mini"
+                type="primary"
+                @click="changeCreateCardType"
+                >切换题卡创建方式</el-button
+              >
+            </td>
+            <td>
+              <el-button
+                class="btn-danger"
+                type="text"
+                @click="deleteAttachment(index)"
+                >删除</el-button
+              >
+            </td>
+          </tr>
+          <tr v-if="!paperAttachments.length">
+            <td colspan="5">
+              <p class="tips-info text-center">暂无数据</p>
+            </td>
+          </tr>
+        </table>
+
+        <p class="tips-info tips-dark mb-2">
+          提示:多卷型试卷由于会绑定一个答题卡模板,因此试卷结构必须相同。多卷型试卷之间客观题要求试题内容相同,可允许大题内的小题题序不同。
+        </p>
+
+        <el-form>
+          <el-form-item label="单次抽卷卷型数量:" label-width="150">
+            <el-input-number
+              v-model="examTaskDetail.drawCount"
+              :min="1"
+              :max="maxFetchCount"
+              :step="1"
+              step-strictly
+              :controls="false"
+            ></el-input-number>
+          </el-form-item>
+        </el-form>
+
+        <h4 class="mb-2">备注说明:</h4>
+        <el-input
+          class="mb-2"
+          v-model="examTaskDetail.remark"
+          type="textarea"
+          resize="none"
+          :rows="2"
+          :maxlength="100"
+          clearable
+          show-word-limit
+          placeholder="建议不超过100个字"
+        ></el-input>
+
+        <h4 class="mb-2">上传入库审核表(最多4张)</h4>
+        <div class="image-list">
+          <div
+            class="image-item"
+            v-for="(img, index) in paperConfirmAttachments"
+            :key="index"
+          >
+            <img
+              :src="img.url"
+              :alt="img.filename"
+              title="点击查看大图"
+              @click="toPreview(index)"
+            />
+            <div class="image-delete">
+              <i
+                class="el-icon-delete-solid"
+                @click="deletePaperConfirmAttachment(index)"
+              ></i>
+            </div>
+          </div>
+          <div
+            v-if="paperConfirmAttachments.length < 4"
+            class="image-item image-add"
+            title="上传入库审核表"
+            @click="toUploadPaperConfirm"
+          >
+            <i class="el-icon-plus"></i>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- upload-paper-dialog -->
+    <upload-paper-dialog
+      :paper-attachment="curAttachment"
+      :upload-type="curUploadType"
+      @confirm="uploadConfirm"
+      ref="UploadPaperDialog"
+    ></upload-paper-dialog>
+    <!-- card-option-dialog -->
+    <card-option-dialog
+      ref="CardOptionDialog"
+      :data="task"
+      @upload-sample-over="initData"
+      @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>
+
+<script>
+import UploadPaperDialog from "../UploadPaperDialog";
+import CardOptionDialog from "../CardOptionDialog";
+import SimpleImagePreview from "@/components/SimpleImagePreview";
+import { CARD_SOURCE_TYPE } from "@/constants/enumerate";
+import { switchCardCreateMethod, taskAllApproverPeople } from "../../api";
+
+export default {
+  name: "info-exam-task",
+  components: { UploadPaperDialog, CardOptionDialog, SimpleImagePreview },
+  props: {
+    datas: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      task: {},
+      flows: [
+        {
+          flowId: "160684605807001600",
+          taskName: "提交试卷",
+          taskKey: "usertask1",
+          setup: 1,
+          status: "process",
+          desc: "进行中"
+        },
+        {
+          flowId: "160684605807001600",
+          taskName: "审核试卷",
+          taskKey: "usertask2",
+          setup: 2,
+          status: "wait",
+          desc: "待进行"
+        },
+        {
+          flowId: "160684605807001600",
+          taskName: "审核试卷",
+          taskKey: "usertask3",
+          setup: 3,
+          status: "wait",
+          desc: "待进行"
+        }
+      ],
+      rules: {
+        teachingRoomId: [
+          {
+            required: true,
+            message: "请选择教研室",
+            trigger: "change"
+          }
+        ],
+        courseCode: [
+          {
+            required: true,
+            message: "请选择课程",
+            trigger: "change"
+          }
+        ],
+        cardRuleId: [
+          {
+            required: true,
+            message: "请选择题卡规则",
+            trigger: "change"
+          }
+        ]
+      },
+      // exam-task-detail
+      examTaskDetail: {},
+      paperConfirmAttachmentId: { attachmentId: "", filename: "", url: "" },
+      paperAttachments: [],
+      paperConfirmAttachments: [],
+      curAttachment: {},
+      curUploadType: "paper",
+      attachmentLimitCount: 26,
+      abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
+      // image-preview
+      curImage: {},
+      curImageIndex: 0
+    };
+  },
+  computed: {
+    cardTodoName() {
+      let name = "创建答题卡";
+      if (this.examTaskDetail.cardId) {
+        if (this.examTaskDetail.makeMethod === "SELECT") {
+          name = "选择题卡";
+        } else if (this.examTaskDetail.makeMethod === "SELF") {
+          name = "编辑题卡";
+        } else {
+          // 已经审核的题卡可以自行编辑,未审核的题卡只能查看
+          name =
+            this.examTaskDetail.status === "SUBMIT" ? "编辑题卡" : "查看题卡";
+        }
+      }
+      return name;
+    },
+    createCardTypeName() {
+      return CARD_SOURCE_TYPE[this.examTaskDetail.makeMethod] || "";
+    },
+    maxFetchCount() {
+      return this.paperAttachments.length < 1
+        ? 1
+        : this.paperAttachments.length;
+    }
+  },
+  methods: {
+    // exam-task-detail edit
+    addAtachment() {
+      if (this.paperAttachments.length >= this.attachmentLimitCount) return;
+
+      const newAttachment = {
+        name: this.abc[this.paperAttachments.length],
+        attachmentId: "",
+        filename: "",
+        pages: 0
+      };
+      this.paperAttachments.push(newAttachment);
+    },
+    deleteAttachment(index) {
+      if (this.paperAttachments.length <= 1) {
+        this.$message.error("试卷类型数量不得少于1");
+        return;
+      }
+      this.paperAttachments.splice(index, 1);
+      this.paperAttachments.forEach((item, itemIndex) => {
+        item.name = this.abc[itemIndex];
+      });
+      if (
+        this.examTaskDetail.drawCount &&
+        this.examTaskDetail.drawCount > this.paperAttachments.length
+      ) {
+        this.examTaskDetail.drawCount = this.paperAttachments.length;
+      }
+    },
+    toUpload(attachment) {
+      this.curUploadType = "paper";
+      this.curAttachment = {
+        ...attachment
+      };
+      this.$refs.UploadPaperDialog.open();
+    },
+    toUploadPaperConfirm() {
+      if (this.paperConfirmAttachments.length >= 4) return;
+      this.curUploadType = "paperConfirm";
+      this.curAttachment = {
+        ...this.paperConfirmAttachmentId
+      };
+      this.$refs.UploadPaperDialog.open();
+    },
+    uploadConfirm(attachment, uploadType) {
+      if (uploadType === "paper") {
+        const index = this.paperAttachments.findIndex(
+          item => item.name === attachment.name
+        );
+        this.paperAttachments.splice(index, 1, { ...attachment });
+      } else {
+        this.paperConfirmAttachments.push(attachment);
+      }
+    },
+    deletePaperConfirmAttachment(index) {
+      this.paperConfirmAttachments.splice(index, 1);
+    },
+    toViewCard() {
+      window.open(
+        this.getRouterPath({
+          name: "CardPreview",
+          params: {
+            cardId: this.examTaskDetail.cardId,
+            viewType: "view"
+          }
+        })
+      );
+    },
+    toEditCard() {
+      this.cachePrepareTcpCard();
+      this.$router.push({
+        name: "CardDesign",
+        params: {
+          cardId: this.examTaskDetail.cardId
+        }
+      });
+    },
+    cachePrepareTcpCard() {
+      this.$ls.set("prepareTcPCard", {
+        examTaskId: this.examTask.id,
+        courseCode: this.examTask.courseCode,
+        courseName: this.examTask.courseName,
+        makeMethod: this.examTaskDetail.makeMethod,
+        cardRuleId: this.examTask.cardRuleId
+      });
+    },
+    async toCreateOrViewCard() {
+      const result = await this.toSave(1);
+      if (!result) return;
+      this.task = {
+        ...this.examTask,
+        ...this.examTaskDetail,
+        examTaskId: this.examTask.id
+      };
+      if (!this.examTaskDetail.cardId) {
+        this.$refs.CardOptionDialog.open();
+        return;
+      }
+
+      if (this.examTaskDetail.makeMethod === "SELECT") {
+        this.$refs.CardOptionDialog.open();
+      } else if (this.examTaskDetail.makeMethod === "SELF") {
+        this.toEditCard();
+      } else {
+        // 客服制卡:制作完毕则可以编辑,未制作完毕则可以查看
+        if (this.examTaskDetail.status === "SUBMIT") {
+          this.toEditCard();
+        } else {
+          this.toViewCard();
+        }
+      }
+    },
+    cardConfirm(data) {
+      this.examTaskDetail = this.$objAssign(this.examTaskDetail, data);
+    },
+    async changeCreateCardType() {
+      const h = this.$createElement;
+      const result = await this.$msgbox({
+        title: "切换题卡操作说明",
+        message: h("div", null, [
+          h("p", null, "1、切换题卡会将之前选择题卡数据删除。"),
+          h(
+            "p",
+            null,
+            "2、之前选择专卡进行绘制,切换题卡后再次选择专卡,需要重新开始绘制。"
+          )
+        ]),
+        showCancelButton: true,
+
+        type: "warning"
+      }).catch(() => {});
+      if (result !== "confirm") return;
+
+      await this.clearMakeMethod();
+      this.toCreateOrViewCard();
+    },
+    async clearMakeMethod() {
+      // 清除后台记录的题卡
+      if (this.examTask.id && this.examTaskDetail.cardId)
+        await switchCardCreateMethod(this.examTask.id);
+
+      this.examTaskDetail.makeMethod = "";
+      this.examTaskDetail.cardId = "";
+    },
+    teachingRoomChange() {
+      this.examTask.courseCode = "";
+      this.examTask.courseName = "";
+      this.clearCard();
+    },
+    courseChange(val) {
+      if (!val || !val.code) {
+        this.examTask.courseCode = "";
+        this.examTask.courseName = "";
+        return;
+      }
+      this.examTask.courseName = val.name;
+      this.clearCard();
+      this.updateApproverPeople();
+    },
+    clearCard() {
+      this.clearMakeMethod();
+    },
+    async updateApproverPeople() {
+      const data = await taskAllApproverPeople({
+        courseCode: this.examTask.courseCode
+      });
+      let approvePeople = {};
+      data.approveUserList.forEach(item => {
+        item.users = item.approveUser.map(
+          user => `${user.realName}(${user.orgName})`
+        );
+        item.firstUser = item.users[0];
+        item.moreUser = item.users.length > 1 ? item.users.join(",") : null;
+        approvePeople[item.setup] = item;
+      });
+      this.flows = this.flows.map(flow => {
+        return {
+          ...flow,
+          ...approvePeople[flow.setup]
+        };
+      });
+    },
+    getTaskDetailData() {
+      let data = { ...this.examTaskDetail };
+      data.paperType = this.paperAttachments.map(item => item.name).join(",");
+      data.paperAttachmentIds = JSON.stringify(this.paperAttachments, (k, v) =>
+        k === "url" ? undefined : v
+      );
+      data.paperConfirmAttachmentIds = JSON.stringify(
+        this.paperConfirmAttachments
+      );
+      this.examTaskDetail = data;
+    },
+    checkDataValid() {
+      const attachmentValid = !this.paperAttachments.some(
+        item => !item.attachmentId
+      );
+      // 设置了入库强制包含试卷时,校验试卷是否上传。
+      if (this.examTaskDetail.includePaper && !attachmentValid) {
+        this.$message.error("请完成试卷文件上传!");
+        return;
+      }
+      // if (!this.paperConfirmAttachments.length) {
+      //   this.$message.error("请上传入库审核表!");
+      //   return;
+      // }
+
+      if (!this.examTaskDetail.cardId) {
+        this.$message.error("请选择题卡创建方式!");
+        return;
+      }
+
+      if (
+        this.examTaskDetail.makeMethod !== "SELECT" &&
+        this.examTaskDetail.status !== "SUBMIT"
+      ) {
+        this.$message.error("请先提交题卡!");
+        return;
+      }
+      return true;
+    },
+    // 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);
+    }
+  }
+};
+</script>

+ 15 - 0
src/modules/exam/components/createTaskApply/InfoPrint.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="info-print">
+    info-print
+  </div>
+</template>
+
+<script>
+export default {
+  name: "info-print",
+  data() {
+    return {};
+  },
+  methods: {}
+};
+</script>

+ 5 - 1
src/plugins/axios.js

@@ -8,6 +8,7 @@ import GLOBAL from "../config";
 import { getAuthorization } from "../plugins/crypto";
 import { PLATFORM, DEVICE_ID } from "../constants/app";
 import { initSyncTime, fetchTime } from "../plugins/syncServerTime";
+import { objTypeOf } from "./utils";
 
 // const IS_DEV = false;
 // axios interceptors
@@ -181,7 +182,10 @@ const errorDataCallback = response => {
  */
 const successCallback = data => {
   if (data.code === 200) {
-    if (data.data.hasOwnProperty("success")) {
+    if (
+      objTypeOf(data.data) === "object" &&
+      data.data.hasOwnProperty("success")
+    ) {
       if (data.data.success) {
         return data.data;
       } else {