Jelajahi Sumber

feat: 考生管理和题卡管理修改

zhangjie 1 tahun lalu
induk
melakukan
668bf4a366

+ 2 - 1
src/components/SecpSelect.vue

@@ -4,7 +4,7 @@
       <semester-select
         v-model.trim="filter.semesterId"
         placeholder="学期"
-        default-select
+        :default-select="defaultSelectSemester || defaultSelectExam"
         :clearable="!defaultSelectExam"
         @default-selected="semesterDefaultSelect"
       ></semester-select>
@@ -78,6 +78,7 @@ export default {
       type: Boolean,
       default: true,
     },
+    defaultSelectSemester: { type: Boolean, default: false },
     defaultSelectExam: { type: Boolean, default: false },
   },
   data() {

+ 9 - 0
src/constants/enumerate.js

@@ -153,6 +153,15 @@ export const FLOW_APPROVE_OPERATION_TYPE = {
   END: "终止",
 };
 
+// 考生状态
+export const STUDENT_STATUS = {
+  N: "正常",
+  D: "缓考",
+  F: "免考",
+  M: "缺考",
+  B: "违纪",
+};
+
 // 命题 -------------->
 // 待办任务警告时间
 export const TASK_WARNING_TIME = 3 * 24 * 60 * 60 * 1000;

+ 6 - 0
src/modules/base/api.js

@@ -232,6 +232,9 @@ export const downloadCardFile = (id) => {
     }
   );
 };
