/** * 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' }, // 家长信息 (school_customer_resources) parentInfo: { id: 1001, name: '张家长', phone_number: '13800138000', gender: 'male', age: 35, created_at: '2024-01-01 10:00:00', updated_at: '2024-01-01 10:00:00' }, // 孩子列表 (school_student) childrenList: [ { id: 2001, name: '张小明', gender: 1, // 1男 2女 age: 8.5, // 8岁5个月 birthday: '2015-06-15', user_id: 1001, // 关联家长ID campus_id: 1, campus_name: '总部校区', class_id: 101, class_name: '少儿篮球初级班', note: '性格活泼,运动能力强', status: 1, // 1有效 emergency_contact: '张家长', contact_phone: '13800138000', member_label: '优秀学员', consultant_id: '1', coach_id: '1', coach_name: '王教练', created_at: '2024-01-01 10:00:00', updated_at: '2024-01-01 10:00:00', avatar: 'https://via.placeholder.com/100x100?text=张小明', // 统计数据 total_courses: 12, completed_courses: 8, remaining_courses: 4, attendance_rate: 85.5 }, { id: 2002, name: '张小丽', gender: 2, // 2女 age: 6.2, // 6岁2个月 birthday: '2017-10-20', user_id: 1001, // 关联家长ID campus_id: 2, campus_name: '南山校区', class_id: 102, class_name: '少儿舞蹈基础班', note: '喜欢舞蹈,有艺术天赋', status: 1, // 1有效 emergency_contact: '张家长', contact_phone: '13800138000', member_label: '新学员', consultant_id: '2', coach_id: '2', coach_name: '李教练', created_at: '2024-01-15 10:00:00', updated_at: '2024-01-15 10:00:00', avatar: 'https://via.placeholder.com/100x100?text=张小丽', // 统计数据 total_courses: 8, completed_courses: 3, remaining_courses: 5, attendance_rate: 95.0 }, { id: 2003, name: '张小华', gender: 1, // 1男 age: 10.8, // 10岁8个月 birthday: '2013-04-10', user_id: 1001, // 关联家长ID campus_id: null, // 未分配校区 campus_name: '未分配', class_id: null, // 未分配班级 class_name: '未分配', note: '刚报名,待安排班级', status: 1, // 1有效 emergency_contact: '张家长', contact_phone: '13800138000', member_label: '待分班', consultant_id: '3', coach_id: null, coach_name: '未分配', created_at: '2024-01-20 10:00:00', updated_at: '2024-01-20 10:00:00', avatar: 'https://via.placeholder.com/100x100?text=张小华', // 统计数据 total_courses: 0, completed_courses: 0, remaining_courses: 0, attendance_rate: 0 } ], // 学员信息 (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', test_date: '2024-01-10', bmi: 20.2, test_items: { flexibility: 78, strength: 85, endurance: 82 }, pdf_files: [ { id: 'pdf_001', name: '体测报告_2024-01-10.pdf', size: 1024000, upload_time: '2024-01-10 14:35:00', file_path: '/uploads/fitness/2024/01/fitness_report_001.pdf' } ] }, { id: 2, resource_id: 1001, height: 166, weight: 56, calculateChildHealthScore: 88, created_at: '2024-02-15 09:20:00', test_date: '2024-02-15', bmi: 20.3, test_items: { flexibility: 80, strength: 88, endurance: 85 }, pdf_files: [ { id: 'pdf_002', name: '体测报告_2024-02-15.pdf', size: 1150000, upload_time: '2024-02-15 09:25:00', file_path: '/uploads/fitness/2024/02/fitness_report_002.pdf' } ] } ], total: 2, 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)) } // 家长端API接口 if (checkEndpoint(['/parent/children', 'parent_getChildrenList'])) { return this.createResponse({ data: mockData.childrenList, total: mockData.childrenList.length, parent_info: mockData.parentInfo }, 1, 'success') } // 获取指定孩子信息 if (checkEndpoint(['/parent/child/info', 'parent_getChildInfo'])) { const childId = params.child_id || params.id const child = mockData.childrenList.find(item => item.id == childId) return this.createResponse(child || {}, child ? 1 : 0, child ? 'success' : '孩子信息不存在') } // 获取指定孩子的课程信息 if (checkEndpoint(['/parent/child/courses', 'parent_getChildCourses'])) { const childId = params.child_id || params.id const child = mockData.childrenList.find(item => item.id == childId) if (!child) { return this.createResponse([], 0, '孩子信息不存在') } // 模拟该孩子的课程数据 const childCourses = [ { id: 1, course_name: child.class_name || '未分配班级', teacher_name: child.coach_name || '未分配', campus_name: child.campus_name || '未分配', schedule_time: '周六 09:00-10:30', progress: `${child.completed_courses}/${child.total_courses}`, status: child.class_id ? 'active' : 'inactive', next_class: child.class_id ? '2024-01-20 09:00' : null } ] return this.createResponse({ data: childCourses, total: childCourses.length, child_info: child }, 1, 'success') } // 获取指定孩子的订单信息 if (checkEndpoint(['/parent/child/orders', 'parent_getChildOrders'])) { const childId = params.child_id || params.id const child = mockData.childrenList.find(item => item.id == childId) if (!child) { return this.createResponse([], 0, '孩子信息不存在') } // 模拟该孩子的订单数据 const childOrders = [ { id: 1001, order_no: 'ORD202401001', course_name: child.class_name || '课程包', amount: 2880.00, status: 'paid', status_text: '已支付', created_at: '2024-01-01 10:00:00', pay_time: '2024-01-01 10:05:00' } ] return this.createResponse({ data: childOrders, total: childOrders.length, child_info: child }, 1, 'success') } // 获取学员课程信息 if (checkEndpoint(['/getStudentCourseInfo', 'getStudentCourseInfo'])) { const resourceId = params.resource_id || params.id // 模拟课程信息数据 - 匹配后端API实际返回结构 const courseInfoData = [ { id: 1, course_name: '篮球课', total_count: 28, // 总课时 used_count: 10, // 已使用课时 remaining_count: 18, // 剩余课时 formal_hours: 24, // 正式课时 gift_hours: 4, // 赠送课时 used_formal_hours: 8, // 已使用正式课时 used_gift_hours: 2, // 已使用赠送课时 leave_count: 0, // 请假次数 start_date: '2024-01-01', // 开始日期 expiry_date: '2024-12-31', // 到期日期 status: 'active', // 课程状态 db_status: 1, // 数据库状态 single_session_count: 90, // 单节时长(分钟) main_coach_id: 1, // 主教练ID main_coach_name: '张老师', // 主教练姓名 education_id: null, // 教务ID education_name: '未分配', // 教务姓名 assistant_ids: '', // 助教ID列表 assistant_names: '无', // 助教姓名列表 course_type: '常规课', teacher_name: '张老师', // 兼容字段 course_price: 2880.00, class_duration: 90, // 兼容字段 create_time: '2024-01-01 10:00:00', remark: '学员表现优秀,建议继续加强基础练习' }, { id: 2, course_name: '体能训练课', total_count: 14, used_count: 4, remaining_count: 10, formal_hours: 12, gift_hours: 2, used_formal_hours: 3, used_gift_hours: 1, leave_count: 0, start_date: '2024-01-15', expiry_date: '2024-07-15', // 到期日期 status: 'active', db_status: 1, single_session_count: 60, main_coach_id: 2, main_coach_name: '李教练', education_id: null, education_name: '未分配', assistant_ids: '', assistant_names: '无', course_type: '体能课', teacher_name: '李教练', // 兼容字段 course_price: 1680.00, class_duration: 60, // 兼容字段 create_time: '2024-01-15 14:00:00', remark: '需要加强核心力量训练' } ] return this.createResponse(courseInfoData, 1, 'success') } // 其他家长端API的Mock数据处理 if (checkEndpoint(['/parent/child/materials', 'parent_getChildMaterials'])) { return this.createResponse({ data: [], total: 0 }, 1, 'success') } if (checkEndpoint(['/parent/child/services', 'parent_getChildServices'])) { return this.createResponse({ data: [], total: 0 }, 1, 'success') } if (checkEndpoint(['/parent/child/messages', 'parent_getChildMessages'])) { return this.createResponse({ data: [], total: 0 }, 1, 'success') } if (checkEndpoint(['/parent/child/contracts', 'parent_getChildContracts'])) { return this.createResponse({ data: [], total: 0 }, 1, 'success') } // 学员信息 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/service/list', 'getStudentServiceList'])) { const studentId = params.student_id || params.id || 1 // 模拟学员服务记录数据 const serviceListData = [ { id: 1, service_name: '游泳技能训练', preview_image_url: 'https://via.placeholder.com/200x120?text=游泳训练', description: '专业游泳技能指导,提升水中运动能力和安全意识', service_type: '技能训练', status: 'active', logs: [ { id: 101, status: 1, // completed service_content: '学员表现优秀,掌握了蛙泳基本动作\n• 蛙泳姿势:90%完成度\n• 呼吸节奏:85%完成度\n• 水中平衡:95%完成度', service_staff: '张教练', service_time: '2024-01-21 09:00:00', customer_feedback: '孩子很喜欢游泳课,教练很耐心', service_rating: 5, remark: '学员进步明显,建议继续巩固基础动作', updated_at: '2024-01-21 10:30:00' }, { id: 102, status: 1, // completed service_content: '继续巩固蛙泳技术,开始学习自由泳\n• 自由泳入门:良好\n• 换气技巧:需要练习\n• 游泳距离:100米连续', service_staff: '张教练', service_time: '2024-01-25 09:00:00', customer_feedback: '孩子进步很快,很有天赋', service_rating: 5, remark: '可以开始进阶训练', updated_at: '2024-01-25 10:30:00' } ], total_count: 2, completed_count: 2 }, { id: 2, service_name: '体能综合测评', preview_image_url: 'https://via.placeholder.com/200x120?text=体能测评', description: '全面体能测试与评估,制定个性化训练方案', service_type: '体能测评', status: 'active', logs: [ { id: 201, status: 1, // completed service_content: '体能测试结果良好,建议加强核心力量训练\n• 柔韧性:优秀\n• 平衡能力:良好\n• 耐力水平:需提升', service_staff: '李教练', service_time: '2024-01-14 14:00:00', customer_feedback: '测试很全面,建议很有用', service_rating: 4, remark: '整体素质不错,有提升空间', updated_at: '2024-01-14 15:30:00' } ], total_count: 1, completed_count: 1 }, { id: 3, service_name: '篮球技巧训练', preview_image_url: 'https://via.placeholder.com/200x120?text=篮球训练', description: '篮球基础技巧和战术训练,提升球感和协调性', service_type: '球类运动', status: 'active', logs: [ { id: 301, status: 0, // pending service_content: '本次训练重点练习运球和投篮\n• 运球技巧:有进步\n• 投篮姿势:需要调整\n• 团队配合:积极主动', service_staff: '王教练', service_time: '2024-01-26 16:00:00', customer_feedback: '', service_rating: null, remark: '训练进行中...', updated_at: '2024-01-26 16:00:00' }, { id: 302, status: 1, // completed service_content: '基础运球和传球练习\n• 基本运球:掌握良好\n• 双手传球:需要加强\n• 移动中运球:有待提高', service_staff: '王教练', service_time: '2024-01-19 16:00:00', customer_feedback: '教练很专业,孩子很喜欢', service_rating: 4, remark: '基础扎实,继续练习', updated_at: '2024-01-19 17:30:00' } ], total_count: 2, completed_count: 1 } ] return this.createResponse(serviceListData, 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 ) case '/fitness/record/pdf/preview': // PDF预览Mock数据 return this.createResponse({ file_url: 'https://example.com/fitness-report.pdf', file_name: '体测报告_' + (params.record_id || '123') + '.pdf', file_size: 1024000, preview_url: 'https://example.com/preview/fitness-report.pdf', download_url: 'https://example.com/download/fitness-report.pdf' }, 1, 'PDF预览链接获取成功') 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', '/fitness/record/pdf/preview', // 学员端专用API - URL匹配 '/customerResourcesAuth/info', // xy_memberInfo '/xy/physicalTest', // xy_physicalTest '/xy/personCourseSchedule', // xy_personCourseSchedule相关 '/xy/assignment', // xy_assignment相关 '/xy/service/list', // xy/service/list - 学员服务记录 '/xy/login', // xy_login '/getStudentCourseInfo', // 获取学员课程信息 // 家长端专用API - URL匹配 '/parent/children', // parent_getChildrenList '/parent/child/info', // parent_getChildInfo '/parent/child/courses', // parent_getChildCourses '/parent/child/orders', // parent_getChildOrders '/parent/child/materials', // parent_getChildMaterials '/parent/child/services', // parent_getChildServices '/parent/child/messages', // parent_getChildMessages '/parent/child/contracts', // parent_getChildContracts '/parent/child/update', // parent_updateChildInfo // 学员端专用API - 方法名匹配(用于开发调试) 'xy_memberInfo', 'xy_physicalTest', 'xy_personCourseSchedule', 'xy_assignment', 'xy_assignmentsInfo', 'xy_assignmentSubmitObj', 'xy_personCourseScheduleGetCalendar', 'xy_personCourseScheduleGetMyCoach', 'getStudentServiceList', // 学员服务记录列表 'xy_login', 'getStudentCourseInfo', // 家长端专用API - 方法名匹配(用于开发调试) 'parent_getChildrenList', 'parent_getChildInfo', 'parent_getChildCourses', 'parent_getChildOrders', 'parent_getChildMaterials', 'parent_getChildServices', 'parent_getChildMessages', 'parent_getChildContracts', 'parent_updateChildInfo' ] return mockableEndpoints.some(endpoint => url.includes(endpoint)) } } // 创建全局Mock服务实例 const mockService = new MockService() export default mockService