import apiClient from './index.js' /** * 通用的获取所有分页数据的函数 * @param {Function} apiCall - API调用函数 * @param {Object} params - 查询参数 * @returns {Promise} 所有页面的数据数组 */ 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 } 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 } /** * 列出某 task 的所有图片元数据(spec 0004 子资源)。响应按 DRF 标准分页 * { count, next, previous, results },这里把结果数组拉平返回。 * @param {number} taskId * @param {Object} [params] * @returns {Promise} 图片元数据数组(每项含 id / mime_type / file_name / key / etag / size_bytes / 审计字段) */ export const listTaskImages = async (taskId, params = {}) => { const listPage = async (p) => { const response = await apiClient.get(`/api/tasks/${taskId}/images/`, { params: p }) return response.data } return fetchAllPages(listPage, params) } /** * 创建 task 图片(spec 0004 子资源)。body 走 StdtTaskImagesWrite schema: * 必填 image_base64,可选 mime_type/file_name。后端在 POST 时校验 ≤ 20 张软上限。 * @param {number} taskId * @param {{mime_type?: string, file_name?: string, image_base64: string}} payload * @returns {Promise} StdtTaskImagesWrite 响应(含新分配的 id) */ export const createTaskImage = async (taskId, payload) => { const response = await apiClient.post(`/api/tasks/${taskId}/images/`, payload) console.log(`Task image created for task ${taskId}:`, response.data) return response.data } /** * 删除 task 图片(spec 0004 子资源)。DELETE 是软删——后端只翻 deleted_flag, * 不会真删 row;行还在表里、COS 上对象也不动,前端通过 refetch 自然看不到。 * @param {number} taskId * @param {number} imageId */ export const deleteTaskImage = async (taskId, imageId) => { const response = await apiClient.delete(`/api/tasks/${taskId}/images/${imageId}/`) console.log(`Task image ${imageId} for task ${taskId} deleted`) return response.data } /** * 获取 task 图片的二进制内容(spec 0004 子资源 /content/)。 * 必须 responseType: 'blob' + Accept 通配,否则 DRF 默认 JSON renderer 返 406。 * @param {number} taskId * @param {number} imageId * @returns {Promise} 解析为 Blob */ export const getTaskImageContent = async (taskId, imageId) => { const response = await apiClient.get( `/api/tasks/${taskId}/images/${imageId}/content/`, { responseType: 'blob', headers: { Accept: '*/*' }, } ) console.log(`Task image ${imageId} content for task ${taskId} fetched`) return response.data } /** * 单页API调用函数(内部使用) */ const getTasksPage = async (params = {}) => { const response = await apiClient.get('/api/tasks/', { params }) return response.data } /** * 获取所有作业任务 * @param {Object} params - 查询参数(student_id / subject_id / term_id / story_id) * @returns {Promise} 全部任务的扁平数组(已处理分页) */ export const getTasks = async (params = {}) => { try { 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 if (params.story_id) queryParams.story_id = params.story_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) }) return allTasks } catch (error) { console.error('Failed to fetch tasks:', error) throw error } } /** * 根据ID获取作业任务 */ 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 任务字段。spec 0004 后不再含 image_XX,新图片走 * /api/tasks/{id}/images/ 子资源。 */ 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 * @param {Object} taskData 任务字段。spec 0004 后不再含 image_XX / delete_image_XX; * 改图、删图走 image 子资源。 */ 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 } } /** * 删除作业任务。spec 0004 / ADR-0004:软删,图片 row 不会被级联软删。 */ 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 } }