|
@@ -0,0 +1,342 @@
|
|
|
|
+<template>
|
|
|
|
+ <a-modal
|
|
|
|
+ v-model:visible="visible"
|
|
|
|
+ :width="500"
|
|
|
|
+ title-align="start"
|
|
|
|
+ :align-center="false"
|
|
|
|
+ :mask-closable="false"
|
|
|
|
+ :esc-to-close="false"
|
|
|
|
+ :footer="false"
|
|
|
|
+ fullscreen
|
|
|
|
+ @before-open="modalBeforeOpen"
|
|
|
|
+ >
|
|
|
|
+ <template #title> 班级详情 </template>
|
|
|
|
+
|
|
|
|
+ <div class="part-box is-filter">
|
|
|
|
+ <a-space class="filter-line" :size="12" wrap>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.college"
|
|
|
|
+ placeholder="学院"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.majorName"
|
|
|
|
+ placeholder="专业"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.className"
|
|
|
|
+ placeholder="班级"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.studentName"
|
|
|
|
+ placeholder="姓名"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.studentCode"
|
|
|
|
+ placeholder="学号"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ <a-input-group>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.startStudentCode"
|
|
|
|
+ placeholder="起始学号"
|
|
|
|
+ :style="{ width: '160px' }"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ <span class="mlr-1">-</span>
|
|
|
|
+ <a-input
|
|
|
|
+ v-model.trim="searchModel.endStudentCode"
|
|
|
|
+ placeholder="终止学号"
|
|
|
|
+ :style="{ width: '160px' }"
|
|
|
|
+ allow-clear
|
|
|
|
+ >
|
|
|
|
+ </a-input>
|
|
|
|
+ </a-input-group>
|
|
|
|
+ <a-input-group>
|
|
|
|
+ <a-input-number
|
|
|
|
+ v-model.trim="searchModel.startScore"
|
|
|
|
+ :style="{ width: '100px' }"
|
|
|
|
+ placeholder="成绩最低分"
|
|
|
|
+ :step="0.01"
|
|
|
|
+ :precision="2"
|
|
|
|
+ :min="0"
|
|
|
|
+ :max="9999"
|
|
|
|
+ hide-button
|
|
|
|
+ />
|
|
|
|
+ <a-input-number
|
|
|
|
+ v-model.trim="searchModel.endScore"
|
|
|
|
+ :style="{ width: '100px' }"
|
|
|
|
+ placeholder="成绩最高分"
|
|
|
|
+ :step="0.01"
|
|
|
|
+ :precision="2"
|
|
|
|
+ :min="0"
|
|
|
|
+ :max="9999"
|
|
|
|
+ hide-button
|
|
|
|
+ />
|
|
|
|
+ </a-input-group>
|
|
|
|
+ <a-input-group>
|
|
|
|
+ <a-input-number
|
|
|
|
+ v-model.trim="searchModel.objectiveStartScore"
|
|
|
|
+ :style="{ width: '100px' }"
|
|
|
|
+ placeholder="客观题最低总分"
|
|
|
|
+ :step="0.01"
|
|
|
|
+ :precision="2"
|
|
|
|
+ :min="0"
|
|
|
|
+ :max="9999"
|
|
|
|
+ hide-button
|
|
|
|
+ />
|
|
|
|
+ <a-input-number
|
|
|
|
+ v-model.trim="searchModel.objectiveEndScore"
|
|
|
|
+ :style="{ width: '100px' }"
|
|
|
|
+ placeholder="客观题最高总分"
|
|
|
|
+ :step="0.01"
|
|
|
|
+ :precision="2"
|
|
|
|
+ :min="0"
|
|
|
|
+ :max="9999"
|
|
|
|
+ hide-button
|
|
|
|
+ />
|
|
|
|
+ </a-input-group>
|
|
|
|
+ <a-input-group>
|
|
|
|
+ <a-input-number
|
|
|
|
+ v-model.trim="searchModel.subjectiveStartScore"
|
|
|
|
+ :style="{ width: '100px' }"
|
|
|
|
+ placeholder="主观题最低总分"
|
|
|
|
+ :step="0.01"
|
|
|
|
+ :precision="2"
|
|
|
|
+ :min="0"
|
|
|
|
+ :max="9999"
|
|
|
|
+ hide-button
|
|
|
|
+ />
|
|
|
|
+ <a-input-number
|
|
|
|
+ v-model.trim="searchModel.subjectiveEndScore"
|
|
|
|
+ :style="{ width: '100px' }"
|
|
|
|
+ placeholder="主观题最高总分"
|
|
|
|
+ :step="0.01"
|
|
|
|
+ :precision="2"
|
|
|
|
+ :min="0"
|
|
|
|
+ :max="9999"
|
|
|
|
+ hide-button
|
|
|
|
+ />
|
|
|
|
+ </a-input-group>
|
|
|
|
+ <a-button type="primary" @click="search">查询</a-button>
|
|
|
|
+ </a-space>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div class="part-box">
|
|
|
|
+ <a-space class="part-action" :size="6">
|
|
|
|
+ <a-button
|
|
|
|
+ type="text"
|
|
|
|
+ :disabled="loading || !dataList?.length"
|
|
|
|
+ @click="toDownloadFilter"
|
|
|
|
+ >
|
|
|
|
+ <template #icon>
|
|
|
|
+ <svg-icon name="icon-import" />
|
|
|
|
+ </template>
|
|
|
|
+ 批量下载查询数据
|
|
|
|
+ </a-button>
|
|
|
|
+ <a-button
|
|
|
|
+ type="text"
|
|
|
|
+ :disabled="!multipleSelections.length"
|
|
|
|
+ @click="toDownloadSelection"
|
|
|
|
+ >
|
|
|
|
+ <template #icon>
|
|
|
|
+ <svg-icon name="icon-add" />
|
|
|
|
+ </template>
|
|
|
|
+ 批量下载选择数据
|
|
|
|
+ </a-button>
|
|
|
|
+ </a-space>
|
|
|
|
+ <a-table
|
|
|
|
+ class="page-table"
|
|
|
|
+ :columns="columns"
|
|
|
|
+ :data="dataList"
|
|
|
|
+ :pagination="pagination"
|
|
|
|
+ :scroll="{ x: 600 }"
|
|
|
|
+ :bordered="false"
|
|
|
|
+ row-key="studentId"
|
|
|
|
+ :row-selection="{
|
|
|
|
+ type: 'checkbox',
|
|
|
|
+ showCheckedAll: true,
|
|
|
|
+ onlyCurrent: false,
|
|
|
|
+ }"
|
|
|
|
+ @selection-change="selectionChange"
|
|
|
|
+ >
|
|
|
|
+ <template #courseCode="{ record }">
|
|
|
|
+ {{ courseNameCodeFilter(record) }}
|
|
|
|
+ </template>
|
|
|
|
+ <template #checkTime="{ record }">
|
|
|
|
+ {{ checkTimeFilter(record) }}
|
|
|
|
+ </template>
|
|
|
|
+ <template #action="{ record }">
|
|
|
|
+ <a-button type="text" class="btn-primary" @click="toDownload(record)"
|
|
|
|
+ >下载</a-button
|
|
|
|
+ >
|
|
|
|
+ </template>
|
|
|
|
+ </a-table>
|
|
|
|
+ </div>
|
|
|
|
+ </a-modal>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup lang="ts">
|
|
|
|
+ import { reactive, ref } from 'vue';
|
|
|
|
+ import { TableColumnData } from '@arco-design/web-vue';
|
|
|
|
+
|
|
|
|
+ import useModal from '@/hooks/modal';
|
|
|
|
+ import useTable from '@/hooks/table';
|
|
|
|
+ import { courseNameCodeFilter } from '@/utils/filter';
|
|
|
|
+ import { objModifyAssign, parseTimeRangeDateAndTime } from '@/utils/utils';
|
|
|
|
+
|
|
|
|
+ import { trackExportDetailListPage } from '@/api/task';
|
|
|
|
+ import {
|
|
|
|
+ TrackExportDetailItem,
|
|
|
|
+ TrackExportItem,
|
|
|
|
+ TrackExportDetailListFilter,
|
|
|
|
+ } from '@/api/types/task';
|
|
|
|
+ import useLoading from '@/hooks/loading';
|
|
|
|
+
|
|
|
|
+ defineOptions({
|
|
|
|
+ name: 'TrackExportDetail',
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const props = defineProps<{
|
|
|
|
+ rowData: TrackExportItem;
|
|
|
|
+ }>();
|
|
|
|
+
|
|
|
|
+ const emit = defineEmits<{
|
|
|
|
+ (
|
|
|
|
+ e: 'downloadByFilter',
|
|
|
|
+ row: TrackExportItem,
|
|
|
|
+ filterData: TrackExportDetailListFilter
|
|
|
|
+ ): any;
|
|
|
|
+ (
|
|
|
|
+ e: 'downloadByStudents',
|
|
|
|
+ row: TrackExportItem,
|
|
|
|
+ students: TrackExportDetailItem[]
|
|
|
|
+ ): any;
|
|
|
|
+ }>();
|
|
|
|
+
|
|
|
|
+ /* modal */
|
|
|
|
+ const { visible, open, close } = useModal();
|
|
|
|
+ defineExpose({ open, close });
|
|
|
|
+
|
|
|
|
+ const defaultSearchModel = {
|
|
|
|
+ examId: '',
|
|
|
|
+ paperNumber: '',
|
|
|
|
+ college: '',
|
|
|
|
+ majorName: '',
|
|
|
|
+ className: '',
|
|
|
|
+ studentName: '',
|
|
|
|
+ studentCode: '',
|
|
|
|
+ startStudentCode: '',
|
|
|
|
+ endStudentCode: '',
|
|
|
|
+ startScore: undefined,
|
|
|
|
+ endScore: undefined,
|
|
|
|
+ objectiveStartScore: undefined,
|
|
|
|
+ objectiveEndScore: undefined,
|
|
|
|
+ subjectiveStartScore: undefined,
|
|
|
|
+ subjectiveEndScore: undefined,
|
|
|
|
+ orderType: undefined,
|
|
|
|
+ orderField: undefined,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const searchModel = reactive({ ...defaultSearchModel });
|
|
|
|
+ let searchedModel = { ...searchModel };
|
|
|
|
+ const multipleSelections = ref<TrackExportDetailItem[]>([]);
|
|
|
|
+
|
|
|
|
+ const columns: TableColumnData[] = [
|
|
|
|
+ {
|
|
|
|
+ title: '姓名',
|
|
|
|
+ dataIndex: 'studentName',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '学号',
|
|
|
|
+ dataIndex: 'studentCode',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '院系',
|
|
|
|
+ dataIndex: 'collegeName',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '专业',
|
|
|
|
+ dataIndex: 'majorName',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '班级',
|
|
|
|
+ dataIndex: 'className',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '考试时间',
|
|
|
|
+ slotName: 'checkTime',
|
|
|
|
+ width: 180,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '课程(代码)',
|
|
|
|
+ slotName: 'courseCode',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '成绩',
|
|
|
|
+ dataIndex: 'totalScore',
|
|
|
|
+ width: 80,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ title: '操作',
|
|
|
|
+ slotName: 'action',
|
|
|
|
+ width: 80,
|
|
|
|
+ fixed: 'right',
|
|
|
|
+ cellClass: 'action-column',
|
|
|
|
+ },
|
|
|
|
+ ];
|
|
|
|
+ const { dataList, pagination, toPage } = useTable<TrackExportDetailItem>(
|
|
|
|
+ trackExportDetailListPage,
|
|
|
|
+ searchModel,
|
|
|
|
+ false
|
|
|
|
+ );
|
|
|
|
+ const { loading, setLoading } = useLoading();
|
|
|
|
+ async function search() {
|
|
|
|
+ setLoading(true);
|
|
|
|
+ searchedModel = { ...searchModel };
|
|
|
|
+ await toPage(1).catch(() => {});
|
|
|
|
+ setLoading(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function checkTimeFilter(row: TrackExportDetailItem) {
|
|
|
|
+ const { date, time } = parseTimeRangeDateAndTime(
|
|
|
|
+ row.examStartTime,
|
|
|
|
+ row.examEndTime
|
|
|
|
+ );
|
|
|
|
+ return `${date || '--'} ${time || '--'}`;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function selectionChange(keys: (string | number)[]) {
|
|
|
|
+ if (!dataList.value) return;
|
|
|
|
+ console.log(keys);
|
|
|
|
+ multipleSelections.value = dataList.value.filter((item) =>
|
|
|
|
+ keys.includes(item.studentId)
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function toDownloadFilter() {
|
|
|
|
+ emit('downloadByFilter', props.rowData, searchedModel);
|
|
|
|
+ }
|
|
|
|
+ function toDownloadSelection() {
|
|
|
|
+ emit('downloadByStudents', props.rowData, multipleSelections.value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function toDownload(row: TrackExportDetailItem) {
|
|
|
|
+ emit('downloadByStudents', props.rowData, [row]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function modalBeforeOpen() {
|
|
|
|
+ objModifyAssign(searchModel, defaultSearchModel);
|
|
|
|
+ objModifyAssign(searchModel, props.rowData);
|
|
|
|
+ search();
|
|
|
|
+ }
|
|
|
|
+</script>
|