fix(前端): 修复 ID 类型和分页 total 类型不匹配问题

- 将 Props 中 ID 字段从 number 改为 number | string,兼容后端 Long 序列化为 String
- 修复分页组件 total 字段类型,使用 Number() 转换避免 Vue warn
- 影响组件: PrepareNavigation, LessonCard, SelectLessonsModal 等
- 影响视图: StudentListView, TeacherListView, ParentListView 等
This commit is contained in:
En 2026-03-25 10:47:19 +08:00
parent 5c9be63347
commit 55343ead0b
34 changed files with 39 additions and 38 deletions

View File

@ -4,7 +4,8 @@
"Bash(mvn compile:*)",
"Bash(sed:*)",
"Bash(grep:*)",
"Bash(export:*)"
"Bash(export:*)",
"Bash(git:*)"
]
}
}

View File

@ -133,7 +133,7 @@ import type { Theme } from '@/api/theme';
interface BasicInfoData {
name: string;
themeId: number | undefined;
themeId: number | string | undefined;
grades: string[];
pictureBookName: string;
coreContent: string;

View File

@ -63,7 +63,7 @@ import { getLessonByType, createLesson, updateLesson, deleteLesson as deleteLess
import { parseAssessmentDataForDisplay } from '@/utils/assessmentData';
interface Props {
courseId: number;
courseId: number | string;
}
const props = defineProps<Props>();

View File

@ -63,7 +63,7 @@ import { getLessonByType, createLesson as createLessonApi, updateLesson, deleteL
import { parseAssessmentDataForDisplay } from '@/utils/assessmentData';
interface Props {
courseId: number;
courseId: number | string;
courseName: string;
}

View File

@ -106,7 +106,7 @@ interface DomainConfig {
}
interface Props {
courseId: number;
courseId: number | string;
courseName: string;
}

View File

@ -200,7 +200,7 @@ import LessonStepsEditor from './LessonStepsEditor.vue';
import type { StepData } from './LessonStepsEditor.vue';
export interface LessonData {
id?: number;
id?: number | string;
tempId?: string;
lessonType: string;
name: string;

View File

@ -95,7 +95,7 @@ import {
} from '@ant-design/icons-vue';
export interface StepData {
id?: number;
id?: number | string;
tempId?: string;
name: string;
content: string;

View File

@ -163,7 +163,7 @@ const fetchData = async () => {
...(filters.status ? { status: filters.status } : {}),
});
dataSource.value = data.items;
pagination.total = data.total;
pagination.total = Number(data.total);
} catch (error) {
console.error('获取套餐列表失败', error);
message.error('获取套餐列表失败');

View File

@ -267,7 +267,7 @@ const fetchCourses = async () => {
// API { items, total, page, pageSize }
courses.value = (data as any).items || [];
pagination.total = (data as any).total || 0;
pagination.total = Number((data as any).total) || 0;
console.log('📊 课程列表数据:', courses.value, '总数:', pagination.total);
} catch (error) {
console.error('获取课程包列表失败:', error);

View File

@ -250,7 +250,7 @@ const fetchCourses = async () => {
//
validationPassed: item.status !== 'REJECTED',
}));
pagination.total = data.total || 0;
pagination.total = Number(data.total) || 0;
} catch (error) {
console.error('获取审核列表失败:', error);
message.error('获取审核列表失败');

View File

@ -130,7 +130,7 @@ import type { Theme } from '@/api/theme';
interface BasicInfoData {
name: string;
themeId: number | undefined;
themeId: number | string | undefined;
grades: string[];
pictureBookName: string;
coreContent: string;

View File

@ -58,7 +58,7 @@ import type { LessonData } from '@/components/course/LessonConfigPanel.vue';
import { getLessonByType, createLesson, updateLesson, deleteLesson as deleteLessonApi } from '@/api/lesson';
interface Props {
courseId: number;
courseId: number | string;
}
const props = defineProps<Props>();

View File

@ -58,7 +58,7 @@ import type { LessonData } from '@/components/course/LessonConfigPanel.vue';
import { getLessonByType, createLesson as createLessonApi, updateLesson, deleteLesson as deleteLessonApi } from '@/api/lesson';
interface Props {
courseId: number;
courseId: number | string;
courseName: string;
}

View File

@ -101,7 +101,7 @@ interface DomainConfig {
}
interface Props {
courseId: number;
courseId: number | string;
courseName: string;
}

View File

@ -218,7 +218,7 @@ const fetchPackages = async () => {
pageSize: pagination.pageSize,
}) as any;
packages.value = res.list || [];
pagination.total = res.total || 0;
pagination.total = Number(res.total) || 0;
} catch (error) {
console.error('获取套餐列表失败:', error);
message.error('获取套餐列表失败');

View File

@ -511,7 +511,7 @@ const fetchItems = async () => {
...filters,
});
items.value = result?.list ?? [];
pagination.total = result?.total ?? 0;
pagination.total = Number(result?.total) ?? 0;
} catch (error) {
message.error('获取资源列表失败');
} finally {

View File

@ -483,7 +483,7 @@ const loadData = async () => {
collectionId: searchForm.collectionId,
});
tenants.value = res.list;
pagination.total = res.total;
pagination.total = Number(res.total);
} catch (error) {
console.error('加载租户列表失败', error);
} finally {

View File

@ -569,7 +569,7 @@ const loadClassStudents = async (classId: number) => {
pageSize: studentsPagination.pageSize,
});
classStudents.value = result.list;
studentsPagination.total = result.total;
studentsPagination.total = Number(result.total);
} catch (error) {
console.error('Failed to load class students:', error);
} finally {

View File

@ -246,7 +246,7 @@ const loading = ref(false);
const authLoading = ref(false);
const authModalVisible = ref(false);
const searchKeyword = ref('');
const selectedCourseIds = ref<number[]>([]);
const selectedCourseIds = ref<(number | string)[]>([]);
//
const filters = reactive({
@ -401,7 +401,7 @@ const searchCourses = () => {
}, 500);
};
const toggleCourseSelection = (id: number) => {
const toggleCourseSelection = (id: number | string) => {
const index = selectedCourseIds.value.indexOf(id);
if (index > -1) {
selectedCourseIds.value.splice(index, 1);

View File

@ -330,7 +330,7 @@ const fetchFeedbacks = async () => {
teacherId: filters.teacherId,
});
feedbacks.value = result.list;
pagination.total = result.total;
pagination.total = Number(result.total);
} catch (error) {
message.error('获取反馈列表失败');
} finally {

View File

@ -449,7 +449,7 @@ const loadParents = async () => {
keyword: searchKeyword.value || undefined,
});
parents.value = result.list;
pagination.total = result.total;
pagination.total = Number(result.total);
} catch (error) {
console.error('Failed to load parents:', error);
} finally {
@ -684,7 +684,7 @@ const loadStudentsForSelect = async () => {
classId: studentClassFilter.value || undefined,
});
studentTableData.value = result.list;
studentPagination.total = result.total;
studentPagination.total = Number(result.total);
} catch (error) {
console.error('Failed to load students:', error);
studentTableData.value = [];

View File

@ -219,7 +219,7 @@ const loadLogs = async () => {
...filters,
});
logs.value = res.list;
pagination.total = res.total;
pagination.total = Number(res.total);
} catch (error) {
message.error('加载日志失败');
} finally {
@ -241,7 +241,7 @@ const loadModules = async () => {
const loadStats = async () => {
try {
const res = await getOperationLogStats(filters.startDate, filters.endDate);
stats.total = res.total;
stats.total = Number(res.total);
stats.modules = res.modules || [];
} catch (error) {
console.error('加载统计失败', error);

View File

@ -444,7 +444,7 @@ const loadStudents = async () => {
keyword: searchKeyword.value || undefined,
});
students.value = result.list;
pagination.total = result.total;
pagination.total = Number(result.total);
} catch (error) {
console.error('Failed to load students:', error);
} finally {

View File

@ -329,7 +329,7 @@ const loadTeachers = async () => {
keyword: searchKeyword.value || undefined,
});
teachers.value = result.list;
pagination.total = result.total;
pagination.total = Number(result.total);
} catch (error) {
console.error('Failed to load teachers:', error);
} finally {

View File

@ -322,7 +322,7 @@ const loadCourses = async () => {
pictureUrl: item.coverImagePath ?? item.pictureUrl,
};
});
pagination.total = data.total || 0;
pagination.total = Number(data.total) || 0;
} catch (error: any) {
message.error(error.message || '获取课程列表失败');
} finally {

View File

@ -109,7 +109,7 @@ const loading = ref(false);
//
const selectedSection = ref<'overview' | 'lesson'>('overview');
const selectedLessonId = ref<number | null>(null);
const selectedLessonId = ref<number | string | null>(null);
const selectedItem = ref<string>('basic');
const selectedStep = ref<any>(null);

View File

@ -88,7 +88,7 @@ import {
const props = defineProps<{
lesson: any;
courseId: number;
courseId: number | string;
lessonType: string;
index: number;
}>();

View File

@ -278,7 +278,7 @@ const props = defineProps<{
course: any;
lessons: any[];
selectedSection: 'overview' | 'lesson';
selectedLessonId: number | null;
selectedLessonId: number | string | null;
selectedItem: string;
}>();

View File

@ -117,7 +117,7 @@ const props = defineProps<{
const emit = defineEmits<{
'update:open': [value: boolean];
'confirm': [lessonIds: number[], mode: string];
'confirm': [lessonIds: (number | string)[], mode: string];
}>();
const visible = computed({
@ -126,7 +126,7 @@ const visible = computed({
});
const selectionMode = ref<'all' | 'custom'>('all');
const selectedLessonIds = ref<number[]>([]);
const selectedLessonIds = ref<(number | string)[]>([]);
//
const introductionLesson = computed(() =>

View File

@ -308,7 +308,7 @@ const fetchFeedbacks = async () => {
pageSize: pagination.pageSize,
});
feedbacks.value = result.items;
pagination.total = result.total;
pagination.total = Number(result.total);
} catch (error) {
message.error('获取反馈列表失败');
} finally {

View File

@ -335,7 +335,7 @@ const loadRecords = async () => {
keyword: filters.keyword || undefined,
});
records.value = res.list || [];
pagination.total = res.total || 0;
pagination.total = Number(res.total) || 0;
} catch (error) {
message.error('加载档案失败');
} finally {

View File

@ -11,7 +11,7 @@
import Step4IntroLessonAdmin from '@/components/course-edit/Step4IntroLesson.vue';
defineProps<{
schoolCourseId: number;
schoolCourseId: number | string;
lessonData?: any;
}>();

View File

@ -12,7 +12,7 @@
import Step5CollectiveLessonAdmin from '@/components/course-edit/Step5CollectiveLesson.vue';
defineProps<{
schoolCourseId: number;
schoolCourseId: number | string;
lessonData?: any;
}>();

View File

@ -12,7 +12,7 @@
import Step6DomainLessonsAdmin from '@/components/course-edit/Step6DomainLessons.vue';
defineProps<{
schoolCourseId: number;
schoolCourseId: number | string;
domainLessons?: {
LANGUAGE?: any;
HEALTH?: any;