|
|
<!-- src/components/WrongQuestion/WrongQuestionTable.vue --><template> <div class="table-container"> <table> <thead> <tr> <th>ID</th> <th>题干</th> <th>题目类型</th> <th>出错次数</th> <th>出错率</th> <th>推荐课程</th> <th>操作</th> </tr> </thead> <tbody> <tr v-for="(item,index) in wrongQuestions" :key="item.id"> <td>{{ (page- 1) * pageSize + index + 1 }}</td> <td>{{ item.stem }}</td> <td>{{ item.questionTypeName }}</td> <td>{{ item.errorCount }}</td> <td>{{ item.errorRate }}%</td> <td>{{ item.CrName }}</td> <td class="operation-cell"> <button class="btn-red small" @click="viewUser(item)">出错用户</button> <button class="btn-red small" @click="viewQuestion(item)">查看题目</button> </td> </tr> </tbody> </table>
<!-- 分页控件 --> <div class="pagination-container"> <div class="pagination-info"> 共 {{ total }} 条记录,第 {{ page }} 页 </div> <div class="pagination-controls"> <button class="btn-pagination" :disabled="page <= 1" @click="changePage(1)" > 首页 </button> <button class="btn-pagination" :disabled="page <= 1" @click="changePage(page - 1)" > 上一页 </button>
<input type="number" class="page-input" :value="page" @keyup.enter="jumpToPage" min="1" :max="totalPages" />
<span class="page-info">/ {{ totalPages }}</span>
<button class="btn-pagination" :disabled="page >= totalPages" @click="changePage(page + 1)" > 下一页 </button> <button class="btn-pagination" :disabled="page >= totalPages" @click="changePage(totalPages)" > 尾页 </button> </div> </div>
<!-- 用户弹窗 --> <div v-if="showUserModal" class="modal-overlay"> <div class="modal-content"> <h3>出错用户列表</h3> <table class="user-table"> <thead> <tr> <th>用户名称</th> <th>用户身份</th> <th>出错次数</th> </tr> </thead> <tbody> <tr v-for="user in errorUsers" :key="user.user_name"> <td>{{ user.user_name }}</td> <td>{{ user.user_identity }}</td> <td>{{ user.error_count }}</td> </tr> </tbody> </table> <button class="btn-close" @click="closeModal">关闭</button> </div> </div>
<!-- 查看题目详情弹窗 --> <div v-if="showViewModal" class="modal-overlay" @click.self="closeViewModal"> <div class="view-modal-content" @click.stop> <div class="modal-header"> <h3>题目详情</h3> <button class="close-btn" @click="closeViewModal">×</button> </div> <div class="view-modal-body"> <p class="question-text">{{ currentQuestion.stem }}</p>
<div class="options-container"> <div v-for="option in ['A', 'B', 'C', 'D']" :key="option" :class="[option === currentQuestion.correctAnswer ? 'option-item-correct' : 'option-item']" > {{ `${option}. ${currentQuestion[`option${option}`]}` }} </div> </div> </div> <div class="modal-footer"> <button class="btn-red" @click="closeViewModal">退出</button> </div> </div> </div> </div></template>
<script>import { getQuestions } from '@/api/question.js';
export default { name: 'WrongQuestionTable', data() { return { wrongQuestions: [], total: 0, page: 1, pageSize: 20, showUserModal: false, errorUsers: [], showViewModal: false, currentQuestion: {}, currentFilters: {} } }, computed: { totalPages() { try { return this.total !== 0 ? Math.ceil(this.total / this.pageSize) : 1; } catch(error) { console.error('计算总页数时出错:', error); return 1; } } }, methods: { setFilters(filters) { this.currentFilters = filters; this.page = 1; this.fetchWrongQuestions(); },
async fetchWrongQuestions() { try { const params = new URLSearchParams(); params.append('page', this.page); params.append('page_size', this.pageSize);
// 处理过滤条件
const questionTypeIdMap = { '股票知识': 1, '企业文化': 2 }; if (this.currentFilters.questionType) { params.append('question_type_id', questionTypeIdMap[this.currentFilters.questionType]); }
const courseRecommendationIdMap = { '量能擒牛': 1, '价格破译': 2, '量价时空综合': 3 }; if (this.currentFilters.course) { params.append('course_recommendation_id', courseRecommendationIdMap[this.currentFilters.course]); }
if (this.currentFilters.keyword) { params.append('stem', this.currentFilters.keyword); }
const response = await getQuestions(params);
if (response.data.code === 200) { this.wrongQuestions = response.data.data.list this.total = response.data.data.total; } else { console.error('接口返回错误:', response.data.msg) } } catch (error) { console.error('获取错题数据失败:', error) } },
viewUser(item) { this.$emit('view-user', item) this.fetchErrorUsers(item.id) },
async fetchErrorUsers(questionId) { try { const { getUsersByQuestionId } = await import('@/api/wrongQuestion') const response = await getUsersByQuestionId(questionId)
if (response.data.code === 200) { this.errorUsers = response.data.data.list || [] this.showUserModal = true } else { console.error('获取用户失败:', response.data.msg) } } catch (error) { console.error('请求失败:', error) } },
async viewQuestion(item) { const row = document.querySelector(`[data-id="${item.id}"]`) if (row) { row.scrollIntoView({ behavior: 'smooth', block: 'center' }) }
try { // 使用统一的API调用方式
const params = { Page: 1, PageSize: 100, id: item.id }
const response = await getQuestions(params)
if (response.data.code === 200 && response.data.data.list && response.data.data.list.length > 0) { const rawQuestion = response.data.data.list.find(q => q.id === item.id)
if (!rawQuestion) { alert('未找到该题目!') return }
this.currentQuestion = { id: rawQuestion.id, stem: rawQuestion.stem, optionA: rawQuestion.A, optionB: rawQuestion.B, optionC: rawQuestion.C, optionD: rawQuestion.D, correctAnswer: rawQuestion.correctAnswer, questionTypeName: rawQuestion.questionTypeName, CrName: rawQuestion.CrName }
this.showViewModal = true } else { alert('未找到该题目!') } } catch (error) { console.error('获取题目详情失败:', error) alert('网络错误,请检查连接!') } },
closeViewModal() { this.showViewModal = false },
changePage(newPage) { if (newPage >= 1 && newPage <= this.totalPages) { this.page = newPage; this.fetchWrongQuestions(); } },
jumpToPage(event) { const targetPage = parseInt(event.target.value) if (targetPage >= 1 && targetPage <= this.totalPages) { this.page = targetPage; this.fetchWrongQuestions(); } else { event.target.value = this.page } },
closeModal() { this.showUserModal = false this.errorUsers = [] } }, mounted() { this.fetchWrongQuestions(); }}</script>
<style scoped>.table-container { width: 100%; border-collapse: collapse; margin-top: 10px;}
table { width: 100%; border-collapse: collapse; background-color: white;}
th,td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd;}
th { background-color: #f2f2f2; font-weight: normal; color: #333; display: table-cell !important; vertical-align: middle !important;}
tr:hover { background-color: #f9f9f9;}
.operation-cell { display: flex; gap: 16px;}
/* 分页样式 */.pagination-container { display: flex; justify-content: flex-start; align-items: center; margin-top: 20px; padding: 0 10px;}
.pagination-info { font-size: 14px; color: #666; margin-right: 20px;}
.pagination-controls { display: flex; align-items: center; gap: 10px;}
.btn-pagination { padding: 6px 12px; background-color: #f2f2f2; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s;}
.btn-pagination:hover:not(:disabled) { background-color: #e0e0e0;}
.btn-pagination:disabled { background-color: #f5f5f5; color: #ccc; cursor: not-allowed;}
.page-input { width: 50px; padding: 6px; border: 1px solid #ddd; border-radius: 4px; text-align: center; font-size: 14px;}
.page-info { font-size: 14px; color: #666;}
/* 弹窗样式 */.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1000;}
.modal-content { background: white; padding: 20px; border-radius: 8px; width: 600px; max-width: 90%; box-shadow: 0 4px 12px rgba(0,0,0,0.1);}
.view-modal-content { background-color: white; border-radius: 8px; width: 750px; max-width: 90%; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); overflow: hidden;}
.view-modal-body { padding: 20px; max-height: 600px; overflow-y: auto;}
.question-text { font-size: 16px; margin-bottom: 20px; line-height: 1.5;}
.options-container { display: flex; flex-direction: column; gap: 10px;}
.option-item { padding: 10px; border-radius: 6px; background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; transition: all 0.2s;}
.option-item-correct { padding: 10px; border-radius: 6px; background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; transition: all 0.2s; background-color: #dc3545 !important; color: white !important; border-color: #c82333 !important; font-weight: bold;}
.modal-header { padding: 20px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;}
.modal-header h3 { margin: 0; font-size: 18px; color: #333;}
.close-btn { background: none; border: none; font-size: 24px; cursor: pointer; color: #666; padding: 5px; border-radius: 50%; transition: color 0.2s;}
.close-btn:hover { color: #e74c3c;}
.modal-footer { padding: 20px; border-top: 1px solid #eee; display: flex; justify-content: flex-end; gap: 16px;}
.user-table { width: 100%; border-collapse: collapse; margin-top: 10px;}
.user-table th,.user-table td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd;}
.user-table th { background-color: #f2f2f2;}
.btn-close { margin-top: 15px; padding: 8px 16px; background-color: #e74c3c; color: white; border: none; border-radius: 4px; cursor: pointer;}</style>
|