From 2324c324586831269673c4ee3413fde651e60f62 Mon Sep 17 00:00:00 2001 From: zeyan <258785420@qq.com> Date: Wed, 29 Oct 2025 18:10:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apiController/StudentManager.php | 45 +- niucloud/app/api/route/route.php | 1 + .../service/api/apiService/StudentService.php | 27 +- .../service/api/student/StudentService.php | 1 + uniapp/api/apiRoute.js | 1614 +---------------- .../client-info-card/client-info-card.vue | 46 +- uniapp/components/order-list-card/index.vue | 911 ++++++++-- .../order-list-card/qrcode-payment-dialog.vue | 207 +++ uniapp/components/schedule/ScheduleDetail.vue | 274 ++- .../student-edit-popup.less | 49 +- .../student-edit-popup/student-edit-popup.vue | 70 +- .../student-info-card/student-info-card.vue | 24 +- .../coach/schedule/schedule_table.vue | 62 +- .../clue/class_arrangement_detail.vue | 1 + uniapp/pages-market/clue/clue_info.vue | 718 +------- uniapp/pages-market/clue/edit_clues.vue | 201 +- 16 files changed, 1588 insertions(+), 2663 deletions(-) create mode 100644 uniapp/components/order-list-card/qrcode-payment-dialog.vue diff --git a/niucloud/app/api/controller/apiController/StudentManager.php b/niucloud/app/api/controller/apiController/StudentManager.php index fc983a89..7ddb4c67 100644 --- a/niucloud/app/api/controller/apiController/StudentManager.php +++ b/niucloud/app/api/controller/apiController/StudentManager.php @@ -147,4 +147,47 @@ class StudentManager extends BaseApiService return fail('添加学员失败:' . $e->getMessage()); } } -} \ No newline at end of file + + /** + * 获取学员基本信息(员工端) + * @param int $id 学员ID + * @return \think\Response + */ + public function info($id) + { + // 验证参数 + if (empty($id) || !is_numeric($id)) { + return fail('学员ID无效'); + } + + try { + // 直接查询学员基本信息,不需要权限验证 + $student = \think\facade\Db::table('school_student') + ->where('id', $id) + ->where('deleted_at', 0) + ->find(); + + if (!$student) { + return fail('学员信息不存在'); + } + + // 返回学员基本信息 + $studentInfo = [ + 'id' => $student['id'], + 'name' => $student['name'], + 'gender' => $student['gender'], + 'gender_text' => $student['gender'] == 1 ? '男' : '女', + 'birthday' => $student['birthday'], + 'campus_id' => $student['campus_id'] ?? null, + 'headimg' => $student['headimg'] ? get_image_url($student['headimg']) : '', + 'emergency_contact' => $student['emergency_contact'], + 'contact_phone' => $student['contact_phone'] + ]; + + return success($studentInfo, '获取学员信息成功'); + + } catch (\Exception $e) { + return fail('获取学员信息失败:' . $e->getMessage()); + } + } +} diff --git a/niucloud/app/api/route/route.php b/niucloud/app/api/route/route.php index a546e51d..2efb4a03 100644 --- a/niucloud/app/api/route/route.php +++ b/niucloud/app/api/route/route.php @@ -277,6 +277,7 @@ Route::group(function () { Route::post('student/edit', 'apiController.StudentManager/edit'); //销售端-学员-列表 Route::get('student/list', 'apiController.StudentManager/list'); + Route::get('student/info/:id', 'apiController.StudentManager/info'); //教练端-学员-我的学员列表 Route::get('coach/students/my', 'apiController.CoachStudent/getMyStudents'); diff --git a/niucloud/app/service/api/apiService/StudentService.php b/niucloud/app/service/api/apiService/StudentService.php index 8efa76a8..9a00827f 100644 --- a/niucloud/app/service/api/apiService/StudentService.php +++ b/niucloud/app/service/api/apiService/StudentService.php @@ -64,7 +64,7 @@ class StudentService extends BaseApiService // 插入数据库 $id = Db::table('school_student')->insertGetId($insertData); - + if ($id) { $res['code'] = 1; $res['msg'] = '添加成功'; @@ -115,7 +115,7 @@ class StudentService extends BaseApiService if (!empty($data['name'])) { $where[] = ['s.name', 'like', '%' . $data['name'] . '%']; } - + if (!empty($data['phone'])) { $where[] = ['s.contact_phone', 'like', '%' . $data['phone'] . '%']; } @@ -146,8 +146,7 @@ class StudentService extends BaseApiService // 查询该学员的课程安排记录,按日期排序获取一访和二访信息 $visitRecords = Db::table('school_person_course_schedule') ->where([ - ['person_id', '=', $student['id']], - ['person_type', '=', 'student'] + ['student_id', '=', $student['id']] ]) ->order('course_date', 'asc') ->select() @@ -197,27 +196,27 @@ class StudentService extends BaseApiService // 如果指定了parent_resource_id,则查询该资源下的学生 if (!empty($data['parent_resource_id'])) { $resourceId = $data['parent_resource_id']; - + // 验证当前用户是否有权限访问该资源 $resource = Db::table('school_customer_resources') ->where('id', $resourceId) ->where('consultant', $userId) ->where('deleted_at', 0) ->find(); - + if (empty($resource)) { // 用户无权限访问该资源 return []; } - + // 查询该资源关联的学生ID $studentIds = Db::table('school_student_courses') ->where('resource_id', $resourceId) ->column('student_id'); - + return array_values(array_unique($studentIds)); } - + // 如果没有指定资源ID,则查询当前用户(教练)负责的所有学生 return $this->getCoachStudentIds($userId, $data); } @@ -305,13 +304,13 @@ class StudentService extends BaseApiService if (empty($token)) { return 0; } - + // 去掉Bearer前缀 $token = str_replace('Bearer ', '', $token); - + // 使用项目的TokenAuth类解析token,类型为personnel(员工端) $tokenInfo = \core\util\TokenAuth::parseToken($token, 'personnel'); - + if (!empty($tokenInfo)) { // 从jti中提取用户ID(格式:用户ID_类型) $jti = $tokenInfo['jti'] ?? ''; @@ -322,7 +321,7 @@ class StudentService extends BaseApiService } } } - + return 0; } catch (\Exception $e) { return 0; @@ -363,4 +362,4 @@ class StudentService extends BaseApiService return $res; } -} \ No newline at end of file +} diff --git a/niucloud/app/service/api/student/StudentService.php b/niucloud/app/service/api/student/StudentService.php index 105a23a2..3b83f185 100644 --- a/niucloud/app/service/api/student/StudentService.php +++ b/niucloud/app/service/api/student/StudentService.php @@ -184,6 +184,7 @@ class StudentService extends BaseService 'contact_phone' => $student['contact_phone'], 'note' => $student['note'], 'headimg' => $student['headimg'] ? get_image_url($student['headimg']) : '', + 'campus_id' => $student['campus_id'] ?? null, // 添加校区ID ]; // 处理体测信息 diff --git a/uniapp/api/apiRoute.js b/uniapp/api/apiRoute.js index 760c75e7..7b098c89 100644 --- a/uniapp/api/apiRoute.js +++ b/uniapp/api/apiRoute.js @@ -6,7 +6,6 @@ export default { //统一登录接口 async unifiedLogin(data = {}) { const response = await http.post('/login/unified', data) - console.log('统一登录响应:', response) return response }, //教师/销售端详情 @@ -54,206 +53,6 @@ export default { async resetPassword(data = {}) { return await http.post('/common/resetPassword', data) }, - - // 课程安排列表 - Mock版本 - async getCourseScheduleListMock(data = {}) { - // 延迟模拟网络请求 - await new Promise(resolve => setTimeout(resolve, 500)) - - // 模拟课程数据 - const mockCourses = [ - { - id: 101, - date: '2025-07-14', // 周一 - time: '09:00', - courseName: '少儿形体课', - students: '已报名8人', - teacher: '张教练', - teacher_id: 1, - status: '未点名', - type: 'normal', // 普通课程 - venue: '舞蹈室A', - venue_id: 1, - class_id: 1, - duration: 1, - }, - { - id: 102, - date: '2025-07-14', // 周一 - time: '14:00', - courseName: '成人瑜伽', - students: '已报名12人', - teacher: '李教练', - teacher_id: 2, - status: '已点名', - type: 'normal', // 普通课程 - venue: '瑜伽B', - venue_id: 2, - class_id: 2, - duration: 1, - }, - { - id: 103, - date: '2025-07-15', // 周二 - time: '10:00', - courseName: '私教训练', - students: '已报名1人', - teacher: '王教练', - teacher_id: 3, - status: '未点名', - type: 'private', // 私教课程 - venue: '健身C', - venue_id: 3, - class_id: 3, - duration: 1, - }, - { - id: 104, - date: '2025-07-15', // 周二 - time: '16:00', - courseName: '儿童游泳', - students: '已报名6人', - teacher: '刘教练', - teacher_id: 4, - status: '未点名', - type: 'normal', // 普通课程 - venue: '泳池D', - venue_id: 4, - class_id: 4, - duration: 1, - }, - { - id: 105, - date: '2025-07-17', // 周四 - time: '14:00', - courseName: '暑季特训营', - students: '已报名15人', - teacher: '赵教练', - teacher_id: 5, - status: '未点名', - type: 'activity', // 活动课程 - venue: '综合场馆E', - venue_id: 5, - class_id: 5, - duration: 2, // 持续2小时 - }, - ] - - // 根据筛选条件过滤课程 - let filteredCourses = [...mockCourses] - - // 日期范围筛选 - if (data.start_date && data.end_date) { - filteredCourses = filteredCourses.filter(course => { - return course.date >= data.start_date && course.date <= data.end_date - }) - } - - // 教练筛选 - if (data.coach_id) { - const coachIds = Array.isArray(data.coach_id) ? data.coach_id : [data.coach_id] - filteredCourses = filteredCourses.filter(course => { - return coachIds.includes(course.teacher_id) - }) - } - - // 场地筛选 - if (data.venue_id) { - const venueIds = Array.isArray(data.venue_id) ? data.venue_id : [data.venue_id] - filteredCourses = filteredCourses.filter(course => { - return venueIds.includes(course.venue_id) - }) - } - - // 班级筛选 - if (data.class_id) { - const classIds = Array.isArray(data.class_id) ? data.class_id : [data.class_id] - filteredCourses = filteredCourses.filter(course => { - return classIds.includes(course.class_id) - }) - } - - // 时间段筛选 - if (data.time_range) { - switch (data.time_range) { - case 'morning': // 上午 - filteredCourses = filteredCourses.filter(course => { - const hour = parseInt(course.time.split(':')[0]) - return hour >= 8 && hour < 12 - }) - break - case 'afternoon': // 下午 - filteredCourses = filteredCourses.filter(course => { - const hour = parseInt(course.time.split(':')[0]) - return hour >= 12 && hour < 18 - }) - break - case 'evening': // 晚上 - filteredCourses = filteredCourses.filter(course => { - const hour = parseInt(course.time.split(':')[0]) - return hour >= 18 && hour < 22 - }) - break - } - } - - // 处理结果格式 - const result = { - list: filteredCourses.map(course => ({ - id: course.id, - course_date: course.date, - time_info: { - start_time: course.time, - end_time: this.calculateEndTime(course.time, course.duration), - duration: course.duration * 60, - }, - course_name: course.courseName, - enrolled_count: parseInt(course.students.match(/\d+/)[0]) || 0, - coach_name: course.teacher, - teacher_id: course.teacher_id, - status_text: course.status, - course_type: course.type, - venue_name: course.venue, - venue_id: course.venue_id, - campus_name: this.getCampusName(course.venue_id), - class_id: course.class_id, - available_capacity: course.type === 'private' ? 1 : (course.type === 'activity' ? 30 : 15), - time_slot: `${course.time}-${this.calculateEndTime(course.time, course.duration)}`, - })), - total: filteredCourses.length, - } - - return { - code: 1, - data: result, - msg: 'SUCCESS', - } - }, - - // 计算结束时间 - calculateEndTime(startTime, duration) { - const [hours, minutes] = startTime.split(':').map(Number) - let endHours = hours + duration - let endMinutes = minutes - - if (endHours >= 24) { - endHours -= 24 - } - - return `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}` - }, - - // 根据场地ID获取校区名称 - getCampusName(venueId) { - const campusMap = { - 1: '总部校区', - 2: '南山校区', - 3: '福田校区', - 4: '罗湖校区', - 5: '宝安校区', - } - return campusMap[venueId] || '总部校区' - }, //公共端-获取全部员工列表 async common_getPersonnelAll(data = {}) { return await http.get('/personnel/getPersonnelAll', data) @@ -546,7 +345,6 @@ export default { //学生登陆接口 async xy_login(data = {}) { const response = await http.post('/customerResourcesAuth/login', data) - console.log('学生登录响应:', response) return response }, //学生详情 @@ -730,370 +528,101 @@ export default { //↓↓↓↓↓↓↓↓↓↓↓↓-----课程预约相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ // 获取可预约课程列表 async getAvailableCourses(data = {}) { - try { - // 过滤掉undefined、null、空字符串的参数 - const params = {} - if (data.date !== undefined && data.date !== null && data.date !== '') { - params.date = data.date - } - if (data.start_date !== undefined && data.start_date !== null && data.start_date !== '') { - params.start_date = data.start_date - } - if (data.end_date !== undefined && data.end_date !== null && data.end_date !== '') { - params.end_date = data.end_date - } - if (data.coach_id !== undefined && data.coach_id !== null && data.coach_id !== '') { - params.coach_id = data.coach_id - } - if (data.venue_id !== undefined && data.venue_id !== null && data.venue_id !== '') { - params.venue_id = data.venue_id - } - if (data.course_type !== undefined && data.course_type !== null && data.course_type !== '') { - params.course_type = data.course_type - } - - const response = await http.get('/course-booking/available/' + data.student_id, params) - - // 检查响应状态,如果失败则降级到Mock数据 - if (response.code !== 1) { - console.warn('API返回错误,降级到Mock数据:', response.msg) - return await this.getAvailableCoursesMock(data) - } - - return response - } catch (error) { - console.error('获取可预约课程错误:', error) - // 返回模拟数据作为后备 - return await this.getAvailableCoursesMock(data) + // 过滤掉undefined、null、空字符串的参数 + const params = {} + if (data.date !== undefined && data.date !== null && data.date !== '') { + params.date = data.date } + if (data.start_date !== undefined && data.start_date !== null && data.start_date !== '') { + params.start_date = data.start_date + } + if (data.end_date !== undefined && data.end_date !== null && data.end_date !== '') { + params.end_date = data.end_date + } + if (data.coach_id !== undefined && data.coach_id !== null && data.coach_id !== '') { + params.coach_id = data.coach_id + } + if (data.venue_id !== undefined && data.venue_id !== null && data.venue_id !== '') { + params.venue_id = data.venue_id + } + if (data.course_type !== undefined && data.course_type !== null && data.course_type !== '') { + params.course_type = data.course_type + } + + return await http.get('/course-booking/available/' + data.student_id, params) }, // 创建课程预约 async createBooking(data = {}) { - try { - const response = await http.post('/course-booking/create', data) - - // 检查响应状态,如果失败则返回模拟成功响应 - if (response.code !== 1) { - console.warn('创建预约API返回错误,返回模拟成功响应:', response.msg) - return { - code: 1, - msg: '预约成功(模拟)', - data: { booking_id: Date.now() }, - } - } - - return response - } catch (error) { - console.error('创建预约错误:', error) - // 模拟成功响应 - return { - code: 1, - msg: '预约成功(模拟)', - data: { booking_id: Date.now() }, - } - } + return await http.post('/course-booking/create', data) }, // 获取我的预约列表 async getMyBookingList(data = {}) { - try { - // 过滤掉undefined值,避免传递"undefined"字符串 - const params = {} - if (data.status !== undefined && data.status !== null && data.status !== '') { - params.status = data.status - } - if (data.start_date !== undefined && data.start_date !== null && data.start_date !== '') { - params.start_date = data.start_date - } - if (data.end_date !== undefined && data.end_date !== null && data.end_date !== '') { - params.end_date = data.end_date - } - - const response = await http.get('/course-booking/my-list/' + data.student_id, params) - - // 检查响应状态,如果失败则降级到Mock数据 - if (response.code !== 1) { - console.warn('获取预约列表API返回错误,降级到Mock数据:', response.msg) - return await this.getMyBookingListMock(data) - } - - return response - } catch (error) { - console.error('获取预约列表错误:', error) - // 返回模拟数据作为后备 - return await this.getMyBookingListMock(data) + // 过滤掉undefined值,避免传递"undefined"字符串 + const params = {} + if (data.status !== undefined && data.status !== null && data.status !== '') { + params.status = data.status + } + if (data.start_date !== undefined && data.start_date !== null && data.start_date !== '') { + params.start_date = data.start_date } + if (data.end_date !== undefined && data.end_date !== null && data.end_date !== '') { + params.end_date = data.end_date + } + + return await http.get('/course-booking/my-list/' + data.student_id, params) }, // 取消预约 async cancelBooking(data = {}) { - try { - const response = await http.post('/course-booking/cancel', data) - - // 检查响应状态,如果失败则返回模拟成功响应 - if (response.code !== 1) { - console.warn('取消预约API返回错误,返回模拟成功响应:', response.msg) - return { - code: 1, - msg: '取消成功(模拟)', - } - } - - return response - } catch (error) { - console.error('取消预约错误:', error) - // 模拟成功响应 - return { - code: 1, - msg: '取消成功(模拟)', - } - } + return await http.post('/course-booking/cancel', data) }, // 获取学员汇总信息 async getStudentSummary(student_id) { - try { - return await http.get(`/student/summary/${student_id}`) - } catch (error) { - console.error('获取学员汇总信息错误:', error) - // 返回模拟数据 - return { - code: 1, - data: { - student_id: student_id, - name: '学员姓名', - booking_qualification: { - can_book: false, - remaining_courses: 0, - reason: '接口调用失败', - }, - }, - } - } - }, - - // 模拟可预约课程数据 - async getAvailableCoursesMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 500)) - - const mockCourses = [ - { - id: 1, - course_date: data.date || '2025-08-01', - start_time: '09:00', - end_time: '10:00', - duration: 60, - course_name: '基础体能训练', - course_type: '基础体能训练', - coach_name: '张教练', - venue_name: '训练馆A', - booking_status: 'available', - max_students: 8, - current_students: 3, - }, - { - id: 2, - course_date: data.date || '2025-08-01', - start_time: '10:30', - end_time: '11:30', - duration: 60, - course_name: '少儿体适能', - course_type: '少儿体适能', - coach_name: '李教练', - venue_name: '训练馆B', - booking_status: 'available', - max_students: 6, - current_students: 2, - }, - { - id: 3, - course_date: data.date || '2025-08-01', - start_time: '14:00', - end_time: '15:00', - duration: 60, - course_name: '专项训练', - course_type: '专项训练', - coach_name: '王教练', - venue_name: '训练馆A', - booking_status: 'full', - max_students: 4, - current_students: 4, - }, - ] - - return { - code: 1, - data: { - list: mockCourses, - total: mockCourses.length, - }, - msg: 'SUCCESS', - } - }, - - // 模拟我的预约列表数据 - async getMyBookingListMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 300)) - - const mockBookings = [ - { - id: 1, - booking_date: this.formatDateString(new Date(Date.now() + 24 * 60 * 60 * 1000)), - start_time: '16:00', - end_time: '17:00', - coach_name: '张教练', - course_type: '基础体能训练', - venue_name: '训练馆A', - status: 0, - status_text: '待上课', - }, - ] - - return { - code: 1, - data: { - list: mockBookings, - total: mockBookings.length, - }, - msg: 'SUCCESS', - } + return await http.get(`/student/summary/${student_id}`) }, //↓↓↓↓↓↓↓↓↓↓↓↓-----课程安排相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ // 获取课程安排列表(支持学员和教练端) async getCourseScheduleList(data = {}) { - try { - let response - - // 如果有student_id参数,说明是学员端调用,使用学员端API - if (data.student_id) { - response = await http.get('/course-schedule/list/' + data.student_id, { - date: data.date, - status: data.status, - start_date: data.start_date, - end_date: data.end_date, - }) - } else { - // 否则是教练端调用,使用教练端API - response = await http.get('/courseSchedule/list', { - start_date: data.start_date, - end_date: data.end_date, - coach_id: data.coach_id, - venue_id: data.venue_id, - class_id: data.class_id, - time_range: data.time_range, - view_type: data.view_type, - page: data.page || 1, - limit: data.limit || 9999, - }) - } - - return response - } catch (error) { - console.error('获取课程安排列表错误:', error) - uni.showModal({ - title: '获取课程安排列表错误', - content: JSON.stringify(error), - showCancel: false, + let response + + // 如果有student_id参数,说明是学员端调用,使用学员端API + if (data.student_id) { + response = await http.get('/course-schedule/list/' + data.student_id, { + date: data.date, + status: data.status, + start_date: data.start_date, + end_date: data.end_date, + }) + } else { + // 否则是教练端调用,使用教练端API + response = await http.get('/courseSchedule/list', { + start_date: data.start_date, + end_date: data.end_date, + coach_id: data.coach_id, + venue_id: data.venue_id, + class_id: data.class_id, + time_range: data.time_range, + view_type: data.view_type, + page: data.page || 1, + limit: data.limit || 9999, }) } - }, + return response + }, // 申请课程请假 async requestCourseLeave(data = {}) { - try { - const response = await http.post('/course-schedule/leave', data) - return response - } catch (error) { - console.error('申请课程请假错误:', error) - // 模拟请假申请成功 - return { - code: 1, - msg: '请假申请已提交', - } - } + return await http.post('/course-schedule/leave', data) }, + // 获取课程安排详情(用于课程调整页面) async getCourseScheduleInfo(data = {}) { - try { - // 使用真实的API接口获取课程安排详情 - 调整页面专用接口 - const result = await http.get('/courseSchedule/info', data) - console.log('获取课程安排详情:', result) - return result - } catch (error) { - console.error('获取课程安排详情失败:', error) - // 如果接口调用失败,降级到Mock数据 - return this.getCourseScheduleInfoMock(data) - } - }, - - // 模拟课程安排详情数据 - async getCourseScheduleInfoMock(data = {}) { - // 模拟数据加载延迟 - await new Promise(resolve => setTimeout(resolve, 500)) - - // 使用默认学生数据 - const defaultStudents = [ - { - id: 1, - name: '张三', - avatar: '/static/icon-img/avatar.png', - status: 0, - status_text: '未点名', - statusClass: 'status-pending', - }, - { - id: 2, - name: '李四', - avatar: '/static/icon-img/avatar.png', - status: 1, - status_text: '已点名', - statusClass: 'status-present', - }, - { - id: 3, - name: '王五', - avatar: '/static/icon-img/avatar.png', - status: 2, - status_text: '请假', - statusClass: 'status-leave', - }, - ] - - // 课程安排模拟数据 - const mockScheduleInfo = { - id: parseInt(data.schedule_id), - course_name: '大课7+1类型', - course_date: '2025-07-25', - time_slot: '09:00-10:00', - venue_name: '时间范围教室', - campus_name: '测试校区', - coach_name: '老六', - status: 'pending', - status_text: '即将开始', - class_info: { - id: 1, - class_name: '少儿形体班', - }, - course_duration: 60, - students: defaultStudents, - course_info: { - total_hours: 20, - use_total_hours: 8, - gift_hours: 2, - use_gift_hours: 1, - start_date: '2025-06-01', - end_date: '2025-12-31', - }, - } - - return { - code: 1, - data: mockScheduleInfo, - msg: 'SUCCESS', - } + return await http.get('/courseSchedule/info', data) }, // 创建课程安排 async createCourseSchedule(data = {}) { @@ -1127,77 +656,21 @@ export default { }, // 检查教练时间冲突 async checkCoachConflict(data = {}) { - // 未登录或测试模式使用模拟数据 - if (!uni.getStorageSync('token')) { - return this.checkCoachConflictMock(data) - } return await http.get('/courseSchedule/checkCoachConflict', data) }, - // 模拟教练时间冲突检查 - async checkCoachConflictMock(data = {}) { - // 模拟数据加载延迟 - await new Promise(resolve => setTimeout(resolve, 300)) - - // 模拟冲突检查逻辑 - const { coach_id, date, time_slot } = data - - // 日期匹配 2025-07-14 或 2025-07-15 - const conflictDates = ['2025-07-14', '2025-07-15'] - - // 特定教练和时间段的冲突场景 - const hasConflict = ( - // 张教练在特定日期的时间冲突 - (coach_id == 1 && conflictDates.includes(date) && time_slot === '09:00-10:00') || - // 李教练在特定日期的时间冲突 - (coach_id == 2 && conflictDates.includes(date) && time_slot === '14:00-15:00') || - // 随机生成一些冲突情况进行测试 - (Math.random() < 0.2 && coach_id && date && time_slot) - ) - - return { - code: 1, - data: { - has_conflict: hasConflict, - conflict_schedules: hasConflict ? [ - { - id: Math.floor(Math.random() * 1000), - course_name: hasConflict ? '冲突课程' : '', - time_slot: time_slot, - venue_name: '测试场地', - }, - ] : [], - }, - msg: 'SUCCESS', - } - }, // 获取课程安排统计 async getCourseScheduleStatistics(data = {}) { - try { - // 如果有student_id参数,使用学员个人统计接口 - if (data.student_id) { - const response = await http.get('/course-schedule/statistics/' + data.student_id, { - start_date: data.start_date, - end_date: data.end_date, - }) - return response - } else { - // 否则使用全局统计接口 - return await http.get('/course-schedule/courseSchedule/statistics', data) - } - } catch (error) { - console.error('获取课程统计失败:', error) - // 返回默认统计数据 - return { - code: 1, - data: { - total_courses: 0, - completed_courses: 0, - scheduled_courses: 0, - cancelled_courses: 0, - }, - msg: '获取统计数据成功', - } + // 如果有student_id参数,使用学员个人统计接口 + if (data.student_id) { + const response = await http.get('/course-schedule/statistics/' + data.student_id, { + start_date: data.start_date, + end_date: data.end_date, + }) + return response + } else { + // 否则使用全局统计接口 + return await http.get('/course-schedule/courseSchedule/statistics', data) } }, // 获取筛选选项 @@ -1280,378 +753,54 @@ export default { // 移除学员(统一接口) async removeStudent(data = {}) { - try { - const response = await http.post('/course/removeStudentFromSchedule', data) - return response - } catch (error) { - console.error('移除学员失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '移除学员成功(模拟)', - data: {} - } - } + return await http.post('/course/removeStudentFromSchedule', data) }, // 恢复学员(统一接口) async restoreStudent(data = {}) { - try { - const response = await http.post('/course/restoreStudent', data) - return response - } catch (error) { - console.error('恢复学员失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '恢复学员成功(模拟)', - data: {} - } - } + return await http.post('/course/restoreStudent', data) }, //↓↓↓↓↓↓↓↓↓↓↓↓-----统一课程安排详情管理接口(与admin端保持一致)-----↓↓↓↓↓↓↓↓↓↓↓↓ // 获取课程安排详情(新统一接口 - 对接admin端) async getCourseArrangementDetail(data = {}) { - try { - const response = await http.get('/course/scheduleDetail', data) - return response - } catch (error) { - console.error('获取课程安排详情失败:', error) - // 降级到 Mock 数据 - return await this.getCourseArrangementDetailMock(data) - } + return await http.get('/course/scheduleDetail', data) }, // 搜索学员(新统一接口 - 对接admin端) async searchStudentsForArrangement(data = {}) { - try { - const response = await http.get('/course/searchStudents', data) - return response - } catch (error) { - console.error('搜索学员失败:', error) - // 降级到 Mock 数据 - return await this.searchStudentsForArrangementMock(data) - } + return await http.get('/course/searchStudents', data) }, // 添加学员到课程安排(新统一接口 - 对接admin端) async addStudentToArrangement(data = {}) { - try { - const response = await http.post('/course/addStudentToSchedule', data) - return response - } catch (error) { - console.error('添加学员失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '添加学员成功(模拟)', - data: { id: Date.now() } - } - } + return await http.post('/course/addStudentToSchedule', data) }, // 移除学员(新统一接口 - 对接admin端) async removeStudentFromArrangement(data = {}) { - try { - const response = await http.post('/course/removeStudentFromSchedule', data) - return response - } catch (error) { - console.error('移除学员失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '移除学员成功(模拟)', - data: {} - } - } + return await http.post('/course/removeStudentFromSchedule', data) }, // 升级学员(新统一接口 - 对接admin端) async upgradeStudentInArrangement(data = {}) { - try { - const response = await http.post('/course/upgradeStudent', data) - return response - } catch (error) { - console.error('升级学员失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '升级学员成功(模拟)', - data: {} - } - } + return await http.post('/course/upgradeStudent', data) }, // 更新学员状态(新统一接口 - 对接admin端) async updateStudentStatusInArrangement(data = {}) { - try { - const response = await http.post('/courseSchedule/updateStudentStatus', data) - return response - } catch (error) { - console.error('更新学员状态失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '更新状态成功(模拟)', - data: {} - } - } + return await http.post('/courseSchedule/updateStudentStatus', data) }, // 删除学员所有未来课程安排 async deleteStudentFutureSchedules(data = {}) { - try { - const response = await http.post('/courseSchedule/deleteStudentFutureSchedules', data) - return response - } catch (error) { - console.error('删除学员未来课程安排失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '删除成功(模拟)', - data: { deleted_count: 0 } - } - } + return await http.post('/courseSchedule/deleteStudentFutureSchedules', data) }, // 恢复学员(新统一接口 - 对接admin端) async restoreStudentInArrangement(data = {}) { - try { - const response = await http.post('/course/restoreStudent', data) - return response - } catch (error) { - console.error('恢复学员失败:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '恢复学员成功(模拟)', - data: {} - } - } - }, - - //↓↓↓↓↓↓↓↓↓↓↓↓-----新统一课程安排Mock数据(与admin端保持一致)-----↓↓↓↓↓↓↓↓↓↓↓↓ - - // 模拟课程安排详情数据(对应admin端格式) - async getCourseArrangementDetailMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 500)) - - const mockStudents = [ - { - id: 1, - person_id: 1, - student_id: 1, - name: '张小明', - phone: '13800138001', - age: 8, - person_type: 'student', - person_type_text: '正式学员', - schedule_type: 1, - status: 0, - course_progress: { - used: 5, - total: 20, - percentage: 25 - } - }, - { - id: 2, - person_id: 2, - resources_id: 2, - name: '李小红', - phone: '13800138002', - age: 7, - person_type: 'customer_resource', - person_type_text: '潜在客户', - schedule_type: 2, - status: 0, - course_progress: { - used: 0, - total: 1, - percentage: 0 - } - } - ] - - return { - code: 1, - data: { - schedule_info: { - id: parseInt(data.schedule_id) || 1, - course_name: '少儿体适能课程', - course_date: '2025-08-16', - time_slot: '09:00-10:00', - venue_name: '训练馆A', - campus_name: '总部校区', - coach_name: '张教练', - status: 'upcoming', - status_text: '即将开始' - }, - formal_students: mockStudents.filter(s => s.schedule_type === 1), - waiting_students: mockStudents.filter(s => s.schedule_type === 2), - formal_empty_seats: [2, 3, 4, 5], - waiting_empty_seats: [2, 3] - }, - msg: 'SUCCESS' - } - }, - - // 模拟搜索学员数据(对应admin端格式) - async searchStudentsForArrangementMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 300)) - - const mockResults = [ - { - id: 101, - person_id: 101, - student_id: 101, - name: '王小华', - phone: '13800138101', - age: 9, - person_type: 'student', - person_type_text: '正式学员' - }, - { - id: 102, - person_id: 102, - resources_id: 102, - name: '赵小美', - phone: '13800138102', - age: 6, - person_type: 'customer_resource', - person_type_text: '潜在客户' - } - ] - - // 根据关键词过滤 - let filteredResults = mockResults - if (data.keyword) { - filteredResults = mockResults.filter(student => - student.name.includes(data.keyword) || student.phone.includes(data.keyword) - ) - } - - return { - code: 1, - data: { - list: filteredResults, - total: filteredResults.length - }, - msg: 'SUCCESS' - } - }, - - //↓↓↓↓↓↓↓↓↓↓↓↓-----统一课程安排Mock数据-----↓↓↓↓↓↓↓↓↓↓↓↓ - - // 模拟课程安排详情数据 - async getScheduleDetailMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 500)) - - const mockStudents = [ - { - id: 1, - person_id: 1, - student_id: 1, - name: '张小明', - phone: '13800138001', - age: 8, - person_type: 'student', - person_type_text: '正式学员', - schedule_type: 1, - status: 0, - course_progress: { - used: 5, - total: 20, - percentage: 25 - } - }, - { - id: 2, - person_id: 2, - resources_id: 2, - name: '李小红', - phone: '13800138002', - age: 7, - person_type: 'customer_resource', - person_type_text: '潜在客户', - schedule_type: 2, - status: 0, - course_progress: { - used: 0, - total: 1, - percentage: 0 - } - } - ] - - return { - code: 1, - data: { - schedule_info: { - id: parseInt(data.schedule_id) || 1, - course_name: '少儿体适能课程', - course_date: '2025-08-16', - time_slot: '09:00-10:00', - venue_name: '训练馆A', - campus_name: '总部校区', - coach_name: '张教练', - status: 'upcoming', - status_text: '即将开始' - }, - formal_students: mockStudents.filter(s => s.schedule_type === 1), - waiting_students: mockStudents.filter(s => s.schedule_type === 2), - formal_empty_seats: [2, 3, 4, 5], - waiting_empty_seats: [2, 3] - }, - msg: 'SUCCESS' - } - }, - - // 模拟搜索学员数据 - async searchStudentsMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 300)) - - const mockResults = [ - { - id: 101, - person_id: 101, - student_id: 101, - name: '王小华', - phone: '13800138101', - age: 9, - person_type: 'student', - person_type_text: '正式学员' - }, - { - id: 102, - person_id: 102, - resources_id: 102, - name: '赵小美', - phone: '13800138102', - age: 6, - person_type: 'customer_resource', - person_type_text: '潜在客户' - } - ] - - // 根据关键词过滤 - let filteredResults = mockResults - if (data.keyword) { - filteredResults = mockResults.filter(student => - student.name.includes(data.keyword) || student.phone.includes(data.keyword) - ) - } - - return { - code: 1, - data: { - list: filteredResults, - total: filteredResults.length - }, - msg: 'SUCCESS' - } + return await http.post('/course/restoreStudent', data) }, //↓↓↓↓↓↓↓↓↓↓↓↓-----学员出勤管理相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ @@ -1768,12 +917,9 @@ export default { return await http.get('/student/mychild') }, - // 获取学员基本信息 + // 获取学员基本信息(员工端) async getStudentBasicInfo(data = {}) { - const params = { - student_id: data.student_id, - } - return await http.get('/student/student-info', params) + return await http.get(`/student/info/${data.student_id}`) }, //↓↓↓↓↓↓↓↓↓↓↓↓-----员工端合同管理相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ @@ -1820,7 +966,7 @@ export default { async getContractByOrder(data = {}) { return await http.get('/contract/getByOrder', { order_id: data.order_id, - student_id: data.student_id + student_id: data.student_id, }) }, @@ -1828,8 +974,7 @@ export default { // 获取知识文章列表 async getKnowledgeList(data = {}) { - try { - const params = { + const params = { category: data.category, page: data.page || 1, limit: data.limit || 10, @@ -1837,110 +982,35 @@ export default { } const response = await http.get(`/knowledge-test/list/${data.student_id}`, params) return response - } catch (error) { - console.error('获取知识文章列表错误:', error) - // 返回模拟数据作为后备 - return await this.getKnowledgeListMock(data) - } }, // 获取知识分类列表 async getKnowledgeCategories(data = {}) { - try { - const response = await http.get('/knowledge-test/categories') - return response - } catch (error) { - console.error('获取知识分类错误:', error) - // 返回模拟数据作为后备 - return await this.getKnowledgeCategoriesMock() - } - }, - - // 获取推荐文章 - async getRecommendArticles(data = {}) { - try { - const params = { - limit: data.limit || 5, - } - const response = await http.get(`/knowledge-test/recommend/${data.student_id}`, params) + const response = await http.get('/knowledge-test/categories') return response - } catch (error) { - console.error('获取推荐文章错误:', error) - // 返回模拟数据作为后备 - return await this.getRecommendArticlesMock(data) - } }, // 获取文章详情 async getKnowledgeDetail(data = {}) { - try { - const params = { + const params = { student_id: data.student_id, } const response = await http.get(`/knowledge-test/detail/${data.id}`, params) return response - } catch (error) { - console.error('获取文章详情错误:', error) - // 返回模拟数据作为后备 - return await this.getKnowledgeDetailMock(data) - } }, // 标记文章已读 async markArticleRead(data = {}) { - try { - const response = await http.post('/knowledge-test/mark-read', { + const response = await http.post('/knowledge-test/mark-read', { article_id: data.article_id, student_id: data.student_id, }) return response - } catch (error) { - console.error('标记文章已读错误:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '标记已读成功', - data: { message: '标记已读成功' }, - } - } - }, - - // 收藏/取消收藏文章 - async toggleArticleFavorite(data = {}) { - try { - const response = await http.post('/knowledge-test/toggle-favorite', { - article_id: data.article_id, - student_id: data.student_id, - action: data.action, - }) - return response - } catch (error) { - console.error('收藏操作错误:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: data.action === 'add' ? '收藏成功' : '取消收藏成功', - data: { is_favorite: data.action === 'add' }, - } - } - }, - - // 获取知识库统计 - async getKnowledgeStats(data = {}) { - try { - const response = await http.get(`/knowledge-test/stats/${data.student_id}`) - return response - } catch (error) { - console.error('获取知识库统计错误:', error) - // 返回模拟数据作为后备 - return await this.getKnowledgeStatsMock(data) - } }, // 搜索知识文章 async searchKnowledgeArticles(data = {}) { - try { - const params = { + const params = { keyword: data.keyword, category: data.category, page: data.page || 1, @@ -1948,225 +1018,20 @@ export default { } const response = await http.get(`/knowledge-test/search/${data.student_id}`, params) return response - } catch (error) { - console.error('搜索知识文章错误:', error) - // 返回模拟数据作为后备 - return await this.searchKnowledgeArticlesMock(data) - } }, - //↓↓↓↓↓↓↓↓↓↓↓↓-----知识库Mock数据-----↓↓↓↓↓↓↓↓↓↓↓↓ - - // 模拟知识文章列表数据 - async getKnowledgeListMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 500)) - - const mockArticles = [ - { - id: 1, - title: '少儿体适能训练基础知识', - image: '/static/knowledge/article1.jpg', - content: '体适能是指人体所具备的有充足的精力从事日常工作而不易疲劳,同时有余力享受休闲活动的乐趣,能够应付突发状况的身体适应能力。', - table_type: '2', - category_name: '跳绳教案库', - type: 1, - url: '', - status: 1, - create_time: 1627804800, - update_time: 1627804800, - user_permission: '', - is_read: false, - is_favorite: false, - }, - { - id: 2, - title: '儿童运动安全防护指南', - image: '/static/knowledge/article2.jpg', - content: '儿童参与运动时的安全防护措施是确保运动效果和避免运动伤害的重要保障。本文详细介绍了各种运动项目的安全注意事项。', - table_type: '7', - category_name: '少儿安防教案库', - type: 1, - url: '', - status: 1, - create_time: 1627804700, - update_time: 1627804700, - user_permission: '', - is_read: true, - is_favorite: true, - }, - { - id: 3, - title: '篮球基础技巧训练方法', - image: '/static/knowledge/article3.jpg', - content: '篮球作为一项受欢迎的运动项目,需要掌握正确的基础技巧。本教案介绍了运球、投篮、传球等基本技能的训练方法。', - table_type: '4', - category_name: '篮球教案库', - type: 1, - url: '', - status: 1, - create_time: 1627804600, - update_time: 1627804600, - user_permission: '', - is_read: false, - is_favorite: false, - }, - ] - - // 根据分类筛选 - let filteredArticles = mockArticles - if (data.category) { - filteredArticles = mockArticles.filter(article => article.table_type === data.category) - } - // 根据关键词搜索 - if (data.keyword) { - filteredArticles = filteredArticles.filter(article => - article.title.includes(data.keyword) || article.content.includes(data.keyword), - ) - } - - return { - code: 1, - data: { - list: filteredArticles, - current_page: data.page || 1, - last_page: 1, - total: filteredArticles.length, - per_page: data.limit || 10, - }, - msg: '获取知识文章列表成功', - } - }, - // 模拟知识分类数据 - async getKnowledgeCategoriesMock() { - await new Promise(resolve => setTimeout(resolve, 300)) - - return { - code: 1, - data: [ - { value: '1', text: '课程教学大纲', icon: '📖', count: 8 }, - { value: '2', text: '跳绳教案库', icon: '🏃', count: 15 }, - { value: '3', text: '增高教案库', icon: '📏', count: 6 }, - { value: '4', text: '篮球教案库', icon: '🏀', count: 12 }, - { value: '5', text: '强化教案库', icon: '💪', count: 9 }, - { value: '6', text: '空中忍者教案库', icon: '🥷', count: 7 }, - { value: '7', text: '少儿安防教案库', icon: '🛡️', count: 5 }, - { value: '8', text: '体能教案库', icon: '🏋️', count: 11 }, - ], - msg: '获取知识分类成功', - } - }, - // 模拟推荐文章数据 - async getRecommendArticlesMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 400)) - - const mockRecommendArticles = [ - { - id: 1, - title: '少儿体适能训练基础知识', - image: '/static/knowledge/article1.jpg', - summary: '体适能是指人体所具备的有充足的精力从事日常工作而不易疲劳,同时有余力享受休闲活动的乐趣...', - category_name: '跳绳教案库', - create_time: 1627804800, - read_count: 156, - }, - { - id: 2, - title: '儿童运动安全防护指南', - image: '/static/knowledge/article2.jpg', - summary: '儿童参与运动时的安全防护措施是确保运动效果和避免运动伤害的重要保障...', - category_name: '少儿安防教案库', - create_time: 1627804700, - read_count: 89, - }, - ] - - return { - code: 1, - data: mockRecommendArticles.slice(0, data.limit || 5), - msg: '获取推荐文章成功', - } - }, - // 模拟文章详情数据 - async getKnowledgeDetailMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 600)) - - return { - code: 1, - data: { - id: data.id, - title: '少儿体适能训练基础知识', - image: '/static/knowledge/article1.jpg', - content: ` -

什么是体适能?

-

体适能是指人体所具备的有充足的精力从事日常工作而不易疲劳,同时有余力享受休闲活动的乐趣,能够应付突发状况的身体适应能力。

- -

少儿体适能的重要性

-

1. 促进身体发育:通过科学的运动训练,可以促进儿童骨骼、肌肉的健康发育。

-

2. 提高运动能力:培养儿童的协调性、平衡性、柔韧性等基本运动能力。

-

3. 增强体质:提高儿童的心肺功能,增强免疫力。

- -

训练原则

-

• 循序渐进:从简单到复杂,从易到难

-

• 因材施教:根据儿童的年龄特点和个体差异制定训练计划

-

• 寓教于乐:将训练内容游戏化,提高儿童参与的积极性

- `, - table_type: '2', - category_name: '跳绳教案库', - type: 1, - url: '', - status: 1, - create_time: 1627804800, - update_time: 1627804800, - user_permission: '', - exam_papers_id: 0, - is_read: false, - is_favorite: false, - }, - msg: '获取文章详情成功', - } - }, - // 模拟知识库统计数据 - async getKnowledgeStatsMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 300)) - - return { - code: 1, - data: { - total_articles: 45, - favorites: 8, - read_articles: 23, - categories_count: { - '1': 8, - '2': 15, - '3': 6, - '4': 12, - '5': 9, - '6': 7, - '7': 5, - '8': 11, - }, - }, - msg: '获取知识库统计成功', - } - }, - // 模拟搜索知识文章数据 - async searchKnowledgeArticlesMock(data = {}) { - // 复用知识文章列表的Mock数据,根据关键词进行筛选 - return await this.getKnowledgeListMock(data) - }, //↓↓↓↓↓↓↓↓↓↓↓↓-----学员端消息管理相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ // 获取学员消息列表 async getStudentMessageList(data = {}) { - try { - const params = { + const params = { message_type: data.message_type, page: data.page || 1, limit: data.limit || 10, @@ -2175,83 +1040,29 @@ export default { } const response = await http.get(`/message/list/${data.student_id}`, params) return response - } catch (error) { - console.error('获取学员消息列表错误:', error) - // 返回模拟数据作为后备 - return await this.getStudentMessageListMock(data) - } }, // 获取消息详情 async getStudentMessageDetail(data = {}) { - try { - const params = { + const params = { student_id: data.student_id, } const response = await http.get(`/message/detail/${data.message_id}`, params) return response - } catch (error) { - console.error('获取消息详情错误:', error) - // 返回模拟数据作为后备 - return await this.getStudentMessageDetailMock(data) - } }, // 标记消息已读 async markStudentMessageRead(data = {}) { - try { - const response = await http.post('/message/mark-read', { + const response = await http.post('/message/mark-read', { message_id: data.message_id, student_id: data.student_id, }) return response - } catch (error) { - console.error('标记消息已读错误:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '标记已读成功', - data: { message: '标记已读成功' }, - } - } - }, - - // 批量标记消息已读 - async markStudentMessageBatchRead(data = {}) { - try { - const response = await http.post('/message/mark-batch-read', { - student_id: data.student_id, - message_ids: data.message_ids, - message_type: data.message_type, - }) - return response - } catch (error) { - console.error('批量标记已读错误:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '批量标记成功', - data: { message: '批量标记成功', updated_count: data.message_ids?.length || 0 }, - } - } - }, - - // 获取学员消息统计 - async getStudentMessageStats(data = {}) { - try { - const response = await http.get(`/message/stats/${data.student_id}`) - return response - } catch (error) { - console.error('获取消息统计错误:', error) - // 返回模拟数据作为后备 - return await this.getStudentMessageStatsMock(data) - } }, // 获取对话中的所有消息 async getConversationMessages(data = {}) { - try { - const params = { + const params = { student_id: data.student_id, from_type: data.from_type, from_id: data.from_id, @@ -2260,245 +1071,10 @@ export default { } const response = await http.get('/message/conversation', params) return response - } catch (error) { - console.error('获取对话消息错误:', error) - // 返回空对话作为后备 - return { - code: 1, - data: { - list: [], - current_page: 1, - last_page: 1, - total: 0, - per_page: 20, - has_more: false, - }, - msg: 'SUCCESS', - } - } - }, - - // 学员回复消息 - async replyMessage(data = {}) { - try { - const response = await http.post('/message/reply', { - student_id: data.student_id, - to_type: data.to_type, - to_id: data.to_id, - content: data.content, - message_type: data.message_type || 'text', - title: data.title || '', - }) - return response - } catch (error) { - console.error('回复消息错误:', error) - // 返回模拟成功响应 - return { - code: 1, - msg: '回复发送成功', - data: { - message: '回复发送成功', - data: { - id: Date.now(), - content: data.content, - created_at: new Date().toISOString().replace('T', ' ').slice(0, 19), - create_time: Math.floor(Date.now() / 1000), - from_name: '我', - is_sent_by_student: true, - }, - }, - } - } - }, - - // 搜索学员消息 - async searchStudentMessages(data = {}) { - try { - const params = { - keyword: data.keyword, - message_type: data.message_type, - page: data.page || 1, - limit: data.limit || 10, - } - const response = await http.get(`/message/search/${data.student_id}`, params) - return response - } catch (error) { - console.error('搜索消息错误:', error) - // 返回模拟数据作为后备 - return await this.searchStudentMessagesMock(data) - } }, - //↓↓↓↓↓↓↓↓↓↓↓↓-----学员端消息管理Mock数据-----↓↓↓↓↓↓↓↓↓↓↓↓ - - // 模拟学员消息列表数据 - async getStudentMessageListMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 500)) - - const mockMessages = [ - { - id: 1, - from_type: 'system', - from_id: 0, - message_type: 'system', - title: '欢迎使用学员端', - content: '欢迎使用学员端,您可以在这里查看课程安排、作业任务等信息。', - business_id: null, - business_type: '', - is_read: 0, - read_time: null, - create_time: Math.floor(Date.now() / 1000) - 3600, - type_text: '系统消息', - from_name: '系统', - summary: '欢迎使用学员端,您可以在这里查看课程安排、作业任务等信息。', - }, - { - id: 2, - from_type: 'personnel', - from_id: 1, - message_type: 'homework', - title: '新作业任务', - content: '您有一项新的作业任务:完成本周的体能训练计划,请按时提交。', - business_id: 1, - business_type: 'homework', - is_read: 0, - read_time: null, - create_time: Math.floor(Date.now() / 1000) - 1800, - type_text: '作业任务', - from_name: '教务老师', - summary: '您有一项新的作业任务:完成本周的体能训练计划,请按时提交。', - }, - { - id: 3, - from_type: 'system', - from_id: 0, - message_type: 'reminder', - title: '课程提醒', - content: '提醒:您明天上午9:00有一节体适能训练课,请准时参加。', - business_id: 1, - business_type: 'course', - is_read: 1, - read_time: new Date(Date.now() - 900 * 1000).toISOString(), - create_time: Math.floor(Date.now() / 1000) - 7200, - type_text: '课程提醒', - from_name: '系统', - summary: '提醒:您明天上午9:00有一节体适能训练课,请准时参加。', - }, - { - id: 4, - from_type: 'personnel', - from_id: 2, - message_type: 'notification', - title: '重要通知', - content: '本周六将举行家长开放日活动,欢迎家长朋友们前来参观指导。', - business_id: null, - business_type: '', - is_read: 0, - read_time: null, - create_time: Math.floor(Date.now() / 1000) - 86400, - type_text: '通知公告', - from_name: '教务老师', - summary: '本周六将举行家长开放日活动,欢迎家长朋友们前来参观指导。', - }, - { - id: 5, - from_type: 'system', - from_id: 0, - message_type: 'feedback', - title: '课程评价邀请', - content: '您上次参加的体适能训练课已结束,请对本次课程进行评价。', - business_id: 2, - business_type: 'course', - is_read: 1, - read_time: new Date(Date.now() - 3600 * 1000).toISOString(), - create_time: Math.floor(Date.now() / 1000) - 172800, - type_text: '反馈评价', - from_name: '系统', - summary: '您上次参加的体适能训练课已结束,请对本次课程进行评价。', - }, - ] - - // 根据消息类型筛选 - let filteredMessages = mockMessages - if (data.message_type && data.message_type !== 'all') { - filteredMessages = mockMessages.filter(msg => msg.message_type === data.message_type) - } - // 根据已读状态筛选 - if (data.is_read !== '' && data.is_read !== undefined) { - filteredMessages = filteredMessages.filter(msg => msg.is_read == data.is_read) - } - // 根据关键词搜索 - if (data.keyword) { - filteredMessages = filteredMessages.filter(msg => - msg.title.includes(data.keyword) || msg.content.includes(data.keyword), - ) - } - return { - code: 1, - data: { - list: filteredMessages, - current_page: data.page || 1, - last_page: 1, - total: filteredMessages.length, - per_page: data.limit || 10, - has_more: false, - }, - msg: '获取消息列表成功', - } - }, - - // 模拟消息详情数据 - async getStudentMessageDetailMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 300)) - - return { - code: 1, - data: { - id: data.message_id, - from_type: 'system', - from_id: 0, - message_type: 'system', - title: '欢迎使用学员端', - content: '欢迎使用学员端,您可以在这里查看课程安排、作业任务等信息。如有任何问题,请随时联系我们的客服团队。', - business_id: null, - business_type: '', - is_read: 0, - read_time: null, - create_time: Math.floor(Date.now() / 1000) - 3600, - type_text: '系统消息', - from_name: '系统', - }, - msg: '获取消息详情成功', - } - }, - // 模拟消息统计数据 - async getStudentMessageStatsMock(data = {}) { - await new Promise(resolve => setTimeout(resolve, 300)) - - return { - code: 1, - data: { - total_messages: 12, - unread_messages: 5, - read_messages: 7, - type_counts: { - 'system': 3, - 'notification': 2, - 'homework': 3, - 'feedback': 2, - 'reminder': 2, - }, - }, - msg: '获取消息统计成功', - } - }, - // 模拟搜索消息数据 - async searchStudentMessagesMock(data = {}) { - // 复用消息列表的Mock数据,根据关键词进行筛选 - return await this.getStudentMessageListMock(data) - }, } diff --git a/uniapp/components/client-info-card/client-info-card.vue b/uniapp/components/client-info-card/client-info-card.vue index 5c5fe555..cf0356b1 100644 --- a/uniapp/components/client-info-card/client-info-card.vue +++ b/uniapp/components/client-info-card/client-info-card.vue @@ -22,7 +22,7 @@ - + @@ -35,19 +35,19 @@ 分配顾问: - {{ $util.safeGet(clientInfo, 'customerResource.consultant_name', '未知顾问') }} + {{ $util.safeGet(clientInfo, 'customerResource.consultant_name', '---') }} 性别: {{ $util.safeGet(clientInfo, 'customerResource.gender_name', '未知性别') }} - + - @@ -82,11 +82,11 @@ export default { this.$util.makePhoneCall(phoneNumber) this.$emit('call', phoneNumber) }, - + toggleActions() { this.actionsExpanded = !this.actionsExpanded }, - + handleAction(action) { this.$emit('action', { action, client: this.clientInfo }) }, @@ -114,7 +114,7 @@ export default { display: flex; align-items: center; margin-bottom: 30rpx; - + .customer-avatar { width: 80rpx; height: 80rpx; @@ -124,24 +124,24 @@ export default { align-items: center; justify-content: center; margin-right: 20rpx; - + text { color: white; font-size: 32rpx; font-weight: bold; } } - + .customer-info { flex: 1; - + .customer-name { color: white; font-size: 32rpx; font-weight: bold; margin-bottom: 8rpx; } - + .customer-meta { .customer-phone { color: #999; @@ -149,12 +149,12 @@ export default { } } } - + .contact-actions { display: flex; align-items: center; gap: 15rpx; - + .contact-btn { width: 60rpx; height: 60rpx; @@ -163,15 +163,15 @@ export default { display: flex; align-items: center; justify-content: center; - + .contact-icon { font-size: 28rpx; } } - + .action-toggle { padding: 10rpx; - + .toggle-icon { color: #29d3b4; font-size: 24rpx; @@ -186,13 +186,13 @@ export default { display: flex; align-items: center; margin-bottom: 20rpx; - + .info-label { color: #999; font-size: 24rpx; width: 150rpx; } - + .info-value { color: white; font-size: 24rpx; @@ -208,12 +208,12 @@ export default { display: flex; flex-wrap: wrap; gap: 15rpx; - + .action-btn { padding: 15rpx 25rpx; background-color: #29d3b4; border-radius: 25rpx; - + .action-text { color: white; font-size: 22rpx; @@ -221,4 +221,4 @@ export default { } } } - \ No newline at end of file + diff --git a/uniapp/components/order-list-card/index.vue b/uniapp/components/order-list-card/index.vue index b3f4dda1..ec422d77 100644 --- a/uniapp/components/order-list-card/index.vue +++ b/uniapp/components/order-list-card/index.vue @@ -1,150 +1,760 @@ - + + + diff --git a/uniapp/components/schedule/ScheduleDetail.vue b/uniapp/components/schedule/ScheduleDetail.vue index 4b2246cd..5271bf7f 100644 --- a/uniapp/components/schedule/ScheduleDetail.vue +++ b/uniapp/components/schedule/ScheduleDetail.vue @@ -1,15 +1,20 @@ diff --git a/uniapp/components/student-edit-popup/student-edit-popup.less b/uniapp/components/student-edit-popup/student-edit-popup.less index 19816d9e..5415f755 100644 --- a/uniapp/components/student-edit-popup/student-edit-popup.less +++ b/uniapp/components/student-edit-popup/student-edit-popup.less @@ -81,7 +81,54 @@ .form-input { flex: 1; - + + // 头像上传样式 + .avatar-upload { + width: 160rpx; + height: 160rpx; + border-radius: 50%; + overflow: hidden; + border: 2rpx solid #e9ecef; + background: #f8f9fa; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.3s ease; + + &:active { + background: #e9ecef; + transform: scale(0.95); + } + + .avatar-preview { + width: 100%; + height: 100%; + border-radius: 50%; + } + + .avatar-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + + .avatar-icon { + font-size: 48rpx; + color: #29d3b4; + margin-bottom: 8rpx; + font-weight: 300; + } + + .avatar-text { + font-size: 22rpx; + color: #999; + } + } + } + input { width: 100%; height: 80rpx; diff --git a/uniapp/components/student-edit-popup/student-edit-popup.vue b/uniapp/components/student-edit-popup/student-edit-popup.vue index 5de1a87b..6ef9377b 100644 --- a/uniapp/components/student-edit-popup/student-edit-popup.vue +++ b/uniapp/components/student-edit-popup/student-edit-popup.vue @@ -13,7 +13,20 @@ 基本信息 - + + + 头像 + + + + + + + 上传头像 + + + + + 姓名 @@ -151,6 +164,7 @@