/** * UniApp Mock数据服务 * 支持环境变量控制,默认开启Mock数据 * 提供与API响应结构一致的数据格式 */ import { isMockEnabled, isDebug } from '@/common/config.js' // Mock数据规则 - 基于MockJS规则 const mockRules = { // 用户数据规则 user: { 'id|+1': 1, 'username': '@cname', 'phone': /^1[3-9]\d{9}$/, 'avatar': '@image("100x100", "#50B347", "#FFF", "Avatar")', 'email': '@email', 'status|1': ['active', 'inactive'], 'created_at': '@datetime', 'updated_at': '@datetime' }, // 学生数据规则 student: { 'id|+1': 1, 'name': '@cname', 'student_no': '@string("number", 10)', 'phone': /^1[3-9]\d{9}$/, 'avatar': '@image("100x100", "#50B347", "#FFF", "Student")', 'class_id|1-20': 1, 'status|1': ['active', 'inactive', 'graduated'], 'created_at': '@datetime' }, // 课程数据规则 course: { 'id|+1': 1, 'name': '@ctitle(5, 15)', 'description': '@cparagraph(1, 3)', 'teacher_id|1-10': 1, 'price|100-1000.2': 1, 'duration|30-120': 1, 'status|1': ['active', 'inactive'], 'created_at': '@datetime' }, // 课程表数据规则 schedule: { 'id|+1': 1, 'course_id|1-20': 1, 'teacher_id|1-10': 1, 'classroom': '@ctitle(3, 8)', 'date': '@date', 'start_time': '@time', 'end_time': '@time', 'status|1': ['scheduled', 'completed', 'cancelled'] } } // 生成Mock数据的函数 function generateMockData(rule, count = 1) { const result = [] for (let i = 0; i < count; i++) { const item = {} for (const key in rule) { if (key.includes('|')) { const [field, mockRule] = key.split('|') if (mockRule.includes('+')) { item[field] = i + 1 } else if (mockRule.includes('-')) { const [min, max] = mockRule.split('-') item[field] = Math.floor(Math.random() * (max - min + 1)) + parseInt(min) } else if (mockRule === '1') { const options = rule[key] item[field] = Array.isArray(options) ? options[Math.floor(Math.random() * options.length)] : options } } else { item[key] = rule[key] } } result.push(item) } return count === 1 ? result[0] : result } // Mock数据存储 const mockData = { // 用户相关数据 users: generateMockData(mockRules.user, 50), students: generateMockData(mockRules.student, 100), courses: generateMockData(mockRules.course, 30), schedules: generateMockData(mockRules.schedule, 200), // 登录用户信息 currentUser: { id: 1, username: '张三', phone: '13800138000', avatar: 'https://via.placeholder.com/100x100?text=User', email: 'zhangsan@example.com', status: 'active', role: 'student', created_at: '2024-01-01 10:00:00', updated_at: '2024-01-01 10:00:00' }, // 学员信息 (xy_memberInfo) memberInfo: { id: 1001, name: '李小明', student_no: 'ST202401001', phone: '13800138001', age: 15, gender: 1, // 1男 2女 classes_count: 8, // 我的课程数 sign_count: 15, // 已上课时 stay_sign_count: 5, // 待上课时 created_at: '2024-01-01 08:00:00', memberHasOne: { headimg: 'https://via.placeholder.com/144x144?text=Student', id: 1001 }, customerResources: { member: { headimg: 'https://via.placeholder.com/144x144?text=Student' } } }, // 体测数据 (xy_physicalTest) physicalTestData: { data: [ { id: 1, resource_id: 1001, height: 165, weight: 55, calculateChildHealthScore: 85, created_at: '2024-01-10 14:30:00', bmi: 20.2, test_items: { flexibility: 78, strength: 85, endurance: 82 } } ], total: 1, page: 1, pages: 1 }, // 课程安排数据 (xy_personCourseSchedule) personCourseSchedule: { data: [ { id: 2001, resources_id: 1001, course_date: '2024-01-16', time_slot: '09:00-10:30', status: '0', // 0待上课 1已上课 2请假 courseScheduleHasOne: { venue: { venue_name: '篮球馆A' }, course: { course_name: '青少年篮球训练' } }, created_at: '2024-01-15 10:00:00' }, { id: 2002, resources_id: 1001, course_date: '2024-01-18', time_slot: '14:00-15:30', status: '0', courseScheduleHasOne: { venue: { venue_name: '足球场B' }, course: { course_name: '足球基础课' } }, created_at: '2024-01-15 10:00:00' } ], total: 2, page: 1, pages: 1 }, // 作业数据 (xy_assignment) assignmentData: { data: [ { id: 3001, resources_id: 1001, description: '完成本周的体能训练视频拍摄,展示标准动作', content_type: 2, // 1图片 2视频 3文本 content_text: 'https://example.com/video.mp4', status: '2', // 1待批改 2未提交 3已提交 created_at: '2024-01-14 16:00:00', student: { name: '李小明', customerResources: { member: { headimg: 'https://via.placeholder.com/50x50?text=Student' } } } }, { id: 3002, resources_id: 1001, description: '上传训练心得体会,字数不少于200字', content_type: 3, content_text: '今天的训练很充实,学到了很多新的技巧...', status: '3', created_at: '2024-01-12 10:00:00', student: { name: '李小明', customerResources: { member: { headimg: 'https://via.placeholder.com/50x50?text=Student' } } } } ], total: 2, page: 1, pages: 1 }, // 日历数据 (xy_personCourseScheduleGetCalendar) calendarData: { '2024-01-15': [ { id: 2001, course_name: '篮球训练', time_slot: '09:00-10:30', status: 'scheduled' } ], '2024-01-16': [ { id: 2002, course_name: '足球基础', time_slot: '14:00-15:30', status: 'scheduled' } ] }, // 教练信息 (xy_personCourseScheduleGetMyCoach) coachData: { data: [ { id: 5001, name: '王教练', phone: '13800135001', specialty: '篮球', experience: '5年教学经验', avatar: 'https://via.placeholder.com/100x100?text=Coach', introduction: '专业篮球教练,擅长青少年基础训练和技能提升', courses: ['青少年篮球', '篮球进阶训练'] } ], total: 1 }, // 学生课程表 studentSchedules: [ { id: 1, course_name: '数学基础', teacher_name: '王老师', classroom: '101教室', date: '2024-01-15', start_time: '09:00', end_time: '10:30', status: 'scheduled' }, { id: 2, course_name: '英语口语', teacher_name: '李老师', classroom: '202教室', date: '2024-01-15', start_time: '14:00', end_time: '15:30', status: 'scheduled' } ], // 考试成绩 examResults: [ { id: 1, exam_name: '期中考试', course_name: '数学', score: 85, total_score: 100, rank: 5, exam_date: '2024-01-10', status: 'published' }, { id: 2, exam_name: '期末考试', course_name: '英语', score: 92, total_score: 100, rank: 2, exam_date: '2024-01-12', status: 'published' } ] } // Mock服务类 class MockService { constructor() { this.enabled = isMockEnabled this.debug = isDebug this.init() } init() { if (this.debug) { console.log('Mock服务状态:', this.enabled ? '已启用' : '已禁用') } } // 统一的响应格式 createResponse(data, code = 200, message = 'success') { return { code, message, data, timestamp: Date.now() } } // 分页响应格式 createPaginatedResponse(list, page = 1, size = 10, total = null) { const actualTotal = total || list.length const start = (page - 1) * size const end = start + size const paginatedList = list.slice(start, end) return this.createResponse({ list: paginatedList, total: actualTotal, page: parseInt(page), size: parseInt(size), pages: Math.ceil(actualTotal / size) }) } // 模拟网络延迟 async delay(ms = 500) { return new Promise(resolve => setTimeout(resolve, ms)) } // 获取Mock数据 async getMockData(endpoint, params = {}) { if (!this.enabled) { return null } await this.delay() // 根据端点返回相应的Mock数据 - 支持完整URL和方法名匹配 const checkEndpoint = (patterns) => { return patterns.some(pattern => endpoint.includes(pattern)) } // 学员信息 if (checkEndpoint(['/customerResourcesAuth/info', 'xy_memberInfo'])) { return this.createResponse(mockData.memberInfo, 1, 'success') } // 体测数据 if (checkEndpoint(['/xy/physicalTest', 'xy_physicalTest'])) { return this.createResponse(mockData.physicalTestData, 1, 'success') } // 课程安排 if (checkEndpoint(['/xy/personCourseSchedule', 'xy_personCourseSchedule']) && !endpoint.includes('getCalendar') && !endpoint.includes('getMyCoach')) { // 根据status参数过滤数据 let scheduleData = mockData.personCourseSchedule.data if (params.status !== undefined) { scheduleData = scheduleData.filter(item => item.status === params.status) } return this.createResponse({ data: scheduleData, total: scheduleData.length, page: params.page || 1, pages: Math.ceil(scheduleData.length / (params.limit || 10)) }, 1, 'success') } // 日历数据 if (checkEndpoint(['/xy/personCourseSchedule/getCalendar', 'xy_personCourseScheduleGetCalendar'])) { return this.createResponse(mockData.calendarData, 1, 'success') } // 教练信息 if (checkEndpoint(['/xy/personCourseSchedule/getMyCoach', 'xy_personCourseScheduleGetMyCoach'])) { return this.createResponse(mockData.coachData, 1, 'success') } // 作业列表 if (checkEndpoint(['/xy/assignment', 'xy_assignment']) && !endpoint.includes('/info') && !endpoint.includes('submitObj')) { // 根据status参数过滤作业数据 let assignmentData = mockData.assignmentData.data if (params.status !== undefined) { assignmentData = assignmentData.filter(item => item.status === params.status) } return this.createResponse({ data: assignmentData, total: assignmentData.length, page: params.page || 1, pages: Math.ceil(assignmentData.length / (params.limit || 10)) }, 1, 'success') } // 作业详情 if (checkEndpoint(['/xy/assignment/info', 'xy_assignmentsInfo'])) { const assignmentId = params.id || params.assignment_id const assignment = mockData.assignmentData.data.find(item => item.id == assignmentId) return this.createResponse(assignment || {}, assignment ? 1 : 0, assignment ? 'success' : '作业不存在') } // 作业提交 if (checkEndpoint(['/xy/assignment/submitObj', 'xy_assignmentSubmitObj'])) { return this.createResponse({}, 1, '作业提交成功') } // 学生登录 if (checkEndpoint(['/xy/login', 'xy_login'])) { return this.createResponse({ token: 'mock_token_' + Date.now(), user: mockData.memberInfo, expires_in: 7200 }, 1, '登录成功') } // 原有的通用接口 switch (endpoint) { case '/user/info': return this.createResponse(mockData.currentUser) case '/student/schedule': return this.createResponse(mockData.studentSchedules) case '/student/exam/results': return this.createResponse(mockData.examResults) case '/courses': return this.createPaginatedResponse( mockData.courses, params.page || 1, params.size || 10 ) case '/students': return this.createPaginatedResponse( mockData.students, params.page || 1, params.size || 10 ) default: return this.createResponse(null, 404, '接口未找到') } } // 检查是否应该使用Mock数据 shouldUseMock(url) { if (!this.enabled) return false // 定义需要Mock的接口列表 const mockableEndpoints = [ '/user/info', '/student/schedule', '/student/exam/results', '/courses', '/students', // 学员端专用API - URL匹配 '/customerResourcesAuth/info', // xy_memberInfo '/xy/physicalTest', // xy_physicalTest '/xy/personCourseSchedule', // xy_personCourseSchedule相关 '/xy/assignment', // xy_assignment相关 '/xy/login', // xy_login // 学员端专用API - 方法名匹配(用于开发调试) 'xy_memberInfo', 'xy_physicalTest', 'xy_personCourseSchedule', 'xy_assignment', 'xy_assignmentsInfo', 'xy_assignmentSubmitObj', 'xy_personCourseScheduleGetCalendar', 'xy_personCourseScheduleGetMyCoach', 'xy_login' ] return mockableEndpoints.some(endpoint => url.includes(endpoint)) } } // 创建全局Mock服务实例 const mockService = new MockService() export default mockService