fix: 修复题目管理页面的 TypeScript 类型错误

This commit is contained in:
QDKF 2025-09-06 01:20:37 +08:00
parent 3d5d34b660
commit e1b32c2c3c
2 changed files with 59 additions and 136 deletions

View File

@ -500,7 +500,7 @@ const createNewQuestion = async (bankId: string) => {
try {
// API
const questionData = {
parentId: null, // IDnull
parentId: undefined, // IDundefined
type: getQuestionTypeNumber(questionForm.type),
content: questionForm.title,
analysis: questionForm.explanation || '',
@ -547,43 +547,6 @@ const createNewQuestion = async (bankId: string) => {
}
};
//
const handleSingleChoiceQuestion = async (questionId: string) => {
try {
//
const optionPromises = questionForm.options.map((option, index) => {
const isCorrect = questionForm.correctAnswer === index ? 1 : 0;
return ExamApi.createQuestionOption({
questionId,
content: option.content,
izCorrent: isCorrect,
orderNo: index + 1
});
});
console.log('🚀 第二步:添加选项,选项数量:', questionForm.options.length);
await Promise.all(optionPromises);
console.log('✅ 选项添加成功');
//
if (questionForm.correctAnswer !== null) {
const correctOption = questionForm.options[questionForm.correctAnswer];
const answerData = {
questionId,
answerText: correctOption.content,
orderNo: 1
};
console.log('🚀 第三步:添加答案:', answerData);
await ExamApi.createQuestionAnswer(answerData);
console.log('✅ 答案添加成功');
}
} catch (error: any) {
console.error('处理单选题失败:', error);
throw error;
}
};
//
const validateAnswers = (): boolean => {
@ -600,7 +563,7 @@ const validateAnswers = (): boolean => {
message.error('单选题至少需要2个选项');
return false;
}
if (questionForm.options.some(option => !option.content.trim())) {
if (questionForm.options.some((option: any) => !option.content.trim())) {
message.error('请填写所有选项的内容');
return false;
}
@ -615,7 +578,7 @@ const validateAnswers = (): boolean => {
message.error('多选题至少需要2个选项');
return false;
}
if (questionForm.options.some(option => !option.content.trim())) {
if (questionForm.options.some((option: any) => !option.content.trim())) {
message.error('请填写所有选项的内容');
return false;
}
@ -631,7 +594,7 @@ const validateAnswers = (): boolean => {
}
break;
case 'fill_blank':
if (questionForm.fillBlankAnswers.length === 0 || questionForm.fillBlankAnswers.every(answer => !answer.content.trim())) {
if (questionForm.fillBlankAnswers.length === 0 || questionForm.fillBlankAnswers.every((answer: any) => !answer.content.trim())) {
message.error('请设置填空题的参考答案');
return false;
}

View File

@ -3,94 +3,61 @@
<div class="breadcrumb-section">
<n-breadcrumb>
<n-breadcrumb-item @click="goToQuestionBank">
<n-icon><ChevronBackOutline /></n-icon>
<n-icon>
<ChevronBackOutline />
</n-icon>
题库管理
</n-breadcrumb-item>
<n-breadcrumb-item>{{ currentBankTitle }}</n-breadcrumb-item>
</n-breadcrumb>
</div>
<div class="header-section">
<h1 class="title">{{ currentBankTitle }}</h1>
<n-space class="actions-group">
<n-button type="primary" @click="addQuestion">添加试题</n-button>
<n-button ghost @click="importQuestions">导入</n-button>
<n-button ghost @click="exportQuestions">导出</n-button>
<n-button type="error" ghost @click="deleteSelected" :disabled="selectedRowKeys.length === 0">删除</n-button>
<n-button type="error" ghost @click="deleteSelected"
:disabled="selectedRowKeys.length === 0">删除</n-button>
<n-button @click="setCategoryForSelected" :disabled="selectedRowKeys.length === 0">分类设置</n-button>
<n-select
v-model:value="filters.category"
placeholder="分类"
:options="[{ label: '全部', value: '' }, ...allCategoryOptions]"
style="width: 120px"
@update:value="handleFilterChange"
/>
<n-input
v-model:value="filters.keyword"
placeholder="请输入想要搜索的内容"
style="width: 200px"
clearable
/>
<n-select v-model:value="filters.category" placeholder="分类"
:options="[{ label: '全部', value: '' }, ...allCategoryOptions]" style="width: 120px"
@update:value="handleFilterChange" />
<n-input v-model:value="filters.keyword" placeholder="请输入想要搜索的内容" style="width: 200px" clearable />
<n-button type="primary" @click="searchQuestions">搜索</n-button>
</n-space>
</div>
<n-data-table
ref="tableRef"
:columns="columns"
:data="questionList"
:loading="loading"
:pagination="paginationConfig"
:row-key="(row: Question) => row.id"
:checked-row-keys="selectedRowKeys"
@update:checked-row-keys="handleCheck"
class="question-table"
:single-line="false"
/>
<n-data-table ref="tableRef" :columns="columns" :data="questionList" :loading="loading"
:pagination="paginationConfig" :row-key="(row: any) => row.id" :checked-row-keys="selectedRowKeys"
@update:checked-row-keys="handleCheck" class="question-table" :single-line="false" />
<!-- 导入弹窗 -->
<ImportModal
v-model:show="showImportModal"
template-name="question_template.xlsx"
import-type="question"
@success="handleImportSuccess"
@template-download="handleTemplateDownload"
/>
<ImportModal v-model:show="showImportModal" template-name="question_template.xlsx" import-type="question"
@success="handleImportSuccess" @template-download="handleTemplateDownload" />
<!-- 分类设置弹窗 -->
<n-modal
v-model:show="showCategoryModal"
preset="dialog"
title="分类设置"
style="width: 500px;"
>
<n-modal v-model:show="showCategoryModal" preset="dialog" title="分类设置" style="width: 500px;">
<div class="category-modal-content">
<div class="selected-info">
<n-alert type="info" :show-icon="false" style="margin-bottom: 16px;">
已选择 {{ selectedRowKeys.length }} 个试题
</n-alert>
</div>
<div class="category-selection">
<div class="form-item">
<label>选择分类</label>
<n-select
v-model:value="selectedCategory"
:options="allCategoryOptions"
placeholder="请选择分类"
style="width: 100%;"
/>
<n-select v-model:value="selectedCategory" :options="allCategoryOptions" placeholder="请选择分类"
style="width: 100%;" />
</div>
<div v-if="showAddCategoryInput" class="form-item">
<label>新分类名称</label>
<n-space>
<n-input
v-model:value="newCategoryName"
placeholder="请输入新分类名称"
style="width: 200px;"
@keyup.enter="addNewCategory"
/>
<n-input v-model:value="newCategoryName" placeholder="请输入新分类名称" style="width: 200px;"
@keyup.enter="addNewCategory" />
<n-button type="primary" @click="addNewCategory" :disabled="!newCategoryName.trim()">
添加
</n-button>
@ -98,7 +65,7 @@
</div>
</div>
</div>
<template #action>
<n-space>
<n-button @click="showAddCategoryInput = !showAddCategoryInput" secondary type="info">
@ -113,12 +80,7 @@
</n-modal>
<!-- 分类管理弹窗 -->
<n-modal
v-model:show="showCategoryManageModal"
preset="dialog"
title="分类管理"
style="width: 600px;"
>
<n-modal v-model:show="showCategoryManageModal" preset="dialog" title="分类管理" style="width: 600px;">
<div class="category-manage-content">
<div class="category-header">
<n-space>
@ -127,15 +89,11 @@
</n-button>
</n-space>
</div>
<div v-if="showAddCategoryInManage" class="add-category-section">
<n-space>
<n-input
v-model:value="newCategoryInManage"
placeholder="请输入分类名称"
style="width: 200px;"
@keyup.enter="addCategoryInManage"
/>
<n-input v-model:value="newCategoryInManage" placeholder="请输入分类名称" style="width: 200px;"
@keyup.enter="addCategoryInManage" />
<n-button type="primary" @click="addCategoryInManage" :disabled="!newCategoryInManage.trim()">
添加
</n-button>
@ -144,7 +102,7 @@
</n-button>
</n-space>
</div>
<div class="category-list">
<n-list>
<n-list-item v-for="category in customCategories" :key="category.value">
@ -163,7 +121,7 @@
</n-list>
</div>
</div>
<template #action>
<n-space>
<n-button @click="closeCategoryManageModal">关闭</n-button>
@ -210,6 +168,8 @@ interface Question {
score: number;
creator: string;
createTime: string;
parentId?: string; // parentId
analysis?: string; // analysis
}
//
@ -333,7 +293,7 @@ const createColumns = ({
width: 100,
align: 'center' as const,
render(row: Question) {
const categoryInfo = allCategoryOptions.value.find(cat => cat.value === row.category);
const categoryInfo = allCategoryOptions.value.find((cat: any) => cat.value === row.category);
return categoryInfo ? categoryInfo.label : row.category;
}
},
@ -377,27 +337,27 @@ const createColumns = ({
align: 'center' as const,
render(row: Question) {
const buttons: VNode[] = [];
buttons.push(
h(NButton, {
size: 'small',
type: 'primary',
ghost: true,
style: 'margin: 0 3px;',
onClick: () => handleAction('编辑', row)
h(NButton, {
size: 'small',
type: 'primary',
ghost: true,
style: 'margin: 0 3px;',
onClick: () => handleAction('编辑', row)
}, { default: () => '编辑' })
);
buttons.push(
h(NButton, {
size: 'small',
type: 'error',
ghost: true,
style: 'margin: 0 3px;',
onClick: () => handleAction('删除', row)
h(NButton, {
size: 'small',
type: 'error',
ghost: true,
style: 'margin: 0 3px;',
onClick: () => handleAction('删除', row)
}, { default: () => '删除' })
);
return h(NSpace, {}, { default: () => buttons });
}
}
@ -420,7 +380,7 @@ const generateMockData = (): Question[] => {
const mockData: Question[] = [];
const types = ['single_choice', 'multiple_choice', 'true_false', 'fill_blank', 'short_answer'];
const difficulties = ['easy', 'medium', 'hard'];
const categories = customCategories.value.map(cat => cat.value);
const categories = customCategories.value.map((cat: any) => cat.value);
const creators = ['王建国', '李明', '张三', '刘老师'];
for (let i = 1; i <= 50; i++) {
@ -492,7 +452,7 @@ const loadQuestions = async () => {
let allData: Question[] = [];
// API
if (response.data && (response.data.code === 200 || response.data.code === 0) && response.data.result) {
if (response.data && typeof response.data === 'object' && 'code' in response.data && (response.data.code === 200 || response.data.code === 0) && 'result' in response.data && response.data.result && Array.isArray(response.data.result)) {
// API
allData = response.data.result.map((item: any, index: number) => ({
id: item.id || `question_${index}`,
@ -746,7 +706,7 @@ const addNewCategory = () => {
}
//
const exists = customCategories.value.some(cat => cat.label === trimmedName);
const exists = customCategories.value.some((cat: any) => cat.label === trimmedName);
if (exists) {
message.warning('该分类已存在');
return;
@ -775,8 +735,8 @@ const applyCategoryChange = async () => {
await new Promise(resolve => setTimeout(resolve, 300));
//
const selectedCategoryLabel = allCategoryOptions.value.find(cat => cat.value === selectedCategory.value)?.label || selectedCategory.value;
questionList.value.forEach(question => {
const selectedCategoryLabel = allCategoryOptions.value.find((cat: any) => cat.value === selectedCategory.value)?.label || selectedCategory.value;
questionList.value.forEach((question: any) => {
if (selectedRowKeys.value.includes(question.id)) {
question.category = selectedCategory.value;
}
@ -811,7 +771,7 @@ const addCategoryInManage = () => {
}
//
const exists = customCategories.value.some(cat => cat.label === trimmedName);
const exists = customCategories.value.some((cat: any) => cat.label === trimmedName);
if (exists) {
message.warning('该分类已存在');
return;
@ -841,13 +801,13 @@ const editCategory = (category: { label: string; value: string }) => {
const deleteCategory = (categoryValue: string) => {
// 使
const hasQuestions = questionList.value.some(q => q.category === categoryValue);
const hasQuestions = questionList.value.some((q: any) => q.category === categoryValue);
if (hasQuestions) {
message.warning('该分类下还有试题,不能删除');
return;
}
const index = customCategories.value.findIndex(cat => cat.value === categoryValue);
const index = customCategories.value.findIndex((cat: any) => cat.value === categoryValue);
if (index > -1) {
const categoryName = customCategories.value[index].label;
customCategories.value.splice(index, 1);