Browse Source

修改 bug

master
王泽彦 8 months ago
parent
commit
55178e85f4
  1. 15
      niucloud/app/adminapi/controller/course_schedule/CourseSchedule.php
  2. 3
      niucloud/app/api/controller/apiController/Course.php
  3. 26
      niucloud/app/api/controller/apiController/CourseScheduleController.php
  4. 24
      niucloud/app/api/controller/student/StudentController.php
  5. 23
      niucloud/app/api/route/route.php
  6. 21
      niucloud/app/api/route/student.php
  7. 29
      niucloud/app/service/admin/course_schedule/CourseScheduleService.php
  8. 143
      niucloud/app/service/api/apiService/CourseScheduleService.php
  9. 430
      niucloud/app/service/api/apiService/CourseService.php
  10. 60
      niucloud/app/service/api/student/StudentService.php
  11. 38
      uniapp/api/apiRoute.js
  12. 195
      uniapp/pages-market/clue/class_arrangement_detail.vue
  13. 1
      uniapp/pages.json

15
niucloud/app/adminapi/controller/course_schedule/CourseSchedule.php

@ -156,19 +156,4 @@ class CourseSchedule extends BaseAdminController
]); ]);
return success((new CourseScheduleService())->courseInfo($data['id'])); return success((new CourseScheduleService())->courseInfo($data['id']));
} }
public function addSchedule(){
$data = $this->request->params([
["resources_id",''],
["person_type",''],
["schedule_id",''],
["course_date",''],
["time_slot",''],
["schedule_type", 1], // 1=临时, 2=固定
["course_type", 1], // 1=加课, 2=体验课, 3=补课, 4=试听课
["position", ''] // 位置信息
]);
return (new CourseScheduleService())->addSchedule($data);
}
} }

3
niucloud/app/api/controller/apiController/Course.php

@ -129,7 +129,8 @@ class Course extends BaseApiService
$data = $this->request->params([ $data = $this->request->params([
["id", ''], ["id", ''],
["resources_id", ''], ["resources_id", ''],
["remark", ''] ["remark", ''],
["student_id", '']
]); ]);
return (new CourseService())->schedule_del($data); return (new CourseService())->schedule_del($data);
} }

26
niucloud/app/api/controller/apiController/CourseScheduleController.php

@ -205,6 +205,32 @@ class CourseScheduleController extends BaseApiController
} }
} }
/**
* 升级等待位学员为正式学员
*/
public function upgradeStudentSchedule()
{
$data = $this->request->post();
// 验证必要参数
if (empty($data['resources_id']) || empty($data['schedule_id'])) {
return fail('参数不完整');
}
if (empty($data['from_schedule_type']) || empty($data['to_schedule_type'])) {
return fail('升级类型参数不完整');
}
$service = new CourseScheduleService();
$result = $service->upgradeStudentSchedule($data);
if ($result['code'] == 1) {
return success($result['msg'], $result['data'] ?? []);
} else {
return fail($result['msg']);
}
}
/** /**
* 获取筛选选项(教练、课程、班级等) * 获取筛选选项(教练、课程、班级等)
*/ */

24
niucloud/app/api/controller/student/StudentController.php

@ -318,4 +318,28 @@ class StudentController extends BaseController
return fail($e->getMessage()); return fail($e->getMessage());
} }
} }
/**
* 获取学员课程统计
* @param int $student_id
* @return Response
*/
public function getCourseStatistics($student_id)
{
$data = $this->request->params([
['start_date', ''],
['end_date', '']
]);
$data['student_id'] = $student_id;
try {
$service = new StudentService();
$result = $service->getCourseStatistics($data);
return success($result, '获取课程统计成功');
} catch (\Exception $e) {
return fail($e->getMessage());
}
}
} }

23
niucloud/app/api/route/route.php

