Bläddra i källkod

Merge branch 'master' of http://git.qmth.com.cn/ExamCloud-3/examcloud-web-admin

chenken 6 år sedan
förälder
incheckning
e8b3401dfa

+ 1 - 0
package.json

@@ -16,6 +16,7 @@
     "element-ui": "^2.4.9",
     "lodash": "^4.17.11",
     "moment": "^2.22.2",
+    "print-js": "^1.0.54",
     "randomcolor": "^0.5.3",
     "rasterizehtml": "^1.3.0",
     "register-service-worker": "^1.0.0",

+ 2 - 1
src/constants/constants.js

@@ -4,5 +4,6 @@ export const MARKING_API = "/api/ecs_marking"; //阅卷API
 export const DATA_PROCESS_API = "/api/ecs_data_process"; //数据中间层API
 export const OE_API = "/api/ecs_oe"; //网考API
 export const QUESTION_API = "/api/ecs_ques"; //题库API
-export const OUTLET_API = "/api/ecs_outlet";
+export const EXCHANGE_API = "/api/ecs_outlet"; //接口机
 export const PRINT_API = "/api/ecs_prt";
+export const TASK_API = "/api/ctr/task";

+ 1 - 0
src/directives/directives.js

@@ -0,0 +1 @@
+import "../modules/questions/directives/directives";

+ 1 - 0
src/filters/filters.js

@@ -0,0 +1 @@
+import "../modules/questions/filters/filters";

+ 1 - 0
src/main.js

@@ -7,6 +7,7 @@ import "./plugins/element.js";
 import "./plugins/axios";
 import "./plugins/vueAwesome";
 import "./directives/directives.js";
+import "./filters/filters.js";
 import "./styles/global.css";
 
 Vue.config.productionTip = process.env.NODE_ENV !== "production";

+ 5 - 0
src/modules/examwork/routes/routes.js

@@ -11,6 +11,11 @@ export default [
         path: "student", //学生管理
         meta: { pageName: "学生管理" },
         component: student
+      },
+      {
+        path: "exam_student_import", //学生管理
+        meta: { pageName: "考生导入" },
+        component: student
       }
     ]
   }

+ 433 - 0
src/modules/examwork/view/examInfo.vue

