123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671 |
- <template>
- <div class="info-print-task">
- <p v-if="IS_MODEL2" class="tips-info mb-2">
- 考试需要命题老师提交具体印刷份数
- </p>
- <p v-else class="tips-info mb-2">
- 考试需要命题老师提交完整的考务数据,每个卷袋表示一个考场,人数字段为应考人数,备份数量为该考场试卷题卡备用数量
- </p>
- <el-form ref="modalFormComp" label-position="top">
- <el-form-item label="考试时间:" required>
- <el-date-picker
- v-model="createDate"
- type="date"
- value-format="timestamp"
- placeholder="考试日期"
- style="width: 150px"
- :editable="false"
- @change="timeChange"
- >
- </el-date-picker>
- <el-time-picker
- is-range
- v-model="createTime"
- range-separator="至"
- start-placeholder="考试开始时间"
- end-placeholder="考试结束时间"
- placeholder="选择时间范围"
- value-format="timestamp"
- :editable="false"
- @change="timeChange"
- >
- </el-time-picker>
- </el-form-item>
- <el-form-item
- label="考试对象:"
- required
- style="margin-bottom: 0"
- ></el-form-item>
- </el-form>
- <div v-if="IS_MODEL2" class="part-box">
- <div class="box-justify mb-1">
- <div></div>
- <el-button type="primary" @click="toSelectClass">选择班级</el-button>
- </div>
- <table class="table">
- <colgroup>
- <col width="90" />
- <col width="120" />
- <col width="120" />
- <col width="200" />
- <col width="300" />
- </colgroup>
- <tr>
- <th>卷袋序号</th>
- <th>印刷份数</th>
- <th>备份数量</th>
- <th>印刷室</th>
- <th>班级</th>
- </tr>
- <tr>
- <td>1</td>
- <td>
- <el-input-number
- v-model="modalForm.totalSubjects"
- class="width-full"
- :min="1"
- :max="999999"
- :step="1"
- step-strictly
- :controls="false"
- ></el-input-number>
- </td>
- <td>
- <el-input-number
- v-model="modalForm.backupCount"
- class="width-full"
- :min="infoExamPrintPlan.backupCount"
- :max="999999"
- :step="1"
- step-strictly
- :controls="false"
- ></el-input-number>
- </td>
- <td>
- <el-select
- v-model="modalForm.printHouseId"
- placeholder="请选择"
- class="width-full"
- filterable
- >
- <el-option
- v-for="room in printHouses"
- :key="room.printHouseId"
- :value="room.printHouseId"
- :label="room.printHouseName"
- ></el-option>
- </el-select>
- </td>
- <td>
- {{ model2ClassList.map((item) => item.clazzName).join(",") }}
- </td>
- </tr>
- </table>
- </div>
- <div v-else class="part-box">
- <div class="box-justify mb-2">
- <div>
- <p>
- 每个卷袋包含一个考场全部文件(试卷、题卡、卷袋贴、签到表等文件)
- </p>
- <p>
- 共{{ packageInfos.packageCount }}个卷袋,{{
- packageInfos.studentCount
- }}个考生,共印试卷{{ packageInfos.paperCount }}份(正式{{
- packageInfos.paperReleaseCount
- }}份,备用{{ packageInfos.paperBackupCount }}份)
- </p>
- </div>
- <div>
- <el-button
- v-if="checkPrivilege('button', 'ExamTaskStudentObjectImport')"
- type="success"
- icon="el-icon-download"
- @click="downloadTemplate('examTaskStudent')"
- >模板下载</el-button
- >
- <upload-button
- v-if="checkPrivilege('button', 'ExamTaskStudentObjectImport')"
- btn-icon="el-icon-circle-plus-outline"
- btn-content="批量导入"
- btn-type="success"
- :upload-url="uploadUrl"
- :format="['xls', 'xlsx']"
- accept=".xls,.xlsx"
- @valid-error="validError"
- @upload-success="uploadSuccess"
- >
- </upload-button>
- <el-button
- v-if="checkPrivilege('button', 'ExamTaskStudentObject')"
- type="primary"
- :disabled="studentUploaded && !!tableData.length"
- @click="toAdd"
- >新增考试对象</el-button
- >
- </div>
- </div>
- <el-table ref="TableList" :data="tableData" border>
- <el-table-column type="index" width="80" label="卷袋序号">
- </el-table-column>
- <el-table-column prop="className" label="考试对象" width="160">
- </el-table-column>
- <el-table-column prop="studentCount" label="人数" width="60">
- </el-table-column>
- <el-table-column prop="backupCount" label="备份数量" width="90">
- <template slot-scope="scope">
- <el-input-number
- v-model="scope.row.backupCount"
- style="width: 60px"
- :min="scope.row.minBackupCount"
- :max="99999"
- :step="1"
- step-strictly
- :controls="false"
- @change="backupCountChange"
- ></el-input-number>
- </template>
- </el-table-column>
- <el-table-column prop="examPlace" label="校区" width="140">
- <template slot-scope="scope">
- <el-input
- v-model.trim="scope.row.examPlace"
- :maxlength="100"
- clearable
- ></el-input>
- </template>
- </el-table-column>
- <el-table-column prop="examRoom" label="考试地点" width="140">
- <template slot-scope="scope">
- <el-input
- v-model.trim="scope.row.examRoom"
- :maxlength="50"
- clearable
- ></el-input>
- </template>
- </el-table-column>
- <el-table-column prop="printHouseName" label="印刷室" width="140">
- <template slot-scope="scope">
- <el-select
- v-model="scope.row.printHouseId"
- placeholder="请选择"
- filterable
- @change="() => printHouseChange(scope.row)"
- >
- <el-option
- v-for="room in printHouses"
- :key="room.printHouseId"
- :value="room.printHouseId"
- :label="room.printHouseName"
- ></el-option>
- </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"
- class-name="action-column"
- align="center"
- fixed="right"
- >
- <template slot-scope="scope">
- <el-button
- class="btn-danger"
- type="text"
- @click="toDelete(scope.$index)"
- >取消</el-button
- >
- <el-button
- class="btn-primary"
- type="text"
- @click="toViewStudent(scope.row)"
- >查看考生</el-button
- >
- </template>
- </el-table-column>
- </el-table>
- </div>
- <!-- ModifyExamStudent -->
- <modify-exam-student
- ref="ModifyExamStudent"
- :disabled-ids="disabledStudentIds"
- :course-code="infoExamTask.courseCode"
- :show-student="showStudent"
- :object-types="objectTypes"
- :selected-ids="IS_MODEL2 ? model2ClassIds : null"
- @modified="examStudentModified"
- ></modify-exam-student>
- <!-- PreviewTaskStudent -->
- <preview-task-student
- ref="PreviewTaskStudent"
- :student-list="examStudentList"
- ></preview-task-student>
- </div>
- </template>
- <script>
- import { calcSum, getTimeDatestamp } from "@/plugins/utils";
- import { examRuleDetail } from "../../../base/api";
- import { listTaskPrintHouse } from "../../api";
- import ModifyExamStudent from "./ModifyExamStudent";
- import PreviewTaskStudent from "./PreviewTaskStudent";
- import { mapState, mapMutations } from "vuex";
- import UploadButton from "@/components/UploadButton";
- import templateDownload from "@/mixins/templateDownload";
- export default {
- name: "info-print-task",
- components: { ModifyExamStudent, PreviewTaskStudent, UploadButton },
- mixins: [templateDownload],
- data() {
- return {
- modalForm: {
- examStartTime: "",
- examEndTime: "",
- paperNumber: "",
- courseName: "",
- courseCode: "",
- totalSubjects: 1,
- printHouseId: "",
- backupCount: null,
- classId: "",
- },
- tableData: [],
- model2ClassList: [],
- model2ClassIds: [],
- curRow: {},
- printHouses: [],
- extendFields: [],
- packageInfos: {
- packageCount: 0,
- studentCount: 0,
- paperCount: 0,
- paperReleaseCount: 0,
- paperBackupCount: 0,
- },
- selectedStudentIds: [],
- disabledStudentIds: [],
- examStudentList: [],
- showStudent: false,
- objectTypes: [],
- // date-picker
- curCreateTime: [],
- createDate: "",
- createTime: [],
- // import
- uploadUrl: "/api/admin/exam/task/exam_task_exam_student_import",
- dfilename: "学生导入模板.xlsx",
- studentUploaded: false,
- };
- },
- computed: {
- ...mapState("exam", [
- "infoExamTask",
- "infoExamTaskDetail",
- "infoPrintTask",
- "infoExamPrintPlan",
- ]),
- IS_MODEL2() {
- return this.infoExamTask.examModel === "MODEL2";
- },
- },
- watch: {
- "infoExamTask.courseCode": function (val, oldval) {
- if (val !== oldval) this.initData();
- },
- "infoExamPrintPlan.backupCount": function (val, oldval) {
- if (val !== oldval) this.planBackupCountChange();
- },
- },
- mounted() {
- this.getExtendFields();
- this.getPrintHouses();
- const curDate = getTimeDatestamp(Date.now());
- const hour = 60 * 60 * 1000;
- this.curCreateTime = [curDate + 8 * hour, curDate + 10 * hour];
- this.createTime = [...this.curCreateTime];
- },
- methods: {
- ...mapMutations("exam", ["updateTaskInfo"]),
- initData() {
- if (this.IS_MODEL2) {
- this.modalForm.backupCount = this.infoExamPrintPlan.backupCount;
- return;
- }
- this.modalForm = Object.assign(this.modalForm, {
- paperNumber: this.infoExamTask.paperNumber,
- courseName: this.infoExamTask.courseName,
- courseCode: this.infoExamTask.courseCode,
- });
- const { examStartTime, examEndTime } = this.infoPrintTask;
- if (examStartTime && examEndTime) {
- this.createTime = [examStartTime, examEndTime];
- this.createDate = getTimeDatestamp(examStartTime);
- this.modalForm.examStartTime = this.createTime[0];
- this.modalForm.examEndTime = this.createTime[1];
- }
- this.tableData = [];
- this.updatePackageInfos();
- this.updateData();
- },
- planBackupCountChange() {
- this.tableData.forEach((item) => {
- Object.assign(item, this.getBackupCount(item.studentCount));
- });
- this.updatePackageInfos();
- },
- getBackupCount(studentCount) {
- const { backupCount } = this.infoExamPrintPlan;
- if (backupCount < 1) {
- const count = Math.ceil(backupCount * studentCount);
- return { backupCount: count, minBackupCount: count };
- }
- return { backupCount, minBackupCount: backupCount };
- },
- checkTime() {
- if (!this.modalForm.examStartTime || !this.modalForm.examEndTime) {
- this.$message.error("请选择考试时间!");
- return false;
- }
- if (this.modalForm.examStartTime >= this.modalForm.examEndTime) {
- this.$message.error("考试开始时间必须小于考试结束时间!");
- return false;
- }
- return true;
- },
- checkData() {
- if (!this.checkTime()) return Promise.reject();
- if (this.IS_MODEL2) {
- if (!this.modalForm.totalSubjects) {
- this.$message.error("请输入印刷份数!");
- return Promise.reject();
- }
- if (!this.modalForm.printHouseId) {
- this.$message.error("请选择印刷室!");
- return Promise.reject();
- }
- if (!this.modalForm.classId) {
- this.$message.error("请选择班级!");
- return Promise.reject();
- }
- return Promise.resolve(true);
- }
- if (!this.tableData.length) {
- this.$message.error("请添加考试对象!");
- return Promise.reject();
- }
- let errorMsg = [];
- this.tableData.forEach((row) => {
- let errorFields = [];
- this.extendFields.forEach((field) => {
- if (!row.extends[field.code]) {
- errorFields.push(field.name);
- }
- });
- if (!row.backupCount) {
- errorFields.push("备份数量");
- }
- if (!row.printHouseId) {
- errorFields.push("印刷室");
- }
- if (errorFields.length) {
- errorMsg.push(
- `考试对象${row.className}中,${errorFields.join("、")}必须填写`
- );
- }
- });
- if (errorMsg.length) {
- this.$message.error(errorMsg.join("。"));
- return Promise.reject();
- }
- return Promise.resolve(true);
- },
- 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);
- nrow.examStartTime = this.modalForm.examStartTime;
- nrow.examEndTime = this.modalForm.examEndTime;
- return nrow;
- });
- this.updateTaskInfo({
- infoPrintTask: {
- ...this.modalForm,
- list: tableData,
- },
- });
- },
- updatePackageInfos() {
- this.packageInfos.packageCount = this.tableData.length;
- this.packageInfos.studentCount = calcSum(
- this.tableData.map((item) => item.studentCount)
- );
- this.packageInfos.paperReleaseCount = this.packageInfos.studentCount;
- this.packageInfos.paperBackupCount = calcSum(
- this.tableData.map((item) => item.backupCount || 0)
- );
- this.packageInfos.paperCount =
- 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();
- },
- timeChange() {
- if (!this.createDate || !this.createTime) {
- this.modalForm.examStartTime = null;
- this.modalForm.examEndTime = null;
- return;
- }
- const curDate = getTimeDatestamp(this.createDate);
- const timeDate = getTimeDatestamp(this.createTime[0]);
- this.modalForm.examStartTime = curDate + this.createTime[0] - timeDate;
- this.modalForm.examEndTime = curDate + this.createTime[1] - timeDate;
- },
- backupCountChange() {
- this.updatePackageInfos();
- },
- printHouseChange(row) {
- const curHouse = this.printHouses.find(
- (item) => item.printHouseId === row.printHouseId
- );
- if (curHouse) {
- row.printHouseName = curHouse.printHouseName;
- }
- },
- toAdd() {
- if (!this.infoExamTask.courseCode) {
- this.$message.error("请先选择课程");
- return;
- }
- const types = {
- TEACH_CLAZZ_STUDENT: this.checkPrivilege("button", "MyTeachCourse"),
- BASIC_CLAZZ_STUDENT: this.checkPrivilege("button", "StudentLibrary"),
- };
- this.disabledStudentIds = this.getTabelStudentIds();
- this.objectTypes = Object.keys(types).filter((k) => types[k]);
- this.showStudent = this.checkPrivilege("button", "SelectStudent");
- this.$refs.ModifyExamStudent.open();
- },
- getTabelStudentIds() {
- let ids = [];
- this.tableData.forEach((item) => {
- item.examTaskStudentObjectParamList.forEach((elem) => {
- ids.push(elem.id);
- });
- });
- return ids;
- },
- getInitTableRow() {
- let modalFormData = { ...this.modalForm };
- delete modalFormData.printHouseId;
- let data = {
- id: this.$randomCode(),
- examPlace: "",
- examRoom: "",
- classId: "",
- className: "",
- studentCount: "",
- printHouseId: "",
- printHouseName: "",
- extendFields: "",
- backupCount: 0,
- minBackupCount: 0,
- isSelectStudent: true,
- examTaskStudentObjectParamList: [],
- ...modalFormData,
- };
- let extendFieldModal = {};
- this.extendFields.forEach((field) => {
- extendFieldModal[field.code] = "";
- });
- data.extends = extendFieldModal;
- return data;
- },
- examStudentModified({ selectedStudents, isSelectStudent }) {
- if (this.IS_MODEL2) {
- this.model2ClassList = selectedStudents.map((item) => {
- return {
- clazzId: item.clazzId,
- clazzName: item.clazzName,
- };
- });
- this.model2ClassIds = this.model2ClassList.map((item) => item.clazzId);
- this.modalForm.classId = this.model2ClassIds.join();
- return;
- }
- if (this.studentUploaded) {
- this.tableData = [];
- this.studentUploaded = false;
- }
- let examTaskStudentObjectParamList = [];
- selectedStudents.forEach((item) => {
- examTaskStudentObjectParamList.push(...item.children);
- });
- let tableRow = this.$objAssign(this.getInitTableRow(), {
- classId: selectedStudents.map((item) => item.clazzId).join(),
- className: selectedStudents.map((item) => item.clazzName).join(),
- studentCount: examTaskStudentObjectParamList.length,
- examTaskStudentObjectParamList,
- isSelectStudent,
- ...this.getBackupCount(examTaskStudentObjectParamList.length),
- });
- this.tableData.push(tableRow);
- this.updatePackageInfos();
- },
- toDelete(index) {
- this.tableData.splice(index, 1);
- this.updatePackageInfos();
- if (!this.tableData.length) {
- this.$refs.ModifyExamStudent.clearSelectedExamObjectType();
- }
- },
- toViewStudent(row) {
- // console.log(row);
- this.examStudentList = row.examTaskStudentObjectParamList.map((item) => {
- return {
- id: item.id,
- studentName: item.studentName,
- studentCode: item.studentCode,
- className: item.basicClazzName,
- };
- });
- this.$refs.PreviewTaskStudent.open();
- },
- // import
- validError(errorData) {
- this.$message.error(errorData.message);
- },
- uploadSuccess(res) {
- this.studentUploaded = true;
- this.$message.success("导入成功!");
- this.$refs.ModifyExamStudent.clearTypeData();
- this.tableData = res.data.map((item) => {
- const initRow = this.getInitTableRow();
- let examTaskStudentObjectParamList = [];
- item.examTaskStudentObjectResultList.forEach((elem) => {
- elem.studentInfoList.forEach((std) => {
- examTaskStudentObjectParamList.push({
- ...std,
- studentClazzType: elem.studentClazzType,
- id: `${elem.clazzId}_${std.studentId}`,
- });
- });
- });
- let tableRow = this.$objAssign(initRow, {
- classId: item.examTaskStudentObjectResultList
- .map((item) => item.clazzId)
- .join(),
- className: item.examTaskStudentObjectResultList
- .map((item) => item.clazzName)
- .join(),
- examRoom: item.examRoom,
- examPlace: item.examPlace,
- studentCount: examTaskStudentObjectParamList.length,
- examTaskStudentObjectParamList,
- ...this.getBackupCount(examTaskStudentObjectParamList.length),
- });
- return tableRow;
- });
- this.updatePackageInfos();
- },
- // model2 select class
- toSelectClass() {
- if (!this.infoExamTask.courseCode) {
- this.$message.error("请先选择课程");
- return;
- }
- this.disabledStudentIds = [];
- this.objectTypes = ["BASIC_CLAZZ_STUDENT"];
- this.showStudent = false;
- this.$refs.ModifyExamStudent.open();
- },
- },
- };
- </script>
|