feat:hls流误删导致视频报错,作业资料接口对接,逻辑处理下载,课程列表按钮按照 后端请求分为需传token 和不需要根据是否登录判断

This commit is contained in:
小张 2025-09-05 19:46:11 +08:00
parent 71ea0bbfb4
commit 6b685501dd
3 changed files with 433 additions and 79 deletions

View File

@ -117,7 +117,7 @@ export class ExamApi {
*/ */
static async getQuestionDetail(questionId: string): Promise<ApiResponse<Question>> { static async getQuestionDetail(questionId: string): Promise<ApiResponse<Question>> {
console.log('🚀 查询题目详情:', { questionId }) console.log('🚀 查询题目详情:', { questionId })
const response = await ApiRequest.get<Question>(`/biz/repo/repoList/${questionId}`) const response = await ApiRequest.get<Question>(`/aiol/aiolRepo/repoList/${questionId}`)
console.log('✅ 查询题目详情成功:', response) console.log('✅ 查询题目详情成功:', response)
return response return response
} }
@ -127,7 +127,7 @@ export class ExamApi {
*/ */
static async createQuestion(data: CreateQuestionRequest): Promise<ApiResponse<string>> { static async createQuestion(data: CreateQuestionRequest): Promise<ApiResponse<string>> {
console.log('🚀 添加题目:', data) console.log('🚀 添加题目:', data)
const response = await ApiRequest.post<string>('/gen/question/question/add', data) const response = await ApiRequest.post<string>('/aiol/aiolQuestion/add', data)
console.log('✅ 添加题目成功:', response) console.log('✅ 添加题目成功:', response)
return response return response
} }
@ -137,7 +137,7 @@ export class ExamApi {
*/ */
static async updateQuestion(data: UpdateQuestionRequest): Promise<ApiResponse<string>> { static async updateQuestion(data: UpdateQuestionRequest): Promise<ApiResponse<string>> {
console.log('🚀 编辑题目:', data) console.log('🚀 编辑题目:', data)
const response = await ApiRequest.put<string>('/gen/question/question/edit', data) const response = await ApiRequest.put<string>('/aiol/aiolQuestion/edit', data)
console.log('✅ 编辑题目成功:', response) console.log('✅ 编辑题目成功:', response)
return response return response
} }
@ -145,15 +145,15 @@ export class ExamApi {
/** /**
* *
*/ */
static async deleteQuestion(id: string): Promise<ApiResponse<string>> { static async deleteQuestion(questionId: string): Promise<ApiResponse<string>> {
console.log('🚀 删除题目:', { id }) console.log('🚀 删除题目:', { questionId })
const response = await ApiRequest.delete<string>('/gen/question/question/delete', { const response = await ApiRequest.delete<string>(`/aiol/aiolQuestion/delete?id=${questionId}`)
params: { id }
})
console.log('✅ 删除题目成功:', response) console.log('✅ 删除题目成功:', response)
return response return response
} }
// ========== 题目选项管理 ========== // ========== 题目选项管理 ==========
/** /**

View File

@ -263,6 +263,19 @@ const message = useMessage();
const questionId = route.params.questionId as string | undefined; const questionId = route.params.questionId as string | undefined;
const isEditMode = ref(!!questionId); const isEditMode = ref(!!questionId);
//
const getQuestionTypeKey = (type: number): string => {
const typeMap: { [key: number]: string } = {
0: 'single_choice', //
1: 'multiple_choice', //
2: 'true_false', //
3: 'fill_blank', //
4: 'short_answer', //
5: 'composite' //
};
return typeMap[type] || 'single_choice';
};
// //
const formRef = ref(); const formRef = ref();
@ -288,16 +301,16 @@ const categoryOptions = ref([
// //
const difficultyOptions = ref([ const difficultyOptions = ref([
{ label: '简单', value: 'easy' }, { label: '简单', value: 0 },
{ label: '中等', value: 'medium' }, { label: '中等', value: 1 },
{ label: '困难', value: 'hard' } { label: '困难', value: 2 }
]); ]);
// //
const questionForm = reactive({ const questionForm = reactive({
type: 'single_choice', // type: 'single_choice', //
category: '', category: '',
difficulty: '', difficulty: 0, //
score: 10, score: 10,
title: '', title: '',
options: [ options: [
@ -323,12 +336,13 @@ const formRules = {
trigger: 'change' trigger: 'change'
}, },
category: { category: {
required: true, required: false,
message: '请选择分类', message: '请选择分类',
trigger: 'change' trigger: 'change'
}, },
difficulty: { difficulty: {
required: true, required: true,
type: 'number',
message: '请选择难度', message: '请选择难度',
trigger: 'change' trigger: 'change'
}, },
@ -397,14 +411,20 @@ const getQuestionTypeNumber = (type: string): number => {
return typeMap[type] || 0; return typeMap[type] || 0;
}; };
// //
const getDifficultyNumber = (difficulty: string): number => { const getDifficultyNumber = (difficulty: number | string): number => {
//
if (typeof difficulty === 'number') {
return difficulty;
}
//
const difficultyMap: Record<string, number> = { const difficultyMap: Record<string, number> = {
'easy': 1, // 'easy': 0, //
'medium': 2, // 'medium': 1, //
'hard': 3 // 'hard': 2 //
}; };
return difficultyMap[difficulty] || 1; return difficultyMap[difficulty] || 0;
}; };
// //
@ -478,8 +498,9 @@ const saveQuestion = async () => {
// //
const createNewQuestion = async (bankId: string) => { const createNewQuestion = async (bankId: string) => {
try { try {
// questionId // API
const questionData = { const questionData = {
parentId: null, // IDnull
type: getQuestionTypeNumber(questionForm.type), type: getQuestionTypeNumber(questionForm.type),
content: questionForm.title, content: questionForm.title,
analysis: questionForm.explanation || '', analysis: questionForm.explanation || '',
@ -487,37 +508,33 @@ const createNewQuestion = async (bankId: string) => {
score: questionForm.score score: questionForm.score
}; };
console.log('🚀 第一步:创建题目题干:', questionData); console.log('🚀 创建题目,数据:', questionData);
const questionResponse = await ExamApi.createQuestion(questionData); const response = await ExamApi.createQuestion(questionData);
console.log('📊 创建题目API响应:', response);
if (!questionResponse.data) { // API
throw new Error('创建题目失败未返回题目ID'); let success = false;
let questionId = null;
if (response.data) {
const apiResponse = response.data as any;
// {success, code, result}
if (typeof apiResponse === 'object' && ('success' in apiResponse || 'code' in apiResponse)) {
success = apiResponse.success === true || apiResponse.code === 200 || apiResponse.code === 0;
questionId = apiResponse.result || apiResponse.data;
} else {
// ID
success = true;
questionId = apiResponse;
}
} }
const createdQuestionId = questionResponse.data; if (!success) {
console.log('✅ 题目创建成功questionId:', createdQuestionId); throw new Error('创建题目失败');
//
if (questionForm.type === 'single_choice') {
await handleSingleChoiceQuestion(createdQuestionId);
} }
// TODO:
// else if (questionForm.type === 'multiple_choice') {
// await handleMultipleChoiceQuestion(createdQuestionId);
// } else if (questionForm.type === 'true_false') {
// await handleTrueFalseQuestion(createdQuestionId);
// }
//
// console.log('✅ 题目创建成功题目ID:', questionId);
const questionRepoData = {
repoId: bankId,
questionId: createdQuestionId
};
console.log('🚀 最后一步:绑定题目到题库:', questionRepoData);
await ExamApi.createQuestionRepo(questionRepoData);
console.log('✅ 题目绑定到题库成功');
message.success('题目保存成功'); message.success('题目保存成功');
@ -772,36 +789,252 @@ const validateCompositeQuestion = (): boolean => {
// //
onMounted(async () => { onMounted(async () => {
console.log('AddQuestion 组件挂载完成');
console.log('编辑模式:', isEditMode.value);
console.log('题目ID:', questionId);
// //
if (isEditMode.value && questionId) { if (isEditMode.value && questionId) {
await loadQuestionData(questionId); //
if (route.query.questionData) {
try {
const questionData = JSON.parse(route.query.questionData as string);
console.log('📊 从路由参数获取题目数据:', questionData);
renderQuestionData(questionData);
} catch (error) {
console.error('❌ 解析路由参数中的题目数据失败:', error);
// API
await loadQuestionData(questionId);
}
} else {
// API
await loadQuestionData(questionId);
}
} }
}); });
//
const renderQuestionData = (questionData: any) => {
console.log('🎨 开始渲染题目数据:', questionData);
if (!questionData) return;
const { question, answer = [], children = [] } = questionData;
if (question) {
//
questionForm.type = getQuestionTypeKey(question.type);
questionForm.title = question.content || '';
questionForm.explanation = question.analysis || '';
questionForm.score = question.score || 10;
questionForm.difficulty = question.difficulty || 0;
console.log('📝 题目基本信息:', {
type: questionForm.type,
title: questionForm.title,
explanation: questionForm.explanation,
score: questionForm.score
});
//
if (question.type === 0) { //
renderSingleChoiceData(answer);
} else if (question.type === 1) { //
renderMultipleChoiceData(answer);
} else if (question.type === 2) { //
renderTrueFalseData(answer);
} else if (question.type === 3) { //
renderFillBlankData(answer);
} else if (question.type === 4) { //
renderShortAnswerData(answer);
} else if (question.type === 5) { //
renderCompositeData(children);
}
}
};
//
const renderSingleChoiceData = (answers: any[]) => {
console.log('🔘 渲染单选题数据:', answers);
if (answers && answers.length > 0) {
// orderNo
const sortedAnswers = answers.sort((a, b) => a.orderNo - b.orderNo);
//
questionForm.options = sortedAnswers.map(answer => ({
content: answer.content || ''
}));
// orderNo10
const correctAnswer = sortedAnswers.find(answer => answer.izCorrent === 1);
if (correctAnswer) {
questionForm.correctAnswer = correctAnswer.orderNo - 1;
}
console.log('✅ 单选题渲染完成:', {
options: questionForm.options,
correctAnswer: questionForm.correctAnswer
});
}
};
//
const renderMultipleChoiceData = (answers: any[]) => {
console.log('☑️ 渲染多选题数据:', answers);
if (answers && answers.length > 0) {
// orderNo
const sortedAnswers = answers.sort((a, b) => a.orderNo - b.orderNo);
//
questionForm.options = sortedAnswers.map(answer => ({
content: answer.content || ''
}));
//
questionForm.correctAnswers = sortedAnswers
.filter(answer => answer.izCorrent === 1)
.map(answer => answer.orderNo - 1);
console.log('✅ 多选题渲染完成:', {
options: questionForm.options,
correctAnswers: questionForm.correctAnswers
});
}
};
//
const renderTrueFalseData = (answers: any[]) => {
console.log('✔️ 渲染判断题数据:', answers);
if (answers && answers.length > 0) {
const correctAnswer = answers.find(answer => answer.izCorrent === 1);
if (correctAnswer) {
// content""""
questionForm.trueFalseAnswer = correctAnswer.content === '正确' || correctAnswer.content === 'true';
}
console.log('✅ 判断题渲染完成:', {
trueFalseAnswer: questionForm.trueFalseAnswer
});
}
};
//
const renderFillBlankData = (answers: any[]) => {
console.log('📝 渲染填空题数据:', answers);
if (answers && answers.length > 0) {
questionForm.fillBlankAnswers = answers.map(answer => ({
content: answer.content || '',
score: 1,
caseSensitive: false
}));
console.log('✅ 填空题渲染完成:', {
fillBlankAnswers: questionForm.fillBlankAnswers
});
}
};
//
const renderShortAnswerData = (answers: any[]) => {
console.log('📄 渲染简答题数据:', answers);
if (answers && answers.length > 0) {
questionForm.shortAnswer = answers[0]?.content || '';
console.log('✅ 简答题渲染完成:', {
shortAnswer: questionForm.shortAnswer
});
}
};
//
const renderCompositeData = (children: any[]) => {
console.log('🔗 渲染复合题数据:', children);
if (children && children.length > 0) {
questionForm.compositeData = {
subQuestions: children.map((child: any) => ({
id: child.question?.id,
type: getQuestionTypeKey(child.question?.type || 0),
title: child.question?.content || '',
explanation: child.question?.analysis || '',
score: child.question?.score || 1,
options: child.answer || [],
correctAnswer: null,
correctAnswers: []
}))
};
console.log('✅ 复合题渲染完成:', {
subQuestions: questionForm.compositeData.subQuestions.length
});
}
};
// 使 // 使
const loadQuestionData = async (id: string) => { const loadQuestionData = async (id: string) => {
try { try {
// TODO: console.log('🚀 开始加载题目数据题目ID:', id);
// const response = await ExamApi.getQuestionDetail(id);
// if (response.data) { //
// // const response = await ExamApi.getQuestionDetail(id);
// } console.log('📊 题目详情API响应:', response);
console.log('加载题目数据题目ID:', id);
message.info('编辑模式数据加载暂未实现'); // API
let questionData = null;
let success = false;
if (response.data) {
const apiResponse = response.data as any;
// {success, code, result}
if (typeof apiResponse === 'object' && 'result' in apiResponse) {
success = apiResponse.success === true || apiResponse.code === 200 || apiResponse.code === 0;
questionData = apiResponse.result;
} else {
//
success = true;
questionData = apiResponse;
}
}
if (success && questionData) {
console.log('✅ 获取题目详情成功,开始渲染数据');
renderQuestionData(questionData);
} else {
console.error('❌ 获取题目详情失败');
message.error('获取题目详情失败');
}
} catch (error) { } catch (error) {
console.error('加载题目数据错误:', error); console.error('❌ 加载题目数据异常:', error);
message.error('加载题目数据失败,请检查网络连接'); message.error('加载题目数据失败,请检查网络连接');
} }
}; };
const getDifficultyLabel = (difficulty: string): string => { const getDifficultyLabel = (difficulty: number | string): string => {
const difficultyMap: { [key: string]: string } = { const difficultyMap: { [key: number]: string } = {
0: '简单',
1: '中等',
2: '困难'
};
//
if (typeof difficulty === 'number') {
return difficultyMap[difficulty] || '未知';
}
//
const stringMap: { [key: string]: string } = {
'easy': '简单', 'easy': '简单',
'medium': '中等', 'medium': '中等',
'hard': '困难' 'hard': '困难'
}; };
return difficultyMap[difficulty] || difficulty; return stringMap[difficulty] || difficulty;
}; };
const getCategoryLabel = (category: string): string => { const getCategoryLabel = (category: string): string => {

View File

@ -302,6 +302,11 @@ const createColumns = ({
width: 300, width: 300,
ellipsis: { ellipsis: {
tooltip: true tooltip: true
},
render(row: Question) {
//
const prefix = row.parentId ? '  └ ' : '';
return prefix + row.title;
} }
}, },
{ {
@ -311,11 +316,12 @@ const createColumns = ({
align: 'center' as const, align: 'center' as const,
render(row: Question) { render(row: Question) {
const typeMap: { [key: string]: { text: string; type: any } } = { const typeMap: { [key: string]: { text: string; type: any } } = {
'single_choice': { text: '单选题', type: 'info' }, '单选题': { text: '单选题', type: 'info' },
'multiple_choice': { text: '多选题', type: 'warning' }, '多选题': { text: '多选题', type: 'warning' },
'true_false': { text: '判断题', type: 'success' }, '判断题': { text: '判断题', type: 'success' },
'fill_blank': { text: '填空题', type: 'error' }, '填空题': { text: '填空题', type: 'error' },
'short_answer': { text: '简答题', type: 'default' } '简答题': { text: '简答题', type: 'default' },
'复合题': { text: '复合题', type: 'primary' }
}; };
const typeInfo = typeMap[row.type] || { text: row.type, type: 'default' }; const typeInfo = typeMap[row.type] || { text: row.type, type: 'default' };
return h(NTag, { type: typeInfo.type, size: 'small' }, { default: () => typeInfo.text }); return h(NTag, { type: typeInfo.type, size: 'small' }, { default: () => typeInfo.text });
@ -338,9 +344,9 @@ const createColumns = ({
align: 'center' as const, align: 'center' as const,
render(row: Question) { render(row: Question) {
const difficultyMap: { [key: string]: { text: string; type: any } } = { const difficultyMap: { [key: string]: { text: string; type: any } } = {
'easy': { text: '易', type: 'success' }, '简单': { text: '简单', type: 'success' },
'medium': { text: '中', type: 'warning' }, '中等': { text: '中', type: 'warning' },
'hard': { text: '难', type: 'error' } '困难': { text: '难', type: 'error' }
}; };
const diffInfo = difficultyMap[row.difficulty] || { text: row.difficulty, type: 'default' }; const diffInfo = difficultyMap[row.difficulty] || { text: row.difficulty, type: 'default' };
return h(NTag, { type: diffInfo.type, size: 'small' }, { default: () => diffInfo.text }); return h(NTag, { type: diffInfo.type, size: 'small' }, { default: () => diffInfo.text });
@ -450,6 +456,29 @@ const searchQuestions = () => {
loadQuestions(); loadQuestions();
}; };
//
const getQuestionTypeText = (type: number): string => {
const typeMap: { [key: number]: string } = {
0: '单选题',
1: '多选题',
2: '判断题',
3: '填空题',
4: '简答题',
5: '复合题'
};
return typeMap[type] || '未知类型';
};
//
const getDifficultyText = (difficulty: number): string => {
const difficultyMap: { [key: number]: string } = {
0: '简单',
1: '中等',
2: '困难'
};
return difficultyMap[difficulty] || '未知';
};
// //
const loadQuestions = async () => { const loadQuestions = async () => {
loading.value = true; loading.value = true;
@ -463,18 +492,20 @@ const loadQuestions = async () => {
let allData: Question[] = []; let allData: Question[] = [];
// API // API
if (response.code === 200 && response.data) { if (response.data && (response.data.code === 200 || response.data.code === 0) && response.data.result) {
// API // API
allData = response.data.map((item: any, index: number) => ({ allData = response.data.result.map((item: any, index: number) => ({
id: item.id || `question_${index}`, id: item.id || `question_${index}`,
sequence: index + 1, sequence: index + 1,
title: item.title || item.content || '题目内容', title: item.content || '题目内容',
type: item.type || '单选题', type: getQuestionTypeText(item.type),
category: item.category || '未分类', category: item.category || '未分类',
difficulty: item.difficulty || '简单', difficulty: getDifficultyText(item.difficulty),
score: item.score || 10, score: item.score || 10,
creator: item.createBy || item.creator || '未知', creator: item.createBy || '未知',
createTime: item.createTime || new Date().toISOString() createTime: item.createTime || new Date().toISOString(),
parentId: item.parentId,
analysis: item.analysis
})); }));
console.log('✅ 题目数据转换成功:', allData.length, '条题目'); console.log('✅ 题目数据转换成功:', allData.length, '条题目');
} else { } else {
@ -560,13 +591,103 @@ const deleteSelected = () => {
console.log('批量删除:', selectedRowKeys.value); console.log('批量删除:', selectedRowKeys.value);
}; };
const editQuestion = (id: string) => { const editQuestion = async (id: string) => {
console.log('编辑题目:', id); console.log('🔍 编辑题目题目ID:', id);
router.push(`/teacher/exam-management/add-question/${currentBankId.value}/${id}`);
try {
//
console.log('🚀 调用题目详情接口...');
const response = await ExamApi.getQuestionDetail(id);
console.log('📊 题目详情API响应:', response);
// API
let questionData = null;
let success = false;
if (response.data) {
// 使API
const apiResponse = response.data as any;
// {success, code, result}
if (typeof apiResponse === 'object' && 'result' in apiResponse) {
success = apiResponse.success === true || apiResponse.code === 200 || apiResponse.code === 0;
questionData = apiResponse.result;
} else {
//
success = true;
questionData = apiResponse;
}
}
if (success && questionData) {
console.log('✅ 获取题目详情成功:', questionData);
//
router.push({
path: `/teacher/exam-management/add-question/${currentBankId.value}/${id}`,
query: {
questionData: JSON.stringify(questionData),
mode: 'edit'
}
});
} else {
console.error('❌ 获取题目详情失败:', response);
message.error('获取题目详情失败');
}
} catch (error) {
console.error('❌ 获取题目详情异常:', error);
message.error('获取题目详情失败,请稍后重试');
}
}; };
const deleteQuestion = (id: string) => { const deleteQuestion = async (id: string) => {
console.log('删除题目:', id); console.log('🗑️ 删除题目题目ID:', id);
try {
//
const confirmed = await new Promise((resolve) => {
const dialog = window.confirm('确定要删除这道题目吗?删除后将无法恢复!');
resolve(dialog);
});
if (!confirmed) {
console.log('用户取消删除');
return;
}
console.log('🚀 调用删除题目API...');
const response = await ExamApi.deleteQuestion(id);
console.log('📊 删除题目API响应:', response);
// API
let success = false;
if (response.data) {
const apiResponse = response.data as any;
// {success, code, result}
if (typeof apiResponse === 'object' && ('success' in apiResponse || 'code' in apiResponse)) {
success = apiResponse.success === true || apiResponse.code === 200 || apiResponse.code === 0;
} else {
//
success = true;
}
}
if (success) {
console.log('✅ 删除题目成功');
message.success('题目删除成功');
//
await loadQuestions();
} else {
console.error('❌ 删除题目失败');
message.error('删除题目失败');
}
} catch (error) {
console.error('❌ 删除题目异常:', error);
message.error('删除题目失败,请稍后重试');
}
}; };
// //