@ -323,12 +323,13 @@ Route::group(function () {
Route::get('courseSchedule/venueAvailableTime', 'apiController.CourseSchedule/getVenueAvailableTime'); Route::get('courseSchedule/venueAvailableTime', 'apiController.CourseSchedule/getVenueAvailableTime');
//员工端-检查教练时间冲突 //员工端-检查教练时间冲突
Route::get('courseSchedule/checkCoachConflict', 'apiController.CourseSchedule/checkCoachConflict'); Route::get('courseSchedule/checkCoachConflict', 'apiController.CourseSchedule/checkCoachConflict');
//员工端-获取课程安排统计
Route::get('courseSchedule/statistics', 'apiController.CourseSchedule/getScheduleStatistics');
//员工端-学员加入课程安排 //员工端-学员加入课程安排
Route::post('courseSchedule/joinSchedule', 'apiController.CourseSchedule/joinSchedule'); Route::post('courseSchedule/joinSchedule', 'apiController.CourseSchedule/joinSchedule');
//员工端-学员退出课程安排 //员工端-学员退出课程安排
Route::post('courseSchedule/leaveSchedule', 'apiController.CourseSchedule/leaveSchedule'); Route::post('courseSchedule/leaveSchedule', 'apiController.CourseSchedule/leaveSchedule');
//员工端-升级等待位学员为正式学员
Route::post('course/upgradeStudentSchedule', 'apiController.CourseSchedule/upgradeStudentSchedule');
//员工端-获取筛选选项 //员工端-获取筛选选项
Route::get('courseSchedule/filterOptions', 'apiController.CourseSchedule/getFilterOptions'); Route::get('courseSchedule/filterOptions', 'apiController.CourseSchedule/getFilterOptions');
//员工端-获取场地时间选项 //员工端-获取场地时间选项
@ -559,6 +560,13 @@ Route::group(function () {
// 清除字典缓存 // 清除字典缓存
Route::post('dict/clear_cache', 'common.Dict/clearDictCache'); Route::post('dict/clear_cache', 'common.Dict/clearDictCache');
// 学员签到
Route::post('checkin', 'student.AttendanceController/checkin');
// 学员请假
Route::post('leave', 'student.AttendanceController/leave');
// 学员取消
Route::post('cancel', 'student.AttendanceController/cancel');
})->middleware(ApiChannel::class) })->middleware(ApiChannel::class)
->middleware(ApiPersonnelCheckToken::class, true) ->middleware(ApiPersonnelCheckToken::class, true)
->middleware(ApiLog::class); ->middleware(ApiLog::class);
@ -576,17 +584,6 @@ Route::group(function () {
})->middleware(ApiChannel::class) })->middleware(ApiChannel::class)
->middleware(ApiLog::class); ->middleware(ApiLog::class);
// 学员出勤管理(测试)
Route::group('student/attendance', function () {
// 学员签到
Route::post('checkin', 'student.AttendanceController/checkin');
// 学员请假
Route::post('leave', 'student.AttendanceController/leave');
// 学员取消
Route::post('cancel', 'student.AttendanceController/cancel');
})->middleware(ApiChannel::class)
->middleware(ApiLog::class);
//学员端路由 //学员端路由
include_once __DIR__ . '/student.php'; include_once __DIR__ . '/student.php';

21
niucloud/app/api/route/student.php

