فهرست منبع

综合组卷管理

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

+ 1 - 1
package.json

@@ -18,7 +18,7 @@
     "axios-progress-bar": "^1.2.0",
     "bootstrap": "^4.6.0",
     "echarts": "^4.9.0",
-    "element-ui": "^2.15.0",
+    "element-ui": "2.15.6",
     "html2canvas": "^1.4.1",
     "js-md5": "^0.7.3",
     "lodash": "^4.17.15",

+ 5 - 3
src/assets/styles/base.scss

@@ -139,10 +139,10 @@ body {
     border: 1px solid $--color-border-dark;
     border-radius: 5px;
     display: inline-flex;
-    overflow: hidden;
+    // overflow: hidden;
     justify-content: space-between;
     align-items: center;
-    width: 220px;
+    width: 260px;
 
     &:last-child {
       border: none;
@@ -171,9 +171,11 @@ body {
   .el-form-item__content {
     flex-grow: 2;
   }
-  .el-input__inner {
+  .el-input__inner,
+  .el-select__input {
     border: none;
     padding-left: 9px;
+    margin: 0;
   }
   .el-input.is-disabled {
     .el-input__inner {

+ 31 - 0
src/constants/datePickerOptions.js

@@ -0,0 +1,31 @@
+export default {
+  shortcuts: [
+    {
+      text: "最近一周",
+      onClick(picker) {
+        const end = new Date();
+        const start = new Date();
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+        picker.$emit("pick", [start, end]);
+      },
+    },
+    {
+      text: "最近一个月",
+      onClick(picker) {
+        const end = new Date();
+        const start = new Date();
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+        picker.$emit("pick", [start, end]);
+      },
+    },
+    {
+      text: "最近三个月",
+      onClick(picker) {
+        const end = new Date();
+        const start = new Date();
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+        picker.$emit("pick", [start, end]);
+      },
+    },
+  ],
+};

+ 3 - 7
src/modules/card/api.js

@@ -9,13 +9,9 @@ export const questionTeacherQueryApi = (name) => {
   });
 };
 export const courseQueryApi = (name) => {
-  return $httpWithMsg.get(
-    QUESTION_API + "/course/query",
-    {},
-    {
-      params: { name },
-    }
-  );
+  return $httpWithMsg.get(QUESTION_API + "/course/query", {
+    params: { name },
+  });
 };
 // card-mamage
 export const cardListApi = (datas) => {

+ 5 - 12
src/modules/card/views/CardManage.vue

@@ -11,13 +11,13 @@
         <el-form-item label="课程">
           <el-select
             v-model="searchForm.courseId"
-            :remote-method="getCourses4Search"
+            :remote-method="getCoursesList"
             :loading="courseLoading4Search"
             remote
             filterable
             clearable
             placeholder="请选择"
-            @clear="getCourses4Search('')"
+            @clear="getCoursesList('')"
           >
             <el-option
               v-for="item in courseList"
@@ -320,18 +320,11 @@ export default {
     delete window.emitResult;
   },
   methods: {
-    getCourses4Search(query) {
+    async getCoursesList(query) {
       this.courseLoading4Search = true;
-      this.$httpWithMsg
-        .get(QUESTION_API + "/course/query?name=" + query)
-        .then((response) => {
-          this.courseList = response.data;
-          this.courseLoading4Search = false;
-        });
-    },
-    async getCoursesList() {
-      const res = await courseQueryApi();
+      const res = await courseQueryApi(query);
       this.courseList = res.data || [];
+      this.courseLoading4Search = false;
     },
     async search() {
       if (this.loading) return;

+ 23 - 0
src/modules/questions/api.js

@@ -0,0 +1,23 @@
+import { $httpWithMsg } from "../../plugins/axios";
+import { QUESTION_API } from "@/constants/constants.js";
+
+export const paperPageListApi = (datas) => {
+  return $httpWithMsg.get(
+    `${QUESTION_API}/importPaper/${datas.pageNumber}/${datas.pageSize}`,
+    {
+      params: datas,
+    }
+  );
+  // return $httpWithMsg.post(`${QUESTION_API}/user/assignteacher/1/100`, datas);
+};
+export const courseQueryApi = (name, enable) => {
+  return $httpWithMsg.get(`${QUESTION_API}/course/query`, {
+    params: {
+      name,
+      enable: enable || undefined,
+    },
+  });
+};
+export const synthesisBuildPaperApi = (datas) => {
+  return $httpWithMsg.post(`${QUESTION_API}/user/assignteac`, datas);
+};

+ 11 - 0
src/modules/questions/routes/routes.js

@@ -25,6 +25,8 @@ import Course from "../views/Course.vue";
 import user from "../views/user.vue";
 import data_previllege from "../views/data_previllege.vue";
 import PaperStorage from "../views/PaperStorage.vue";
+import SynthesisPaper from "../views/SynthesisPaper.vue";
+import SynthesisPaperStorage from "../views/SynthesisPaperStorage.vue";
 import ViewPaper from "../views/ViewPaper.vue";
 import OrgProperty from "../views/OrgProperty.vue";
 import PaperPendingTrial from "../views/PaperPendingTrial.vue";
@@ -170,6 +172,15 @@ export default [
         path: "paper_storage/:isClear",
         component: PaperStorage,
       },
+      {
+        path: "synthesis_paper_storage",
+        component: SynthesisPaperStorage,
+      },
+      {
+        path: "synthesis_paper",
+        name: "SynthesisPaper",
+        component: SynthesisPaper,
+      },
       {
         path: "license", //授权管理
         component: License,

+ 64 - 0
src/modules/questions/views/OrgProperty.vue

@@ -185,6 +185,56 @@
           </el-form-item>
         </template>
       </el-form>
+
+      <!-- 登录配置 -->
+      <el-form v-if="activeName === 'tab4'" label-width="120px">
+        <el-form-item label="短信验证">
+          <el-radio-group v-model="form.properties.LOGIN_CODE_CHECK">
+            <el-radio label="true">开启</el-radio>
+            <el-radio label="false">关闭</el-radio>
+          </el-radio-group>
+          <div class="tips-info">*开启后,登录需要输入手机验证码</div>
+        </el-form-item>
+        <el-form-item label="安全U盾">
+          <el-radio-group v-model="form.properties.LOGIN_UD_CHECK">
+            <el-radio label="true">开启</el-radio>
+            <el-radio label="false">关闭</el-radio>
+          </el-radio-group>
+          <div class="tips-info">*开启后,需要插入安全U盾才能正常登录</div>
+        </el-form-item>
+        <template v-if="form.properties.LOGIN_UD_CHECK == 'true'">
+          <el-form-item>
+            <el-radio-group v-model="form.properties.LOGIN_UD_CHECK_ONECE">
+              <el-radio label="false"
+                >安全策略1
+                <span class="tips-info margin-left-10"
+                  >使用期间均会检测安全U盾是否正常,如果出现异常,会强制踢出用户进入异常提示页面</span
+                ></el-radio
+              >
+
+              <div class="margin-top-20"></div>
+              <el-radio label="true"
+                >安全策略2
+                <span class="tips-info margin-left-10"
+                  >仅对登录阶段进行检测,如果未检测到安全U盾,无法登录</span
+                ></el-radio
+              >
+            </el-radio-group>
+          </el-form-item>
+        </template>
+      </el-form>
+      <!-- 组卷配置 -->
+      <el-form v-if="activeName === 'tab5'" label-width="120px">
+        <el-form-item label="综合组卷">
+          <el-radio-group v-model="form.properties.PAPER_BUILD_SYNTHESIS">
+            <el-radio label="true">开启</el-radio>
+            <el-radio label="false">关闭</el-radio>
+          </el-radio-group>
+          <div class="tips-info">
+            *开启跨课程组卷模式,支持将多个课程试题组到一份试卷下
+          </div>
+        </el-form-item>
+      </el-form>
     </div>
   </section>
 </template>
@@ -215,6 +265,14 @@ export default {
           name: "查重配置",
           val: "tab3",
         },
+        {
+          name: "登录配置",
+          val: "tab4",
+        },
+        {
+          name: "组卷配置",
+          val: "tab5",
+        },
       ],
       activeName: "tab1",
       rootOrgName: "",
@@ -237,6 +295,12 @@ export default {
           CHECK_DUPLICATE: "false",
           CHECK_DUPLICATE_THRESHOLD: 80,
           CHECK_DUPLICATE_COUNT: 5,
+          // 登录
+          LOGIN_CODE_CHECK: "false",
+          LOGIN_UD_CHECK: "false",
+          LOGIN_UD_CHECK_ONECE: "false",
+          // 综合组卷
+          PAPER_BUILD_SYNTHESIS: "false",
         },
       },
       rules: {

+ 375 - 0
src/modules/questions/views/SynthesisPaper.vue

@@ -0,0 +1,375 @@
+<template>
+  <div
+    v-loading="fullscreenLoading"
+    class="synthesis-paper gen-paper-detail"
+    element-loading-text="正在组卷中..."
+  >
+    <div class="part-box">
+      <div class="part-box-header">
+        <h1 class="part-box-title">综合组卷</h1>
+        <div>
+          <el-button
+            type="primary"
+            icon="icon icon-save-white"
+            :loading="fullscreenLoading"
+            @click="confirmGenPaper"
+            >确定</el-button
+          >
+          <el-button type="danger" plain icon="icon icon-back" @click="goback"
+            >返回</el-button
+          >
+        </div>
+      </div>
+      <el-form
+        ref="modalFormComp"
+        class="part-filter-form"
+        :model="modalForm"
+        :rules="rules"
+        inline
+      >
+        <el-form-item prop="courseName" label="业务课名称" style="width: 300px">
+          <el-input
+            v-model="modalForm.courseName"
+            placeholder="业务课名称"
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="courseNo" label="业务课代码" style="width: 300px">
+          <el-input
+            v-model="modalForm.courseNo"
+            placeholder="业务课代码"
+          ></el-input>
+        </el-form-item>
+        <el-form-item prop="paperName" label="试卷名称" style="width: 300px">
+          <el-input
+            v-model="modalForm.paperName"
+            placeholder="试卷名称"
+          ></el-input>
+        </el-form-item>
+        <span class="tips-info margin-left-10"
+          >会作为试卷标题展示在试卷卷头部分</span
+        >
+        <br />
+        <el-form-item label="组卷模式">
+          <el-radio-group v-model="modalForm.genModelType">
+            <el-radio label="A-Type">自动组卷</el-radio>
+            <!-- <el-radio label="M-Type">手动组卷</el-radio> -->
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 试题来源 -->
+    <div class="part-box">
+      <div class="gen-step-title">
+        <h3>题源选择</h3>
+      </div>
+      <div class="gen-step-body">
+        <el-form class="part-filter-form" :inline="true">
+          <el-form-item label="课程" style="width: 280px">
+            <el-select
+              v-model="filter.courseId"
+              :remote-method="getCoursesList"
+              :loading="courseLoading"
+              remote
+              filterable
+              clearable
+              multiple
+              placeholder="请选择"
+              @clear="getCoursesList('')"
+            >
+              <el-option
+                v-for="item in courseList"
+                :key="item.id"
+                :label="item.name + ' - ' + item.code"
+                :value="item.id"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="题源选择">
+            <el-select v-model="filter.paperType" placeholder="题源选择">
+              <!-- <el-option label="题库来源" value="IMPORT"></el-option> -->
+              <el-option label="卷库来源" value="GENERATE"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="创建时间" style="width: 460px">
+            <el-date-picker
+              v-model="createTime"
+              type="datetimerange"
+              :picker-options="pickerOptions"
+              range-separator="-"
+              start-placeholder="创建开始时间"
+              end-placeholder="创建结束时间"
+              value-format="timestamp"
+              align="right"
+              unlink-panels
+            >
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" :loading="loading" @click="toPage(1)"
+              >查询</el-button
+            >
+          </el-form-item>
+        </el-form>
+        <el-table v-loading="loading" class="part-box-border" :data="paperList">
+          <el-table-column width="50" align="center">
+            <template slot-scope="scope">
+              <el-checkbox
+                v-model="scope.row.selected"
+                @change="paperSelectChange(scope.row)"
+              ></el-checkbox>
+            </template>
+          </el-table-column>
+          <el-table-column prop="courseName" label="课程名称">
+          </el-table-column>
+          <el-table-column prop="courseCode" label="课程代码">
+          </el-table-column>
+          <el-table-column prop="name" label="试卷名称"> </el-table-column>
+          <el-table-column prop="totalScore" label="总分" width="100">
+          </el-table-column>
+          <el-table-column prop="unitCount" label="小题数量" width="200">
+          </el-table-column>
+        </el-table>
+        <div class="part-page">
+          <el-pagination
+            :current-page="current"
+            :page-size="size"
+            :page-sizes="[10, 20, 50, 100, 200, 300]"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+            @current-change="toPage"
+            @size-change="pageSizeChange"
+          >
+          </el-pagination>
+        </div>
+      </div>
+    </div>
+
+    <!-- 已选试卷 -->
+    <div class="part-box">
+      <div class="gen-step-title">
+        <h3>选中试卷列表</h3>
+      </div>
+      <div class="gen-step-body">
+        <el-table class="part-box-border" :data="selectPapers">
+          <el-table-column prop="courseName" label="课程名称">
+          </el-table-column>
+          <el-table-column prop="courseCode" label="课程代码">
+          </el-table-column>
+          <el-table-column prop="aliasName" label="试卷名称">
+            <template slot-scope="scope">
+              <el-input
+                v-model="scope.row.aliasName"
+                placeholder="请输入试卷名称"
+              ></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="220">
+            <template slot-scope="scope">
+              <el-button
+                size="mini"
+                type="danger"
+                plain
+                @click="toRemovePaper(scope.row)"
+                >移除</el-button
+              >
+              <el-button
+                v-if="scope.$index"
+                size="mini"
+                type="primary"
+                plain
+                @click="toMoveupPaper(scope.row)"
+                >上移</el-button
+              >
+              <el-button
+                v-if="scope.$index !== dataListLastInd"
+                size="mini"
+                type="primary"
+                plain
+                @click="toMovedownPaper(scope.row)"
+                >下移</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  paperPageListApi,
+  courseQueryApi,
+  synthesisBuildPaperApi,
+} from "../api";
+import pickerOptions from "@/constants/datePickerOptions";
+
+export default {
+  data() {
+    return {
+      modalForm: {
+        courseName: "",
+        courseNo: "",
+        paperName: "",
+        genModelType: "A-Type",
+      },
+      rules: {
+        courseName: [
+          {
+            required: true,
+            message: "请输入业务课名称",
+            trigger: "change",
+          },
+          {
+            max: 100,
+            message: "业务课名称不可超过100字符",
+          },
+        ],
+        courseNo: [
+          {
+            required: true,
+            message: "请输入业务课代码",
+            trigger: "change",
+          },
+          {
+            max: 100,
+            message: "业务课代码不可超过100字符",
+          },
+        ],
+        paperName: [
+          {
+            required: true,
+            message: "请输入试卷名称",
+            trigger: "change",
+          },
+          {
+            max: 100,
+            message: "试卷名称不可超过100字符",
+          },
+        ],
+      },
+      filter: {
+        courseId: "",
+        paperType: "GENERATE",
+        createStartTime: "",
+        createEndTime: "",
+      },
+      current: 1,
+      size: 10,
+      total: 0,
+      loading: false,
+      paperList: [],
+      selectPapers: [],
+      courseList: [],
+      courseLoading: false,
+      fullscreenLoading: false,
+      // date-picker
+      createTime: [],
+      pickerOptions,
+    };
+  },
+  computed: {
+    dataListLastInd() {
+      return this.selectPapers.length - 1;
+    },
+  },
+  mounted() {
+    this.getCoursesList();
+  },
+  methods: {
+    async getCoursesList(query) {
+      this.courseLoading = true;
+      query = query && query.trim();
+      const res = await courseQueryApi(query, "true");
+      this.courseList = res.data || [];
+      this.courseLoading = false;
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size,
+      };
+      if (this.createTime) {
+        datas.createStartTime = this.createTime[0];
+        datas.createEndTime = this.createTime[1];
+      }
+      const res = await paperPageListApi(datas);
+      const selectedPaperIds = this.selectPapers.map((item) => item.id);
+      this.paperList = res.data.content.map((item) => {
+        let nitem = {
+          id: item.id,
+          courseName: item.course.name,
+          courseCode: item.course.code,
+          name: item.name,
+          totalScore: item.totalScore,
+          unitCount: item.unitCount,
+          selected: selectedPaperIds.includes(item.id),
+        };
+        return nitem;
+      });
+      this.total = res.data.totalElements;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    pageSizeChange(size) {
+      this.size = size;
+      this.toPage(1);
+    },
+    paperSelectChange(row) {
+      if (row.selected) {
+        const paper = this.paperList.find((item) => item.id === row.id);
+        this.selectPapers.push({ ...paper, aliasName: paper.name });
+      } else {
+        this.toRemovePaper(row);
+      }
+    },
+    toRemovePaper(row) {
+      this.selectPapers = this.selectPapers.filter(
+        (item) => item.id !== row.id
+      );
+    },
+    toMoveupPaper(row) {
+      const pos = this.selectPapers.findIndex((item) => item.id === row.id);
+      if (!pos) return;
+      const curPaper = this.selectPapers.splice(pos, 1)[0];
+      this.selectPapers.splice(pos - 1, 0, curPaper);
+    },
+    toMovedownPaper(row) {
+      const pos = this.selectPapers.findIndex((item) => item.id === row.id);
+      if (pos === this.selectPapers.length - 1) return;
+      const curPaper = this.selectPapers.splice(pos, 1)[0];
+      this.selectPapers.splice(pos + 1, 0, curPaper);
+    },
+    async confirmGenPaper() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (!this.selectPapers.length) {
+        this.$message.error("请选择试卷");
+        return;
+      }
+
+      if (this.fullscreenLoading) return;
+      this.fullscreenLoading = true;
+
+      let datas = { ...this.modalForm };
+      datas.papers = this.selectPapers.map((item) => {
+        return {
+          id: item.id,
+          aliasName: item.aliasName,
+        };
+      });
+      const res = await synthesisBuildPaperApi(datas).catch(() => {});
+      this.fullscreenLoading = false;
+      if (!res) return;
+
+      this.$message.success("组卷成功!");
+      this.goback();
+    },
+  },
+};
+</script>

+ 453 - 0
src/modules/questions/views/SynthesisPaperStorage.vue

@@ -0,0 +1,453 @@
+<template>
+  <section class="content">
+    <div class="part-box">
+      <h2 class="part-box-title">综合卷列表</h2>
+
+      <el-form class="part-filter-form" :inline="true" :model="formSearch">
+        <el-form-item label="课程名称">
+          <el-select
+            v-model="formSearch.courseId"
+            filterable
+            :remote-method="getCourses"
+            remote
+            clearable
+            placeholder="全部"
+            @change="courseChange"
+            @clear="getCourses('')"
+          >
+            <el-option
+              v-for="item in courseInfoSelect"
+              :key="item.courseId"
+              :label="item.courseInfo"
+              :value="item.courseId"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="试卷名称">
+          <el-input v-model="formSearch.name" placeholder="试卷名称"></el-input>
+        </el-form-item>
+        <el-form-item label="录入人">
+          <el-input
+            v-model="formSearch.creator"
+            placeholder="录入人"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="修改人">
+          <el-input
+            v-model="formSearch.lastModifyName"
+            placeholder="修改人"
+          ></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="danger" @click="searchFrom">查询</el-button>
+          <el-button type="danger" plain @click="resetForm">重置</el-button>
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action">
+        <div>
+          <el-button
+            type="danger"
+            plain
+            icon="icon icon-delete"
+            :disabled="noBatchSelected"
+            @click="batchDeleteGenPaper"
+            >删除成卷
+          </el-button>
+          <el-button
+            type="primary"
+            plain
+            icon="icon icon-export"
+            :disabled="noBatchSelected"
+            @click="openBatchExportPaperDialog"
+            >下载成卷</el-button
+          >
+        </div>
+        <el-button
+          type="primary"
+          icon="icon icon-plus-white"
+          @click="toBuildPaper"
+          >综合组卷</el-button
+        >
+      </div>
+    </div>
+    <div class="part-box">
+      <el-table
+        v-loading="loading"
+        element-loading-text="拼命加载中"
+        :data="tableData"
+        @selection-change="selectChange"
+      >
+        <el-table-column
+          type="selection"
+          width="50"
+          align="center"
+        ></el-table-column>
+        <el-table-column label="业务课名称" width="180">
+          <template slot-scope="scope">
+            <span>{{ scope.row.course.name }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="业务课代码" width="100">
+          <template slot-scope="scope">
+            <span>{{ scope.row.course.code }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="试卷名称" width="180">
+          <template slot-scope="scope">
+            <span>{{ scope.row.name }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="试卷总分"
+          width="103"
+          sortable
+          prop="totalScore"
+        >
+        </el-table-column>
+        <el-table-column
+          label="试卷难度"
+          width="103"
+          sortable
+          prop="difficultyDegree"
+        >
+        </el-table-column>
+        <el-table-column
+          label="大题数量"
+          width="103"
+          sortable
+          prop="paperDetailCount"
+        >
+        </el-table-column>
+        <el-table-column
+          label="创建时间"
+          width="153"
+          sortable
+          prop="creationTime"
+        >
+        </el-table-column>
+        <el-table-column label="修改人" width="150">
+          <template slot-scope="scope">
+            <span>{{ scope.row.lastModifyName }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="修改时间"
+          width="153"
+          sortable
+          prop="updateTime"
+        >
+        </el-table-column>
+        <el-table-column label="操作" width="150" fixed="right">
+          <template slot-scope="scope">
+            <div class="operate_left">
+              <el-button
+                size="mini"
+                type="primary"
+                plain
+                @click="editPaper(scope.row)"
+                >编辑</el-button
+              >
+              <el-button
+                size="mini"
+                type="primary"
+                plain
+                @click="viewPaper(scope.row)"
+                >预览</el-button
+              >
+              <el-button
+                size="mini"
+                type="primary"
+                plain
+                @click="openExportDialog(scope.row)"
+                >下载</el-button
+              >
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          :current-page="currentPage"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100, 200, 300]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="total"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        >
+        </el-pagination>
+      </div>
+    </div>
+
+    <!-- 下载 -->
+    <el-dialog
+      title="下载试卷"
+      :visible.sync="exportDialog"
+      width="600px"
+      :modal="false"
+      append-to-body
+      custom-class="side-dialog"
+    >
+      <el-form :model="exportModel" label-position="right" label-width="80px">
+        <el-form-item v-if="exportModel.courseName" label="课程名称">
+          {{ exportModel.courseName }}
+        </el-form-item>
+        <el-form-item v-if="exportModel.courseCode" label="课程代码">
+          {{ exportModel.courseCode }}
+        </el-form-item>
+        <el-form-item label="导出内容">
+          <el-checkbox-group v-model="exportModel.exportContentList">
+            <el-checkbox label="PAPER">试卷</el-checkbox>
+            <el-checkbox label="ANSWER">答案</el-checkbox>
+            <el-checkbox label="THEMIS_PACKAGE">数据包</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item v-if="showSeqMode" label="小题序号">
+          <el-radio-group v-model="exportModel.seqMode" class="input">
+            <el-radio label="MODE1">单题型连续</el-radio>
+            <el-radio label="MODE2">客观题整体连续</el-radio>
+            <el-radio label="MODE3">按大题独立</el-radio>
+            <el-radio label="MODE5">整卷连续</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button type="primary" @click="exportPaperInfo">开始导出</el-button>
+      </div>
+    </el-dialog>
+  </section>
+</template>
+
+<script>
+import { QUESTION_API } from "@/constants/constants";
+import { mapState } from "vuex";
+import { courseQueryApi } from "../api";
+
+export default {
+  data() {
+    return {
+      courseLoading: false,
+      formSearch: {
+        courseId: "",
+        courseName: "",
+        creator: "",
+        lastModifyName: "",
+        name: "",
+      },
+      tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 0,
+      loading: false,
+      courseList: [],
+      selectedPaperIds: [],
+      exportDialog: false,
+      exportModel: {
+        id: "",
+        courseCode: "",
+        courseName: "",
+        exportContentList: [],
+        seqMode: "MODE1",
+      },
+    };
+  },
+  computed: {
+    courseInfoSelect() {
+      var courseList = [];
+      for (let course of this.courseList) {
+        var courseInfo = course.name + "(" + course.code + ")";
+        var courseId = course.id;
+        var courseName = course.name;
+        courseList.push({
+          courseId: courseId,
+          courseInfo: courseInfo,
+          courseName: courseName,
+        });
+      }
+      return courseList;
+    },
+    noBatchSelected() {
+      return this.selectedPaperIds.length === 0;
+    },
+    showSeqMode() {
+      return (
+        this.exportModel.exportContentList.includes("PAPER") ||
+        this.exportModel.exportContentList.includes("ANSWER")
+      );
+    },
+    ...mapState({ user: (state) => state.user }),
+  },
+  created() {
+    this.initData();
+  },
+  methods: {
+    async getCourses(query) {
+      this.courseLoading = true;
+      query = query && query.trim();
+      const res = await courseQueryApi(query, "true");
+      this.courseList = res.data || [];
+      this.courseLoading = false;
+    },
+    courseChange() {
+      const course = this.courseList.find(
+        (item) => item.id === this.formSearch.courseId
+      );
+      if (course) {
+        this.formSearch.courseName = course.name;
+      }
+    },
+    resetForm() {
+      this.formSearch = {
+        courseId: "",
+        courseName: "",
+        creator: "",
+        lastModifyName: "",
+        name: "",
+      };
+    },
+    //查询
+    searchFrom() {
+      this.currentPage = 1;
+      this.searchGenPaper();
+    },
+    searchGenPaper() {
+      this.loading = true;
+      const url = `${QUESTION_API}/paper_storage/findPage/${this.currentPage}/${this.pageSize}`;
+      this.$http.get(url, { params: this.formSearch }).then((response) => {
+        this.tableData = response.data.content;
+        this.total = response.data.totalElements;
+      });
+      this.loading = false;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchGenPaper();
+    },
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.currentPage = 1;
+      this.searchGenPaper();
+    },
+    selectChange(row) {
+      this.selectedPaperIds = row.map((item) => item.id);
+    },
+    viewPaper(row) {
+      console.log(row);
+    },
+    editPaper(row) {
+      this.cacheSearchInfo();
+      console.log(row);
+    },
+    openExportDialog(row) {
+      this.exportModel.id = row.id;
+      this.exportModel.courseCode = row.course.code;
+      this.exportModel.courseName = row.course.name;
+      this.exportModel.exportContentList = [];
+
+      this.exportDialog = true;
+    },
+    toBuildPaper() {
+      this.cacheSearchInfo();
+      this.$router.push({ name: "SynthesisPaper" });
+    },
+    // batch action
+    async batchDeleteGenPaper() {
+      if (!this.selectedPaperIds.length) {
+        this.$notify({
+          message: "请勾选删除的数据",
+          type: "warning",
+        });
+        return;
+      }
+
+      const confirm = await this.$confirm("确认删除试卷吗?", "提示", {
+        type: "warning",
+      }).catch(() => {});
+      if (confirm !== "confirm") return;
+
+      const res = await this.$http
+        .delete(QUESTION_API + "/paper/" + this.selectedPaperIds.join())
+        .catch((error) => {
+          this.$notify({
+            message: error.response.data.desc,
+            type: "error",
+          });
+        });
+
+      if (!res) return;
+      this.$notify({
+        message: "删除成功",
+        type: "success",
+      });
+
+      this.searchGenPaper();
+      this.selectedPaperIds = [];
+    },
+    openBatchExportPaperDialog() {
+      if (!this.selectedPaperIds.length) {
+        this.$notify({
+          message: "请勾选数据",
+          type: "warning",
+        });
+        return;
+      }
+
+      this.exportModel = {
+        id: "",
+        courseCode: "",
+        courseName: "",
+        exportContentList: [],
+        seqMode: "MODE1",
+      };
+      this.exportDialog = true;
+    },
+    //导出试卷,答案,机考数据包
+    exportPaperInfo() {
+      if (!this.exportModel.exportContentList.length) {
+        this.$notify({
+          message: "请选择导出内容",
+          type: "error",
+        });
+        return false;
+      }
+
+      const { key, token } = this.user;
+      const paperIds = this.selectedPaperIds.join();
+      const contents = this.exportModel.exportContentList.join();
+      this.exportDialog = false;
+      if (paperIds) {
+        window.location.href = `${QUESTION_API}/paper/batch_export/${paperIds}/${contents}/onLine/?psw=&$key=${key}&$token=${token}&seqMode=${this.exportModel.seqMode}`;
+      } else {
+        window.location.href = `${QUESTION_API}/paper/export/${this.exportModel.id}/${contents}/onLine/?psw=&$key=${key}&$token=${token}&seqMode=${this.exportModel.seqMode}`;
+      }
+    },
+    // init
+    initData() {
+      const cacheInfo = window.sessionStorage.getItem("synthesis-paper");
+      if (cacheInfo) {
+        const { currentPage, pageSize, formSearch } = JSON.parse(cacheInfo);
+        this.formSearch = { ...formSearch };
+        this.currentPage = currentPage;
+        this.pageSize = pageSize;
+        this.handleCurrentChange(this.currentPage);
+        window.sessionStorage.removeItem("synthesis-paper");
+      } else {
+        this.handleCurrentChange(1);
+      }
+
+      this.getCourses(this.formSearch.courseName);
+    },
+    cacheSearchInfo() {
+      window.sessionStorage.setItem(
+        "synthesis-paper",
+        JSON.stringify({
+          formSearch: this.formSearch,
+          currentPage: this.currentPage,
+          pageSize: this.pageSize,
+        })
+      );
+    },
+  },
+};
+</script>