@@ -0,0 +1,433 @@
+<template>
+  <div>
+    <section class="content" style="margin-top: -10px;">
+      <div class="box box-info">
+        <!-- 头信息 -->
+        <div
+          class="box-header with-border"
+          style="background-color:#D3DCE6;margin-bottom:20px;"
+        >
+          <h3 class="box-title">考务管理 > 考试管理 > 考试信息</h3>
+          <div class="box-tools pull-right">
+            <button
+              type="button"
+              class="btn btn-box-tool"
+              data-widget="collapse"
+            >
+              <i class="fa fa-minus"></i>
+            </button>
+          </div>
+        </div>
+
+        <!-- 正文信息 -->
+        <div class="box-body">
+          <el-form
+            :inline="true"
+            :model="formSearch"
+            label-position="right"
+            label-width="70px"
+          >
+            <el-form-item label="考试名称" class="pull-left">
+              <el-input
+                v-model="formSearch.name"
+                auto-complete="off"
+              ></el-input>
+            </el-form-item>
+            <el-form-item label="类型" class="pull-left">
+              <el-select
+                v-model="formSearch.examType"
+                placeholder="请选择"
+                clearable
+              >
+                <el-option
+                  v-for="item in examTypeList"
+                  :label="item.label"
+                  :value="item.value"
+                  :key="item.value"
+                >
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item class="pull-right buttonframe">
+              <el-button
+                v-if="rolePrivileges.search_exam"
+                size="small"
+                type="primary"
+                icon="search"
+                @click="searchForm"
+                >查询
+              </el-button>
+              <el-button
+                v-if="rolePrivileges.add_exam"
+                size="small"
+                type="primary"
+                icon="plus"
+                @click="addExamInfoDialog"
+                >新增
+              </el-button>
+            </el-form-item>
+          </el-form>
+
+          <!-- 弹出窗口 -->
+          <el-dialog
+            title="请选择考试类型:"
+            size="small"
+            v-model="examInfoDialog"
+          >
+            <el-button type="primary" @click="toTradition">传统考试</el-button>
+            <el-button type="primary" @click="toOnline">网络考试</el-button>
+            <el-button type="primary" @click="toPractice">练习考试</el-button>
+            <el-button type="primary" @click="toOffline">离线考试</el-button>
+            <el-button type="primary" @click="toPrint">
+              分布式印刷考试</el-button
+            >
+            <div slot="footer" class="dialog-footer">
+              <el-button @click="examInfoDialog = false;">取 消</el-button>
+            </div>
+          </el-dialog>
+
+          <!-- 页面列表 -->
+          <el-table
+            v-loading="loading"
+            element-loading-text="拼命加载中"
+            :data="tableData"
+            border
+            style="width: 100%;text-align:center;"
+            @selection-change="selectChange"
+          >
+            <el-table-column type="selection" width="55"></el-table-column>
+            <el-table-column inline-template width="80" label="ID">
+              <div>
+                <span>{{ row.id }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="180" label="考试名称">
+              <div>
+                <span>{{ row.name }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="100" label="考试类型">
+              <div>
+                <span>{{ getExamType(row.examType) }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="开始时间">
+              <div>
+                <span>{{ row.beginTime }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="结束时间">
+              <div>
+                <span>{{ row.endTime }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="更新时间">
+              <div>
+                <span>{{ row.updateTime }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="80" label="状态">
+              <div>
+                <span>
+                  <el-tag :type="getTag(row.enable)">
+                    {{ getEnable(row.enable) }}
+                  </el-tag>
+                </span>
+              </div>
+            </el-table-column>
+            <el-table-column :context="_self" inline-template label="操作">
+              <div>
+                <el-button
+                  v-if="rolePrivileges.update_exam"
+                  size="mini"
+                  type="info"
+                  @click="editExamInfoDialog(row);"
+                >
+                  修改
+                </el-button>
+                <el-button
+                  v-if="!row.enable && rolePrivileges.change_exam_availability"
+                  size="mini"
+                  type="success"
+                  @click="enableById(row);"
+                >
+                  <i class="fa fa-check" aria-hidden="true"></i>启用
+                </el-button>
+                <el-button
+                  v-else-if="rolePrivileges.change_exam_availability"
+                  size="mini"
+                  type="warning"
+                  @click="disableById(row);"
+                >
+                  <i class="fa fa-close" aria-hidden="true"></i>禁用
+                </el-button>
+                <!--
+                  <el-button v-if="rolePrivileges.exam_course_setting" size="mini" type="info"
+                          @click="showExamCourseSettingsDialog(row)">
+                      课程设置
+                  </el-button>
+                  <el-button v-if="rolePrivileges.exam_org_setting" size="mini" type="info"
+                          @click="showExamOrgSettingsDialog(row)">
+                      学习中心设置
+                  </el-button>
+                -->
+              </div>
+            </el-table-column>
+          </el-table>
+          <div class="page pull-right">
+            <el-pagination
+              @current-change="handleCurrentChange"
+              :current-page="currentPage"
+              :page-size="pageSize"
+              layout="total, prev, pager, next, jumper"
+              :total="total"
+            >
+            </el-pagination>
+          </div>
+        </div>
+      </div>
+    </section>
+  </div>
+</template>
+<style>
+.page {
+  margin-top: 10px;
+}
+
+.buttonframe {
+  margin-left: 20px;
+}
+
+.el-table th > .cell {
+  text-align: center;
+}
+
+.el-textarea__inner {
+  resize: none;
+}
+</style>
+<script>
+import { core_api, exam_work_api, EXAM_TYPE } from "../store/global";
+import { mapState } from "vuex";
+
+export default {
+  data() {
+    return {
+      rolePrivileges: {
+        search_exam: false,
+        add_exam: false,
+        del_exam: false,
+        update_exam: false,
+        change_exam_availability: false,
+        exam_course_setting: false,
+        exam_org_setting: false
+      },
+      formSearch: {
+        name: "",
+        examType: ""
+      },
+      loading: false,
+      examTypeList: EXAM_TYPE,
+      tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
+      formLabelWidth: "120px",
+      examInfoDialog: false,
+      examId: "",
+      selectedExamIds: [],
+      button: {}
+    };
+  },
+  computed: {
+    ...mapState({ user: state => state.user }),
+    examIds() {
+      var examIds = "";
+      for (let examId of this.selectedExamIds) {
+        if (!examIds) {
+          examIds += examId;
+        } else {
+          examIds += "," + examId;
+        }
+      }
+      return examIds;
+    }
+  },
+
+  methods: {
+    selectChange(row) {
+      this.selectedExamIds = [];
+      row.forEach((element, index) => {
+        console.log(index);
+        this.selectedExamIds.push(element.id);
+      });
+      console.log(this.selectedExamIds);
+    },
+    getTag(status) {
+      if (status == true) {
+        return "success";
+      } else if (status == false) {
+        return "danger";
+      }
+      return status;
+    },
+    getEnable(enable) {
+      if (enable == true) {
+        return "启用";
+      } else if (enable == false) {
+        return "禁用";
+      }
+      return enable;
+    },
+    enableById(row) {
+      this.$confirm("是否启用该考试?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        var url = exam_work_api + "/exam/enable/" + row.id;
+        this.$http
+          .put(url, {})
+          .then(response => {
+            console.log(response);
+            this.$notify({
+              type: "success",
+              message: "开启成功!"
+            });
+            this.searchForm();
+          })
+          .catch(response => {
+            if (response.status == 500) {
+              this.$notify({
+                showClose: true,
+                message: response.body.desc,
+                type: "error"
+              });
+            }
+          });
+      });
+    },
+    disableById(row) {
+      this.$confirm("是否禁用该考试?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "error"
+      }).then(() => {
+        var url = exam_work_api + "/exam/disable/" + row.id;
+        this.$http
+          .put(url, {})
+          .then(response => {
+            console.log(response);
+            this.$notify({
+              type: "success",
+              message: "禁用成功!"
+            });
+            this.searchForm();
+          })
+          .catch(response => {
+            if (response.status == 500) {
+              this.$notify({
+                showClose: true,
+                message: response.body.desc,
+                type: "error"
+              });
+            }
+          });
+      });
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchForm();
+    },
+    //查询方法
+    searchForm() {
+      var param = new URLSearchParams(this.formSearch);
+      var url =
+        exam_work_api +
+        "/exam/queryPage/" +
+        (this.currentPage - 1) +
+        "/" +
+        this.pageSize +
+        "?" +
+        param;
+      this.loading = true;
+      this.$http.get(url).then(response => {
+        console.log(response);
+        this.tableData = response.body.list;
+        this.total = response.body.total;
+        this.loading = false;
+      });
+    },
+    addExamInfoDialog() {
+      this.examInfoDialog = true;
+      this.examId = "";
+    },
+    editExamInfoDialog(row) {
+      if (row.examType == "ONLINE") {
+        this.$router.push({ path: "/index/onlineExam/" + row.id });
+      } else if (row.examType == "TRADITION") {
+        this.$router.push({ path: "/index/traditionExam/" + row.id });
+      } else if (row.examType == "PRACTICE") {
+        this.$router.push({ path: "/index/practiceExam/" + row.id });
+      } else if (row.examType == "OFFLINE") {
+        this.$router.push({ path: "/index/offlineExam/" + row.id });
+      } else if (row.examType == "PRINT_EXAM") {
+        this.$router.push({ path: "/index/printExam/" + row.id });
+      }
+    },
+    showExamCourseSettingsDialog(row) {
+      this.$router.push({ path: "/index/examCourseSettings/" + row.id });
+    },
+    showExamOrgSettingsDialog(row) {
+      this.$router.push({ path: "/index/examOrgSettings/" + row.id });
+    },
+    toTradition() {
+      this.$router.push({ path: "/index/traditionExam/add" });
+    },
+    toOnline() {
+      this.$router.push({ path: "/index/onlineExam/add" });
+    },
+    toPractice() {
+      this.$router.push({ path: "/index/practiceExam/add" });
+    },
+    toOffline() {
+      this.$router.push({ path: "/index/offlineExam/add" });
+    },
+    toPrint() {
+      this.$router.push({ path: "/index/printExam/add" });
+    },
+    getExamType(examType) {
+      for (let tempExamType of this.examTypeList) {
+        if (tempExamType.value == examType) {
+          return tempExamType.label;
+        }
+      }
+    },
+    initPrivileges() {
+      var url = core_api + "/rolePrivilege/checkPrivileges";
+      var params = {
+        privilegeCodes: Object.keys(this.rolePrivileges).toString()
+      };
+      this.$http.post(url, params, { emulateJSON: true }).then(
+        response => {
+          this.rolePrivileges = response.body;
+        },
+        response => {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+        }
+      );
+    }
+  },
+  //初始化查询
+  created() {
+    this.initPrivileges();
+    this.searchForm();
+  }
+};
+</script>

+ 1943 - 0
src/modules/examwork/view/examStudent.vue

@@ -0,0 +1,1943 @@
+<style>
+.page {
+  margin-top: 10px;
+}
+
+.buttonframe {
+  margin-left: 20px;
+}
+
+.el-table th > .cell {
+  text-align: center;
+}
+
+.el-textarea__inner {
+  resize: none;
+}
+
+.input {
+  width: 170px;
+}
+
+.select_input {
+  width: 195px;
+}
+
+.dialog-footer {
+  text-align: center;
+}
+
+.form_width {
+  width: 200px;
+}
+</style>
+<template>
+  <div>
+    <section class="content" style="margin-top: -10px;">
+      <!-- 头信息 -->
+      <div
+        class="box-header with-border"
+        style="background-color:#D3DCE6;margin-bottom:20px;"
+      >
+        <h3 class="box-title">考生信息</h3>
+        <div class="box-tools pull-right">
+          <button type="button" class="btn btn-box-tool" data-widget="collapse">
+            <i class="fa fa-minus"></i>
+          </button>
+        </div>
+      </div>
+
+      <!-- 正文信息 -->
+      <div class="box-body">
+        <!-- 搜索表单 -->
+        <el-form
+          :inline="true"
+          :model="formSearch"
+          label-position="right"
+          label-width="100px"
+        >
+          <el-form-item label="考试" class="pull-left">
+            <el-select
+              class="input"
+              :remote-method="queryExams4Search"
+              remote
+              :loading="queryExams4SearchLoading"
+              filterable
+              clearable
+              v-model="formSearch.examId"
+              placeholder="请选择"
+            >
+              <el-option
+                v-for="item in examList4Search"
+                :label="item.name"
+                :value="item.id"
+                :key="item.id"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="姓名" class="pull-left">
+            <el-input
+              class="input"
+              placeholder="请输入姓名"
+              v-model="formSearch.studentName"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="学号" class="pull-left">
+            <el-input
+              class="input"
+              placeholder="请输入学号"
+              v-model="formSearch.studentCode"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="专业" class="pull-left">
+            <el-input
+              class="input"
+              placeholder="请输入专业"
+              v-model="formSearch.specialtyName"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="课程" class="pull-left">
+            <el-select
+              class="input"
+              :remote-method="getCourses4Search"
+              :loading="courseLoading4Search"
+              remote
+              filterable
+              clearable
+              v-model="formSearch.courseId"
+              placeholder="请选择"
+            >
+              <el-option
+                v-for="item in courseList4Search"
+                :label="item.name + ' - ' + item.code"
+                :value="item.id"
+                :key="item.id"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="学习中心" class="pull-left">
+            <el-select
+              class="input"
+              :remote-method="getOrgList4Search"
+              :loading="getOrgList4SearchLoading"
+              remote
+              filterable
+              clearable
+              v-model="formSearch.orgId"
+              placeholder="请选择"
+              :disabled="pureLC"
+            >
+              <el-option
+                v-for="item in orgList4Search"
+                :label="item.name + ' - ' + item.code"
+                :value="item.id"
+                :key="item.id"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="采集人" class="pull-left">
+            <el-input
+              class="input"
+              placeholder="请输入采集人"
+              v-model="formSearch.infoCollector"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="身份证" class="pull-left">
+            <el-input
+              class="input"
+              placeholder="请输入身份证"
+              v-model="formSearch.identityNumber"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="考点" class="pull-left">
+            <el-input
+              class="input"
+              placeholder="请输入考点"
+              v-model="formSearch.examSite"
+            ></el-input>
+          </el-form-item>
+          <el-form-item class="pull-right buttonframe">
+            <el-button
+              v-if="rolePrivileges.search_examStudent"
+              size="small"
+              type="primary"
+              icon="search"
+              @click="searchForm"
+              >查询
+            </el-button>
+            <el-button
+              v-if="rolePrivileges.add_examStudent"
+              size="small"
+              type="primary"
+              icon="plus"
+              @click="openAddingDialog"
+              >新增
+            </el-button>
+            <el-button
+              v-if="rolePrivileges.copy_examStudent"
+              size="small"
+              type="primary"
+              icon="document"
+              @click="copy"
+              >复制
+            </el-button>
+            <el-button
+              v-if="rolePrivileges.del_examStudent"
+              size="small"
+              type="danger"
+              icon="delete"
+              @click="deleteStuBatch"
+              >删除
+            </el-button>
+            <el-button
+              v-if="rolePrivileges.del_examStudent"
+              size="small"
+              type="danger"
+              icon="delete"
+              @click="deleteStuByExam"
+              >批次删除
+            </el-button>
+          </el-form-item>
+        </el-form>
+
+        <!-- 新增弹出窗口 -->
+        <el-dialog
+          @close="closeAddingStudentDialog"
+          title="考生信息页面"
+          v-model="addingStudentDialog"
+        >
+          <el-form
+            :model="examStudentForm"
+            size="large"
+            :rules="rules"
+            ref="addingStudentForm"
+          >
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="考试"
+                  :label-width="formLabelWidth"
+                  prop="examId"
+                >
+                  <el-select
+                    class="input"
+                    :remote-method="queryExams4InsertOrUpdate"
+                    :loading="queryExams4InsertOrUpdateLoading"
+                    remote
+                    filterable
+                    clearable
+                    v-model="examStudentForm.examId"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in examList4InsertOrUpdate"
+                      :label="item.name"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="姓名"
+                  :label-width="formLabelWidth"
+                  prop="studentName"
+                >
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.studentName"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="学号"
+                  :label-width="formLabelWidth"
+                  prop="studentCode"
+                >
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.studentCode"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="身份证号"
+                  :label-width="formLabelWidth"
+                  prop="identityNumber"
+                >
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.identityNumber"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="学习中心"
+                  :label-width="formLabelWidth"
+                  prop="orgId"
+                >
+                  <el-select
+                    class="input"
+                    :remote-method="getOrgList4InsertOrUpdate"
+                    :loading="getOrgList4InsertOrUpdateLoading"
+                    remote
+                    filterable
+                    clearable
+                    v-model="examStudentForm.orgId"
+                    placeholder="请选择"
+                    :disabled="pureLC"
+                  >
+                    <el-option
+                      v-for="item in orgList4InsertOrUpdate"
+                      :label="item.name + ' - ' + item.code"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="课程"
+                  :label-width="formLabelWidth"
+                  prop="courseId"
+                >
+                  <el-select
+                    :remote-method="getCourses4InsertOrUpdate"
+                    :loading="courseLoading4InsertOrUpdate"
+                    remote
+                    filterable
+                    clearable
+                    class="input"
+                    v-model="examStudentForm.courseId"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in courseList4InsertOrUpdate"
+                      :label="item.name + ' - ' + item.code"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="试卷类型"
+                  :label-width="formLabelWidth"
+                  prop="paperType"
+                >
+                  <el-select
+                    class="input"
+                    v-model="examStudentForm.paperType"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in paperTypeList"
+                      :label="item"
+                      :value="item"
+                      :key="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item label="专业" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.specialtyName"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item label="考点" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.examSite"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item label="年级" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.grade"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item label="采集人" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.infoCollector"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item label="电话" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.phone"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+          <div class="dialog-footer">
+            <el-button type="primary" @click="addStudent">确 定</el-button>
+            <el-button @click="closeAddingStudentDialog">取 消</el-button>
+          </div>
+        </el-dialog>
+
+        <!-- 修改弹出窗口 -->
+        <el-dialog
+          @close="closeUpdateStudentDialog"
+          title="考生信息页面"
+          v-model="updateStudentDialog"
+        >
+          <el-form
+            :model="examStudentForm"
+            size="large"
+            :rules="rules"
+            ref="updateStudentForm"
+          >
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="考试"
+                  :label-width="formLabelWidth"
+                  prop="examId"
+                >
+                  <el-select
+                    class="input"
+                    :remote-method="queryExams4InsertOrUpdate"
+                    :loading="queryExams4InsertOrUpdateLoading"
+                    remote
+                    disabled
+                    filterable
+                    clearable
+                    v-model="examStudentForm.examId"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in examList4InsertOrUpdate"
+                      :label="item.name"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="姓名"
+                  :label-width="formLabelWidth"
+                  prop="studentName"
+                >
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.studentName"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="学号"
+                  :label-width="formLabelWidth"
+                  prop="studentCode"
+                >
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.studentCode"
+                    readonly
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="身份证号"
+                  :label-width="formLabelWidth"
+                  prop="identityNumber"
+                >
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.identityNumber"
+                    readonly
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="学习中心"
+                  :label-width="formLabelWidth"
+                  prop="orgId"
+                >
+                  <el-select
+                    class="input"
+                    :remote-method="getOrgList4InsertOrUpdate"
+                    :loading="getOrgList4InsertOrUpdateLoading"
+                    remote
+                    filterable
+                    clearable
+                    v-model="examStudentForm.orgId"
+                    placeholder="请选择"
+                    :disabled="pureLC"
+                  >
+                    <el-option
+                      v-for="item in orgList4InsertOrUpdate"
+                      :label="item.name + ' - ' + item.code"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="课程"
+                  :label-width="formLabelWidth"
+                  prop="courseId"
+                >
+                  <el-select
+                    :remote-method="getCourses4InsertOrUpdate"
+                    :loading="courseLoading4InsertOrUpdate"
+                    remote
+                    filterable
+                    clearable
+                    disabled
+                    class="input"
+                    v-model="examStudentForm.courseId"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in courseList4InsertOrUpdate"
+                      :label="item.name + ' - ' + item.code"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item
+                  label="试卷类型"
+                  :label-width="formLabelWidth"
+                  prop="paperType"
+                >
+                  <el-select
+                    class="input"
+                    v-model="examStudentForm.paperType"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in paperTypeList"
+                      :label="item"
+                      :value="item"
+                      :key="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item label="专业" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.specialtyName"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item label="考点" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.examSite"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item label="年级" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.grade"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="10">
+                <el-form-item label="采集人" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.infoCollector"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="10">
+                <el-form-item label="电话" :label-width="formLabelWidth">
+                  <el-input
+                    class="input"
+                    v-model="examStudentForm.phone"
+                    auto-complete="off"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+          <div class="dialog-footer">
+            <el-button type="primary" @click="updateStudent">确 定</el-button>
+            <el-button @click="closeUpdateStudentDialog">取 消</el-button>
+          </div>
+        </el-dialog>
+
+        <!-- 复制弹窗 -->
+        <el-dialog title="考生信息复制" size="tiny" v-model="studentCopyDialog">
+          <el-form
+            :model="studentCopyForm"
+            :rules="rules"
+            ref="studentCopyForm"
+          >
+            <el-row>
+              <el-form-item
+                label="源考试批次"
+                prop="sourceExamId"
+                :label-width="formLabelWidth"
+              >
+                <el-select
+                  class="input"
+                  :remote-method="queryExams4CopyFrom"
+                  remote
+                  :loading="queryExams4CopyFromLoading"
+                  filterable
+                  clearable
+                  v-model="studentCopyForm.sourceExamId"
+                  placeholder="请选择"
+                >
+                  <el-option
+                    v-for="item in examList4CopyFrom"
+                    :label="item.name"
+                    :value="item.id"
+                    :key="item.id"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-row>
+            <el-row>
+              <el-form-item
+                label="目标考试批次"
+                prop="targetExamId"
+                :label-width="formLabelWidth"
+              >
+                <el-select
+                  class="input"
+                  :remote-method="queryExams4CopyTo"
+                  remote
+                  :loading="queryExams4CopyToLoading"
+                  filterable
+                  clearable
+                  v-model="studentCopyForm.targetExamId"
+                  placeholder="请选择"
+                >
+                  <el-option
+                    v-for="item in examList4CopyTo"
+                    :label="item.name"
+                    :value="item.id"
+                    :key="item.id"
+                    :disabled="!item.enable"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-row>
+            <el-row>
+              <div class="dialog-footer">
+                <el-button type="primary" @click="copyStudent">确 定</el-button>
+                <el-button @click="studentCopyDialog = false;">取 消</el-button>
+              </div>
+            </el-row>
+          </el-form>
+        </el-dialog>
+
+        <!-- 页面列表 -->
+        <el-table
+          v-loading="loading"
+          element-loading-text="拼命加载中"
+          :data="tableData"
+          border
+          style="width: 100%;text-align:center;"
+          @selection-change="selectChange"
+        >
+          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column inline-template label="ID">
+            <div>
+              <span>{{ row.id }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column label="考生">
+            <template scope="scope">
+              <el-popover trigger="hover" placement="left">
+                <div style="font-size: 18px;font-family: 新宋体">
+                  <tr>
+                    <td style="color: green">姓名</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.studentName }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">身份证号</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.identityNumber }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">学号</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.studentCode }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">学习中心名称</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.orgName }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">学习中心编码</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.orgCode }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">课程名称</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.courseName }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">课程编码</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.courseCode }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">年级</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.grade }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">电话</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.phone }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">专业</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.specialtyName }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">采集人</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.infoCollector }}
+                    </td>
+                  </tr>
+                  <tr>
+                    <td style="color: green">考点</td>
+                    <td style="color:purple;padding-left: 20px;">
+                      {{ scope.row.examSite }}
+                    </td>
+                  </tr>
+                </div>
+
+                <div slot="reference" class="name-wrapper">
+                  <span>{{ scope.row.studentName }}</span>
+                </div>
+              </el-popover>
+            </template>
+          </el-table-column>
+          <el-table-column inline-template label="学号">
+            <div>
+              <span>{{ row.studentCode }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column inline-template label="身份证号">
+            <div>
+              <span>{{ row.identityNumber }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column inline-template label="学习中心">
+            <div>
+              <span>{{ row.orgName }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column inline-template label="考试名称">
+            <div>
+              <span>{{ row.examName }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column inline-template label="课程名称">
+            <div>
+              <span>{{ row.courseName }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column inline-template width="168" label="更新时间">
+            <div>
+              <span>{{ row.updateTime }}</span>
+            </div>
+          </el-table-column>
+          <el-table-column inline-template width="80" label="状态">
+            <div>
+              <span>
+                <el-tag :type="getTag(row.enable)">{{
+                  getEnable(row.enable)
+                }}</el-tag>
+              </span>
+            </div>
+          </el-table-column>
+          <el-table-column
+            :context="_self"
+            width="250"
+            inline-template
+            label="操作"
+          >
+            <div v-if="row.locked">
+              <font style="color: red;">锁定中,请稍后操作</font>
+            </div>
+            <div v-else>
+              <el-button size="mini" type="info" @click="showPhoto(row);">
+                查看照片
+              </el-button>
+              <el-button
+                v-if="rolePrivileges.update_examStudent"
+                size="mini"
+                type="info"
+                @click="openUpdateDialog(row);"
+              >
+                修改
+              </el-button>
+              <el-button
+                v-if="
+                  null != row.enable &&
+                    !row.enable &&
+                    rolePrivileges.change_exam_student_availability
+                "
+                size="mini"
+                type="success"
+                @click="enableExamStudent(row);"
+                >启用
+              </el-button>
+              <el-button
+                v-else-if="rolePrivileges.change_exam_student_availability"
+                size="mini"
+                type="danger"
+                @click="disableExamStudent(row);"
+                >禁用
+              </el-button>
+              <el-button
+                v-if="rolePrivileges.del_examStudent"
+                size="mini"
+                type="danger"
+                @click="deleteExamStudent(row);"
+                >删除
+              </el-button>
+            </div>
+          </el-table-column>
+        </el-table>
+        <div class="page pull-right">
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page="currentPage"
+            :page-size="pageSize"
+            layout="total, prev, pager, next, jumper"
+            :total="total"
+          >
+          </el-pagination>
+        </div>
+
+        <el-dialog title="错误提示" v-model="errDialog">
+          <div
+            class="text-danger"
+            v-for="errMessage in errMessages"
+            :key="errMessage.lineNum"
+          >
+            第{{ errMessage.lineNum }}行:{{ errMessage.msg }}
+          </div>
+          <span slot="footer" class="dialog-footer">
+            <el-button @click="errDialog = false;">确定</el-button>
+          </span>
+        </el-dialog>
+
+        <el-dialog @close="closePhotoDialog" title="照片" v-model="photoDialog">
+          <div class="student_photo">
+            <img :src="photo.url" alt="学生照片" height="20%" width="30%" />
+          </div>
+        </el-dialog>
+      </div>
+    </section>
+  </div>
+</template>
+
+<script>
+import { task_api, core_api, exam_work_api, photo_url } from "../store/global";
+import { mapState } from "vuex";
+
+export default {
+  data() {
+    var validateStuCode = (rule, value, callback) => {
+      if (
+        this.examStudentForm.studentCode &&
+        this.examStudentForm.studentCode.length < 6
+      ) {
+        callback(new Error("学号至少6位"));
+      } else {
+        callback();
+      }
+    };
+    var validateIdenNum = (rule, value, callback) => {
+      if (this.examStudentForm.identityNumber === "") {
+        return callback(new Error("请输入身份证"));
+      }
+      if (
+        this.examStudentForm.identityNumber &&
+        this.examStudentForm.identityNumber.length < 6
+      ) {
+        callback(new Error("身份证至少6位"));
+      } else {
+        callback();
+      }
+    };
+    return {
+      rolePrivileges: {
+        search_examStudent: false,
+        add_examStudent: false,
+        import_examStudent: false,
+        copy_examStudent: false,
+        del_examStudent: false,
+        update_examStudent: false,
+        change_exam_student_availability: false
+      },
+      isSuperAdmin: false,
+      pureLC: false,
+      lc_id: null,
+      lc_code: null,
+      lc_name: null,
+      loading: false,
+      courseLoading4Search: false,
+      courseLoading4InsertOrUpdate: false,
+      photoDialog: false,
+      photo: { url: "" },
+      specialtyList: [],
+      button: {},
+      errDialog: false,
+      errMessages: [],
+      uploadAction: exam_work_api + "/exam_student/import",
+      uploadData: { examId: "" },
+      fileLoading: false,
+      fileList: [],
+      uploadHeaders: {},
+      orgList4Search: [],
+      getOrgList4SearchLoading: false,
+      formSearch: {
+        rootOrgId: null,
+        examId: "",
+        studentCode: "",
+        studentName: "",
+        orgId: null,
+        specialtyName: "",
+        courseId: null,
+        infoCollector: "",
+        identityNumber: ""
+      },
+      paperTypeList: [
+        "A",
+        "B",
+        "C",
+        "D",
+        "E",
+        "F",
+        "G",
+        "H",
+        "I",
+        "J",
+        "K",
+        "L",
+        "M",
+        "N",
+        "O",
+        "P",
+        "Q",
+        "R",
+        "S",
+        "T",
+        "U",
+        "V",
+        "W",
+        "X",
+        "Y",
+        "Z"
+      ],
+      courseList4Search: [],
+      courseList4InsertOrUpdate: [],
+
+      examList4Search: [],
+      examList4InsertOrUpdate: [],
+      examList4Import: [],
+      examList4CopyFrom: [],
+      examList4CopyTo: [],
+
+      queryExams4SearchLoading: false,
+      queryExams4InsertOrUpdateLoading: false,
+      queryExams4ImportLoading: false,
+      queryExams4CopyFromLoading: false,
+      queryExams4CopyToLoading: false,
+
+      selectedExamStuIds: [],
+      addingStudentDialog: false,
+      updateStudentDialog: false,
+      studentPhoDialog: false,
+      studentImportDialog: false,
+      studentCopyDialog: false,
+
+      tableData: [],
+
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
+
+      formLabelWidth: "120px",
+
+      orgList4InsertOrUpdate: [],
+      getOrgList4InsertOrUpdateLoading: false,
+      examStudentForm: {
+        id: null,
+        examId: "",
+        courseId: null,
+        studentId: null,
+        studentName: "",
+        studentCode: "",
+        identityNumber: "",
+        specialtyName: "",
+        orgId: "",
+        examSite: "",
+        grade: "",
+        phone: "",
+        infoCollector: "",
+        paperType: "X"
+      },
+
+      studentImportForm: {
+        examId: ""
+      },
+      studentCopyForm: {
+        sourceExamId: "",
+        targetExamId: ""
+      },
+      result: false,
+
+      rules: {
+        examId: [
+          {
+            type: "number",
+            required: true,
+            message: "请选择考试",
+            trigger: "change"
+          }
+        ],
+        studentName: [
+          { required: true, message: "请输入姓名", trigger: "blur" }
+        ],
+        studentCode: [{ validator: validateStuCode, trigger: "blur" }],
+        identityNumber: [
+          { required: true, validator: validateIdenNum, trigger: "blur" }
+        ],
+        courseId: [
+          {
+            type: "number",
+            required: true,
+            message: "请选择课程",
+            trigger: "change"
+          }
+        ],
+        paperType: [
+          { required: false, message: "请输入试卷类型", trigger: "blur" }
+        ],
+        orgId: [
+          {
+            type: "number",
+            required: true,
+            message: "请选择学习中心",
+            trigger: "change"
+          }
+        ],
+        sourceExamId: [
+          {
+            type: "number",
+            required: true,
+            message: "请选择源考试批次",
+            trigger: "change"
+          }
+        ],
+        targetExamId: [
+          {
+            type: "number",
+            required: true,
+            message: "请选择目标考试批次",
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+
+  computed: {
+    ...mapState({ user: state => state.user }),
+    examStuIds() {
+      var examStuIds = "";
+      for (let examStuId of this.selectedExamStuIds) {
+        if (!examStuIds) {
+          examStuIds += examStuId;
+        } else {
+          examStuIds += "," + examStuId;
+        }
+      }
+      return examStuIds;
+    }
+  },
+
+  methods: {
+    getTag(status) {
+      if (status == true) {
+        return "success";
+      } else if (status == false) {
+        return "danger";
+      } else {
+        return status;
+      }
+    },
+    getEnable(enable) {
+      if (enable == true) {
+        return "启用";
+      } else if (enable == false) {
+        return "禁用";
+      } else {
+        return "启用";
+      }
+    },
+    queryExams4Search(name) {
+      this.queryExams(name, "search");
+    },
+    queryExams4InsertOrUpdate(name) {
+      this.queryExams(name, "insertOrUpdate");
+    },
+    queryExams4Import(name) {
+      this.queryExams(name, "import");
+    },
+    queryExams4CopyFrom(name) {
+      this.queryExams(name, "copyFrom");
+    },
+    queryExams4CopyTo(name) {
+      this.queryExams(name, "copyTo");
+    },
+    queryExams(name, where) {
+      console.log("queryExams; name: " + name);
+      if ("search" == where) {
+        this.queryExams4SearchLoading = true;
+      } else if ("insertOrUpdate" == where) {
+        this.queryExams4InsertOrUpdateLoading = true;
+      } else if ("import" == where) {
+        this.queryExams4ImportLoading = true;
+      } else if ("copyFrom" == where) {
+        this.queryExams4CopyFromLoading = true;
+      } else if ("copyTo" == where) {
+        this.queryExams4CopyToLoading = true;
+      }
+      this.$http
+        .get(exam_work_api + "/exam/queryByNameLike?name=" + name)
+        .then(response => {
+          if ("search" == where) {
+            this.queryExams4SearchLoading = false;
+            this.examList4Search = response.body;
+          } else if ("insertOrUpdate" == where) {
+            this.queryExams4InsertOrUpdateLoading = false;
+            this.examList4InsertOrUpdate = response.body;
+          } else if ("import" == where) {
+            this.queryExams4ImportLoading = false;
+            this.examList4Import = response.body;
+          } else if ("copyFrom" == where) {
+            this.queryExams4CopyFromLoading = false;
+            this.examList4CopyFrom = response.body;
+          } else if ("copyTo" == where) {
+            this.queryExams4CopyToLoading = false;
+            this.examList4CopyTo = response.body;
+          }
+        })
+        .catch(response => {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+          if ("search" == where) {
+            this.queryExams4SearchLoading = false;
+          } else if ("insertOrUpdate" == where) {
+            this.queryExams4InsertOrUpdateLoading = false;
+          } else if ("import" == where) {
+            this.queryExams4ImportLoading = false;
+          } else if ("copyFrom" == where) {
+            this.queryExams4CopyFromLoading = false;
+          } else if ("copyTo" == where) {
+            this.queryExams4CopyToLoading = false;
+          }
+        });
+    },
+    getOrgList4Search(orgName) {
+      this.getOrgList(orgName, "search");
+    },
+    getOrgList4InsertOrUpdate(orgName) {
+      this.getOrgList(orgName, "insertOrUpdate");
+    },
+    getOrgList(orgName, where) {
+      if (Object.prototype.toString.call(orgName) != "[object String]") {
+        return;
+      }
+      orgName = orgName.split(" - ")[0];
+      if ("search" == where) {
+        this.getOrgList4SearchLoading = true;
+      } else if ("insertOrUpdate" == where) {
+        this.getOrgList4InsertOrUpdateLoading = true;
+      }
+
+      var url =
+        core_api + "/org/query?" + new URLSearchParams({ name: orgName });
+      this.$http
+        .get(url)
+        .then(response => {
+          if ("search" == where) {
+            this.getOrgList4SearchLoading = false;
+            this.orgList4Search = response.body;
+          } else if ("insertOrUpdate" == where) {
+            this.getOrgList4InsertOrUpdateLoading = false;
+            this.orgList4InsertOrUpdate = response.body;
+          }
+        })
+        .catch(response => {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+          if ("search" == where) {
+            this.getOrgList4SearchLoading = false;
+          } else if ("insertOrUpdate" == where) {
+            this.getOrgList4InsertOrUpdateLoading = false;
+          }
+        });
+    },
+    closePhotoDialog() {
+      this.photo.url = "";
+      this.photoDialog = false;
+    },
+    showPhoto(row) {
+      var url = core_api + "/student/" + row.studentId;
+      this.$http.get(url).then(response => {
+        if (response.body.photoPath) {
+          this.photo.url = photo_url + response.body.photoPath;
+          this.photoDialog = true;
+        } else {
+          this.$notify({
+            showClose: true,
+            message: "未上传照片",
+            type: "error"
+          });
+        }
+      });
+    },
+    getExcelTitle(row) {
+      return "第" + row + "行";
+    },
+    getCourseName(code) {
+      for (let course of this.courseList) {
+        if (code == course.code) {
+          return course.name;
+        }
+      }
+    },
+    specialtySelect(code) {
+      console.log(code);
+      for (let specialty of this.specialtyList) {
+        if (code == specialty.code) {
+          return specialty.name;
+        }
+      }
+    },
+    selectChange(row) {
+      this.selectedExamStuIds = [];
+      row.forEach((element, index) => {
+        console.log(index);
+        this.selectedExamStuIds.push(element.id);
+      });
+      console.log(this.selectedExamStuIds);
+    },
+    //查询方法
+    searchForm() {
+      var param = new URLSearchParams(this.formSearch);
+      this.loading = true;
+      var url =
+        exam_work_api +
+        "/exam_student/examStudentPage/" +
+        (this.currentPage - 1) +
+        "/" +
+        this.pageSize +
+        "?" +
+        param;
+      this.$http
+        .get(url)
+        .then(response => {
+          this.tableData = response.body.list;
+          this.total = response.body.total;
+          this.loading = false;
+        })
+        .catch(function(response) {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+        });
+    },
+    //查询所有课程
+    getSpecialtys() {
+      var orgId = this.user.orgId;
+      this.$http
+        .get(core_api + "/specialty/all?orgId=" + orgId)
+        .then(response => {
+          console.log(response);
+          this.specialtyList = response.body;
+        });
+    },
+    getCourses4Search(query) {
+      query = query.split(" - ")[0];
+      if (query) {
+        this.courseLoading4Search = true;
+        this.$http
+          .get(core_api + "/course/query?name=" + query)
+          .then(response => {
+            this.courseList4Search = response.body;
+            this.courseLoading4Search = false;
+          });
+      } else {
+        this.courseList4Search = [];
+      }
+    },
+    getCourses4InsertOrUpdate(query) {
+      query = query.split(" - ")[0];
+      if (query) {
+        this.courseLoading4InsertOrUpdate = true;
+        this.$http
+          .get(core_api + "/course/query?name=" + query)
+          .then(response => {
+            this.courseList4InsertOrUpdate = response.body;
+            this.courseLoading4InsertOrUpdate = false;
+          });
+      } else {
+        this.courseList4InsertOrUpdate = [];
+      }
+    },
+    //新增信息
+    addStudent() {
+      var url = exam_work_api + "/exam_student";
+      this.$refs.addingStudentForm.validate(valid => {
+        if (valid) {
+          this.$http.put(url, this.examStudentForm).then(
+            response => {
+              console.log(response);
+              this.$notify({
+                type: "success",
+                message: "保存成功"
+              });
+              this.addingStudentDialog = false;
+              this.searchForm();
+            },
+            response => {
+              if (response.status == 500) {
+                this.$notify({
+                  showClose: true,
+                  message: response.body.desc,
+                  type: "error"
+                });
+              }
+            }
+          );
+        } else {
+          return false;
+        }
+      });
+    },
+    //更新
+    updateStudent() {
+      var url = exam_work_api + "/exam_student";
+      this.$refs.updateStudentForm.validate(valid => {
+        if (valid) {
+          this.$http.put(url, this.examStudentForm).then(
+            response => {
+              console.log(response);
+              this.$notify({
+                type: "success",
+                message: "更新成功"
+              });
+              this.updateStudentDialog = false;
+              this.searchForm();
+            },
+            response => {
+              if (response.status == 500) {
+                this.$notify({
+                  showClose: true,
+                  message: response.body.desc,
+                  type: "error"
+                });
+              }
+            }
+          );
+        } else {
+          return false;
+        }
+      });
+    },
+    //删除方法
+    deleteExamStudent(row) {
+      this.$confirm("是否删除考生?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "error"
+      }).then(() => {
+        var url = exam_work_api + "/exam_student/" + row.id;
+        this.$http.delete(url).then(
+          response => {
+            console.log(response);
+            this.$notify({
+              type: "success",
+              message: "删除成功!"
+            });
+            this.searchForm();
+          },
+          response => {
+            if (response.status == 500) {
+              this.$notify({
+                showClose: true,
+                message: response.body.desc,
+                type: "error"
+              });
+            }
+          }
+        );
+      });
+    },
+    //批量删除方法
+    deleteStuBatch() {
+      if (this.examStuIds.length == 0) {
+        this.$notify({
+          type: "warning",
+          message: "请选择要删除的考生"
+        });
+        return;
+      }
+      this.$confirm("是否删除考生?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "error"
+      }).then(() => {
+        var url = exam_work_api + "/exam_student/" + this.examStuIds;
+        this.$http.delete(url).then(
+          response => {
+            console.log(response);
+            this.$notify({
+              type: "success",
+              message: "删除成功!"
+            });
+            this.searchForm();
+          },
+          response => {
+            if (response.status == 500) {
+              this.$notify({
+                showClose: true,
+                message: response.body.desc,
+                type: "error"
+              });
+            }
+          }
+        );
+      });
+    },
+    //按批次删除方法
+    deleteStuByExam() {
+      if (!this.formSearch.examId) {
+        this.$notify({
+          type: "warning",
+          message: "请选择要删除的批次"
+        });
+        return;
+      }
+
+      this.$msgbox({
+        title: "提示",
+        message: "是否删除该批次所有考生?",
+        showCancelButton: false,
+        confirmButtonText: "确定",
+        beforeClose: (action, instance, done) => {
+          if (action === "confirm") {
+            instance.confirmButtonLoading = true;
+            instance.confirmButtonText = "执行中...";
+
+            let inst = instance;
+            let delExamStudentDone = done;
+            var url =
+              exam_work_api + "/exam_student/exam/" + this.formSearch.examId;
+            this.$http.delete(url).then(
+              response => {
+                console.log(response);
+                this.$notify({
+                  type: "success",
+                  message: "删除成功!"
+                });
+                inst.confirmButtonLoading = false;
+                delExamStudentDone();
+                this.searchForm();
+              },
+              response => {
+                if (response.status == 500) {
+                  this.$notify({
+                    showClose: true,
+                    message: response.body.desc,
+                    type: "error"
+                  });
+                }
+                inst.confirmButtonLoading = false;
+                delExamStudentDone();
+              }
+            );
+          } else {
+            done();
+          }
+        }
+      }).then(action => {
+        console.log(action);
+      });
+    },
+
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchForm();
+    },
+    //新增
+    openAddingDialog() {
+      if (this.$refs.addingStudentForm) {
+        this.$refs.addingStudentForm.resetFields();
+      }
+      this.examStudentForm.examId = null;
+      this.examStudentForm.studentName = null;
+      this.examStudentForm.studentCode = null;
+      this.examStudentForm.identityNumber = null;
+      this.examStudentForm.courseId = null;
+      this.examStudentForm.examSite = null;
+      this.examStudentForm.grade = null;
+      this.examStudentForm.paperType = "X";
+      this.examStudentForm.specialtyName = null;
+      this.examStudentForm.phone = null;
+      this.examStudentForm.infoCollector = null;
+      if (this.pureLC) {
+        this.examStudentForm.orgId = this.lc_id;
+        this.orgList4InsertOrUpdate = [
+          { id: this.lc_id, name: this.lc_name, code: this.lc_code }
+        ];
+      } else {
+        this.examStudentForm.orgId = null;
+        this.orgList4InsertOrUpdate = null;
+      }
+      this.examList4InsertOrUpdate = [];
+      this.courseList4InsertOrUpdate = [];
+
+      this.queryExams4InsertOrUpdate("");
+      this.addingStudentDialog = true;
+    },
+    //修改
+    openUpdateDialog(row) {
+      if (this.$refs.updateStudentForm) {
+        this.$refs.updateStudentForm.resetFields();
+      }
+      this.orgList4InsertOrUpdate = [
+        { id: row.orgId, name: row.orgName, code: row.orgCode }
+      ];
+      this.courseList4InsertOrUpdate = [
+        { id: row.courseId, name: row.courseName, code: row.courseCode }
+      ];
+      this.examList4InsertOrUpdate = [{ id: row.examId, name: row.examName }];
+
+      this.examStudentForm.id = row.id;
+      this.examStudentForm.examId = row.examId;
+      this.examStudentForm.courseId = row.courseId;
+      this.examStudentForm.studentId = row.studentId;
+      this.examStudentForm.studentName = row.studentName;
+      this.examStudentForm.studentCode = row.studentCode;
+      this.examStudentForm.identityNumber = row.identityNumber;
+      this.examStudentForm.specialtyName = row.specialtyName;
+      this.examStudentForm.orgId = row.orgId;
+      this.examStudentForm.examSite = row.examSite;
+      this.examStudentForm.grade = row.grade;
+      this.examStudentForm.phone = row.phone;
+      this.examStudentForm.infoCollector = row.infoCollector;
+      this.examStudentForm.paperType = row.paperType;
+
+      this.updateStudentDialog = true;
+    },
+    //禁用
+    disableExamStudent(row) {
+      this.$confirm("是否禁用所选考生?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        var url = exam_work_api + "/exam_student/disable/" + row.id;
+        this.$http.put(url).then(response => {
+          console.log(response);
+          this.$notify({
+            type: "success",
+            message: "禁用成功"
+          });
+          this.searchForm();
+        });
+      });
+    },
+    //启用
+    enableExamStudent(row) {
+      this.$confirm("是否启用所选考生?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        var url = exam_work_api + "/exam_student/enable/" + row.id;
+        this.$http.put(url).then(response => {
+          console.log(response);
+          this.$notify({
+            type: "success",
+            message: "启用成功"
+          });
+          this.searchForm();
+        });
+      });
+    },
+    closeAddingStudentDialog() {
+      this.addingStudentDialog = false;
+    },
+    closeUpdateStudentDialog() {
+      this.updateStudentDialog = false;
+    },
+    //导入
+    imp() {
+      this.studentImportDialog = true;
+      this.initUpload();
+    },
+    //复制
+    copy() {
+      if (this.$refs.studentCopyForm) {
+        this.$refs.studentCopyForm.resetFields();
+      }
+      this.studentCopyDialog = true;
+      this.studentCopyForm.sourceExamId = null;
+      this.studentCopyForm.targetExamId = null;
+      this.examList4CopyFrom = [];
+      this.examList4CopyTo = [];
+    },
+    //复制学生
+    copyStudent() {
+      this.$refs.studentCopyForm.validate(valid => {
+        if (valid) {
+          if (
+            this.studentCopyForm.sourceExamId ==
+            this.studentCopyForm.targetExamId
+          ) {
+            this.$notify({
+              type: "error",
+              message: "源批次与目标批次不能相同"
+            });
+            return;
+          }
+          var url =
+            task_api +
+            "/copyExamStudent/addCopyTask?" +
+            new URLSearchParams({
+              examId1: this.studentCopyForm.sourceExamId,
+              examId2: this.studentCopyForm.targetExamId
+            });
+
+          this.fileLoading = true;
+          this.$http.post(url, {}).then(
+            response => {
+              console.log(response);
+              this.$notify({
+                type: "success",
+                message: "复制中,请稍后查看"
+              });
+              this.studentCopyDialog = false;
+              this.fileLoading = false;
+              this.searchForm();
+            },
+            response => {
+              if (response.status == 500) {
+                this.$notify({
+                  showClose: true,
+                  message: response.body.desc,
+                  type: "error"
+                });
+              }
+              this.fileLoading = false;
+            }
+          );
+        } else {
+          return false;
+        }
+      });
+    },
+    beforeUpload(file) {
+      console.log(file);
+    },
+    uploadProgress(event, file, fileList) {
+      console.log("uploadProgress");
+      console.log(event);
+      console.log(file);
+      console.log(fileList);
+    },
+    uploadSuccess(response, file, fileList) {
+      console.log("uploadSuccess");
+      console.log(response);
+      console.log(file);
+      console.log(fileList);
+      if (response.failNum > 0) {
+        this.errMessages = response.failRecords;
+        this.errDialog = true;
+      } else {
+        this.$notify({
+          message: "上传成功",
+          type: "success"
+        });
+      }
+
+      this.fileLoading = false;
+      this.studentImportDialog = false;
+      this.searchForm();
+    },
+    uploadError(response, file, fileList) {
+      console.log("uploadSuccess");
+      console.log(response);
+      console.log(file);
+      console.log(fileList);
+
+      var jsonStr = response.message.substring(4);
+      var resp = eval("(" + jsonStr + ")");
+      if (response.status == 500) {
+        this.$notify({
+          message: resp.desc,
+          type: "error"
+        });
+      }
+      this.fileLoading = false;
+    },
+    initUpload() {
+      if (this.$refs.studentImportForm) {
+        this.$refs.studentImportForm.resetFields();
+      }
+      this.fileList = [];
+      this.studentImportForm.examId = "";
+      this.studentImportForm.examList4Import = [];
+    },
+    checkUpload() {
+      if (!this.studentImportForm.examId) {
+        this.$notify({
+          message: "请选择考试批次",
+          type: "error"
+        });
+        return false;
+      } else {
+        this.uploadData.examId = this.studentImportForm.examId;
+      }
+      var fileList = this.$refs.upload.uploadFiles;
+      if (fileList.length == 0) {
+        this.$notify({
+          message: "上传文件不能为空",
+          type: "error"
+        });
+        return false;
+      }
+      if (fileList.length > 1) {
+        this.$notify({
+          message: "每次只能上传一个文件",
+          type: "error"
+        });
+        return false;
+      }
+      for (let file of fileList) {
+        if (!file.name.endsWith(".xlsx")) {
+          this.$notify({
+            message: "上传文件必须为xlsx格式",
+            type: "error"
+          });
+          this.initUpload();
+          return false;
+        }
+      }
+      return true;
+    },
+    //确定上传
+    submitUpload() {
+      if (!this.checkUpload()) {
+        return false;
+      }
+      this.$refs.upload.submit();
+      this.fileLoading = true;
+    },
+    //清空文件
+    removeFile() {
+      this.$refs.upload.clearFiles();
+    },
+    //下载模板
+    exportFile() {
+      window.location.href = "/api/ecs_exam_work/exam_student/download";
+    },
+    initPrivileges() {
+      var url = core_api + "/rolePrivilege/checkPrivileges";
+      var params = {
+        privilegeCodes: Object.keys(this.rolePrivileges).toString()
+      };
+      this.$http.post(url, params, { emulateJSON: true }).then(
+        response => {
+          this.rolePrivileges = response.body;
+        },
+        response => {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+        }
+      );
+    },
+    init() {
+      for (let role of this.user.roleList) {
+        if (role.roleCode == "SUPER_ADMIN") {
+          this.isSuperAdmin = true;
+          continue;
+        } else if (role.roleCode == "LC_USER") {
+          this.pureLC = true;
+          continue;
+        }
+      }
+
+      if (1 < this.user.roleList.length) {
+        this.pureLC = false;
+      }
+
+      this.formSearch.rootOrgId = this.user.rootOrgId;
+      if (this.pureLC) {
+        var url = core_api + "/user/" + this.user.userId;
+        this.$http.get(url).then(
+          response => {
+            var userInfo = response.body;
+            this.lc_id = userInfo.orgId;
+            this.lc_name = userInfo.orgName;
+            this.lc_code = userInfo.orgCode;
+            this.orgList4Search = [
+              { id: this.lc_id, name: this.lc_name, code: this.lc_code }
+            ];
+            this.orgList4InsertOrUpdate = [
+              { id: this.lc_id, name: this.lc_name, code: this.lc_code }
+            ];
+            this.formSearch.orgId = this.lc_id;
+            this.examStudentForm.orgId = this.lc_id;
+            this.queryExams4Search("");
+            this.searchForm();
+          },
+          response => {
+            if (response.status == 500) {
+              this.$notify({
+                showClose: true,
+                message: response.body.desc,
+                type: "error"
+              });
+            }
+          }
+        );
+      } else {
+        this.queryExams4Search("");
+        this.searchForm();
+      }
+    }
+  },
+  created() {
+    this.initPrivileges();
+    this.init();
+    this.uploadHeaders = {
+      key: this.user.key,
+      token: this.user.token
+    };
+  }
+};
+</script>

+ 410 - 0
src/modules/examwork/view/examStudentImport.vue

@@ -0,0 +1,410 @@
+<template>
+  <div>
+    <section class="content" style="margin-top: -10px;">
+      <div class="box box-info">
+        <!-- 头信息 -->
+        <div class="box-header with-border">
+          <h3 class="box-title">考生导入</h3>
+          <div class="box-tools pull-right">
+            <button
+              type="button"
+              class="btn btn-box-tool"
+              data-widget="collapse"
+            >
+              <i class="fa fa-minus"></i>
+            </button>
+          </div>
+        </div>
+
+        <!-- 正文信息 -->
+        <div class="box-body">
+          <el-form
+            :inline="true"
+            :model="formSearch"
+            label-position="right"
+            label-width="100px"
+          >
+            <el-form-item class="pull-right buttonframe">
+              <el-button size="small" type="primary" icon="upload2" @click="imp"
+                >导入
+              </el-button>
+            </el-form-item>
+          </el-form>
+
+          <!-- 导入弹窗 -->
+          <el-dialog
+            title="考生信息导入页"
+            size="tiny"
+            v-model="studentImportDialog"
+          >
+            <el-form :model="studentImportForm" ref="studentImportForm">
+              <el-row>
+                <el-form-item
+                  style="margin-left:30px"
+                  label="考试"
+                  prop="value"
+                >
+                  <el-select
+                    class="input"
+                    :remote-method="queryExams"
+                    remote
+                    :loading="queryExamsLoading"
+                    filterable
+                    clearable
+                    v-model="studentImportForm.examId"
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in examList"
+                      :label="item.name"
+                      :value="item.id"
+                      :key="item.id"
+                      :disabled="!item.enable"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-row>
+              <el-row>
+                <el-form-item style="margin-left:30px">
+                  <el-upload
+                    class="form_left"
+                    ref="upload"
+                    accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+                    :action="uploadAction"
+                    :headers="uploadHeaders"
+                    :data="uploadData"
+                    :before-upload="beforeUpload"
+                    :on-progress="uploadProgress"
+                    :on-success="uploadSuccess"
+                    :on-error="uploadError"
+                    :file-list="fileList"
+                    :auto-upload="false"
+                    :multiple="false"
+                  >
+                    <el-button size="small" slot="trigger" type="primary"
+                      >选择文件</el-button
+                    >
+                    <el-button
+                      size="small"
+                      style="margin-left:10px;"
+                      type="success"
+                      @click="submitUpload"
+                      >确认上传
+                    </el-button>
+                    <el-button
+                      size="small"
+                      style="margin-left: 10px;"
+                      type="danger"
+                      @click="removeFile"
+                      >清空文件
+                    </el-button>
+                    <el-button size="small" type="info" @click="exportFile"
+                      >下载模板
+                    </el-button>
+                    <div slot="tip" class="el-upload__tip">
+                      只能上传xlsx文件
+                    </div>
+                  </el-upload>
+                </el-form-item>
+              </el-row>
+            </el-form>
+          </el-dialog>
+
+          <!-- 页面列表 -->
+          <el-table
+            :data="tableData"
+            border
+            style="width: 100%;text-align:center;"
+          >
+            <el-table-column inline-template width="100" label="ID">
+              <div>
+                <span>{{ row.id }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="顶级机构">
+              <div>
+                <span>{{ row.rootOrgName }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="考试">
+              <div>
+                <span>{{ row.examName }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="上传文件名">
+              <div>
+                <span>{{ row.fileName }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="状态">
+              <div>
+                <span>{{ row.statusDesc }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template label="异常">
+              <div>
+                <span>{{ row.errorDesc }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template width="170" label="上传时间">
+              <div>
+                <span>{{ row.creationTime }}</span>
+              </div>
+            </el-table-column>
+            <el-table-column inline-template label="操作" width="190">
+              <div>
+                <el-button
+                  size="mini"
+                  type="warning"
+                  @click="getUploadedFile(row.id);"
+                  >下载导入文件
+                </el-button>
+                <el-button
+                  v-if="
+                    row.status == 'DATA_PROCESSING_COMPLETE' ||
+                      row.status == 'ERROR'
+                  "
+                  size="mini"
+                  type="warning"
+                  @click="getReports(row.id);"
+                  >导出报告
+                </el-button>
+              </div>
+            </el-table-column>
+          </el-table>
+          <div class="page pull-right">
+            <el-pagination
+              @current-change="handleCurrentChange"
+              :current-page="currentPage"
+              :page-size="pageSize"
+              layout="total, prev, pager, next, jumper"
+              :total="total"
+            >
+            </el-pagination>
+          </div>
+        </div>
+      </div>
+    </section>
+  </div>
+</template>
+<style scoped></style>
+<script>
+import { mapActions, mapState } from "vuex";
+import { USER_SIGNIN } from "../store/user";
+import { task_api, exam_work_api } from "../store/global";
+
+export default {
+  data() {
+    return {
+      formSearch: {},
+      uploadAction: task_api + "/examStudentImport/import",
+      studentImportDialog: false,
+      examList: [],
+      uploadHeaders: {},
+      uploadData: { examId: "" },
+      fileList: [],
+      fileLoading: false,
+      queryExamsLoading: false,
+      studentImportForm: {
+        examId: null
+      },
+
+      tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 0
+    };
+  },
+  computed: {
+    ...mapState({ user: state => state.user })
+  },
+  methods: {
+    ...mapActions([USER_SIGNIN]),
+
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.queryTableDatas();
+    },
+    imp() {
+      this.studentImportDialog = true;
+      this.initUpload();
+    },
+    initUpload() {
+      if (this.$refs.studentImportForm) {
+        this.$refs.studentImportForm.resetFields();
+      }
+      this.fileList = [];
+      this.studentImportForm.examId = null;
+      this.examList = [];
+    },
+    beforeUpload(file) {
+      console.log(file);
+    },
+    uploadProgress(event, file, fileList) {
+      console.log("uploadProgress");
+      console.log(event);
+      console.log(file);
+      console.log(fileList);
+    },
+    uploadSuccess(response, file, fileList) {
+      console.log("uploadSuccess");
+      console.log(response);
+      console.log(file);
+      console.log(fileList);
+      this.$notify({
+        message: "上传成功",
+        type: "success"
+      });
+      this.fileLoading = false;
+      this.studentImportDialog = false;
+      this.queryTableDatas();
+    },
+    uploadError(response, file, fileList) {
+      console.log("uploadError");
+      console.log(response);
+      console.log(file);
+      console.log(fileList);
+      var jsonStr = response.message.substring(4);
+      var resp = eval("(" + jsonStr + ")");
+      if (response.status == 500) {
+        this.$notify({
+          message: resp.desc,
+          type: "error"
+        });
+      }
+      this.fileLoading = false;
+    },
+    //确定上传
+    submitUpload() {
+      if (!this.checkUpload()) {
+        return false;
+      }
+      this.$refs.upload.submit();
+      this.fileLoading = true;
+    },
+    checkUpload() {
+      if (!this.studentImportForm.examId) {
+        this.$notify({
+          message: "请选择考试批次",
+          type: "error"
+        });
+        return false;
+      } else {
+        this.uploadData.examId = this.studentImportForm.examId;
+      }
+      var fileList = this.$refs.upload.uploadFiles;
+      if (fileList.length == 0) {
+        this.$notify({
+          message: "上传文件不能为空",
+          type: "error"
+        });
+        return false;
+      }
+      if (fileList.length > 1) {
+        this.$notify({
+          message: "每次只能上传一个文件",
+          type: "error"
+        });
+        return false;
+      }
+      for (let file of fileList) {
+        if (!file.name.endsWith(".xlsx")) {
+          this.$notify({
+            message: "上传文件必须为xlsx格式",
+            type: "error"
+          });
+          this.initUpload();
+          return false;
+        }
+      }
+      return true;
+    },
+    //清空文件
+    removeFile() {
+      this.$refs.upload.clearFiles();
+    },
+    //下载模板
+    exportFile() {
+      window.location.href =
+        "/api/ecs_exam_work/exam_student/downloadTemplate?$key=" +
+        this.user.key +
+        "&$token=" +
+        this.user.token;
+    },
+    //下载报告
+    getReports(id) {
+      window.location.href =
+        task_api +
+        "/examStudentImport/getReports/" +
+        id +
+        "?$key=" +
+        this.user.key +
+        "&$token=" +
+        this.user.token;
+    },
+    //下载导入文件
+    getUploadedFile(id) {
+      window.location.href =
+        task_api +
+        "/examStudentImport/getUploadedFile/" +
+        id +
+        "?$key=" +
+        this.user.key +
+        "&$token=" +
+        this.user.token;
+    },
+    queryExams(name) {
+      console.log("queryExams; name: " + name);
+      this.queryExamsLoading = true;
+      this.$http
+        .get(exam_work_api + "/exam/queryByNameLike?name=" + name)
+        .then(response => {
+          this.queryExamsLoading = false;
+          this.examList = response.body;
+        })
+        .catch(response => {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+          this.queryExamsLoading = false;
+        });
+    },
+    queryTableDatas: function() {
+      var url =
+        task_api +
+        "/examStudentImport/all/" +
+        (this.currentPage - 1) +
+        "/" +
+        this.pageSize;
+      this.$http
+        .get(url)
+        .then(response => {
+          console.log(response);
+          this.tableData = response.body.list;
+          this.total = response.body.total;
+        })
+        .catch(response => {
+          if (response.status == 500) {
+            this.$notify({
+              showClose: true,
+              message: response.body.desc,
+              type: "error"
+            });
+          }
+        });
+    }
+  },
+  created() {
+    this.queryTableDatas();
+    this.uploadHeaders = {
+      key: this.user.key,
+      token: this.user.token
+    };
+  }
+};
+</script>

+ 6 - 2
src/modules/examwork/view/student.vue

@@ -417,7 +417,11 @@
 </template>
 
 <script>
-import { CORE_API, EXAM_WORK_API, OUTLET_API } from "@/constants/constants.js";
+import {
+  CORE_API,
+  EXAM_WORK_API,
+  EXCHANGE_API
+} from "@/constants/constants.js";
 import { mapState } from "vuex";
 
 export default {
@@ -462,7 +466,7 @@ export default {
       photo: { url: "" },
 
       errMessages: [],
-      uploadAction: OUTLET_API + "/facepp/add",
+      uploadAction: EXCHANGE_API + "/facepp/add",
       uploadData: {},
       fileLoading: false,
       fileList: [],

+ 0 - 4
src/modules/portal/views/home/HomeMain.vue

@@ -59,10 +59,6 @@ export default {
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
-  /* align-items: center;
-        justify-items: center; */
-  /* justify-content: space-between; */
-  /* align-content: space-between; */
   justify-content: center;
 
   height: 100%;

+ 382 - 29
src/modules/print/view/CourseStatistic.vue

@@ -6,7 +6,7 @@
         class="box-header with-border"
         style="background-color:#d3dce6;margin-bottom:20px;"
       >
-        <h3 class="box-title">课程统计</h3>
+        <h2 class="box-title">课程统计</h2>
         <div class="box-tools pull-right">
           <button type="button" class="btn btn-box-tool" data-widget="collapse">
             <i class="fa fa-minus"></i>
@@ -108,7 +108,7 @@
               size="small"
               type="primary"
               icon="el-icon-menu"
-              @click="openAllotPaperModel"
+              @click="openAllotAllDialog"
               >分配待指定试卷
             </el-button>
 
@@ -116,7 +116,7 @@
               size="small"
               type="primary"
               icon="el-icon-download"
-              @click="openExportAllModel"
+              @click="openExportAllDialog"
               >整体导出
             </el-button>
 
@@ -124,7 +124,7 @@
               size="small"
               type="primary"
               icon="el-icon-download"
-              @click="openExportBatchModel"
+              @click="openExportDialog"
               >批量导出
             </el-button>
 
@@ -152,7 +152,11 @@
           <el-table-column width="80" label="试卷类型" prop="paperType" />
           <el-table-column width="80" label="试卷状态">
             <template slot-scope="scope">
-              {{ scope.row.paperStatusName }}
+              <span
+                @click="openAllotDialog(scope.row);"
+                style="cursor: pointer"
+                >{{ scope.row.paperStatusName }}</span
+              >
             </template>
           </el-table-column>
           <el-table-column width="200" label="试卷名称" prop="paperName" />
@@ -164,7 +168,7 @@
               <el-button
                 size="mini"
                 icon="el-icon-view"
-                v-show="scope.row.paperStatus == '2'"
+                v-show="scope.row.paperStatus > 1"
                 @click="preview(scope.row);"
                 >预览
               </el-button>
@@ -172,7 +176,7 @@
               <el-button
                 size="mini"
                 icon="el-icon-download"
-                v-show="scope.row.paperStatus == '2'"
+                v-show="scope.row.paperStatus > 1"
                 @click="download(scope.row);"
                 >下载
               </el-button>
@@ -191,6 +195,235 @@
           ></el-pagination>
         </div>
       </div>
+
+      <el-dialog
+        title="试卷指定"
+        width="380px"
+        :visible.sync="allotDialog"
+        @close="closeAllotDialog"
+      >
+        <el-form
+          :model="allotForm"
+          ref="allotForm"
+          :rules="rules"
+          label-position="right"
+          label-width="80px"
+        >
+          <el-form-item label="课程名称" prop="courseName">
+            <el-input
+              v-model="allotForm.courseName"
+              :disabled="true"
+              class="w220"
+            >
+              {{ allotForm.courseName }}</el-input
+            >
+          </el-form-item>
+
+          <el-form-item label="试卷类型" prop="paperType">
+            <el-input
+              v-model="allotForm.paperType"
+              :disabled="true"
+              class="w220"
+            >
+              {{ allotForm.paperType }}</el-input
+            >
+          </el-form-item>
+
+          <el-form-item label="试卷名称" prop="coursePaperId">
+            <el-select
+              v-model="allotForm.coursePaperId"
+              placeholder="请选择"
+              class="w220"
+            >
+              <el-option
+                v-for="item in coursePaperList"
+                :value="item.coursePaperId"
+                :key="item.coursePaperId"
+                :label="item.paperName"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+
+          <div style="text-align: center">
+            <el-button type="primary" @click="saveAllot">确 定</el-button>
+            <el-button @click="closeAllotDialog">取 消</el-button>
+          </div>
+        </el-form>
+      </el-dialog>
+
+      <el-dialog title="试卷整体分配" :visible.sync="allotAllDialog">
+        <el-form
+          :model="allotAllForm"
+          label-position="right"
+          label-width="100px"
+        >
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="学校名称">
+                <el-select
+                  v-model="allotAllForm.orgId"
+                  @change="searchExamList(allotAllForm.orgId, 2);"
+                >
+                  <el-option label="请选择" value></el-option>
+                  <el-option
+                    v-for="item in orgList"
+                    :label="item.orgName"
+                    :value="item.orgId"
+                    :key="item.orgId"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="考试名称">
+                <el-select v-model="allotAllForm.examId">
+                  <el-option label="请选择" value></el-option>
+                  <el-option
+                    v-for="item in examList"
+                    :label="item.examName"
+                    :value="item.examId"
+                    :key="item.examId"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="10">
+            <el-col :span="20">
+              <el-form-item>
+                <span style="font-size:20px;color: red;"
+                  >警告!确定后,选中考试中待指定的课程会在推送试卷中随机选取一套试卷,是否确定执行?</span
+                >
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col
+              :span="24"
+              class="text-center"
+              style="border-top: 2px solid;padding-top: 10px;"
+            >
+              <el-button
+                type="primary"
+                :disabled="
+                  allotAllForm.orgId === '' || allotAllForm.examId === ''
+                "
+                @click="saveAllotAll"
+                >确定</el-button
+              >
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-dialog>
+
+      <el-dialog title="导出" :visible.sync="exportDialog">
+        <el-form :model="exportForm" label-position="right" label-width="80px">
+          <el-checkbox-group v-model="exportForm.types">
+            <el-checkbox label="1">试卷</el-checkbox>
+            <el-checkbox label="2">答案</el-checkbox>
+            <el-checkbox label="3">试卷结构</el-checkbox>
+          </el-checkbox-group>
+          <div style="text-align: center">
+            <el-button type="primary" @click="doExport">确定导出</el-button>
+            <el-button @click="closeExportDialog">取 消</el-button>
+          </div>
+        </el-form>
+      </el-dialog>
+
+      <el-dialog title="试卷整体导出" :visible.sync="exportAllDialog">
+        <el-form
+          :model="exportAllForm"
+          label-position="right"
+          label-width="100px"
+        >
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="学校名称">
+                <el-select
+                  v-model="exportAllForm.orgId"
+                  @change="searchExamList(exportAllForm.orgId, 3);"
+                >
+                  <el-option label="请选择" value></el-option>
+                  <el-option
+                    v-for="item in orgList"
+                    :label="item.orgName"
+                    :value="item.orgId"
+                    :key="item.orgId"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="考试名称">
+                <el-select
+                  v-model="exportAllForm.examId"
+                  @change="searchExamCoursePaperTotal"
+                >
+                  <el-option label="请选择" value></el-option>
+                  <el-option
+                    v-for="item in examList"
+                    :label="item.examName"
+                    :value="item.examId"
+                    :key="item.examId"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="试卷总数">{{
+                exportAllForm.allNum
+              }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="已有试卷数">{{
+                exportAllForm.existNum
+              }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="缺少试卷数">{{
+                exportAllForm.missNum
+              }}</el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="10">
+            <el-col :md="20">
+              <el-form-item label="导出内容">
+                <el-checkbox-group v-model="exportAllForm.types">
+                  <el-checkbox label="1">试卷</el-checkbox>
+                  <el-checkbox label="2">答案</el-checkbox>
+                  <el-checkbox label="3">试卷结构</el-checkbox>
+                </el-checkbox-group>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="10">
+            <el-col
+              :span="24"
+              class="text-center"
+              style="border-top: 2px solid;padding-top: 10px;"
+            >
+              <el-button
+                type="primary"
+                :disabled="exportAllForm.existNum == 0"
+                @click="doExportAll"
+                >确定导出</el-button
+              >
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-dialog>
     </div>
   </section>
 </template>
@@ -220,11 +453,149 @@ export default {
       orgList: [],
       examList: [],
       courseList: [],
+      coursePaperList: [],
       coursePaperStatusList: coursePaperStatusList,
-      rules: {}
+      allotDialog: false,
+      allotForm: {
+        id: "",
+        coursePaperId: "",
+        courseName: "",
+        paperType: ""
+      },
+      allotAllDialog: false,
+      allotAllForm: {
+        orgId: "",
+        examId: ""
+      },
+      exportDialog: false,
+      exportForm: {
+        orgId: "",
+        examId: "",
+        courseCode: "",
+        courseName: "",
+        paperType: "",
+        coursePaperId: "",
+        courseId: "",
+        id: ""
+      },
+      exportAllDialog: false,
+      exportAllForm: {
+        orgId: "",
+        examId: "",
+        exportList: [],
+        allNum: 0,
+        existNum: 0,
+        missNum: 0,
+        types: []
+      },
+      rules: {
+        coursePaperId: [
+          { required: true, message: "试卷不能为空!", trigger: "change" }
+        ],
+        courseName: [
+          { required: true, message: "课程不能为空!", trigger: "change" }
+        ],
+        paperType: [
+          { required: true, message: "试卷类型不能为空!", trigger: "change" }
+        ]
+      }
     };
   },
   methods: {
+    searchExamCoursePaperTotal() {
+      /* xxx */
+    },
+    openAllotDialog(row) {
+      /* 试卷状态为"已有"时,打开试卷指定弹窗 */
+      if (row.paperStatus > 0) {
+        this.allotDialog = true;
+        this.allotForm.id = row.id;
+        this.allotForm.coursePaperId = row.coursePaperId;
+        this.allotForm.courseName = row.courseName;
+        this.allotForm.paperType = row.paperType;
+        let params = {
+          orgId: row.orgId,
+          examId: row.examId,
+          courseId: row.courseId
+        };
+        let url = PRINT_API + "/course/paper/list";
+        this.$http.post(url, params).then(
+          response => {
+            this.coursePaperList = response.data;
+          },
+          error => {
+            console.log(error);
+          }
+        );
+      }
+    },
+    closeAllotDialog() {
+      /* 关闭试卷指定弹窗 */
+      this.allotDialog = false;
+    },
+    saveAllot() {
+      /* 保存试卷指定 */
+      this.$refs.allotForm.validate(valid => {
+        if (!valid) {
+          return false;
+        }
+        let url =
+          PRINT_API +
+          "/course/paper/allot/" +
+          this.allotForm.id +
+          "/" +
+          this.allotForm.coursePaperId;
+        this.$http.post(url).then(
+          () => {
+            this.$notify({
+              message: "试卷指定成功!",
+              type: "success"
+            });
+            this.allotDialog = false;
+            this.searchRecords();
+          },
+          () => {
+            this.$notify({
+              message: "试卷指定失败!",
+              type: "error"
+            });
+          }
+        );
+      });
+    },
+    openAllotAllDialog() {
+      /* 打开分配待指定试卷弹窗 */
+      this.allotAllDialog = true;
+    },
+    closeAllotAllDialog() {
+      /* 关闭分配待指定试卷弹窗 */
+      this.allotAllDialog = false;
+    },
+    saveAllotAll() {
+      /* 保存分配待指定试卷 */
+    },
+    openExportDialog() {
+      /* 打开批量导出弹窗 */
+      this.exportDialog = true;
+    },
+    closeExportDialog() {
+      /* 关闭批量导出弹窗 */
+      this.exportDialog = false;
+    },
+    doExport() {
+      /* 批量导出 */
+    },
+    openExportAllDialog() {
+      /* 打开整体导出弹窗 */
+      this.exportAllDialog = true;
+    },
+    closeExportAllDialog() {
+      /* 关闭整体导出弹窗 */
+      this.exportAllDialog = false;
+    },
+    doExportAll() {
+      /* 整体导出 */
+    },
     handlePager(current) {
       /* 处理分页 */
       this.formSearch.pageNo = current;
@@ -297,27 +668,6 @@ export default {
         type: "warning"
       });
     },
-    openAllotPaperModel() {
-      /* 分配待指定试卷 */
-      this.$notify({
-        message: "Todo...",
-        type: "warning"
-      });
-    },
-    openExportBatchModel() {
-      /* 批量导出 */
-      this.$notify({
-        message: "Todo...",
-        type: "warning"
-      });
-    },
-    openExportAllModel() {
-      /* 整体导出 */
-      this.$notify({
-        message: "Todo...",
-        type: "warning"
-      });
-    },
     preview(row) {
       /* 预览试卷PDF */
       console.log(row);
@@ -362,4 +712,7 @@ export default {
 .pull-left {
   float: left;
 }
+.w220 {
+  width: 220px;
+}
 </style>

+ 4 - 1
src/modules/print/view/ExamStructure.vue

@@ -6,7 +6,7 @@
         class="box-header with-border"
         style="background-color:#d3dce6;margin-bottom:20px;"
       >
-        <h3 class="box-title">考试结构</h3>
+        <h2 class="box-title">考试结构</h2>
         <div class="box-tools pull-right">
           <button type="button" class="btn btn-box-tool" data-widget="collapse">
             <i class="fa fa-minus"></i>
@@ -249,4 +249,7 @@ export default {
 .pull-left {
   float: left;
 }
+.w220 {
+  width: 220px;
+}
 </style>

+ 14 - 1
src/modules/print/view/Project.vue

@@ -6,7 +6,7 @@
         class="box-header with-border"
         style="background-color:#d3dce6;margin-bottom:20px;"
       >
-        <h3 class="box-title">项目列表</h3>
+        <h2 class="box-title">项目列表</h2>
         <div class="box-tools pull-right">
           <button type="button" class="btn btn-box-tool" data-widget="collapse">
             <i class="fa fa-minus"></i>
@@ -172,6 +172,7 @@
                   v-model="projectSettingForm.orgId"
                   placeholder="请选择"
                   :disabled="true"
+                  class="w220"
                 >
                   <el-option
                     v-for="item in orgList"
@@ -189,6 +190,7 @@
                   v-model="projectSettingForm.examId"
                   placeholder="请选择"
                   :disabled="true"
+                  class="w220"
                 >
                   <el-option
                     v-for="item in examList"
@@ -209,6 +211,7 @@
                   placeholder="请选择"
                   @change="selectPmName"
                   clearable
+                  class="w220"
                 >
                   <el-option
                     v-for="item in pmList"
@@ -227,6 +230,7 @@
                   placeholder="请选择"
                   @change="selectSupplierName"
                   clearable
+                  class="w220"
                 >
                   <el-option
                     v-for="item in supplierList"
@@ -247,6 +251,7 @@
                   type="datetime"
                   format="yyyy-MM-dd HH:mm:ss"
                   placeholder="选择开始时间"
+                  class="w220"
                 ></el-date-picker>
               </el-form-item>
             </el-col>
@@ -258,6 +263,7 @@
                   type="datetime"
                   format="yyyy-MM-dd HH:mm:ss"
                   placeholder="选择结束时间"
+                  class="w220"
                   :picker-options="prepareEndTimePicker"
                 ></el-date-picker>
               </el-form-item>
@@ -272,6 +278,7 @@
                   type="datetime"
                   format="yyyy-MM-dd HH:mm:ss"
                   placeholder="选择开始时间"
+                  class="w220"
                 ></el-date-picker>
               </el-form-item>
             </el-col>
@@ -283,6 +290,7 @@
                   type="datetime"
                   format="yyyy-MM-dd HH:mm:ss"
                   placeholder="选择结束时间"
+                  class="w220"
                   :picker-options="printEndTimePicker"
                 ></el-date-picker>
               </el-form-item>
@@ -297,6 +305,7 @@
                   type="datetime"
                   format="yyyy-MM-dd HH:mm:ss"
                   placeholder="选择开始时间"
+                  class="w220"
                 ></el-date-picker>
               </el-form-item>
             </el-col>
@@ -308,6 +317,7 @@
                   type="datetime"
                   format="yyyy-MM-dd HH:mm:ss"
                   placeholder="选择结束时间"
+                  class="w220"
                   :picker-options="mailEndTimePicker"
                 ></el-date-picker>
               </el-form-item>
@@ -800,4 +810,7 @@ export default {
 .pull-left {
   float: left;
 }
+.w220 {
+  width: 220px;
+}
 </style>

+ 15 - 4
src/modules/print/view/ProjectStatistic.vue

@@ -6,7 +6,7 @@
         class="box-header with-border"
         style="background-color:#d3dce6;margin-bottom:20px;"
       >
-        <h3 class="box-title">项目统计</h3>
+        <h2 class="box-title">项目统计</h2>
         <div class="box-tools pull-right">
           <button type="button" class="btn btn-box-tool" data-widget="collapse">
             <i class="fa fa-minus"></i>
@@ -161,7 +161,7 @@
           ref="backupSettingForm"
           :rules="rules"
           label-position="right"
-          label-width="80px"
+          label-width="90px"
         >
           <el-tabs v-model="eachPkgTab">
             <el-tab-pane name="first">
@@ -173,6 +173,7 @@
                 <el-input
                   v-model="backupSettingForm.eachPkgPercent"
                   :disabled="!backupSettingForm.needEachPkg"
+                  class="w300"
                   ><template slot="append"
                     >%</template
                   ></el-input
@@ -182,6 +183,7 @@
                 <el-input
                   v-model="backupSettingForm.eachPkgMax"
                   :disabled="!backupSettingForm.needEachPkg"
+                  class="w300"
                   ><template slot="append"
                     >%</template
                   ></el-input
@@ -191,6 +193,7 @@
                 <el-input
                   v-model="backupSettingForm.eachPkgMin"
                   :disabled="!backupSettingForm.needEachPkg"
+                  class="w300"
                   ><template slot="append"
                     >%</template
                   ></el-input
@@ -210,6 +213,7 @@
                   v-model="backupSettingForm.groupType"
                   :disabled="!backupSettingForm.needAlonePkg"
                   placeholder="请选择"
+                  class="w300"
                 >
                   <el-option
                     v-for="item in groupTypeList"
@@ -223,6 +227,7 @@
                 <el-input
                   v-model="backupSettingForm.alonePkgPercent"
                   :disabled="!backupSettingForm.needAlonePkg"
+                  class="w300"
                   ><template slot="append"
                     >%</template
                   >
@@ -232,6 +237,7 @@
                 <el-input
                   v-model="backupSettingForm.alonePkgMax"
                   :disabled="!backupSettingForm.needAlonePkg"
+                  class="w300"
                   ><template slot="append"
                     >%</template
                   ></el-input
@@ -241,6 +247,7 @@
                 <el-input
                   v-model="backupSettingForm.alonePkgMin"
                   :disabled="!backupSettingForm.needAlonePkg"
+                  class="w300"
                   ><template slot="append"
                     >%</template
                   ></el-input
@@ -260,7 +267,7 @@
       <!-- 其它事项弹窗 -->
       <el-dialog
         title="其它事项"
-        width="750px"
+        width="500px"
         :visible.sync="otherSettingDialog"
         @close="closeOtherSettingDialog"
       >
@@ -269,13 +276,14 @@
           ref="otherSettingForm"
           :rules="rules"
           label-position="right"
-          label-width="110px"
+          label-width="90px"
         >
           <el-form-item label="事项内容" prop="remark">
             <el-input
               type="textarea"
               :rows="8"
               v-model="otherSettingForm.remark"
+              class="w300"
             ></el-input>
           </el-form-item>
         </el-form>
@@ -806,4 +814,7 @@ export default {
 .pull-left {
   float: left;
 }
+.w300 {
+  width: 300px;
+}
 </style>

+ 4 - 1
src/modules/print/view/ProjectTemplate.vue

@@ -6,7 +6,7 @@
         class="box-header with-border"
         style="background-color:#d3dce6;margin-bottom:20px;"
       >
-        <h3 class="box-title">模板页面</h3>
+        <h2 class="box-title">模板页面</h2>
         <div class="box-tools pull-right">
           <button type="button" class="btn btn-box-tool" data-widget="collapse">
             <i class="fa fa-minus"></i>
@@ -230,4 +230,7 @@ export default {
 .pull-left {
   float: left;
 }
+.w220 {
+  width: 220px;
+}
 </style>

+ 0 - 68
src/modules/questions/constants/constants.js

@@ -1,7 +1,3 @@
-import Vue from "vue";
-import _ from "lodash";
-import CKEditor from "@ckeditor/ckeditor5-vue";
-export const QUESTION_API = "/api/ecs_ques"; //题库API
 export const LEVEL_TYPE = [
   { label: "专升本", value: "ZSB" },
   { label: "高起专", value: "GQZ" },
@@ -20,76 +16,12 @@ export const PUBLICITY_LIST = [
   { label: "公开", value: true },
   { label: "非公开", value: false }
 ];
-//option字母顺序过滤器
-Vue.filter("optionOrderWordFilter", function(value) {
-  return String.fromCharCode(65 + value);
-});
-//题型过滤器
-Vue.filter("questionType", function(value) {
-  for (let questionType of QUESTION_TYPES) {
-    if (questionType.value === value) {
-      return questionType.label;
-    }
-  }
-});
-
 export const EXAM_TYPES = [
   { value: "TRADITION", label: "传统考试" },
   { value: "ONLINE", label: "网络考试" },
   { value: "PRACTICE", label: "在线练习" }
 ];
-
 export const EXPORT_TYPES = [
   { value: "ONLINE", label: "机考" },
   { value: "NORMAL", label: "普通" }
 ];
-
-Vue.filter("examTypesFilter", function(value) {
-  for (let item of EXAM_TYPES) {
-    if (item.value === value) {
-      return item.label;
-    }
-  }
-});
-Vue.filter("exportTypesFilter", function(value) {
-  for (let item of EXPORT_TYPES) {
-    if (item.value === value) {
-      return item.label;
-    }
-  }
-});
-
-Vue.prototype._ = _;
-Vue.use(CKEditor);
-
-Vue.directive("questionAudio", {
-  bind: function(el, binding, vnode) {
-    addAudio(el, binding, vnode);
-  }
-});
-
-function addAudio(el, binding, vnode) {
-  // console.log(el, binding, vnode);
-  var list = el.getElementsByTagName("a");
-  for (let obj of list) {
-    var questionAudioId = obj.getAttribute("id");
-    if (questionAudioId) {
-      console.log("come in");
-      vnode.context.$http
-        .get(QUESTION_API + "/questionAudio/" + questionAudioId)
-        .then(response => {
-          console.log("response:", response);
-          if (response && response.data) {
-            let audioFlag =
-              '<audio controls><source src="http://exam-cloud-test.b0.upaiyun.com' +
-              response.data.fileUrl +
-              '" type="audio/mpeg"></audio>';
-            var b = document.createElement("span");
-            b.innerHTML = audioFlag;
-            obj.append(b);
-          }
-        });
-    }
-  }
-  console.log("el:", el);
-}

+ 32 - 0
src/modules/questions/directives/directives.js

@@ -0,0 +1,32 @@
+import Vue from "vue";
+import { QUESTION_API } from "@/constants/constants";
+Vue.directive("questionAudio", {
+  bind: function(el, binding, vnode) {
+    addAudio(el, binding, vnode);
+  }
+});
+function addAudio(el, binding, vnode) {
+  // console.log(el, binding, vnode);
+  var list = el.getElementsByTagName("a");
+  for (let obj of list) {
+    var questionAudioId = obj.getAttribute("id");
+    if (questionAudioId) {
+      console.log("come in");
+      vnode.context.$http
+        .get(QUESTION_API + "/questionAudio/" + questionAudioId)
+        .then(response => {
+          console.log("response:", response);
+          if (response && response.data) {
+            let audioFlag =
+              '<audio controls><source src="http://exam-cloud-test.b0.upaiyun.com' +
+              response.data.fileUrl +
+              '" type="audio/mpeg"></audio>';
+            var b = document.createElement("span");
+            b.innerHTML = audioFlag;
+            obj.append(b);
+          }
+        });
+    }
+  }
+  console.log("el:", el);
+}

+ 32 - 0
src/modules/questions/filters/filters.js

@@ -0,0 +1,32 @@
+import Vue from "vue";
+import {
+  QUESTION_TYPES,
+  EXAM_TYPES,
+  EXPORT_TYPES
+} from "../constants/constants";
+//option字母顺序过滤器
+Vue.filter("optionOrderWordFilter", function(value) {
+  return String.fromCharCode(65 + value);
+});
+//题型过滤器
+Vue.filter("questionType", function(value) {
+  for (let questionType of QUESTION_TYPES) {
+    if (questionType.value === value) {
+      return questionType.label;
+    }
+  }
+});
+Vue.filter("examTypesFilter", function(value) {
+  for (let item of EXAM_TYPES) {
+    if (item.value === value) {
+      return item.label;
+    }
+  }
+});
+Vue.filter("exportTypesFilter", function(value) {
+  for (let item of EXPORT_TYPES) {
+    if (item.value === value) {
+      return item.label;
+    }
+  }
+});

+ 223 - 214
src/modules/questions/views/EditOtherQuestion.vue

@@ -1,244 +1,253 @@
 <!-- 编辑填空,问答,判断题 -->
-<style></style>
 <template>
-  <section class="content" v-loading="fullscreenLoading">
-    <div class="box box-info">
-      <div class="box-header with-border">
-        <h3 class="box-title">
-          <span v-if="!quesModel.id">试题新增</span>
-          <span v-if="quesModel.id">试题修改</span>
-        </h3>
-      </div>
-      <div class="box-body">
-        <el-form
-          :model="quesModel"
-          ref="quesModel"
-          :rules="rules"
-          label-position="right"
-          label-width="80px"
-        >
-          <el-row :gutter="10">
-            <el-col :xs="10" :sm="10" :md="10" :lg="10">
-              <el-form-item label="题型">
-                <el-select
-                  :disabled="true"
-                  v-model="quesModel.questionType"
-                  placeholder="请输入题型"
-                >
-                  <el-option
-                    v-for="item in questionTypes"
-                    :label="item.label"
-                    :value="item.value"
-                    :key="item.value"
+  <div id="editOtherApp">
+    <section class="content" v-loading="fullscreenLoading">
+      <div class="box box-info">
+        <div class="box-header with-border">
+          <h3 class="box-title">
+            <span v-if="!quesModel.id">试题新增</span>
+            <span v-if="quesModel.id">试题修改</span>
+          </h3>
+        </div>
+        <div class="box-body">
+          <el-form
+            :model="quesModel"
+            ref="quesModel"
+            :rules="rules"
+            label-position="right"
+            label-width="80px"
+          >
+            <el-row :gutter="10">
+              <el-col :xs="10" :sm="10" :md="10" :lg="10">
+                <el-form-item label="题型">
+                  <el-select
+                    :disabled="true"
+                    v-model="quesModel.questionType"
+                    placeholder="请输入题型"
                   >
-                  </el-option>
-                </el-select>
-              </el-form-item>
-            </el-col>
-          </el-row>
-          <!-- created by weiwenhai -->
-          <el-form-item label="难度">
-            <el-select
-              v-model="quesModel.difficultyDegree"
-              placeholder="请输入难度"
-            >
-              <el-option
-                v-for="item in difficultyDegreeList"
-                :label="item.label"
-                :value="item.value"
-                :key="item.value"
-              >
-              </el-option>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="公开度">
-            <el-select v-model="quesModel.publicity" placeholder="请输入公开度">
-              <el-option
-                v-for="item in publicityList"
-                :label="item.label"
-                :value="item.value"
-                :key="item.value"
+                    <el-option
+                      v-for="item in questionTypes"
+                      :label="item.label"
+                      :value="item.value"
+                      :key="item.value"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <!-- created by weiwenhai -->
+            <el-form-item label="难度">
+              <el-select
+                v-model="quesModel.difficultyDegree"
+                placeholder="请输入难度"
               >
-              </el-option>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="属性列表">
-            <el-tooltip
-              placement="top"
-              v-for="(content, index) in quesModel.quesProperties"
-              :key="index"
-            >
-              <div slot="content">
-                <span v-if="content.firstProperty != null"
-                  >一级属性:{{ content.firstProperty.name }}</span
-                ><br />
-                <span v-if="content.secondProperty != null"
-                  >二级属性:{{ content.secondProperty.name }}</span
+                <el-option
+                  v-for="item in difficultyDegreeList"
+                  :label="item.label"
+                  :value="item.value"
+                  :key="item.value"
                 >
-              </div>
-              <el-tag
-                style="margin-right:5px;"
-                :key="content.id"
-                closable
-                type="success"
-                @close="handleClose(content);"
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="公开度">
+              <el-select
+                v-model="quesModel.publicity"
+                placeholder="请输入公开度"
               >
-                {{ content.coursePropertyName }}
-              </el-tag>
-            </el-tooltip>
-          </el-form-item>
-          <el-row :gutter="20">
-            <el-col :xs="6" :sm="6" :md="6" :lg="6">
-              <el-form-item label="属性名">
-                <el-select
-                  v-model="coursePropertyName"
-                  placeholder="属性名"
-                  @change="searchFirst"
-                  class="property_with"
+                <el-option
+                  v-for="item in publicityList"
+                  :label="item.label"
+                  :value="item.value"
+                  :key="item.value"
                 >
-                  <el-option
-                    v-for="item in coursePropertyList"
-                    :label="item.name"
-                    :value="item.name"
-                    :key="item.name"
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="属性列表">
+              <el-tooltip
+                placement="top"
+                v-for="(content, index) in quesModel.quesProperties"
+                :key="index"
+              >
+                <div slot="content">
+                  <span v-if="content.firstProperty != null"
+                    >一级属性:{{ content.firstProperty.name }}</span
+                  ><br />
+                  <span v-if="content.secondProperty != null"
+                    >二级属性:{{ content.secondProperty.name }}</span
                   >
-                  </el-option>
-                </el-select>
-              </el-form-item>
-            </el-col>
-            <el-col :xs="6" :sm="6" :md="6" :lg="6">
-              <el-form-item label="一级">
-                <el-select
-                  v-model="firstPropertyId"
-                  placeholder="一级"
-                  @change="searchSecond"
-                  class="property_with"
+                </div>
+                <el-tag
+                  style="margin-right:5px;"
+                  :key="content.id"
+                  closable
+                  type="success"
+                  @close="handleClose(content);"
                 >
-                  <el-option
-                    v-for="item in firstPropertyList"
-                    :label="item.name"
-                    :value="item.id"
-                    :key="item.id"
+                  {{ content.coursePropertyName }}
+                </el-tag>
+              </el-tooltip>
+            </el-form-item>
+            <el-row :gutter="20">
+              <el-col :xs="6" :sm="6" :md="6" :lg="6">
+                <el-form-item label="属性名">
+                  <el-select
+                    v-model="coursePropertyName"
+                    placeholder="属性名"
+                    @change="searchFirst"
+                    class="property_with"
                   >
-                  </el-option>
-                </el-select>
-              </el-form-item>
-            </el-col>
-            <el-col :xs="6" :sm="6" :md="6" :lg="6">
-              <el-form-item label="二级">
-                <el-select
-                  v-model="secondPropertyId"
-                  placeholder="二级"
-                  class="property_with"
-                >
-                  <el-option
-                    v-for="item in secondPropertyList"
-                    :label="item.name"
-                    :value="item.id"
-                    :key="item.id"
+                    <el-option
+                      v-for="item in coursePropertyList"
+                      :label="item.name"
+                      :value="item.name"
+                      :key="item.name"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="6" :sm="6" :md="6" :lg="6">
+                <el-form-item label="一级">
+                  <el-select
+                    v-model="firstPropertyId"
+                    placeholder="一级"
+                    @change="searchSecond"
+                    class="property_with"
                   >
-                  </el-option>
-                </el-select>
-              </el-form-item>
-            </el-col>
-            <el-col :xs="3" :sm="3" :md="3" :lg="3">
-              <el-form-item>
-                <el-button
-                  type="info"
-                  @click="insertProperty"
-                  style="margin-left:-30px;"
-                  >新增属性</el-button
-                >
-              </el-form-item>
-            </el-col>
-          </el-row>
-          <!-- end -->
-          <el-row :gutter="10">
-            <el-col :xs="30" :sm="30" :md="30" :lg="30">
-              <el-form-item label="题干" prop="quesBody">
-                <ckeditor
-                  :editor="editor"
-                  v-model="quesModel.quesBody"
-                  :config="editorConfig"
-                ></ckeditor>
-              </el-form-item>
-            </el-col>
-          </el-row>
-
-          <el-row
-            :gutter="10"
-            v-for="quesOption in quesModel.quesOptions"
-            :key="quesOption"
-          >
-            <el-col :xs="30" :sm="30" :md="30" :lg="30">
-              <el-form-item :label="quesOption.number">
-                <ckeditor
-                  :editor="editor"
-                  v-model="quesOption.quesBody"
-                  :config="editorConfig"
-                ></ckeditor>
-              </el-form-item>
-            </el-col>
-          </el-row>
-
-          <!-- 非套题 -->
-          <div
-            v-if="
-              quesModel.questionType !== 'NESTED_ANSWER_QUESTION' &&
-                quesModel.questionType !== 'BOOL_ANSWER_QUESTION'
-            "
-          >
-            <el-form-item label="答案" prop="quesAnswer">
-              <ckeditor
-                :editor="editor"
-                v-model="quesModel.quesAnswer"
-                :config="editorConfig"
-              ></ckeditor>
-            </el-form-item>
-          </div>
-          <div v-if="quesModel.questionType == 'BOOL_ANSWER_QUESTION'">
-            <el-row>
-              <el-col>
-                <el-form-item label="答案" prop="quesAnswer">
+                    <el-option
+                      v-for="item in firstPropertyList"
+                      :label="item.name"
+                      :value="item.id"
+                      :key="item.id"
+                    >
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="6" :sm="6" :md="6" :lg="6">
+                <el-form-item label="二级">
                   <el-select
-                    v-model="quesModel.quesAnswer"
-                    placeholder="请选择"
+                    v-model="secondPropertyId"
+                    placeholder="二级"
+                    class="property_with"
                   >
                     <el-option
-                      v-for="op in options"
-                      :label="op"
-                      :value="op"
-                      :key="op"
+                      v-for="item in secondPropertyList"
+                      :label="item.name"
+                      :value="item.id"
+                      :key="item.id"
                     >
                     </el-option>
                   </el-select>
                 </el-form-item>
               </el-col>
+              <el-col :xs="3" :sm="3" :md="3" :lg="3">
+                <el-form-item>
+                  <el-button
+                    type="info"
+                    @click="insertProperty"
+                    style="margin-left:-30px;"
+                    >新增属性</el-button
+                  >
+                </el-form-item>
+              </el-col>
             </el-row>
-          </div>
-          <div class="paper-top">
-            <el-form-item>
-              <el-button type="primary" @click="saveQues('quesModel');"
-                >保存</el-button
-              >
-              <el-button
-                type="primary"
-                icon="caret-left"
-                @click="backToQuesList();"
-                >返回列表</el-button
-              >
-            </el-form-item>
-          </div>
-        </el-form>
+            <!-- end -->
+            <el-row :gutter="10">
+              <el-col :xs="30" :sm="30" :md="30" :lg="30">
+                <el-form-item label="题干" prop="quesBody">
+                  <ckeditor
+                    :editor="editor"
+                    v-model="quesModel.quesBody"
+                    :config="editorConfig"
+                  ></ckeditor>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row
+              :gutter="10"
+              v-for="quesOption in quesModel.quesOptions"
+              :key="quesOption"
+            >
+              <el-col :xs="30" :sm="30" :md="30" :lg="30">
+                <el-form-item :label="quesOption.number">
+                  <ckeditor
+                    :editor="editor"
+                    v-model="quesOption.quesBody"
+                    :config="editorConfig"
+                  ></ckeditor>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 非套题 -->
+            <div
+              v-if="
+                quesModel.questionType !== 'NESTED_ANSWER_QUESTION' &&
+                  quesModel.questionType !== 'BOOL_ANSWER_QUESTION'
+              "
+            >
+              <el-form-item label="答案" prop="quesAnswer">
+                <ckeditor
+                  :editor="editor"
+                  v-model="quesModel.quesAnswer"
+                  :config="editorConfig"
+                ></ckeditor>
+              </el-form-item>
+            </div>
+            <div v-if="quesModel.questionType == 'BOOL_ANSWER_QUESTION'">
+              <el-row>
+                <el-col>
+                  <el-form-item label="答案" prop="quesAnswer">
+                    <el-select
+                      v-model="quesModel.quesAnswer"
+                      placeholder="请选择"
+                    >
+                      <el-option
+                        v-for="op in options"
+                        :label="op"
+                        :value="op"
+                        :key="op"
+                      >
+                      </el-option>
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </div>
+            <div class="paper-top">
+              <el-form-item>
+                <el-button type="primary" @click="saveQues('quesModel');"
+                  >保存</el-button
+                >
+                <el-button
+                  type="primary"
+                  icon="caret-left"
+                  @click="backToQuesList();"
+                  >返回列表</el-button
+                >
+              </el-form-item>
+            </div>
+          </el-form>
+        </div>
       </div>
-    </div>
-  </section>
+    </section>
+  </div>
 </template>
 <script>
 import { CORE_API } from "@/constants/constants";
 import { QUESTION_TYPES } from "../constants/constants";
+import CKEditor from "@ckeditor/ckeditor5-vue";
 import ClassicEditor from "@ckeditor/ckeditor5-build-inline";
 export default {
+  name: "editOtherApp",
+  components: {
+    ckeditor: CKEditor.component
+  },
   data() {
     return {
       editor: ClassicEditor,

+ 5 - 1
src/modules/questions/views/EditPaper.vue

@@ -3,6 +3,7 @@
     class="paper"
     v-loading="loading"
     element-loading-text="拼命加载中。。。"
+    id="editPaperApp"
   >
     <div class="edit-paper-top">
       <div class="edit-paper-top-inline">
@@ -680,10 +681,13 @@ import { QUESTION_TYPES } from "../constants/constants";
 import { mapState } from "vuex";
 import reduplicate_mark from "../component/reduplicate_mark.vue";
 import randomColor from "randomcolor";
+import CKEditor from "@ckeditor/ckeditor5-vue";
 import ClassicEditor from "@ckeditor/ckeditor5-build-inline";
 export default {
+  name: "editPaperApp",
   components: {
-    reduplicate_mark
+    reduplicate_mark,
+    ckeditor: CKEditor.component
   },
   data() {
     return {

+ 6 - 1
src/modules/questions/views/EditSelectQuestion.vue

@@ -1,5 +1,5 @@
 <template>
-  <div v-loading="fullscreenLoading">
+  <div v-loading="fullscreenLoading" id="editSelectApp">
     <section class="content">
       <div class="box box-info">
         <!-- 头信息 -->
@@ -227,8 +227,13 @@
 <script>
 import { QUESTION_API } from "@/constants/constants";
 import { QUESTION_TYPES } from "../constants/constants";
+import CKEditor from "@ckeditor/ckeditor5-vue";
 import ClassicEditor from "@ckeditor/ckeditor5-build-inline";
 export default {
+  name: "editSelectApp",
+  components: {
+    ckeditor: CKEditor.component
+  },
   data() {
     return {
       editor: ClassicEditor,

+ 3 - 1
src/modules/questions/views/GenPaper.vue

@@ -399,7 +399,9 @@ export default {
         this.formSearch.specialtyNo
       );
       sessionStorage.setItem("gen_paper_currentPage", this.currentPage);
-      this.$router.push({ path: "/edit_paper/" + row.id + "/gen_paper" });
+      this.$router.push({
+        path: "/questions/edit_paper/" + row.id + "/gen_paper"
+      });
     },
     deleteGenPaper(row) {
       this.$confirm("确认删除试卷吗?", "提示", {

+ 3 - 4
src/modules/questions/views/ImportPaper.vue

@@ -401,7 +401,7 @@ export default {
           },
           error => {
             this.$notify({
-              message: error.data.msg,
+              message: error.response.data.msg,
               type: "error"
             });
             this.loading = false;
@@ -433,7 +433,7 @@ export default {
             },
             error => {
               this.$notify({
-                message: error.data.msg,
+                message: error.response.data.msg,
                 type: "error"
               });
               this.loading = false;
@@ -496,8 +496,7 @@ export default {
               this.loading = false;
             },
             error => {
-              console.log("com in error:", error.body);
-              var message = error.body.desc;
+              var message = error.response.body.desc;
               var err = message
                 .replace("[", "")
                 .replace("]", "")

+ 6 - 1
src/modules/questions/views/InsertBluePaperStructure.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div id="insertBlueApp">
     <section class="content">
       <div class="box box-info">
         <!-- 头信息 -->
@@ -223,8 +223,13 @@
 <script>
 import { CORE_API, QUESTION_API } from "@/constants/constants";
 import { QUESTION_TYPES } from "../constants/constants";
+import CKEditor from "@ckeditor/ckeditor5-vue";
 import ClassicEditor from "@ckeditor/ckeditor5-build-inline";
 export default {
+  name: "insertBlueApp",
+  components: {
+    ckeditor: CKEditor.component
+  },
   data() {
     return {
       editor: ClassicEditor,

+ 6 - 1
src/modules/questions/views/InsertPaperStructure.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div id="insertApp">
     <section class="content">
       <div>
         <!-- 头信息 -->
@@ -201,8 +201,13 @@
 
 <script>
 import { CORE_API, QUESTION_API } from "@/constants/constants";
+import CKEditor from "@ckeditor/ckeditor5-vue";
 import ClassicEditor from "@ckeditor/ckeditor5-build-inline";
 export default {
+  name: "insertApp",
+  components: {
+    ckeditor: CKEditor.component
+  },
   data() {
     return {
       editor: ClassicEditor,

+ 1 - 3
src/modules/questions/views/InsertPaperTitle.vue

@@ -369,9 +369,7 @@ export default {
     ...mapState({ user: state => state.user })
   },
   //初始化
-  created() {
-    this.queryCoursesByKeyword();
-  }
+  created() {}
 };
 </script>
 <style scoped>

+ 5 - 0
yarn.lock

@@ -7640,6 +7640,11 @@ pretty@2.0.0:
     extend-shallow "^2.0.1"
     js-beautify "^1.6.12"
 
+print-js@^1.0.54:
+  version "1.0.54"
+  resolved "https://registry.yarnpkg.com/print-js/-/print-js-1.0.54.tgz#f15df027951e9a9165b6d39420d362ba7f0fc130"
+  integrity sha512-tZkwoHJCTS6jqj0UuxhUY9xF8v0rOuAgIZRlfZBOg9D1R4saxznRANkVlAsLW+D4GOOsLq5Zd/OgVk58IfESXA==
+
 private@^0.1.6, private@^0.1.8:
   version "0.1.8"
   resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"