Commit 2b6a8092 authored by Administrator's avatar Administrator
Browse files

added basic tasks calendar page; modified Student/Subject/Term to use pagenization APIs.

parent 8752832b
......@@ -6,7 +6,7 @@ const API_BASE_URL = 'http://192.168.1.52:8001'
// 创建axios实例
const apiClient = axios.create({
baseURL: API_BASE_URL,
timeout: 10000,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
......
import apiClient, { apiEndpoints } from './index.js'
/**
* 通用的获取所有分页数据的函数
* @param {Function} apiCall - API调用函数
* @param {Object} params - 查询参数
* @returns {Promise<Array>} 所有页面的数据数组
*/
const fetchAllPages = async (apiCall, params = {}) => {
let allData = []
let page = 1
let hasNext = true
console.log('Starting to fetch all pages for API call...')
while (hasNext) {
try {
const currentParams = { ...params, page, page_size: 100 } // 每页100条,减少请求次数
console.log(`Fetching page ${page} with params:`, currentParams)
const response = await apiCall(currentParams)
if (response && response.results) {
// 分页格式响应
allData = [...allData, ...response.results]
hasNext = !!response.next
console.log(`Page ${page}: Got ${response.results.length} items, total so far: ${allData.length}, hasNext: ${hasNext}`)
} else if (Array.isArray(response)) {
// 非分页格式响应(向后兼容)
allData = response
hasNext = false
console.log('Non-paginated response detected, got all data at once:', allData.length, 'items')
} else {
console.log('Unexpected response format, stopping pagination')
hasNext = false
}
page++
// 安全检查:防止无限循环
if (page > 100) {
console.warn('Reached maximum page limit (100), stopping pagination')
break
}
} catch (error) {
console.error(`Error fetching page ${page}:`, error)
throw error
}
}
console.log(`Finished fetching all pages. Total items: ${allData.length}`)
return allData
}
/**
* 单页API调用函数(内部使用)
* @param {Object} params - 查询参数(包含分页参数)
* @returns {Promise} API响应
*/
const getStudentsPage = async (params = {}) => {
const response = await apiClient.get(apiEndpoints.STUDENTS.LIST, { params })
return response.data
}
// Get student list
export const getStudents = async () => {
try {
const response = await apiClient.get(apiEndpoints.STUDENTS.LIST)
return response.data
console.log('Fetching all students with pagination support...')
// 使用通用分页函数获取所有数据
const allStudents = await fetchAllPages(getStudentsPage)
console.log('Students API final result:', {
totalCount: allStudents.length,
sampleData: allStudents.slice(0, 3) // 显示前3条数据作为样例
})
return allStudents
} catch (error) {
console.error('Failed to fetch students:', error)
throw new Error(error?.response?.data?.detail || error?.message || 'Failed to fetch students')
}
}
......
import apiClient, { apiEndpoints } from './index.js'
/**
* 通用的获取所有分页数据的函数
* @param {Function} apiCall - API调用函数
* @param {Object} params - 查询参数
* @returns {Promise<Array>} 所有页面的数据数组
*/
const fetchAllPages = async (apiCall, params = {}) => {
let allData = []
let page = 1
let hasNext = true
console.log('Starting to fetch all pages for API call...')
while (hasNext) {
try {
const currentParams = { ...params, page, page_size: 100 } // 每页100条,减少请求次数
console.log(`Fetching page ${page} with params:`, currentParams)
const response = await apiCall(currentParams)
if (response && response.results) {
// 分页格式响应
allData = [...allData, ...response.results]
hasNext = !!response.next
console.log(`Page ${page}: Got ${response.results.length} items, total so far: ${allData.length}, hasNext: ${hasNext}`)
} else if (Array.isArray(response)) {
// 非分页格式响应(向后兼容)
allData = response
hasNext = false
console.log('Non-paginated response detected, got all data at once:', allData.length, 'items')
} else {
console.log('Unexpected response format, stopping pagination')
hasNext = false
}
page++
// 安全检查:防止无限循环
if (page > 100) {
console.warn('Reached maximum page limit (100), stopping pagination')
break
}
} catch (error) {
console.error(`Error fetching page ${page}:`, error)
throw error
}
}
console.log(`Finished fetching all pages. Total items: ${allData.length}`)
return allData
}
/**
* 单页API调用函数(内部使用)
* @param {Object} params - 查询参数(包含分页参数)
* @returns {Promise} API响应
*/
const getSubjectsPage = async (params = {}) => {
const response = await apiClient.get(apiEndpoints.SUBJECTS.LIST, { params })
return response.data
}
// Get subject list
export const getSubjects = async () => {
try {
const response = await apiClient.get(apiEndpoints.SUBJECTS.LIST)
return response.data
console.log('Fetching all subjects with pagination support...')
// 使用通用分页函数获取所有数据
const allSubjects = await fetchAllPages(getSubjectsPage)
console.log('Subjects API final result:', {
totalCount: allSubjects.length,
sampleData: allSubjects.slice(0, 3) // 显示前3条数据作为样例
})
return allSubjects
} catch (error) {
console.error('Failed to fetch subjects:', error)
throw new Error(error?.response?.data?.detail || error?.message || 'Failed to fetch subjects')
}
}
......
import apiClient from './index.js'
/**
* 通用的获取所有分页数据的函数
* @param {Function} apiCall - API调用函数
* @param {Object} params - 查询参数
* @returns {Promise<Array>} 所有页面的数据数组
*/
const fetchAllPages = async (apiCall, params = {}) => {
let allData = []
let page = 1
let hasNext = true
console.log('Starting to fetch all pages for API call...')
while (hasNext) {
try {
const currentParams = { ...params, page, page_size: 100 } // 每页100条,减少请求次数
console.log(`Fetching page ${page} with params:`, currentParams)
const response = await apiCall(currentParams)
if (response && response.results) {
// 分页格式响应
allData = [...allData, ...response.results]
hasNext = !!response.next
console.log(`Page ${page}: Got ${response.results.length} items, total so far: ${allData.length}, hasNext: ${hasNext}`)
} else if (Array.isArray(response)) {
// 非分页格式响应(向后兼容)
allData = response
hasNext = false
console.log('Non-paginated response detected, got all data at once:', allData.length, 'items')
} else {
console.log('Unexpected response format, stopping pagination')
hasNext = false
}
page++
// 安全检查:防止无限循环
if (page > 100) {
console.warn('Reached maximum page limit (100), stopping pagination')
break
}
} catch (error) {
console.error(`Error fetching page ${page}:`, error)
throw error
}
}
console.log(`Finished fetching all pages. Total items: ${allData.length}`)
return allData
}
/**
* 单页API调用函数(内部使用)
* @param {Object} params - 查询参数(包含分页参数)
* @returns {Promise} API响应
*/
const getTasksPage = async (params = {}) => {
const response = await apiClient.get('/api/tasks/', { params })
return response.data
}
/**
* 获取所有作业任务
* @param {Object} params - 查询参数
* @param {number} params.student_id - 学生ID
* @param {number} params.subject_id - 学科ID
* @param {number} params.term_id - 学期ID
* @returns {Promise} 作业任务列表(完整数据,已处理分页)
*/
export const getTasks = async (params = {}) => {
try {
// 构建查询参数,过滤掉null和undefined值
const queryParams = {}
if (params.student_id) queryParams.student_id = params.student_id
if (params.subject_id) queryParams.subject_id = params.subject_id
if (params.term_id) queryParams.term_id = params.term_id
console.log('Tasks API request params:', queryParams)
// 使用通用分页函数获取所有数据
const allTasks = await fetchAllPages(getTasksPage, queryParams)
console.log('Tasks API final result:', {
totalCount: allTasks.length,
sampleData: allTasks.slice(0, 3) // 显示前3条数据作为样例
})
return allTasks
} catch (error) {
console.error('Failed to fetch tasks:', error)
throw error
}
}
/**
* 根据ID获取作业任务
* @param {number} taskId - 作业任务ID
* @returns {Promise} 作业任务详情
*/
export const getTaskById = async (taskId) => {
try {
const response = await apiClient.get(`/api/tasks/${taskId}/`)
console.log('Task detail API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to fetch task detail:', error)
throw error
}
}
/**
* 创建新的作业任务
* @param {Object} taskData - 作业任务数据
* @returns {Promise} 创建的作业任务
*/
export const createTask = async (taskData) => {
try {
const response = await apiClient.post('/api/tasks/', taskData)
console.log('Create task API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to create task:', error)
throw error
}
}
/**
* 更新作业任务
* @param {number} taskId - 作业任务ID
* @param {Object} taskData - 更新的作业任务数据
* @returns {Promise} 更新后的作业任务
*/
export const updateTask = async (taskId, taskData) => {
try {
const response = await apiClient.patch(`/api/tasks/${taskId}/`, taskData)
console.log('Update task API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to update task:', error)
throw error
}
}
/**
* 删除作业任务
* @param {number} taskId - 作业任务ID
* @returns {Promise} 删除结果
*/
export const deleteTask = async (taskId) => {
try {
const response = await apiClient.delete(`/api/tasks/${taskId}/`)
console.log('Delete task API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to delete task:', error)
throw error
}
}
import apiClient, { apiEndpoints } from './index.js'
/**
* 通用的获取所有分页数据的函数
* @param {Function} apiCall - API调用函数
* @param {Object} params - 查询参数
* @returns {Promise<Array>} 所有页面的数据数组
*/
const fetchAllPages = async (apiCall, params = {}) => {
let allData = []
let page = 1
let hasNext = true
console.log('Starting to fetch all pages for API call...')
while (hasNext) {
try {
const currentParams = { ...params, page, page_size: 100 } // 每页100条,减少请求次数
console.log(`Fetching page ${page} with params:`, currentParams)
const response = await apiCall(currentParams)
if (response && response.results) {
// 分页格式响应
allData = [...allData, ...response.results]
hasNext = !!response.next
console.log(`Page ${page}: Got ${response.results.length} items, total so far: ${allData.length}, hasNext: ${hasNext}`)
} else if (Array.isArray(response)) {
// 非分页格式响应(向后兼容)
allData = response
hasNext = false
console.log('Non-paginated response detected, got all data at once:', allData.length, 'items')
} else {
console.log('Unexpected response format, stopping pagination')
hasNext = false
}
page++
// 安全检查:防止无限循环
if (page > 100) {
console.warn('Reached maximum page limit (100), stopping pagination')
break
}
} catch (error) {
console.error(`Error fetching page ${page}:`, error)
throw error
}
}
console.log(`Finished fetching all pages. Total items: ${allData.length}`)
return allData
}
/**
* 单页API调用函数(内部使用)
* @param {Object} params - 查询参数(包含分页参数)
* @returns {Promise} API响应
*/
const getTermsPage = async (params = {}) => {
const response = await apiClient.get(apiEndpoints.TERMS.LIST, { params })
return response.data
}
export const getTerms = async () => {
try {
const response = await apiClient.get(apiEndpoints.TERMS.LIST)
return response.data
console.log('Fetching all terms with pagination support...')
// 使用通用分页函数获取所有数据
const allTerms = await fetchAllPages(getTermsPage)
console.log('Terms API final result:', {
totalCount: allTerms.length,
sampleData: allTerms.slice(0, 3) // 显示前3条数据作为样例
})
return allTerms
} catch (error) {
console.error('Failed to fetch terms:', error)
throw new Error(error?.response?.data?.detail || error?.message || 'Failed to fetch terms')
}
}
......
......@@ -37,5 +37,11 @@ export const GLOBAL_MENU_ITEMS = [
}
]
},
{
nameKey: 'navigation.menu.tasks',
path: '/tasks',
mdiIcon: 'mdi-clipboard-check-multiple-outline',
hasRouter: true
},
// 可以继续添加更多菜单项
];
......@@ -6,6 +6,7 @@ import validation from './common/validation'
import student from './modules/student'
import subject from './modules/subject'
import term from './modules/term'
import task from './modules/task'
import auth from './modules/auth'
import navigation from './modules/navigation'
import appHeader from './components/app-header'
......@@ -21,6 +22,7 @@ export default {
student,
subject,
term,
task,
auth,
navigation,
components: {
......
......@@ -12,6 +12,7 @@ export default {
students: 'Students',
subjects: 'Subjects',
terms: 'Terms',
tasks: 'Task Management',
dashboard: 'Dashboard',
settings: 'Settings',
about: 'About'
......@@ -23,6 +24,7 @@ export default {
students: 'Students',
subjects: 'Subjects',
terms: 'Terms',
tasks: 'Task Management',
profile: 'Profile'
},
......
export default {
title: 'Task Management',
calendar: {
title: 'Task Calendar',
viewTypes: {
month: 'Month View',
week: 'Week View',
day: 'Day View'
},
navigation: {
today: 'Today',
previous: 'Previous',
next: 'Next'
},
noEvents: 'No tasks this month',
enterFullscreen: 'Enter Fullscreen',
exitFullscreen: 'Exit Fullscreen'
},
task: {
name: 'Task Name',
description: 'Task Description',
subject: 'Subject',
student: 'Student',
term: 'Term',
startDate: 'Start Date',
endDate: 'End Date',
completionPercent: 'Completion',
status: {
notStarted: 'Not Started',
inProgress: 'In Progress',
completed: 'Completed'
}
},
filters: {
title: 'Filters',
allStudents: 'All Students',
allSubjects: 'All Subjects',
allTerms: 'All Terms',
apply: 'Apply Filters',
clear: 'Clear Filters',
selectStudentFirst: 'Please select a student first',
expand: 'Expand Filter Panel',
collapse: 'Collapse Filter Panel',
expandToReselect: 'Click to Expand and Reselect'
},
messages: {
loadError: 'Failed to load task data',
noData: 'No task data available'
}
}
......@@ -54,7 +54,9 @@ const i18n = createI18n({
// 全局注入属性
globalInjection: true,
// 开发环境下显示缺失翻译警告
// eslint-disable-next-line no-undef
silentTranslationWarn: process.env.NODE_ENV === 'production',
// eslint-disable-next-line no-undef
silentFallbackWarn: process.env.NODE_ENV === 'production'
})
......
......@@ -6,6 +6,7 @@ import validation from './common/validation'
import student from './modules/student'
import subject from './modules/subject'
import term from './modules/term'
import task from './modules/task'
import auth from './modules/auth'
import navigation from './modules/navigation'
import appHeader from './components/app-header'
......@@ -21,6 +22,7 @@ export default {
student,
subject,
term,
task,
auth,
navigation,
components: {
......
......@@ -12,6 +12,7 @@ export default {
students: '学生',
subjects: '学科',
terms: '学期',
tasks: '作业管理',
dashboard: '仪表盘',
settings: '设置',
about: '关于'
......@@ -23,6 +24,7 @@ export default {
students: '学生',
subjects: '学科',
terms: '学期',
tasks: '作业管理',
profile: '个人资料'
},
......
export default {
title: '作业管理',
calendar: {
title: '作业日历',
viewTypes: {
month: '月视图',
week: '周视图',
day: '日视图'
},
navigation: {
today: '今天',
previous: '上一页',
next: '下一页'
},
noEvents: '本月没有作业',
enterFullscreen: '全屏显示',
exitFullscreen: '退出全屏'
},
task: {
name: '作业名称',
description: '作业描述',
subject: '学科',
student: '学生',
term: '学期',
startDate: '开始日期',
endDate: '截止日期',
completionPercent: '完成度',
status: {
notStarted: '未开始',
inProgress: '进行中',
completed: '已完成'
}
},
filters: {
title: '筛选条件',
allStudents: '所有学生',
allSubjects: '所有学科',
allTerms: '所有学期',
apply: '应用筛选',
clear: '清除筛选',
selectStudentFirst: '请先选择学生',
expand: '展开筛选面板',
collapse: '收起筛选面板',
expandToReselect: '点击展开重新选择'
},
messages: {
loadError: '加载作业数据失败',
noData: '暂无作业数据'
}
}
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
// 批量导入常用组件,避免逐个列举
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
// Labs 组件需要在使用的地方单独导入
const vuetify = createVuetify({
components,
......
......@@ -6,6 +6,7 @@ import ProfileView from '../views/ProfileView.vue'
import StudentView from '../views/StudentView.vue'
import SubjectView from '../views/SubjectView.vue'
import TermView from '../views/TermView.vue'
import TaskView from '../views/TaskView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
......@@ -101,6 +102,23 @@ const router = createRouter({
]
},
},
{
path: '/tasks',
name: 'tasks',
component: TaskView,
meta: {
requiresAuth: true,
layout: 'default',
title: 'Tasks',
breadcrumb: {
key: 'navigation.breadcrumb.tasks'
},
breadcrumbPath: [
{ key: 'navigation.breadcrumb.home', to: '/', disabled: false },
{ key: 'navigation.breadcrumb.tasks', to: '/tasks', disabled: true }
]
},
},
{
path: '/:pathMatch(.*)*',
redirect: '/',
......
......@@ -71,8 +71,11 @@ const fetchStudents = async () => {
isError.value = false
errorMessage.value = ''
try {
const data = await getStudents()
students.value = Array.isArray(data) ? data : (data?.items || [])
const students_data = await getStudents()
console.log('Students data:', students_data)
// 现在API返回的直接是数组(已经处理了所有分页)
students.value = Array.isArray(students_data) ? students_data : []
} catch (e) {
isError.value = true
errorMessage.value = e?.response?.data?.detail || e?.message || t('student.messages.loadError')
......
......@@ -78,8 +78,11 @@ const fetchSubjects = async () => {
isError.value = false
errorMessage.value = ''
try {
const data = await getSubjects()
subjects.value = Array.isArray(data) ? data : (data?.items || [])
const subjects_data = await getSubjects()
console.log('Subjects data:', subjects_data)
// 现在API返回的直接是数组(已经处理了所有分页)
subjects.value = Array.isArray(subjects_data) ? subjects_data : []
} catch (e) {
isError.value = true
errorMessage.value = e?.response?.data?.detail || e?.message || t('subject.messages.loadError')
......
This diff is collapsed.
......@@ -68,8 +68,11 @@ const fetchTerms = async () => {
isError.value = false
errorMessage.value = ''
try {
const data = await getTerms()
terms.value = Array.isArray(data) ? data : (data?.items || [])
const terms_data = await getTerms()
console.log('Terms data:', terms_data)
// 现在API返回的直接是数组(已经处理了所有分页)
terms.value = Array.isArray(terms_data) ? terms_data : []
// 为每个term添加学生姓名(包括已禁用的学生)
terms.value.forEach(term => {
......@@ -90,8 +93,11 @@ const fetchTerms = async () => {
const fetchStudents = async () => {
try {
const data = await getStudents()
students.value = Array.isArray(data) ? data : (data?.items || [])
const students_data = await getStudents()
console.log('Students data:', students_data)
// 现在API返回的直接是数组(已经处理了所有分页)
students.value = Array.isArray(students_data) ? students_data : []
} catch (e) {
console.error('Failed to fetch students:', e)
}
......
......@@ -15,4 +15,8 @@ export default defineConfig({
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
server: {
host: '0.0.0.0',
port: 5173,
},
})
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment