zhangjie 1 anno fa
parent
commit
c5af489245

+ 1 - 0
src/constants/enumerate.js

@@ -195,6 +195,7 @@ export const DATA_TASK_STATUS = {
 export const DATA_TASK_TYPE = {
   USER_IMPORT: "用户导入",
   STUDENT_IMPORT: "学生导入",
+  EXAM_STUDENT_IMPORT: "考生导入",
   CLAZZ_IMPORT: "班级导入",
   QUESTION_MISSION_BATCH_CREATE: "批量新建命题任务",
   SAMPLE_EXPORT: "导出审核样本",

+ 154 - 0
src/constants/menus-data.js

@@ -5059,6 +5059,160 @@ export default [
       },
     ],
   },
+  {
+    id: "35801",
+    name: "考生管理",
+    url: "ExamStudentManage",
+    type: "MENU",
+    parentId: "356",
+    sequence: 61,
+    enable: true,
+    urls: [
+      {
+        id: "362",
+        name: "查询",
+        url: "/api/admin/basic/student/query",
+        type: "URL",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+      {
+        id: "363",
+        name: "新增/编辑",
+        url: "/api/admin/basic/student/save",
+        type: "URL",
+        parentId: "358",
+        sequence: 2,
+        enable: true,
+      },
+      {
+        id: "364",
+        name: "批量删除(逻辑)",
+        url: "/api/admin/basic/student/delete_batch",
+        type: "URL",
+        parentId: "358",
+        sequence: 3,
+        enable: true,
+      },
+      {
+        id: "365",
+        name: "批量导入(异步)",
+        url: "/api/admin/basic/student/data_import",
+        type: "URL",
+        parentId: "358",
+        sequence: 4,
+        enable: true,
+      },
+      {
+        id: "569",
+        name: "根据条件删除(物理)",
+        url: "/api/admin/basic/student/delete_by_condition",
+        type: "URL",
+        parentId: "358",
+        sequence: 5,
+        enable: true,
+      },
+      {
+        id: "815",
+        name: "导出",
+        url: "/api/admin/basic/student/export",
+        type: "URL",
+        parentId: "358",
+        sequence: 6,
+        enable: true,
+      },
+    ],
+    buttons: [
+      {
+        id: "570",
+        name: "批量删除",
+        url: "Delete",
+        type: "BUTTON",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+      {
+        id: "377",
+        name: "查询",
+        url: "Select",
+        type: "BUTTON",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+      {
+        id: "379",
+        name: "新增",
+        url: "Add",
+        type: "BUTTON",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+      {
+        id: "382",
+        name: "导入",
+        url: "Import",
+        type: "BUTTON",
+        parentId: "358",
+        sequence: 2,
+        enable: true,
+      },
+      {
+        id: "814",
+        name: "导出",
+        url: "Export",
+        type: "BUTTON",
+        parentId: "358",
+        sequence: 3,
+        enable: true,
+      },
+    ],
+    links: [
+      {
+        id: "380",
+        name: "编辑",
+        url: "Edit",
+        type: "LINK",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+      {
+        id: "381",
+        name: "删除",
+        url: "Delete",
+        type: "LINK",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+    ],
+    lists: [
+      {
+        id: "378",
+        name: "列表",
+        url: "List",
+        type: "LIST",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+    ],
+    conditions: [
+      {
+        id: "400",
+        name: "查询条件",
+        url: "Condition",
+        type: "CONDITION",
+        parentId: "358",
+        sequence: 1,
+        enable: true,
+      },
+    ],
+  },
   {
     id: "483",
     name: "评卷管理",

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

@@ -579,3 +579,19 @@ export const updateTeacherSimple = (datas) => {
 export const batchAddTeacherSimple = (datas) => {
   return $postParam("/api/admin/teach/course/select_create_teacher", datas);
 };
+
+// exam-student-manage
+export const examStudentListPage = (datas) => {
+  return $postParam("/api/admin/basic/exam_student/page", datas);
+};
+export const deleteExamStudent = (idList) => {
+  return $postParam("/api/admin/basic/exam_student/delete", { idList });
+};
+export const updateExamStudent = (datas) => {
+  return $post("/api/admin/basic/exam_student/save", datas);
+};
+export const exportExamStudent = (datas) => {
+  return $postParam("/api/admin/basic/exam_student/export", datas, {
+    responseType: "blob",
+  });
+};

+ 257 - 0
src/modules/base/components/ModifyExamStudent.vue

@@ -0,0 +1,257 @@
+<template>
+  <el-dialog
+    class="modify-student"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10px"
+    width="500px"
+    :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="80px"
+    >
+      <el-form-item prop="semesterId" label="学期:">
+        <semester-select
+          v-model="modalForm.semesterId"
+          placeholder="学期"
+        ></semester-select>
+      </el-form-item>
+      <el-form-item prop="examId" label="考试:">
+        <exam-select
+          v-model="modalForm.examId"
+          :semester-id="modalForm.semesterId"
+          placeholder="考试"
+        ></exam-select>
+      </el-form-item>
+      <el-form-item prop="courseCode" label="课程:">
+        <course-select
+          v-model.trim="modalForm.courseCode"
+          :semester-id="modalForm.semesterId"
+          :exam-id="modalForm.examId"
+          placeholder="课程"
+          clearable
+        ></course-select>
+      </el-form-item>
+      <el-form-item prop="examStudentName" label="姓名:">
+        <el-input
+          v-model.trim="modalForm.examStudentName"
+          placeholder="请输入姓名"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="studentCode" label="学号:">
+        <el-input
+          v-model.trim="modalForm.studentCode"
+          placeholder="请输入学号"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="学院:">
+        <el-input
+          v-model.trim="modalForm.college"
+          placeholder="学院"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="专业:">
+        <el-input
+          v-model.trim="modalForm.major"
+          placeholder="专业"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="教学班:">
+        <el-input
+          v-model.trim="modalForm.teachClazz"
+          placeholder="教学班"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="teacherName" label="任课老师:">
+        <el-input
+          v-model.trim="modalForm.teacherName"
+          placeholder="任课老师"
+          clearable
+        ></el-input>
+      </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 { updateExamStudent } from "../api";
+
+const initModalForm = {
+  id: null,
+  semesterId: "",
+  examId: "",
+  courseCode: "",
+  examStudentName: "",
+  studentCode: "",
+  college: "",
+  major: "",
+  teachClazz: "",
+  teacherName: "",
+};
+
+export default {
+  name: "modify-exam-student",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "考生";
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: { ...initModalForm },
+      rules: {
+        semesterId: [
+          {
+            required: true,
+            message: "请选择学期",
+            trigger: "change",
+          },
+        ],
+        examId: [
+          {
+            required: true,
+            message: "请选择考试",
+            trigger: "change",
+          },
+        ],
+        courseCode: [
+          {
+            required: true,
+            message: "请选择课程",
+            trigger: "change",
+          },
+        ],
+        examStudentName: [
+          {
+            required: true,
+            message: "请输入姓名",
+            trigger: "change",
+          },
+          {
+            message: "姓名不能超过50个字",
+            max: 50,
+            trigger: "change",
+          },
+        ],
+        studentCode: [
+          {
+            required: true,
+            message: "请输入学号",
+            trigger: "change",
+          },
+          {
+            pattern: /^[a-zA-Z0-9]{1,50}$/,
+            message: "学号只能由数字、字母组成",
+            trigger: "change",
+          },
+          {
+            message: "学号不能超过50个字",
+            max: 50,
+            trigger: "change",
+          },
+        ],
+        college: [
+          {
+            required: false,
+            message: "学院不能超过50个字",
+            max: 50,
+            trigger: "change",
+          },
+        ],
+        major: [
+          {
+            required: false,
+            message: "专业不能超过50个字",
+            max: 50,
+            trigger: "change",
+          },
+        ],
+        teachClazz: [
+          {
+            required: false,
+            message: "教学班不能超过50个字",
+            max: 50,
+            trigger: "change",
+          },
+        ],
+        teacherName: [
+          {
+            required: false,
+            message: "任课老师不能超过50个字",
+            max: 50,
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    initData(val) {
+      if (val.id) {
+        this.modalForm = this.$objAssign(initModalForm, val);
+      } else {
+        this.modalForm = { ...initModalForm };
+      }
+    },
+    visibleChange() {
+      this.initData(this.instance);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    updateClazz() {
+      this.modalForm.clazzId = "";
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const data = await updateExamStudent(this.modalForm).catch(() => {});
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success(this.title + "成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
+  },
+};
+</script>

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

@@ -22,6 +22,7 @@ import CollegeManage from "./views/CollegeManage.vue";
 import ExamManage from "./views/ExamManage.vue";
 import CourseSimpleManage from "./views/CourseSimpleManage.vue";
 import ClazzSimpleManage from "./views/ClazzSimpleManage.vue";
+import ExamStudentManage from "./views/ExamStudentManage.vue";
 
 export default [
   {
@@ -139,4 +140,9 @@ export default [
     name: "CardManage",
     component: CardManage,
   },
+  {
+    path: "/base/exam-student-manage",
+    name: "ExamStudentManage",
+    component: ExamStudentManage,
+  },
 ];

+ 357 - 0
src/modules/base/views/ExamStudentManage.vue

@@ -0,0 +1,357 @@
+<template>
+  <div class="student-manage">
+    <div class="part-box part-box-filter">
+      <el-form ref="FilterForm" label-position="left" label-width="90px" inline>
+        <el-form-item label="学期:">
+          <semester-select
+            v-model="filter.semesterId"
+            default-select
+            placeholder="学期"
+            @default-selected="getList"
+          ></semester-select>
+        </el-form-item>
+        <el-form-item label="考试:">
+          <exam-select
+            v-model="filter.examId"
+            :semester-id="filter.semesterId"
+            placeholder="考试"
+          ></exam-select>
+        </el-form-item>
+        <el-form-item label="课程:">
+          <course-select
+            v-model.trim="filter.courseCode"
+            :semester-id="filter.semesterId"
+            :exam-id="filter.examId"
+            placeholder="课程"
+            clearable
+          ></course-select>
+        </el-form-item>
+        <el-form-item label="任课老师:">
+          <el-input
+            v-model.trim="filter.teacher"
+            placeholder="任课老师"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="学院:">
+          <el-input
+            v-model.trim="filter.college"
+            placeholder="学院"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="专业:">
+          <el-input
+            v-model.trim="filter.major"
+            placeholder="专业"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="班级:">
+          <el-input
+            v-model.trim="filter.teachClazz"
+            placeholder="班级"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="姓名/学号:">
+          <el-input
+            v-model.trim="filter.examStudentInfo"
+            placeholder="姓名/学号"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            v-if="checkPrivilege('button', 'select')"
+            type="primary"
+            @click="toPage(1)"
+            >查询</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <div class="box-justify">
+        <div>
+          <el-button
+            v-if="checkPrivilege('button', 'delete')"
+            type="danger"
+            icon="el-icon-delete"
+            @click="toBatchDelete"
+            >批量删除</el-button
+          >
+          <el-button
+            v-if="checkPrivilege('button', 'export')"
+            type="primary"
+            icon="el-icon-download"
+            :loading="loading"
+            @click="toExportStudent"
+            >导出</el-button
+          >
+        </div>
+        <div>
+          <el-button
+            v-if="checkPrivilege('button', 'import')"
+            type="success"
+            icon="el-icon-upload2"
+            @click="toImport"
+            >导入</el-button
+          >
+          <el-button
+            v-if="checkPrivilege('button', 'import')"
+            type="primary"
+            icon="el-icon-s-order"
+            @click="toDataTask"
+            >导入结果查询</el-button
+          >
+          <el-button
+            v-if="checkPrivilege('button', 'add')"
+            type="primary"
+            icon="el-icon-circle-plus-outline"
+            @click="toAdd"
+            >新增</el-button
+          >
+        </div>
+      </div>
+    </div>
+    <div class="part-box part-box-pad">
+      <el-table
+        ref="TableList"
+        :data="dataList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column
+          type="selection"
+          width="55"
+          align="center"
+        ></el-table-column>
+        <el-table-column prop="courseName" label="课程名称"></el-table-column>
+        <el-table-column prop="courseCode" label="课程代码"></el-table-column>
+        <el-table-column prop="examstudentName" label="姓名"></el-table-column>
+        <el-table-column prop="studentCode" label="学号"></el-table-column>
+        <el-table-column prop="college" label="学院"></el-table-column>
+        <el-table-column prop="major" label="专业"></el-table-column>
+        <el-table-column prop="teachClazz" label="教学班"></el-table-column>
+        <el-table-column prop="paperNumber" label="试卷编号"></el-table-column>
+        <el-table-column prop="teacherName" label="任课老师"></el-table-column>
+        <el-table-column
+          prop="teacherCode"
+          label="任课老师工号"
+          width="120"
+        ></el-table-column>
+        <el-table-column prop="examDate" label="考试日期"></el-table-column>
+        <el-table-column prop="examTime" label="考试时间"></el-table-column>
+        <el-table-column
+          prop="examPlace"
+          label="考点(校区)"
+          width="120"
+        ></el-table-column>
+        <el-table-column
+          prop="examRoom"
+          label="考场(考试教室)"
+          width="140"
+        ></el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          width="100"
+          fixed="right"
+        >
+          <template slot-scope="scope">
+            <el-button
+              v-if="checkPrivilege('link', 'edit')"
+              class="btn-primary"
+              type="text"
+              @click="toEdit(scope.row)"
+              >编辑</el-button
+            >
+            <el-button
+              v-if="checkPrivilege('link', 'delete')"
+              class="btn-danger"
+              type="text"
+              @click="toDelete(scope.row)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total, sizes, prev, pager, next, jumper"
+          :pager-count="5"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+          @size-change="pageSizeChange"
+        >
+        </el-pagination>
+      </div>
+    </div>
+
+    <modify-exam-student
+      :instance="curRow"
+      @modified="getList"
+      ref="ModifyExamStudent"
+    ></modify-exam-student>
+    <!-- ImportFile -->
+    <import-file
+      v-if="checkPrivilege('button', 'import')"
+      ref="ImportFile"
+      title="导入考生"
+      :upload-url="uploadUrl"
+      :format="['xls', 'xlsx']"
+      :download-handle="() => downloadTemplate('examStudent')"
+      :download-filename="dfilename"
+      :auto-upload="false"
+      @upload-success="uploadSuccess"
+    ></import-file>
+    <!-- data-task-dialog -->
+    <data-task-dialog
+      v-if="checkPrivilege('button', 'import')"
+      ref="DataTaskDialog"
+      task-type="EXAM_STUDENT_IMPORT"
+    ></data-task-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  examStudentListPage,
+  deleteExamStudent,
+  exportExamStudent,
+} from "../api";
+import ModifyExamStudent from "../components/ModifyExamStudent";
+import ImportFile from "../../../components/ImportFile.vue";
+import { downloadByApi } from "@/plugins/download";
+import templateDownload from "@/mixins/templateDownload";
+
+export default {
+  name: "exam-student-manage",
+  components: { ModifyExamStudent, ImportFile },
+  mixins: [templateDownload],
+  data() {
+    return {
+      filter: {
+        semesterId: "",
+        examId: "",
+        courseCode: "",
+        teacher: "",
+        college: "",
+        major: "",
+        teachClazz: "",
+        examStudentInfo: "",
+      },
+      queriedFilter: {},
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      dataList: [],
+      multipleSelection: [],
+      curRow: {},
+      loading: false,
+      // import
+      uploadUrl: "/api/admin/basic/exam_student/import",
+      dfilename: "考生导入模板.xlsx",
+    };
+  },
+  computed: {
+    filterHasQuery() {
+      return !Object.keys(this.filter).some(
+        (k) => this.filter[k] !== this.queriedFilter[k]
+      );
+    },
+  },
+  mounted() {
+    // this.getList();
+  },
+  methods: {
+    async getList() {
+      if (!this.checkPrivilege("list", "list")) return;
+
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size,
+      };
+      const data = await examStudentListPage(datas);
+      this.dataList = data.records;
+      this.total = data.total;
+      this.queriedFilter = { ...this.filter };
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val.map((item) => item.id);
+    },
+    toAdd() {
+      this.curRow = {};
+      this.$refs.ModifyExamStudent.open();
+    },
+    toEdit(row) {
+      this.curRow = row;
+      this.$refs.ModifyExamStudent.open();
+    },
+    async toBatchDelete() {
+      if (!this.multipleSelection.length) {
+        this.$message.error("请选择要删除的考生");
+        return;
+      }
+      const confirm = await this.$confirm(
+        `确定要删除当前选择的所有考生吗?`,
+        "提示",
+        {
+          type: "warning",
+        }
+      ).catch(() => {});
+
+      if (confirm !== "confirm") return;
+
+      await deleteExamStudent(this.multipleSelection);
+      this.$message.success("删除成功!");
+      this.deletePageLastItem();
+    },
+    toDelete(row) {
+      this.$confirm(`确定要删除考生【${row.studentName}】吗?`, "提示", {
+        type: "warning",
+      })
+        .then(async () => {
+          await deleteExamStudent([row.id]);
+          this.$message.success("删除成功!");
+          this.deletePageLastItem();
+        })
+        .catch(() => {});
+    },
+    async toExportStudent() {
+      if (this.loading) return;
+
+      this.loading = true;
+      const res = await downloadByApi(() => {
+        return exportExamStudent(this.filter);
+      }, "").catch((e) => {
+        this.$message.error(e || "下载失败,请重新尝试!");
+      });
+      this.loading = false;
+
+      if (!res) return;
+      this.$message.success("下载成功!");
+    },
+    // import
+    toImport() {
+      this.$refs.ImportFile.open();
+    },
+    toDataTask() {
+      this.$refs.DataTaskDialog.open();
+    },
+    validError(errorData) {
+      this.$message.error(errorData.message);
+    },
+    uploadSuccess() {
+      this.$message.success("文件上传成功,后台正在导入!");
+      this.getList();
+    },
+  },
+};
+</script>