@ -58,11 +58,16 @@ Route::group('course-booking', function () {
// 课程安排查看 // 课程安排查看
Route::group('course-schedule', function () { Route::group('course-schedule', function () {
// 获取课程安排列表 // 获取课程安排列表
Route::get('list/:student_id', 'app\api\controller\student\StudentController@getCourseScheduleList'); Route::get('list/:student_id', 'app\\api\\controller\\student\\StudentController@getCourseScheduleList');
// 获取课程详情 // 获取课程详情
Route::get('detail/:schedule_id', 'app\api\controller\student\StudentController@getCourseScheduleDetail'); Route::get('detail/:schedule_id', 'app\\api\\controller\\student\\StudentController@getCourseScheduleDetail');
// 申请课程请假 // 申请课程请假
Route::post('leave', 'app\api\controller\student\StudentController@requestCourseLeave'); Route::post('leave', 'app\\api\\controller\\student\\StudentController@requestCourseLeave');
// 获取学员课程统计
Route::get('statistics/:student_id', 'app\\api\\controller\\student\\StudentController@getCourseStatistics');
//员工端-获取课程安排统计
Route::get('courseSchedule/statistics', 'apiController.CourseSchedule/getScheduleStatistics');
})->middleware(['ApiCheckToken']); })->middleware(['ApiCheckToken']);
// 订单管理 // 订单管理
@ -173,16 +178,6 @@ Route::group('message', function () {
Route::get('search/:student_id', 'app\api\controller\student\MessageController@searchMessages'); Route::get('search/:student_id', 'app\api\controller\student\MessageController@searchMessages');
})->middleware(['ApiCheckToken']); })->middleware(['ApiCheckToken']);
// 学员出勤管理
Route::group('attendance', function () {
// 学员签到
Route::post('checkin', 'student.AttendanceController/checkin');
// 学员请假
Route::post('leave', 'student.AttendanceController/leave');
// 学员取消
Route::post('cancel', 'student.AttendanceController/cancel');
});
// 学员登录相关(无需token验证) // 学员登录相关(无需token验证)
Route::group('auth', function () { Route::group('auth', function () {
Route::post('login/wechat', 'login.WechatLogin/login'); Route::post('login/wechat', 'login.WechatLogin/login');

29
niucloud/app/service/admin/course_schedule/CourseScheduleService.php

@ -323,33 +323,4 @@ class CourseScheduleService extends BaseAdminService
->where('id', $data)->findOrEmpty(); ->where('id', $data)->findOrEmpty();
return $info->toArray(); return $info->toArray();
} }
public function addSchedule(array $data){
$CourseSchedule = new CourseSchedule();
$personCourseSchedule = new PersonCourseSchedule();
dd($data);
if($personCourseSchedule->where([
'resources_id' => $data['resources_id'],
'student_id' => $data['student_id'],
'schedule_id' => $data['schedule_id']
])->find()){
return fail("重复添加");
}
$personCourseSchedule->insert([
'resources_id' => $data['resources_id'],
'student_id' => $data['student_id'],
'person_id' => 1,
'person_type' => $data['person_type'],
'schedule_id' => $data['schedule_id'],
'course_date' => $data['course_date'],
'time_slot' => $data['time_slot'],
'schedule_type' => $data['schedule_type'] ?? 1, // 1=正式位, 2=等待位
'course_type' => $data['course_type'] ?? 1, // 1=正式课, 2=体验课, 3=补课, 4=试听课
]);
$CourseSchedule->where(['id' => $data['schedule_id']])->dec("available_capacity")->update();
return success("添加成功");
}
} }

143
niucloud/app/service/api/apiService/CourseScheduleService.php

