|
|
@@ -9,48 +9,6 @@ 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 = [
|
|
|
@@ -176,197 +134,6 @@ const discussionData = [
|
|
|
}
|
|
|
]
|
|
|
|
|
|
-// 文档数据 - 这是全部课程的汇总数据,数量较大
|
|
|
-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('?')
|
|
|
@@ -405,26 +172,6 @@ const generateWeeklyStatsData = (options) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 生成每日访问数据
|
|
|
-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('?')
|
|
|
@@ -456,56 +203,9 @@ const generateDiscussionData = (options) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 生成文档数据
|
|
|
-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 = {}) => {
|
|
|
@@ -533,5 +233,5 @@ export const getDiscussionData = (params = {}) => {
|
|
|
}
|
|
|
|
|
|
export const getDocumentStats = (params = {}) => {
|
|
|
- return request('teaching-analysis/documents', params, 'get')
|
|
|
+ return request('teachingActivity/documentDetailStatistic', params, 'get')
|
|
|
}
|