[]> {
+ console.log('🚀 批量添加题目答案:', { questionId, answers })
+
+ const promises = answers.map(answer =>
+ this.createQuestionAnswer({ ...answer, questionId })
+ )
+
+ const responses = await Promise.all(promises)
+ console.log('✅ 批量添加题目答案成功:', responses)
+ return responses
+ }
+}
+
+export default ExamApi
\ No newline at end of file
diff --git a/src/api/types.ts b/src/api/types.ts
index 97ad735..cf332b8 100644
--- a/src/api/types.ts
+++ b/src/api/types.ts
@@ -684,3 +684,134 @@ export interface Statistics {
count: number
}>
}
+
+// 考试题库相关类型
+export interface Repo {
+ id: string
+ title: string
+ remark: string
+ questionCount?: number
+ createBy: string
+ createTime: string
+ updateBy: string
+ updateTime: string
+}
+
+export interface Question {
+ id: string
+ parentId: string
+ type: number // 0单选题 1多选题 2判断题 3填空题 4简答题 5复合题
+ content: string
+ analysis: string
+ difficulty: number
+ score: number
+ createBy: string
+ createTime: string
+ updateBy: string
+ updateTime: string
+ options?: QuestionOption[]
+ answers?: QuestionAnswer[]
+}
+
+export interface QuestionOption {
+ id: string
+ questionId: string
+ content: string
+ izCorrent: number // 是否正确答案
+ orderNo: number
+ createBy: string
+ createTime: string
+ updateBy: string
+ updateTime: string
+}
+
+export interface QuestionAnswer {
+ id: string
+ questionId: string
+ answerText: string
+ orderNo: number
+ createBy: string
+ createTime: string
+ updateBy: string
+ updateTime: string
+}
+
+export interface QuestionRepo {
+ id: string
+ repoId: string
+ questionId: string
+ createBy: string
+ createTime: string
+ updateBy: string
+ updateTime: string
+}
+
+// 题库相关请求参数类型
+export interface CreateRepoRequest {
+ title: string
+ remark?: string
+}
+
+export interface UpdateRepoRequest {
+ id: string
+ title: string
+ remark?: string
+}
+
+export interface CreateQuestionRequest {
+ parentId?: string
+ type: number
+ content: string
+ analysis?: string
+ difficulty: number
+ score: number
+}
+
+export interface UpdateQuestionRequest {
+ id: string
+ parentId?: string
+ type: number
+ content: string
+ analysis?: string
+ difficulty: number
+ score: number
+}
+
+export interface CreateQuestionOptionRequest {
+ questionId: string
+ content: string
+ izCorrent: number
+ orderNo: number
+}
+
+export interface UpdateQuestionOptionRequest {
+ id: string
+ questionId: string
+ content: string
+ izCorrent: number
+ orderNo: number
+}
+
+export interface CreateQuestionAnswerRequest {
+ questionId: string
+ answerText: string
+ orderNo: number
+}
+
+export interface UpdateQuestionAnswerRequest {
+ id: string
+ questionId: string
+ answerText: string
+ orderNo: number
+}
+
+export interface CreateQuestionRepoRequest {
+ repoId: string
+ questionId: string
+}
+
+export interface UpdateQuestionRepoRequest {
+ id: string
+ repoId: string
+ questionId: string
+}
diff --git a/src/components/admin/ExamComponents/BatchSetScoreModal.vue b/src/components/admin/ExamComponents/BatchSetScoreModal.vue
index 561047a..9168882 100644
--- a/src/components/admin/ExamComponents/BatchSetScoreModal.vue
+++ b/src/components/admin/ExamComponents/BatchSetScoreModal.vue
@@ -12,24 +12,73 @@
class="big-question-section">
-
-
{{ bigIndex + 1 }}.{{ subIndex + 1 }}
-
- {{ subQuestion.title }}
+
+
+
+
{{ bigIndex + 1 }}.{{ subIndex + 1 }}
+
+ {{ subQuestion.title }}
+
+
{{ getQuestionTypeName(subQuestion.type) }}
- {{ getQuestionTypeName(subQuestion.type) }}
-
-
- 分数:
-
-
+
+ 分数:
+
+
+
+
+
+
+
+
+
+
+
{{ bigIndex + 1 }}.{{ subIndex + 1 }}
+
+ {{ subQuestion.title }}
+
+
{{ getQuestionTypeName(subQuestion.type) }}
+
+
+ 总分:
+ {{ getCompositeQuestionTotalScore(subQuestion) }}
+
+
+
+
+
+
+
+
{{ bigIndex + 1 }}.{{ subIndex + 1 }}.{{ compositeIndex + 1 }}
+
+ {{ compositeSubQ.title }}
+
+
{{ getQuestionTypeName(compositeSubQ.type) }}
+
+
+ 分数:
+
+
+
+
+
+
@@ -159,6 +208,33 @@ const updateQuestionScore = (bigIndex: number, subIndex: number, score: number)
}
};
+// 获取复合题总分
+const getCompositeQuestionTotalScore = (subQuestion: SubQuestion): number => {
+ if (subQuestion.type === QuestionType.COMPOSITE && subQuestion.subQuestions) {
+ return subQuestion.subQuestions.reduce((total, sq) => total + (sq.score || 0), 0);
+ }
+ return subQuestion.score || 0;
+};
+
+// 更新复合题子题目分数
+const updateCompositeSubQuestionScore = (bigIndex: number, subIndex: number, compositeIndex: number, score: number) => {
+ const bigQuestion = questionList.value[bigIndex];
+ const subQuestion = bigQuestion?.subQuestions[subIndex];
+
+ if (subQuestion && subQuestion.type === QuestionType.COMPOSITE && subQuestion.subQuestions) {
+ const compositeSubQ = subQuestion.subQuestions[compositeIndex];
+ if (compositeSubQ) {
+ compositeSubQ.score = score || 0;
+
+ // 重新计算复合题总分
+ subQuestion.score = subQuestion.subQuestions.reduce((total, sq) => total + (sq.score || 0), 0);
+
+ // 重新计算大题总分
+ bigQuestion.totalScore = bigQuestion.subQuestions.reduce((total, sub) => total + (sub.score || 0), 0);
+ }
+ }
+};
+
// 取消批量设置
const cancelBatchSet = () => {
showModal.value = false;
@@ -231,6 +307,41 @@ const confirmBatchSet = () => {
border-color: #d1e7dd;
}
+.composite-question {
+ background-color: #f0f8ff;
+ border-left: 3px solid #1890ff;
+}
+
+.composite-sub-question {
+ margin: 8px 0 8px 20px;
+ padding: 8px 12px;
+ border: 1px solid #d0d0d0;
+ border-radius: 4px;
+ background-color: #ffffff;
+ position: relative;
+}
+
+.composite-sub-question::before {
+ content: "└";
+ position: absolute;
+ left: -15px;
+ top: 8px;
+ color: #1890ff;
+ font-weight: bold;
+}
+
+.composite-sub-header {
+ font-weight: 500;
+ color: #666;
+ font-size: 14px;
+ margin-bottom: 6px;
+}
+
+.total-score {
+ font-weight: 600;
+ color: #1890ff;
+}
+
.question-info {
display: flex;
align-items: center;
diff --git a/src/components/admin/ExamComponents/ExamSettingsModal.vue b/src/components/admin/ExamComponents/ExamSettingsModal.vue
index e8e772f..a96c790 100644
--- a/src/components/admin/ExamComponents/ExamSettingsModal.vue
+++ b/src/components/admin/ExamComponents/ExamSettingsModal.vue
@@ -21,6 +21,11 @@
+
+
+
+
+
@@ -323,6 +328,8 @@ interface ExamSettings {
useLastScore: boolean; // 最后一次练习成绩为最终成绩
};
paperMode: 'show_all' | 'show_current' | 'hide_all';
+ // 新增考试人数限制字段
+ maxParticipants: number | null;
}
// Props 定义
@@ -396,6 +403,8 @@ const formData = ref({
useLastScore: false,
},
paperMode: 'show_all',
+ // 新增考试人数限制字段
+ maxParticipants: null,
});
// 监听 props.examData 变化,更新本地副本
diff --git a/src/components/teacher/CompositeQuestion.vue b/src/components/teacher/CompositeQuestion.vue
index 67462d3..aab5801 100644
--- a/src/components/teacher/CompositeQuestion.vue
+++ b/src/components/teacher/CompositeQuestion.vue
@@ -166,7 +166,10 @@ let nextId = 1
// 监听props变化
watch(() => props.modelValue, (newValue) => {
if (newValue?.subQuestions) {
- subQuestions.value = newValue.subQuestions
+ subQuestions.value = newValue.subQuestions.map(sq => ({ ...sq }));
+ console.log('CompositeQuestion props 更新:', {
+ newSubQuestions: subQuestions.value.map(sq => ({ id: sq.id, title: sq.title, score: sq.score }))
+ });
}
}, { deep: true })
diff --git a/src/main.ts b/src/main.ts
index a680591..58457e9 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -85,6 +85,7 @@ import {
NTimeline,
NTimelineItem,
NMessageProvider,
+ NDialogProvider,
NPopselect
} from 'naive-ui'
@@ -159,6 +160,7 @@ const naive = create({
NTimeline,
NTimelineItem,
NMessageProvider,
+ NDialogProvider,
NPopselect
]
})
diff --git a/src/router/index.ts b/src/router/index.ts
index 1faa399..a4694c9 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -62,6 +62,7 @@ import HomeworkTemplateImport from '@/views/teacher/course/HomeworkTemplateImpor
// 考试管理组件
import ExamManagement from '@/views/teacher/ExamPages/ExamPage.vue'
+import ExamQuestionBankManagement from '@/views/teacher/ExamPages/QuestionBankManagement.vue'
import QuestionManagement from '@/views/teacher/ExamPages/QuestionManagement.vue'
import ExamLibrary from '@/views/teacher/ExamPages/ExamLibrary.vue'
import MarkingCenter from '@/views/teacher/ExamPages/MarkingCenter.vue'
@@ -69,6 +70,7 @@ import AddExam from '@/views/teacher/ExamPages/AddExam.vue'
import AddQuestion from '@/views/teacher/ExamPages/AddQuestion.vue'
import StudentList from '@/views/teacher/ExamPages/StudentList.vue'
import GradingPage from '@/views/teacher/ExamPages/GradingPage.vue'
+import ExamTaking from '@/views/teacher/ExamPages/ExamTaking.vue'
import ChapterEditor from '@/views/teacher/course/ChapterEditor.vue'
@@ -293,10 +295,16 @@ const routes: RouteRecordRaw[] = [
name: 'ExamManagement',
component: ExamManagement,
meta: { title: '考试管理' },
- redirect: '/teacher/exam-management/question-management',
+ redirect: '/teacher/exam-management/question-bank',
children: [
{
- path: 'question-management',
+ path: 'question-bank',
+ name: 'ExamQuestionBankManagement',
+ component: ExamQuestionBankManagement,
+ meta: { title: '题库管理' }
+ },
+ {
+ path: 'question-bank/:bankId/questions',
name: 'QuestionManagement',
component: QuestionManagement,
meta: { title: '试题管理' }
@@ -347,7 +355,7 @@ const routes: RouteRecordRaw[] = [
meta: { title: '试卷预览' }
},
{
- path: 'add-question/:id?',
+ path: 'add-question/:id/:questionId?',
name: 'AddQuestionPage',
component: AddQuestion,
meta: { title: '添加试题' }
@@ -357,7 +365,12 @@ const routes: RouteRecordRaw[] = [
]
},
-
+ {
+ path: '/taking/:id',
+ name: 'ExamTaking',
+ component: ExamTaking,
+ meta: { title: '考试进行中' }
+ },
// 帮助中心
{
diff --git a/src/views/teacher/AdminDashboard.vue b/src/views/teacher/AdminDashboard.vue
index a6734bf..2ee9bd4 100644
--- a/src/views/teacher/AdminDashboard.vue
+++ b/src/views/teacher/AdminDashboard.vue
@@ -36,10 +36,10 @@
@@ -208,15 +223,19 @@
+
+
diff --git a/src/views/teacher/ExamPages/QuestionManagement.vue b/src/views/teacher/ExamPages/QuestionManagement.vue
index 8a5cd60..de07558 100644
--- a/src/views/teacher/ExamPages/QuestionManagement.vue
+++ b/src/views/teacher/ExamPages/QuestionManagement.vue
@@ -1,7 +1,17 @@
+
+
+
+
+ 题库管理
+
+ {{ currentBankName }}
+
+
+
阅卷评语:
+