+export const ableCard = ({ id, enable }) => {
+  return $postParam("/api/admin/exam/card/enable", { id, enable });
+};
 // course-manage
 export const courseListPage = (datas) => {
   return $postParam("/api/admin/basic/course/list", datas);
@@ -609,6 +612,9 @@ export const deleteExamStudent = (idList) => {
 export const updateExamStudent = (datas) => {
   return $post("/api/admin/basic/exam_student/save", datas);
 };
+export const updateExamStudentStatus = (datas) => {
+  return $postParam("/api/admin/basic/exam_student/status", datas);
+};
 export const exportExamStudent = (datas) => {
   return $postParam("/api/admin/basic/exam_student/export", datas, {
     responseType: "blob",

+ 117 - 0
src/modules/base/components/ModifyExamStudentStatus.vue

@@ -0,0 +1,117 @@
+<template>
+  <el-dialog
+    :visible.sync="modalIsShow"
+    title="设置考生状态"
+    width="440px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    destroy-on-close
+    @open="visibleChange"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      :key="modalForm.id"
+      label-width="60px"
+    >
+      <el-form-item prop="status" label="状态:">
+        <el-select
+          v-model="modalForm.status"
+          class="width-full"
+          placeholder="状态"
+        >
+          <el-option
+            v-for="(val, key) in STUDENT_STATUS"
+            :key="key"
+            :value="key"
+            :label="val"
+          >
+          </el-option>
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button @click="cancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { updateExamStudentStatus } from "../api";
+import { STUDENT_STATUS } from "@/constants/enumerate";
+
+const initModalForm = {
+  id: null,
+  status: "",
+};
+
+export default {
+  name: "modify-exam-student-status",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      STUDENT_STATUS,
+      modalForm: { ...initModalForm },
+      rules: {
+        status: [
+          {
+            required: true,
+            message: "请选择状态",
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    initData(val) {
+      this.modalForm = this.$objAssign(initModalForm, val);
+
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+
+    visibleChange() {
+      this.initData(this.instance);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const data = await updateExamStudentStatus(this.modalForm).catch(
+        () => {}
+      );
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success("设置成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
+  },
+};
+</script>

+ 36 - 5
src/modules/base/views/CardManage.vue

@@ -3,11 +3,7 @@
     <div class="part-box part-box-filter part-box-flex">
       <el-form ref="FilterForm" label-position="left" label-width="85px" inline>
         <template v-if="checkPrivilege('condition', 'condition')">
-          <secp-select
-            v-model="filter"
-            defaultSelectExam
-            @exam-default="toPage(1)"
-          ></secp-select>
+          <secp-select v-model="filter"></secp-select>
           <el-form-item label="题卡名称:">
             <el-input
               v-model.trim="filter.title"
@@ -119,6 +115,11 @@
             scope.row.remark | defaultFieldFilter
           }}</span>
         </el-table-column>
+        <el-table-column prop="enable" label="启用/禁用" width="100">
+          <template slot-scope="scope">
+            {{ scope.row.enable | enableFilter }}
+          </template>
+        </el-table-column>
         <el-table-column prop="createTime" label="创建时间" width="170">
           <span slot-scope="scope">{{
             scope.row.createTime | timestampFilter
@@ -195,6 +196,13 @@
               @click="toDownload(scope.row)"
               >下载题卡</el-button
             >
+            <el-button
+              v-if="checkPrivilege('link', 'enable')"
+              :class="scope.row.enable ? 'btn-danger' : 'btn-primary'"
+              type="text"
+              @click="toEnable(scope.row)"
+              >{{ scope.row.enable ? "禁用" : "启用" }}</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
@@ -247,6 +255,7 @@ import {
   deleteCard,
   convertCardImage,
   downloadCardFile,
+  ableCard,
 } from "../api";
 import ModifyCardInfo from "../components/ModifyCardInfo";
 import pickerOptions from "@/constants/datePickerOptions";
@@ -292,6 +301,9 @@ export default {
       curImageIndex: 0,
     };
   },
+  mounted() {
+    this.toPage(1);
+  },
   methods: {
     async getList() {
       if (!this.checkPrivilege("list", "list")) return;
@@ -370,6 +382,25 @@ export default {
       if (!res) return;
       this.$message.success("下载成功!");
     },
+    async toEnable(row) {
+      const action = row.enable ? "禁用" : "启用";
+      const result = await this.$confirm(
+        `确定要${action}题卡【${row.title}】吗?`,
+        "提示",
+        {
+          type: "warning",
+        }
+      ).catch(() => {});
+      if (result !== "confirm") return;
+
+      const enable = !row.enable;
+      await ableCard({
+        id: row.id,
+        enable,
+      });
+      row.enable = enable;
+      this.$message.success("操作成功!");
+    },
     // image-preview
     toPreviewImage(row) {
       this.imageList = row.imageUrls;

+ 57 - 5
src/modules/base/views/ExamStudentManage.vue

@@ -77,6 +77,13 @@
           >
         </div>
         <div>
+          <el-button
+            v-if="checkPrivilege('button', 'ImportTeacher')"
+            type="success"
+            icon="el-icon-upload2"
+            @click="toImportTeacher"
+            >导入任课老师</el-button
+          >
           <el-button
             v-if="checkPrivilege('button', 'import')"
             type="success"
@@ -193,13 +200,25 @@
           label="考场(考试教室)"
           width="140"
         ></el-table-column>
+        <el-table-column prop="status" label="状态" width="100">
+          <template slot-scope="scope">
+            {{ scope.row.status | studentStatusFilter }}
+          </template>
+        </el-table-column>
         <el-table-column
           class-name="action-column"
           label="操作"
-          width="100"
+          width="140"
           fixed="right"
         >
           <template slot-scope="scope">
+            <el-button
+              v-if="checkPrivilege('link', 'edit')"
+              class="btn-primary"
+              type="text"
+              @click="toSet(scope.row)"
+              >设置</el-button
+            >
             <el-button
               v-if="checkPrivilege('link', 'edit')"
               class="btn-primary"
@@ -237,6 +256,12 @@
       @modified="getList"
       ref="ModifyExamStudent"
     ></modify-exam-student>
+    <!-- ModifyExamStudentStatus -->
+    <modify-exam-student-status
+      ref="ModifyExamStudentStatus"
+      :instance="curRow"
+      @modified="getList"
+    ></modify-exam-student-status>
     <!-- ImportFile -->
     <import-file
       v-if="checkPrivilege('button', 'import')"
@@ -248,11 +273,27 @@
         semesterId: filterSe.semesterId,
       }"
       :format="['xls', 'xlsx']"
-      :download-handle="downloadHandle"
+      :download-handle="() => downloadHandle(dfilename)"
       :download-filename="dfilename"
       :auto-upload="false"
       @upload-success="uploadSuccess"
     ></import-file>
+    <!-- ImportFileTeacher -->
+    <import-file
+      v-if="checkPrivilege('button', 'ImportTeacher')"
+      ref="ImportFileTeacher"
+      title="导入任课老师"
+      :upload-url="uploadTeacherUrl"
+      :upload-data="{
+        examId: filterSe.examId,
+        semesterId: filterSe.semesterId,
+      }"
+      :format="['xls', 'xlsx']"
+      :download-handle="() => downloadHandle(teacherDfilename)"
+      :download-filename="teacherDfilename"
+      :auto-upload="false"
+      @upload-success="uploadSuccess"
+    ></import-file>
     <!-- data-task-dialog -->
     <data-task-dialog
       v-if="checkPrivilege('button', 'import')"
@@ -270,6 +311,7 @@ import {
 } from "../api";
 import { businessTemplateDownload } from "@/modules/print/api";
 import ModifyExamStudent from "../components/ModifyExamStudent.vue";
+import ModifyExamStudentStatus from "../components/ModifyExamStudentStatus.vue";
 import ImportFile from "../../../components/ImportFile.vue";
 import { downloadByApi } from "@/plugins/download";
 import templateDownload from "@/mixins/templateDownload";
@@ -277,7 +319,7 @@ import { getExamDateTime } from "@/plugins/utils";
 
 export default {
   name: "exam-student-manage",
-  components: { ModifyExamStudent, ImportFile },
+  components: { ModifyExamStudent, ModifyExamStudentStatus, ImportFile },
   mixins: [templateDownload],
   data() {
     return {
@@ -304,6 +346,9 @@ export default {
       // import
       uploadUrl: "/api/admin/basic/exam_student/import",
       dfilename: "考生导入模板.xlsx",
+      // import teacher
+      uploadTeacherUrl: "/api/admin/basic/exam_student/import_teacher",
+      teacherDfilename: "任课老师导入模板.xlsx",
     };
   },
   methods: {
@@ -338,13 +383,13 @@ export default {
     handleSelectionChange(val) {
       this.multipleSelection = val.map((item) => item.id);
     },
-    async downloadHandle() {
+    async downloadHandle(filename) {
       if (this.download) return;
 
       this.download = true;
       const res = await downloadByApi(() => {
         return businessTemplateDownload();
-      }, `考生导入模板.xlsx`).catch((e) => {
+      }, filename).catch((e) => {
         this.$message.error(e || "下载失败,请重新尝试!");
       });
       this.download = false;
@@ -360,6 +405,10 @@ export default {
       this.curRow = row;
       this.$refs.ModifyExamStudent.open();
     },
+    toSet(row) {
+      this.curRow = row;
+      this.$refs.ModifyExamStudentStatus.open();
+    },
     async toBatchDelete() {
       if (!this.multipleSelection.length) {
         this.$message.error("请选择要删除的考生");
@@ -408,6 +457,9 @@ export default {
     toImport() {
       this.$refs.ImportFile.open();
     },
+    toImportTeacher() {
+      this.$refs.ImportFileTeacher.open();
+    },
     toDataTask() {
       this.$refs.DataTaskDialog.open();
     },

+ 3 - 45
src/modules/exam/components/createExamAndPrintTask/InfoPrintTask.vue

@@ -200,20 +200,6 @@
             </el-select>
           </template>
         </el-table-column>
-        <el-table-column
-          v-for="item in extendFields"
-          :key="item.code"
-          :label="item.name"
-          width="120"
-        >
-          <div slot-scope="scope">
-            <el-input
-              v-model="scope.row.extends[item.code]"
-              placeholder="请输入"
-              clearable
-            ></el-input>
-          </div>
-        </el-table-column>
         <el-table-column
           label="操作"
           width="120"
@@ -265,7 +251,6 @@
 <script>
 import { mapState, mapMutations } from "vuex";
 import { calcSum, getExamDateTime, getTimeDatestamp } from "@/plugins/utils";
-import { examRuleDetail } from "../../../base/api";
 import { listTaskPrintHouse } from "../../api";
 import ModifyExamTaskStudent from "./ModifyExamTaskStudent.vue";
 import PreviewTaskStudent from "./PreviewTaskStudent.vue";
@@ -294,7 +279,6 @@ export default {
       model2Students: [],
       curRow: {},
       printHouses: [],
-      extendFields: [],
       packageInfos: {
         packageCount: 0,
         studentCount: 0,
@@ -336,7 +320,6 @@ export default {
     },
   },
   mounted() {
-    this.getExtendFields();
     this.getPrintHouses();
 
     const curDate = getTimeDatestamp(Date.now());
@@ -403,14 +386,9 @@ export default {
         return Promise.reject();
       }
 
-      let errorMsg = [];
+      const errorMsg = [];
       this.tableData.forEach((row) => {
-        let errorFields = [];
-        this.extendFields.forEach((field) => {
-          if (!row.extends[field.code]) {
-            errorFields.push(field.name);
-          }
-        });
+        const errorFields = [];
 
         if (!row.examStartTime || !row.examEndTime) {
           errorFields.push("考试时间");
@@ -441,14 +419,7 @@ export default {
     },
     updateData() {
       const tableData = this.tableData.map((row) => {
-        let nrow = { ...row };
-        let extendFields = this.extendFields.map((field) => {
-          let info = { ...field };
-          info.value = row.extends[field.code];
-          return info;
-        });
-
-        nrow.extendFields = JSON.stringify(extendFields);
+        const nrow = { ...row };
         nrow.examTaskStudentObjectParamList = row.examTaskStudentObjectParamList
           .filter((item) => item.enable)
           .map((item) => item.id);
@@ -475,13 +446,6 @@ export default {
         this.packageInfos.paperReleaseCount +
         this.packageInfos.paperBackupCount;
     },
-    async getExtendFields() {
-      const examRule = await examRuleDetail();
-      this.extendFields = examRule.extendFields
-        ? JSON.parse(examRule.extendFields)
-        : [];
-      this.extendFields = this.extendFields.filter((item) => item.enable);
-    },
     async getPrintHouses() {
       this.printHouses = await listTaskPrintHouse();
     },
@@ -550,7 +514,6 @@ export default {
         studentCount: "",
         printHouseId: "",
         printHouseName: "",
-        extendFields: "",
         backupCount: 0,
         minBackupCount: 0,
         isSelectStudent: true,
@@ -559,11 +522,6 @@ export default {
         canEditTime: false,
         ...modalFormData,
       };
-      let extendFieldModal = {};
-      this.extendFields.forEach((field) => {
-        extendFieldModal[field.code] = "";
-      });
-      data.extends = extendFieldModal;
       return data;
     },
     examStudentModified({ selectedStudents, isSelectStudent }) {

+ 1 - 0
src/modules/login/views/LoginOpen.vue

@@ -45,6 +45,7 @@ export default {
         this.$ls.set("schoolName", curSchool.name, this.GLOBAL.authTimeout);
         const res = await getSchoolInfo(curSchool.code);
         this.$ls.set("schoolLogo", res.logo);
+        this.$ls.set("schoolInfo", res);
       }
       this.$ls.set("user", data, this.GLOBAL.authTimeout);
 

+ 4 - 0
src/plugins/filters.js

@@ -25,6 +25,7 @@ import {
   EXAM_NUMBER_STYLE,
   FLOW_TYPE,
   MARK_MODE_TYPE,
+  STUDENT_STATUS,
 } from "../constants/enumerate";
 import { formatDate } from "../plugins/utils";
 
@@ -128,3 +129,6 @@ Vue.filter("examNumberStyleFilter", function (val) {
 Vue.filter("markModeTypeFilter", function (val) {
   return MARK_MODE_TYPE[val] || DEFAULT_FIELD;
 });
+Vue.filter("studentStatusFilter", function (val) {
+  return STUDENT_STATUS[val] || DEFAULT_FIELD;
+});