@ -273,6 +273,7 @@ class CourseScheduleService extends BaseApiService
->leftJoin($this->prefix . 'customer_resources cr', 'pcs.resources_id = cr.id') ->leftJoin($this->prefix . 'customer_resources cr', 'pcs.resources_id = cr.id')
->leftJoin($this->prefix . 'member m', 'cr.member_id = m.member_id') ->leftJoin($this->prefix . 'member m', 'cr.member_id = m.member_id')
->where('pcs.schedule_id', $scheduleId) ->where('pcs.schedule_id', $scheduleId)
->where('pcs.status', 0) // 只统计未请假的学员(status=0)
->where('pcs.deleted_at', 0) ->where('pcs.deleted_at', 0)
->field([ ->field([
'pcs.*', 'pcs.*',
@ -538,12 +539,13 @@ class CourseScheduleService extends BaseApiService
$schedule['class_info'] = null; $schedule['class_info'] = null;
} }
// 获取历史变更记录 // 获取历史变更记录(注释掉,表不存在)
$schedule['change_history'] = Db::name('course_schedule_changes') // $schedule['change_history'] = Db::name('course_schedule_changes')
->where('schedule_id', $scheduleId) // ->where('schedule_id', $scheduleId)
->order('created_at DESC') // ->order('created_at DESC')
->select() // ->select()
->toArray(); // ->toArray();
$schedule['change_history'] = [];
return $schedule; return $schedule;
@ -1655,4 +1657,133 @@ class CourseScheduleService extends BaseApiService
]; ];
} }
} }
/**
* 升级等待位学员为正式学员
* @param array $data 升级数据
* @return array 升级结果
*/
public function upgradeStudentSchedule(array $data)
{
try {
// 验证必填字段
if (empty($data['resources_id']) || empty($data['schedule_id'])) {
return [
'code' => 0,
'msg' => '课程安排ID和资源ID不能为空'
];
}
if (empty($data['from_schedule_type']) || empty($data['to_schedule_type'])) {
return [
'code' => 0,
'msg' => '升级类型参数不完整'
];
}
// 验证升级方向(只能从等待位升级到正式位)
if ($data['from_schedule_type'] != 2 || $data['to_schedule_type'] != 1) {
return [
'code' => 0,
'msg' => '只能从等待位升级到正式位'
];
}
// 开启事务
Db::startTrans();
$scheduleId = $data['schedule_id'];
$resourcesId = $data['resources_id'];
// 查询课程安排信息
$schedule = Db::name('course_schedule')
->where('id', $scheduleId)
->where('deleted_at', 0)
->find();
if (empty($schedule)) {
Db::rollback();
return [
'code' => 0,
'msg' => '课程安排不存在'
];
}
// 查询等待位学员记录
$enrollment = Db::name('person_course_schedule')
->where('schedule_id', $scheduleId)
->where('resources_id', $resourcesId)
->where('schedule_type', 2) // 等待位
->where('deleted_at', 0)
->find();
if (empty($enrollment)) {
Db::rollback();
return [
'code' => 0,
'msg' => '找不到等待位学员记录'
];
}
// 检查正式位是否已满
$formalCount = Db::name('person_course_schedule')
->where('schedule_id', $scheduleId)
->where('schedule_type', 1) // 正式位
->where('deleted_at', 0)
->count();
$maxStudents = intval($schedule['max_students']);
if ($maxStudents > 0 && $formalCount >= $maxStudents) {
Db::rollback();
return [
'code' => 0,
'msg' => '正式位已满,无法升级'
];
}
// 更新学员记录
$updateData = [
'schedule_type' => 1, // 升级为正式位
'position' => $formalCount + 1, // 新的正式位位置
'updated_at' => date('Y-m-d H:i:s'),
'remark' => ($data['remark'] ?? '') . ' [从等待位升级]'
];
// 如果课程类型是等待位专用类型(3),改为正式课(1)
if ($enrollment['course_type'] == 3) {
$updateData['course_type'] = $data['course_type'] ?? 1;
}
$result = Db::name('person_course_schedule')
->where('id', $enrollment['id'])
->update($updateData);
if ($result === false) {
Db::rollback();
return [
'code' => 0,
'msg' => '升级失败'
];
}
// 提交事务
Db::commit();
return [
'code' => 1,
'msg' => '升级成功',
'data' => [
'enrollment_id' => $enrollment['id'],
'new_position' => $formalCount + 1
]
];
} catch (\Exception $e) {
Db::rollback();
return [
'code' => 0,
'msg' => '学员升级失败:' . $e->getMessage()
];
}
}
} }

430
niucloud/app/service/api/apiService/CourseService.php

File diff suppressed because it is too large

60
niucloud/app/service/api/student/StudentService.php

@ -728,4 +728,64 @@ class StudentService extends BaseService
{ {
return (new StudentLabel())->order('sort desc,create_time desc')->select()->toArray(); return (new StudentLabel())->order('sort desc,create_time desc')->select()->toArray();
} }
/**
* 获取学员课程统计
* @param array $params
* @return array
*/
public function getCourseStatistics($params)
{
$studentId = $params['student_id'];
$startDate = $params['start_date'];
$endDate = $params['end_date'];
// 构建查询条件
$where = [
['pcs.student_id', '=', $studentId],
['pcs.deleted_at', '=', 0],
['cs.deleted_at', '=', 0]
];
// 日期筛选
if (!empty($startDate) && !empty($endDate)) {
$where[] = ['cs.course_date', 'between', [$startDate, $endDate]];
}
// 查询课程安排数据
$scheduleList = Db::table('school_person_course_schedule pcs')
->leftJoin('school_course_schedule cs', 'pcs.schedule_id = cs.id')
->where($where)
->field('pcs.status')
->select()
->toArray();
// 统计各状态数量
$totalCourses = count($scheduleList);
$completedCourses = 0;
$scheduledCourses = 0;
$cancelledCourses = 0;
foreach ($scheduleList as $schedule) {
switch ($schedule['status']) {
case 1: // 已完成
$completedCourses++;
break;
case 0: // 待上课
$scheduledCourses++;
break;
case 2: // 请假
case 3: // 取消
$cancelledCourses++;
break;
}
}
return [
'total_courses' => $totalCourses,
'completed_courses' => $completedCourses,
'scheduled_courses' => $scheduledCourses,
'cancelled_courses' => $cancelledCourses
];
}
} }

