|
|
@@ -10,7 +10,7 @@
|
|
|
</el-form>
|
|
|
</el-col>
|
|
|
<el-col :span="16">
|
|
|
- <class-statistic-table exact-mode/>
|
|
|
+ <class-statistic-table exact-mode @stat-click="handleStatClick"/>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
<el-divider/>
|
|
|
@@ -18,17 +18,104 @@
|
|
|
<el-button type="primary" size="large" @click="handleSubmit">生成试卷</el-button>
|
|
|
</div>
|
|
|
<built-paper-list ref="built" @send="handleSubmit" />
|
|
|
+
|
|
|
+ <!-- 学生列表弹窗 -->
|
|
|
+ <el-dialog v-model="studentDialogVisible" :title="studentDialogTitle" width="1200px" destroy-on-close>
|
|
|
+ <div class="student-table-container">
|
|
|
+ <el-table
|
|
|
+ v-loading="studentLoading"
|
|
|
+ :data="studentList"
|
|
|
+ stripe
|
|
|
+ height="calc(100vh - 350px)"
|
|
|
+ style="width: 100%"
|
|
|
+ >
|
|
|
+ <!-- <el-table-column label="姓名" prop="studentName" width="120" align="center"/> -->
|
|
|
+ <el-table-column label="姓名-手机" prop="namePhone" min-width="180" align="center"/>
|
|
|
+ <el-table-column label="卡号" prop="cardNo" min-width="120" align="center"/>
|
|
|
+ <el-table-column label="注册学校" prop="registerSchool" min-width="120" align="center" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="学校班级" prop="registerClass" min-width="80" align="center" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="培训校区" prop="trainSchool" min-width="120" align="center" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="校区班级" prop="trainClass" min-width="80" align="center" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="考生类型" prop="examType" min-width="150" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <template v-if="scope.row && scope.row.examType && exam_type">
|
|
|
+ <dict-tag :options="exam_type" :value="scope.row.examType" />
|
|
|
+ </template>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="定向" prop="direct" min-width="150" align="center">
|
|
|
+ <template #default="{row}">
|
|
|
+ <div v-if="getFirstDirectedStudyInfo(row.direct)" class="cursor-pointer text-blue-500 hover:text-blue-700" @click.stop="handleShowDirectedStudy(row.direct)">
|
|
|
+ <el-tooltip :content="getFirstDirectedStudyTooltip(row.direct)" placement="top" :disabled="!getFirstDirectedStudyInfo(row.direct)">
|
|
|
+ <div class="directed-study-cell">
|
|
|
+ <div v-if="getFirstDirectedStudyInfo(row.direct).universityName" class="directed-study-line">
|
|
|
+ {{ getFirstDirectedStudyInfo(row.direct).universityName }}
|
|
|
+ </div>
|
|
|
+ <div v-if="getFirstDirectedStudyInfo(row.direct).majorName" class="directed-study-line">
|
|
|
+ {{ getFirstDirectedStudyInfo(row.direct).majorName }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="代理商" prop="agent" min-width="120" align="center" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="单招年份" prop="year" min-width="80" align="center"/>
|
|
|
+ <el-table-column label="省份" prop="province" min-width="80" align="center"/>
|
|
|
+ <el-table-column label="机构" prop="institution" min-width="150" align="center" show-overflow-tooltip/>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 前端分页 -->
|
|
|
+ <div class="student-pagination">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="studentPageNum"
|
|
|
+ v-model:page-size="studentPageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :total="studentTotal"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleStudentPageSizeChange"
|
|
|
+ @current-change="handleStudentPageChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 定向信息弹窗 -->
|
|
|
+ <el-dialog v-model="directDetailVisible" title="定向信息" width="900px" destroy-on-close>
|
|
|
+ <el-table :data="directDetailData" class="w-full" style="width: 100%">
|
|
|
+ <el-table-column label="序号" type="index" width="60" align="center"></el-table-column>
|
|
|
+ <el-table-column label="编码" prop="code" min-width="120" align="center"></el-table-column>
|
|
|
+ <el-table-column label="学校" prop="universityName" min-width="200" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.universityName }}{{ scope.row.universityId ? `(${scope.row.universityId})` : '' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="专业" prop="majorName" min-width="200" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.majorName }}{{ scope.row.majorId ? `(${scope.row.majorId})` : '' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="专业类" prop="majorAncestors" min-width="200" align="center"></el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-dialog>
|
|
|
+ </el-dialog>
|
|
|
</template>
|
|
|
|
|
|
<script setup name="PaperExactIntelligent">
|
|
|
+import { ref, computed, getCurrentInstance } from 'vue'
|
|
|
import consts from "@/utils/consts.js";
|
|
|
import {useProvidePaperBatchCondition} from "@/views/dz/papers/hooks/usePaperBatchCondition.js";
|
|
|
import {useProvidePaperClassStatisticCondition} from "@/views/dz/papers/hooks/usePaperClassStatisticCondition.js";
|
|
|
import ClassStatisticTable from "@/views/dz/papers/components/plugs/class-statistic-table.vue";
|
|
|
import {ElMessage} from "element-plus";
|
|
|
-import {buildPaperExactIntelligent} from "@/api/dz/papers.js";
|
|
|
+import {buildPaperExactIntelligent, getClassesBuildStatsDetail} from "@/api/dz/papers.js";
|
|
|
import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
|
|
|
import BuiltPaperList from "@/views/dz/papers/components/plugs/built-paper-list.vue";
|
|
|
+import DictTag from '@/components/DictTag/index.vue';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance();
|
|
|
+const { exam_type } = proxy.useDict("exam_type");
|
|
|
|
|
|
const type = consts.enums.buildType.ExactIntelligent
|
|
|
const {batchId, batchList, onBatchReady} = useProvidePaperBatchCondition(type, true)
|
|
|
@@ -37,6 +124,187 @@ const {loading} = useInjectGlobalLoading()
|
|
|
const built = ref(null)
|
|
|
const hasBuiltPaper = computed(() => built.value?.hasPaper)
|
|
|
|
|
|
+// 统计字段映射
|
|
|
+const statTypeMap = {
|
|
|
+ 'send': '组卷已完成',
|
|
|
+ 'total': '班级人数',
|
|
|
+ 'unexact': '未定向未组卷',
|
|
|
+ 'unfinish': '组卷未完成',
|
|
|
+ 'unsend': '定向未组卷'
|
|
|
+}
|
|
|
+
|
|
|
+// 学生列表弹窗相关
|
|
|
+const studentDialogVisible = ref(false)
|
|
|
+const studentDialogTitle = ref('')
|
|
|
+const studentList = ref([])
|
|
|
+const studentLoading = ref(false)
|
|
|
+const studentPageNum = ref(1)
|
|
|
+const studentPageSize = ref(10)
|
|
|
+const studentTotal = ref(0)
|
|
|
+const currentStatType = ref('')
|
|
|
+const currentRow = ref(null)
|
|
|
+
|
|
|
+// 定向详情弹窗相关
|
|
|
+const directDetailVisible = ref(false)
|
|
|
+const directDetailData = ref([])
|
|
|
+
|
|
|
+// 解析directedStudy JSON并获取第一个的显示文本(用于tooltip)
|
|
|
+const getFirstDirectedStudyTooltip = (direct) => {
|
|
|
+ if (!direct) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const directedStudy = typeof direct === 'string'
|
|
|
+ ? JSON.parse(direct)
|
|
|
+ : direct;
|
|
|
+
|
|
|
+ if (Array.isArray(directedStudy) && directedStudy.length > 0) {
|
|
|
+ const first = directedStudy[0];
|
|
|
+ const universityName = first?.universityName || '';
|
|
|
+ const majorName = first?.majorName || '';
|
|
|
+ if (universityName || majorName) {
|
|
|
+ const parts = [];
|
|
|
+ if (universityName) parts.push(universityName);
|
|
|
+ if (majorName) parts.push(majorName);
|
|
|
+ return parts.join(' - ');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析directedStudy失败:', e);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+};
|
|
|
+
|
|
|
+// 解析directedStudy JSON并获取第一个的信息对象
|
|
|
+const getFirstDirectedStudyInfo = (direct) => {
|
|
|
+ if (!direct) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const directedStudy = typeof direct === 'string'
|
|
|
+ ? JSON.parse(direct)
|
|
|
+ : direct;
|
|
|
+
|
|
|
+ if (Array.isArray(directedStudy) && directedStudy.length > 0) {
|
|
|
+ const first = directedStudy[0];
|
|
|
+ const universityName = first?.universityName || '';
|
|
|
+ const majorName = first?.majorName || '';
|
|
|
+ if (universityName || majorName) {
|
|
|
+ return {
|
|
|
+ universityName: universityName,
|
|
|
+ majorName: majorName
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析directedStudy失败:', e);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+};
|
|
|
+
|
|
|
+// 获取完整的directedStudy列表
|
|
|
+const getDirectedStudyList = (direct) => {
|
|
|
+ if (!direct) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const directedStudy = typeof direct === 'string'
|
|
|
+ ? JSON.parse(direct)
|
|
|
+ : direct;
|
|
|
+
|
|
|
+ if (Array.isArray(directedStudy)) {
|
|
|
+ return directedStudy.map(item => ({
|
|
|
+ code: item?.code || '-',
|
|
|
+ majorName: item?.majorName || '-',
|
|
|
+ majorId: item?.majorId || null,
|
|
|
+ universityName: item?.universityName || '-',
|
|
|
+ universityId: item?.universityId || null,
|
|
|
+ majorAncestors: item?.majorAncestors || '-'
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析directedStudy失败:', e);
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+};
|
|
|
+
|
|
|
+// 显示定向信息弹窗
|
|
|
+const handleShowDirectedStudy = (direct) => {
|
|
|
+ directDetailData.value = getDirectedStudyList(direct);
|
|
|
+ directDetailVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 处理统计字段点击
|
|
|
+const handleStatClick = async (row, statType) => {
|
|
|
+ console.log('点击统计字段:', { row, statType })
|
|
|
+ if (!row || !statType) {
|
|
|
+ console.error('参数错误:', { row, statType })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ currentRow.value = row
|
|
|
+ currentStatType.value = statType
|
|
|
+ studentDialogTitle.value = `${row.className || ''} - ${statTypeMap[statType] || statType}`
|
|
|
+ studentPageNum.value = 1
|
|
|
+ studentPageSize.value = 10
|
|
|
+
|
|
|
+ // 先显示弹窗,再加载数据
|
|
|
+ studentDialogVisible.value = true
|
|
|
+ await loadStudentList()
|
|
|
+}
|
|
|
+
|
|
|
+// 加载学生列表
|
|
|
+const loadStudentList = async () => {
|
|
|
+ if (!currentRow.value || !batchId.value) {
|
|
|
+ console.error('参数不完整:', { currentRow: currentRow.value, batchId: batchId.value })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ studentLoading.value = true
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ buildType: type,
|
|
|
+ batchId: batchId.value,
|
|
|
+ classId: currentRow.value.classId,
|
|
|
+ statType: currentStatType.value
|
|
|
+ }
|
|
|
+ console.log('请求参数:', params)
|
|
|
+
|
|
|
+ const res = await getClassesBuildStatsDetail(params)
|
|
|
+ console.log('接口响应:', res)
|
|
|
+
|
|
|
+ const allStudents = res.data || []
|
|
|
+ studentTotal.value = allStudents.length
|
|
|
+
|
|
|
+ console.log('学生总数:', studentTotal.value)
|
|
|
+
|
|
|
+ // 前端分页
|
|
|
+ const start = (studentPageNum.value - 1) * studentPageSize.value
|
|
|
+ const end = start + studentPageSize.value
|
|
|
+ studentList.value = allStudents.slice(start, end)
|
|
|
+
|
|
|
+ console.log('当前页学生数据:', studentList.value)
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载学生列表失败:', error)
|
|
|
+ ElMessage.error('加载学生列表失败: ' + (error.message || '未知错误'))
|
|
|
+ } finally {
|
|
|
+ studentLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 分页大小改变
|
|
|
+const handleStudentPageSizeChange = (size) => {
|
|
|
+ studentPageSize.value = size
|
|
|
+ studentPageNum.value = 1
|
|
|
+ loadStudentList()
|
|
|
+}
|
|
|
+
|
|
|
+// 页码改变
|
|
|
+const handleStudentPageChange = (page) => {
|
|
|
+ studentPageNum.value = page
|
|
|
+ loadStudentList()
|
|
|
+}
|
|
|
+
|
|
|
const handleSubmit = async function () {
|
|
|
if (!batchId.value) return ElMessage.error('请选择批次')
|
|
|
const classIds = selectedClasses.value.map(c => c.classId)
|
|
|
@@ -70,5 +338,37 @@ watch(batchId, () => built.value.reset())
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
+.truncate {
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
|
|
|
+.student-table-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: calc(100vh - 300px);
|
|
|
+ min-height: 500px;
|
|
|
+ max-height: calc(100vh - 300px);
|
|
|
+}
|
|
|
+
|
|
|
+.student-pagination {
|
|
|
+ margin-top: 20px;
|
|
|
+ text-align: right;
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 10px 0;
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.directed-study-cell {
|
|
|
+ text-align: center;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.directed-study-line {
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
</style>
|