// 教学活动分析相关接口 import { moduleRequest } from '@/utils/request' import Mock from 'mockjs' const request = moduleRequest(`/api/webapp/`) // Mock 数据配置 Mock.setup({ timeout: '200-600' }) // 课程选项数据 const courseOptions = [ { value: '', label: '全部课程' }, { value: 'course1', label: 'JavaScript基础教程' }, { value: 'course2', label: 'Python数据分析' }, { value: 'course3', label: 'React前端开发' }, { value: 'course4', label: '机器学习入门' }, { value: 'course5', label: 'Vue.js实战开发' }, { value: 'course6', label: 'Node.js后端开发' } ] // 生成日期数据 const generateDateData = (days) => { const dates = [] const today = new Date() for (let i = days - 1; i >= 0; i--) { const date = new Date(today) date.setDate(date.getDate() - i) dates.push(date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })) } return dates } // 生成访问数据 const generateVisitData = (days, courseId = '') => { const data = [] // 全部课程的访问量应该比单个课程高 const courseMultiplier = courseId ? 0.15 + Math.random() * 0.25 : 1.0 for (let i = 0; i < days; i++) { const dayOfWeek = (new Date().getDay() - days + i + 7) % 7 const isWeekend = dayOfWeek === 0 || dayOfWeek === 6 // 全部课程基础访问量更高 const baseValue = isWeekend ? 450 : 680 const randomFactor = 0.7 + Math.random() * 0.6 const finalValue = Math.round(baseValue * randomFactor * courseMultiplier) data.push(finalValue) } return data } // 讨论数据 - 这是全部课程的汇总讨论数据 const discussionData = [ { id: 1, title: 'JavaScript闭包概念理解', author: '张三', createTime: '2024-01-15 10:30', replyCount: 25, lastReplyTime: '2024-01-16 14:20' }, { id: 2, title: 'Python数据分析库选择', author: '李四', createTime: '2024-01-14 16:45', replyCount: 18, lastReplyTime: '2024-01-15 09:15' }, { id: 3, title: 'React组件生命周期', author: '王五', createTime: '2024-01-13 11:20', replyCount: 32, lastReplyTime: '2024-01-14 17:30' }, { id: 4, title: '机器学习算法选择', author: '赵六', createTime: '2024-01-12 14:15', replyCount: 16, lastReplyTime: '2024-01-13 10:45' }, { id: 5, title: '前端性能优化技巧', author: '钱七', createTime: '2024-01-11 09:30', replyCount: 45, lastReplyTime: '2024-01-15 16:20' }, { id: 6, title: 'Vue3 Composition API使用心得', author: '孙八', createTime: '2024-01-10 15:20', replyCount: 38, lastReplyTime: '2024-01-14 11:30' }, { id: 7, title: 'Node.js异步编程最佳实践', author: '周九', createTime: '2024-01-09 13:45', replyCount: 29, lastReplyTime: '2024-01-13 16:15' }, { id: 8, title: '数据库索引优化策略', author: '陈十', createTime: '2024-01-08 11:20', replyCount: 22, lastReplyTime: '2024-01-12 15:40' }, { id: 9, title: 'Web安全防护实践', author: '刘十一', createTime: '2024-01-07 14:30', replyCount: 19, lastReplyTime: '2024-01-11 09:25' }, { id: 10, title: '移动端适配解决方案', author: '杨十二', createTime: '2024-01-06 16:15', replyCount: 27, lastReplyTime: '2024-01-10 13:50' }, { id: 11, title: 'TypeScript类型系统深入', author: '黄十三', createTime: '2024-01-05 10:45', replyCount: 34, lastReplyTime: '2024-01-09 17:20' }, { id: 12, title: 'Docker容器化部署', author: '吴十四', createTime: '2024-01-04 13:20', replyCount: 21, lastReplyTime: '2024-01-08 11:15' }, { id: 13, title: 'GraphQL API设计', author: '郑十五', createTime: '2024-01-03 15:40', replyCount: 15, lastReplyTime: '2024-01-07 14:30' }, { id: 14, title: '微服务架构实践', author: '王十六', createTime: '2024-01-02 09:15', replyCount: 28, lastReplyTime: '2024-01-06 16:45' }, { id: 15, title: 'Redis缓存策略', author: '李十七', createTime: '2024-01-01 11:30', replyCount: 23, lastReplyTime: '2024-01-05 12:20' } ] // 文档数据 - 这是全部课程的汇总数据,数量较大 const documentData = [ { id: 1, name: 'JavaScript基础语法', type: 'PDF文档', viewCount: 4856, completedCount: 3234, completionRate: 66.5, avgReadTime: '25:30', exitRate: 24.6, downloadCount: 1456 }, { id: 2, name: 'Python数据分析入门', type: '在线文档', viewCount: 3234, completedCount: 2587, completionRate: 80.0, avgReadTime: '32:15', exitRate: 18.5, downloadCount: 1234 }, { id: 3, name: 'React组件开发指南', type: 'PDF文档', viewCount: 2987, completedCount: 2289, completionRate: 76.6, avgReadTime: '28:45', exitRate: 22.3, downloadCount: 989 }, { id: 4, name: '机器学习算法详解', type: '在线文档', viewCount: 2756, completedCount: 1908, completionRate: 69.2, avgReadTime: '45:20', exitRate: 30.8, downloadCount: 823 }, { id: 5, name: '前端工程化实践', type: 'PDF文档', viewCount: 2523, completedCount: 1665, completionRate: 66.0, avgReadTime: '38:15', exitRate: 34.0, downloadCount: 689 }, { id: 6, name: 'Vue.js进阶开发', type: '在线文档', viewCount: 2678, completedCount: 1802, completionRate: 67.3, avgReadTime: '35:40', exitRate: 32.7, downloadCount: 756 }, { id: 7, name: 'Node.js后端开发', type: 'PDF文档', viewCount: 2345, completedCount: 1567, completionRate: 66.8, avgReadTime: '42:10', exitRate: 28.9, downloadCount: 634 }, { id: 8, name: '数据库设计原理', type: '在线文档', viewCount: 2123, completedCount: 1489, completionRate: 70.1, avgReadTime: '38:25', exitRate: 26.4, downloadCount: 567 }, { id: 9, name: 'Web安全防护', type: 'PDF文档', viewCount: 1987, completedCount: 1345, completionRate: 67.7, avgReadTime: '33:50', exitRate: 29.8, downloadCount: 498 }, { id: 10, name: '移动端开发实战', type: '在线文档', viewCount: 1876, completedCount: 1234, completionRate: 65.8, avgReadTime: '40:15', exitRate: 31.2, downloadCount: 445 } ] // 生成课程选项数据 const generateCourseOptions = () => { return { code: 200, message: '获取成功', data: courseOptions } } // 生成核心统计数据 const generateStatsData = (options) => { const urlParts = options.url.split('?') const params = urlParts.length > 1 ? new URLSearchParams(urlParts[1]) : new URLSearchParams() const courseId = params.get('courseId') || '' const timeRange = parseInt(params.get('timeRange')) || 30 // 全部课程的数据应该是所有课程的总和,单个课程数据相对较少 const baseMultiplier = courseId ? 0.15 + Math.random() * 0.25 : 1.0 // 单个课程占总数的15%-40% const timeMultiplier = timeRange / 30 // 基础数据 - 全部课程的总数据 const baseStats = { totalDocViewers: 8560, completedDocViewers: 6234, totalDocExits: 1890, totalDiscussions: 1456, totalReplies: 8934 } const calculatedStats = { totalDocViewers: Math.round(baseStats.totalDocViewers * baseMultiplier * timeMultiplier), completedDocViewers: Math.round(baseStats.completedDocViewers * baseMultiplier * timeMultiplier), totalDocExits: Math.round(baseStats.totalDocExits * baseMultiplier * timeMultiplier), totalDiscussions: Math.round(baseStats.totalDiscussions * baseMultiplier * timeMultiplier), totalReplies: Math.round(baseStats.totalReplies * baseMultiplier * timeMultiplier) } // 确保完成人数不超过总观看人数 if (calculatedStats.completedDocViewers > calculatedStats.totalDocViewers) { calculatedStats.completedDocViewers = Math.round(calculatedStats.totalDocViewers * 0.7) } // 计算完成率 const docCompletionRate = calculatedStats.totalDocViewers > 0 ? parseFloat(((calculatedStats.completedDocViewers / calculatedStats.totalDocViewers) * 100).toFixed(1)) : 0 // 计算跳出率 - 单个课程跳出率可能更高 const baseExitRate = courseId ? 25 + Math.random() * 15 : 18 + Math.random() * 12 const docExitRate = parseFloat(baseExitRate.toFixed(1)) // 计算平均回帖数 const avgRepliesPerDiscussion = calculatedStats.totalDiscussions > 0 ? parseFloat((calculatedStats.totalReplies / calculatedStats.totalDiscussions).toFixed(1)) : 0 return { code: 200, message: '获取成功', data: { totalDocViewers: calculatedStats.totalDocViewers, completedDocViewers: calculatedStats.completedDocViewers, docCompletionRate, totalDocExits: calculatedStats.totalDocExits, docExitRate, avgDocExitTime: `${String(Math.floor(Math.random() * 15) + 8).padStart(2, '0')}:${String( Math.floor(Math.random() * 60) ).padStart(2, '0')}`, totalDiscussions: calculatedStats.totalDiscussions, totalReplies: calculatedStats.totalReplies, avgRepliesPerDiscussion } } } // 生成每周统计数据 const generateWeeklyStatsData = (options) => { const urlParts = options.url.split('?') const params = urlParts.length > 1 ? new URLSearchParams(urlParts[1]) : new URLSearchParams() const courseId = params.get('courseId') || '' // 全部课程数据应该是所有课程的总和 const baseMultiplier = courseId ? 0.12 + Math.random() * 0.28 : 1.0 // 单个课程占总数的12%-40% // 基础数据 - 全部课程的总数据 const baseWeeklyStats = { studentWeeklyPosts: 456, studentWeeklyReplies: 1678, teacherWeeklyPosts: 123, teacherWeeklyReplies: 567 } const calculatedStats = { studentWeeklyPosts: Math.round(baseWeeklyStats.studentWeeklyPosts * baseMultiplier), studentWeeklyReplies: Math.round(baseWeeklyStats.studentWeeklyReplies * baseMultiplier), teacherWeeklyPosts: Math.round(baseWeeklyStats.teacherWeeklyPosts * baseMultiplier), teacherWeeklyReplies: Math.round(baseWeeklyStats.teacherWeeklyReplies * baseMultiplier) } return { code: 200, message: '获取成功', data: { studentWeeklyPosts: calculatedStats.studentWeeklyPosts, studentWeeklyReplies: calculatedStats.studentWeeklyReplies, studentAvgPostsPerDay: parseFloat((calculatedStats.studentWeeklyPosts / 7).toFixed(1)), teacherWeeklyPosts: calculatedStats.teacherWeeklyPosts, teacherWeeklyReplies: calculatedStats.teacherWeeklyReplies, teacherAvgPostsPerDay: parseFloat((calculatedStats.teacherWeeklyPosts / 7).toFixed(1)) } } } // 生成每日访问数据 const generateDailyVisitsData = (options) => { const urlParts = options.url.split('?') const params = urlParts.length > 1 ? new URLSearchParams(urlParts[1]) : new URLSearchParams() const courseId = params.get('courseId') || '' const timeRange = parseInt(params.get('timeRange')) || 30 const dates = generateDateData(timeRange) const visits = generateVisitData(timeRange, courseId) return { code: 200, message: '获取成功', data: { dates, visits } } } // 生成讨论数据 const generateDiscussionData = (options) => { const urlParts = options.url.split('?') const params = urlParts.length > 1 ? new URLSearchParams(urlParts[1]) : new URLSearchParams() const courseId = params.get('courseId') || '' const page = parseInt(params.get('page')) || 1 const pageSize = parseInt(params.get('pageSize')) || 10 let filteredData = discussionData if (courseId) { // 单个课程只显示部分讨论数据,模拟该课程相关的讨论 const courseDiscussionCount = Math.floor(discussionData.length * (0.2 + Math.random() * 0.3)) // 20%-50% filteredData = discussionData.slice(0, Math.max(courseDiscussionCount, 2)) // 至少显示2条 } const startIndex = (page - 1) * pageSize const endIndex = startIndex + pageSize const pageData = filteredData.slice(startIndex, endIndex) return { code: 200, message: '获取成功', data: { list: pageData, total: filteredData.length, page, pageSize } } } // 生成文档数据 const generateDocumentData = (options) => { const urlParts = options.url.split('?') const params = urlParts.length > 1 ? new URLSearchParams(urlParts[1]) : new URLSearchParams() const courseId = params.get('courseId') || '' const page = parseInt(params.get('page')) || 1 const pageSize = parseInt(params.get('pageSize')) || 10 let filteredData = [...documentData] if (courseId) { // 单个课程只显示该课程相关的文档,数量相对较少 const courseDocumentCount = Math.floor(documentData.length * (0.25 + Math.random() * 0.35)) // 25%-60% filteredData = documentData.slice(0, Math.max(courseDocumentCount, 3)) // 至少显示3条 // 调整单个课程文档的数据,使其相对较小但合理 filteredData = filteredData.map((doc) => ({ ...doc, viewCount: Math.round(doc.viewCount * (0.15 + Math.random() * 0.25)), // 15%-40%的观看量 completedCount: Math.round(doc.completedCount * (0.15 + Math.random() * 0.25)), downloadCount: Math.round(doc.downloadCount * (0.15 + Math.random() * 0.25)), // 完成率和跳出率保持相对合理的范围 completionRate: parseFloat((doc.completionRate + (Math.random() - 0.5) * 10).toFixed(1)), exitRate: parseFloat((doc.exitRate + (Math.random() - 0.5) * 8).toFixed(1)) })) } const startIndex = (page - 1) * pageSize const endIndex = startIndex + pageSize const pageData = filteredData.slice(startIndex, endIndex) return { code: 200, message: '获取成功', data: { list: pageData, total: filteredData.length, page, pageSize } } } // Mock 接口定义 Mock.mock(/\/api\/webapp\/teaching-analysis\/course-options/, 'get', generateCourseOptions) Mock.mock(/\/api\/webapp\/teaching-analysis\/stats/, 'get', generateStatsData) Mock.mock(/\/api\/webapp\/teaching-analysis\/weekly-stats/, 'get', generateWeeklyStatsData) Mock.mock(/\/api\/webapp\/teaching-analysis\/daily-visits/, 'get', generateDailyVisitsData) Mock.mock(/\/api\/webapp\/teaching-analysis\/discussions/, 'get', generateDiscussionData) Mock.mock(/\/api\/webapp\/teaching-analysis\/documents/, 'get', generateDocumentData) // 导出的API函数 export const getCourseOptions = (params = {}) => { return request('disk/courseinfo/allList', params, 'get') } // 文档观看统计 export const getTeachingStats = (params = {}) => { return request('teachingActivity/documentStatistic', params, 'get') } // 文档跳出分析 export const documentJumpStatistic = (params = {}) => { return request('teachingActivity/documentJumpStatistic', params, 'get') } export const getWeeklyStats = (params = {}) => { return request('teaching-analysis/weekly-stats', params, 'get') } // 开课每日访问人数统计 export const getDailyVisits = (params = {}) => { return request('teachingActivity/courseOpenStatistic', params, 'get') } export const getDiscussionData = (params = {}) => { return request('teaching-analysis/discussions', params, 'get') } export const getDocumentStats = (params = {}) => { return request('teaching-analysis/documents', params, 'get') }