38
uniapp/api/apiRoute.js

@ -776,6 +776,11 @@ export default {
async schedule_del(data = {}) { async schedule_del(data = {}) {
return await http.post('/course/schedule_del', data); return await http.post('/course/schedule_del', data);
}, },
// 升级等待位学员为正式学员
async upgradeStudentSchedule(data = {}) {
return await http.post('/course/upgradeStudentSchedule', data);
},
//课程相关API //课程相关API
//获取学生课程信息列表(包含教练配置) //获取学生课程信息列表(包含教练配置)
@ -1077,11 +1082,11 @@ export default {
}; };
} }
}, },
// 获取课程安排详情 // 获取课程安排详情(用于课程调整页面)
async getCourseScheduleInfo(data = {}) { async getCourseScheduleInfo(data = {}) {
try { try {
// 使用真实的API接口获取课程安排详情 // 使用真实的API接口获取课程安排详情 - 调整页面专用接口
const result = await http.get('/course/scheduleDetail', data); const result = await http.get('/courseSchedule/info', data);
console.log('获取课程安排详情:', result); console.log('获取课程安排详情:', result);
return result; return result;
} catch (error) { } catch (error) {
@ -1214,7 +1219,32 @@ export default {
}, },
// 获取课程安排统计 // 获取课程安排统计
async getCourseScheduleStatistics(data = {}) { async getCourseScheduleStatistics(data = {}) {
return await http.get('/courseSchedule/statistics', 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: '获取统计数据成功'
};
}
}, },
// 学员加入课程安排 // 学员加入课程安排
async joinCourseSchedule(data = {}) { async joinCourseSchedule(data = {}) {

195
uniapp/pages-market/clue/class_arrangement_detail.vue

@ -70,8 +70,10 @@
<view class="student-name">{{ stu.name }}</view> <view class="student-name">{{ stu.name }}</view>
<view class="student-age">年龄{{ stu.age || '未知' }}</view> <view class="student-age">年龄{{ stu.age || '未知' }}</view>
<view class="course-status">课程状态{{ stu.courseStatus }}</view> <view class="course-status">课程状态{{ stu.courseStatus }}</view>
<view class="course-progress">上课情况{{ stu.course_progress.used }}/{{ stu.course_progress.total }} ({{ stu.course_progress.percentage }}%)</view> <view class="course-status">上课情况
<view class="expiry-date">到期时间{{ stu.expiryDate || '未设置' }}</view> {{ stu.course_progress.used }}/{{ stu.course_progress.total }} ({{ stu.course_progress.percentage }}%)
</view>
<view class="expiry-date" v-if="stu.expiryDate">到期时间{{ stu.expiryDate || '未设置' }}</view>
</view> </view>
</view> </view>
@ -565,69 +567,164 @@
viewStudent(stu) { viewStudent(stu) {
console.log(stu, this.schedule_info); console.log(stu, this.schedule_info);
//
let itemList = [];
if (stu.person_type === 'customer_resource') {
itemList.push('取消课程');
//
if (stu.schedule_type === 2 && this.formalEmptySeats.length > 0) {
itemList.push('升级为正式学员');
}
} else {
itemList.push('申请请假');
}
// //
uni.showActionSheet({ uni.showActionSheet({
title: `学员: ${stu.name}`, title: `学员: ${stu.name}`,
itemList: stu.person_type === 'customer_resource' ? ['取消课程'] : ['申请请假'], itemList: itemList,
success: (res) => { success: (res) => {
if (res.tapIndex === 0) { const selectedOption = itemList[res.tapIndex];
//
if (stu.person_type === 'customer_resource') { if (selectedOption === '取消课程') {
// //
uni.showModal({ uni.showModal({
title: '取消课程', title: '取消课程',
content: `是否取消学员 ${stu.name} 的课程?`, content: `是否取消学员 ${stu.name} 的课程?`,
success: async (res) => { success: async (res) => {
if (res.confirm) { if (res.confirm) {
// schedule_del // schedule_del
try { try {
uni.showLoading({ uni.showLoading({
title: '处理中...' title: '处理中...'
});
const params = {
resources_id: stu.resources_id,
id: this.schedule_info.id
};
const result = await apiRoute.schedule_del(params);
uni.hideLoading();
if (result.code === 1) {
uni.showToast({
title: '取消课程成功',
icon: 'success'
}); });
const params = { //
resources_id: stu.resources_id, await this.getScheduleDetail();
id: this.schedule_info.id } else {
};
const result = await apiRoute.schedule_del(params);
uni.hideLoading();
if (result.code === 1) {
uni.showToast({
title: '取消课程成功',
icon: 'success'
});
//
await this.getScheduleDetail();
} else {
uni.showToast({
title: result.msg || '取消课程失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
uni.showToast({ uni.showToast({
title: '操作失败,请重试', title: result.msg || '取消课程失败',
icon: 'none' icon: 'none'
}); });
console.error('取消课程失败:', error);
} }
} catch (error) {
uni.hideLoading();
uni.showToast({
title: '操作失败,请重试',
icon: 'none'
});
console.error('取消课程失败:', error);
} }
} }
}); }
} else if (stu.person_type === 'student') { });
// } else if (selectedOption === '升级为正式学员') {
this.$refs.leaveReasonModal.open(); //
this.currentStudent = stu; // this.confirmUpgradeStudent(stu);
} } else if (selectedOption === '申请请假') {
//
this.$refs.leaveReasonModal.open();
this.currentStudent = stu; //
} }
} }
}); });
}, },
//
confirmUpgradeStudent(stu) {
//
if (this.formalEmptySeats.length === 0) {
uni.showToast({
title: '正式位已满,无法升级',
icon: 'none'
});
return;
}
uni.showModal({
title: '升级确认',
content: `是否将等待位学员 ${stu.name} 升级为正式学员?升级后将占用一个正式位。`,
success: async (res) => {
if (res.confirm) {
await this.upgradeStudent(stu);
}
}
});
},
//
async upgradeStudent(stu) {
try {
uni.showLoading({
title: '升级中...'
});
//
const upgradeData = {
resources_id: stu.resources_id,
schedule_id: this.course_id,
student_id: stu.student_id,
from_schedule_type: 2, //
to_schedule_type: 1, //
position: this.formalStudents.length + 1, //
course_type: stu.course_type === 3 ? 1 : stu.course_type //
};
//
const result = await apiRoute.upgradeStudentSchedule(upgradeData);
uni.hideLoading();
if (result.code === 1) {
uni.showToast({
title: '升级成功',
icon: 'success'
});
//
await this.getScheduleDetail();
} else {
uni.showToast({
title: result.msg || '升级失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('升级学员失败:', error);
//
let errorMsg = '升级失败';
if (error && error.data && error.data.msg) {
errorMsg = error.data.msg;
} else if (error && error.message) {
errorMsg = error.message;
} else if (typeof error === 'string') {
errorMsg = error;
}
uni.showToast({
title: errorMsg,
icon: 'none'
});
}
},
getStatusText(status) { getStatusText(status) {
const statusMap = { const statusMap = {
0: '待上课', 0: '待上课',

1
uniapp/pages.json

@ -46,7 +46,6 @@
"path": "pages/common/dashboard/webview", "path": "pages/common/dashboard/webview",
"style": { "style": {
"navigationBarTitleText": "数据统计", "navigationBarTitleText": "数据统计",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#181A20", "navigationBarBackgroundColor": "#181A20",
"navigationBarTextStyle": "white" "navigationBarTextStyle": "white"
} }

Loading…
Cancel
Save