15 changed files with 1115 additions and 85 deletions
@ -0,0 +1,165 @@ |
|||
<?php |
|||
// +---------------------------------------------------------------------- |
|||
// | Niucloud-admin 企业快速开发的多应用管理平台 |
|||
// +---------------------------------------------------------------------- |
|||
// | 官方网址:https://www.niucloud.com |
|||
// +---------------------------------------------------------------------- |
|||
// | niucloud团队 版权所有 开源版本可自由商用 |
|||
// +---------------------------------------------------------------------- |
|||
// | Author: Niucloud Team |
|||
// +---------------------------------------------------------------------- |
|||
|
|||
namespace app\api\controller\apiController; |
|||
|
|||
use app\Request; |
|||
use app\service\api\apiService\ScheduleOptionsService; |
|||
use core\base\BaseApiService; |
|||
|
|||
/** |
|||
* 课程安排选项接口 |
|||
* Class ScheduleOptions |
|||
* @package app\api\controller\apiController |
|||
*/ |
|||
class ScheduleOptions extends BaseApiService |
|||
{ |
|||
/** |
|||
* 获取所有排课相关的选项列表(统一接口) |
|||
* @param Request $request |
|||
* @return \think\Response |
|||
*/ |
|||
public function getAllOptions(Request $request) |
|||
{ |
|||
try { |
|||
// 从登录用户的角色信息中获取校区ID |
|||
$campus_id = $this->campus_id ?: 0; |
|||
|
|||
$data = $this->request->params([ |
|||
["campus_id", $campus_id], // 校区ID,优先使用传入参数,否则使用登录用户的校区 |
|||
["include_all", false] // 是否包含全部数据(忽略校区过滤) |
|||
]); |
|||
|
|||
$result = (new ScheduleOptionsService())->getAllOptions($data); |
|||
if (!$result['code']) { |
|||
return fail($result['msg']); |
|||
} |
|||
|
|||
return success('获取成功', $result['data']); |
|||
} catch (\Exception $e) { |
|||
return fail('获取选项列表失败:' . $e->getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取课程列表 |
|||
* @param Request $request |
|||
* @return \think\Response |
|||
*/ |
|||
public function getCourseList(Request $request) |
|||
{ |
|||
try { |
|||
$campus_id = $this->campus_id ?: 0; |
|||
|
|||
$data = $this->request->params([ |
|||
["campus_id", $campus_id], |
|||
["keyword", ""], |
|||
["course_type", ""], |
|||
["status", 1], |
|||
["include_all", false] |
|||
]); |
|||
|
|||
$result = (new ScheduleOptionsService())->getCourseList($data); |
|||
if (!$result['code']) { |
|||
return fail($result['msg']); |
|||
} |
|||
|
|||
return success('获取成功', $result['data']); |
|||
} catch (\Exception $e) { |
|||
return fail('获取课程列表失败:' . $e->getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取班级列表 |
|||
* @param Request $request |
|||
* @return \think\Response |
|||
*/ |
|||
public function getClassList(Request $request) |
|||
{ |
|||
try { |
|||
$campus_id = $this->campus_id ?: 0; |
|||
|
|||
$data = $this->request->params([ |
|||
["campus_id", $campus_id], |
|||
["keyword", ""], |
|||
["class_type", ""], |
|||
["status", 1], |
|||
["include_all", false] |
|||
]); |
|||
|
|||
$result = (new ScheduleOptionsService())->getClassList($data); |
|||
if (!$result['code']) { |
|||
return fail($result['msg']); |
|||
} |
|||
|
|||
return success('获取成功', $result['data']); |
|||
} catch (\Exception $e) { |
|||
return fail('获取班级列表失败:' . $e->getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取教练列表 |
|||
* @param Request $request |
|||
* @return \think\Response |
|||
*/ |
|||
public function getCoachList(Request $request) |
|||
{ |
|||
try { |
|||
$campus_id = $this->campus_id ?: 0; |
|||
|
|||
$data = $this->request->params([ |
|||
["campus_id", $campus_id], |
|||
["keyword", ""], |
|||
["status", 1], |
|||
["include_all", false] |
|||
]); |
|||
|
|||
$result = (new ScheduleOptionsService())->getCoachList($data); |
|||
if (!$result['code']) { |
|||
return fail($result['msg']); |
|||
} |
|||
|
|||
return success('获取成功', $result['data']); |
|||
} catch (\Exception $e) { |
|||
return fail('获取教练列表失败:' . $e->getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取场地列表 |
|||
* @param Request $request |
|||
* @return \think\Response |
|||
*/ |
|||
public function getVenueList(Request $request) |
|||
{ |
|||
try { |
|||
$campus_id = $this->campus_id ?: 0; |
|||
|
|||
$data = $this->request->params([ |
|||
["campus_id", $campus_id], |
|||
["keyword", ""], |
|||
["availability_status", 1], |
|||
["include_all", false] |
|||
]); |
|||
|
|||
$result = (new ScheduleOptionsService())->getVenueList($data); |
|||
if (!$result['code']) { |
|||
return fail($result['msg']); |
|||
} |
|||
|
|||
return success('获取成功', $result['data']); |
|||
} catch (\Exception $e) { |
|||
return fail('获取场地列表失败:' . $e->getMessage()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
namespace app\model\school; |
|||
|
|||
use core\base\BaseModel; |
|||
|
|||
/** |
|||
* 校区人员角色关联模型 |
|||
*/ |
|||
class CampusPersonRole extends BaseModel |
|||
{ |
|||
protected $table = 'school_campus_person_role'; |
|||
protected $pk = 'id'; |
|||
|
|||
/** |
|||
* 软删除 |
|||
*/ |
|||
protected $deleteTime = 'deleted_at'; |
|||
protected $defaultSoftDelete = 0; |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
namespace app\model\school; |
|||
|
|||
use core\base\BaseModel; |
|||
|
|||
/** |
|||
* 班级模型 |
|||
*/ |
|||
class SchoolClass extends BaseModel |
|||
{ |
|||
protected $table = 'school_class'; |
|||
protected $pk = 'id'; |
|||
|
|||
/** |
|||
* 软删除 |
|||
*/ |
|||
protected $deleteTime = 'deleted_at'; |
|||
protected $defaultSoftDelete = 0; |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
namespace app\model\school; |
|||
|
|||
use core\base\BaseModel; |
|||
|
|||
/** |
|||
* 人员模型 |
|||
*/ |
|||
class SchoolPersonnel extends BaseModel |
|||
{ |
|||
protected $table = 'school_personnel'; |
|||
protected $pk = 'id'; |
|||
|
|||
/** |
|||
* 软删除 |
|||
*/ |
|||
protected $deleteTime = 'deleted_at'; |
|||
protected $defaultSoftDelete = 0; |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
namespace app\model\school; |
|||
|
|||
use core\base\BaseModel; |
|||
|
|||
/** |
|||
* 场地模型 |
|||
*/ |
|||
class SchoolVenue extends BaseModel |
|||
{ |
|||
protected $table = 'school_venue'; |
|||
protected $pk = 'id'; |
|||
|
|||
/** |
|||
* 软删除 |
|||
*/ |
|||
protected $deleteTime = 'deleted_at'; |
|||
protected $defaultSoftDelete = 0; |
|||
} |
|||
@ -0,0 +1,291 @@ |
|||
<?php |
|||
// +---------------------------------------------------------------------- |
|||
// | Niucloud-admin 企业快速开发的多应用管理平台 |
|||
// +---------------------------------------------------------------------- |
|||
// | 官方网址:https://www.niucloud.com |
|||
// +---------------------------------------------------------------------- |
|||
// | niucloud团队 版权所有 开源版本可自由商用 |
|||
// +---------------------------------------------------------------------- |
|||
// | Author: Niucloud Team |
|||
// +---------------------------------------------------------------------- |
|||
|
|||
namespace app\service\api\apiService; |
|||
|
|||
use app\model\course\Course; |
|||
use app\model\school\SchoolClass; |
|||
use app\model\school\SchoolPersonnel; |
|||
use app\model\school\SchoolVenue; |
|||
use core\base\BaseApiService; |
|||
|
|||
/** |
|||
* 课程安排选项服务 |
|||
* Class ScheduleOptionsService |
|||
* @package app\service\api\apiService |
|||
*/ |
|||
class ScheduleOptionsService extends BaseApiService |
|||
{ |
|||
/** |
|||
* 获取所有排课相关的选项列表(统一接口) |
|||
* @param array $data |
|||
* @return array |
|||
*/ |
|||
public function getAllOptions(array $data) |
|||
{ |
|||
try { |
|||
$campus_id = $data['campus_id'] ?? 0; |
|||
$include_all = $data['include_all'] ?? false; |
|||
|
|||
// 并行获取所有选项 |
|||
$courses = $this->getCourseListData($campus_id, $include_all); |
|||
$classes = $this->getClassListData($campus_id, $include_all); |
|||
$coaches = $this->getCoachListData($campus_id, $include_all); |
|||
$venues = $this->getVenueListData($campus_id, $include_all); |
|||
|
|||
return [ |
|||
'code' => 1, |
|||
'data' => [ |
|||
'courses' => $courses, |
|||
'classes' => $classes, |
|||
'coaches' => $coaches, |
|||
'venues' => $venues, |
|||
'campus_info' => [ |
|||
'campus_id' => $campus_id, |
|||
'include_all' => $include_all |
|||
] |
|||
] |
|||
]; |
|||
} catch (\Exception $e) { |
|||
return [ |
|||
'code' => 0, |
|||
'msg' => '获取选项列表失败:' . $e->getMessage() |
|||
]; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取课程列表 |
|||
* @param array $data |
|||
* @return array |
|||
*/ |
|||
public function getCourseList(array $data) |
|||
{ |
|||
try { |
|||
$campus_id = $data['campus_id'] ?? 0; |
|||
$include_all = $data['include_all'] ?? false; |
|||
|
|||
$courses = $this->getCourseListData($campus_id, $include_all, $data); |
|||
|
|||
return [ |
|||
'code' => 1, |
|||
'data' => $courses |
|||
]; |
|||
} catch (\Exception $e) { |
|||
return [ |
|||
'code' => 0, |
|||
'msg' => '获取课程列表失败:' . $e->getMessage() |
|||
]; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取班级列表 |
|||
* @param array $data |
|||
* @return array |
|||
*/ |
|||
public function getClassList(array $data) |
|||
{ |
|||
try { |
|||
$campus_id = $data['campus_id'] ?? 0; |
|||
$include_all = $data['include_all'] ?? false; |
|||
|
|||
$classes = $this->getClassListData($campus_id, $include_all, $data); |
|||
|
|||
return [ |
|||
'code' => 1, |
|||
'data' => $classes |
|||
]; |
|||
} catch (\Exception $e) { |
|||
return [ |
|||
'code' => 0, |
|||
'msg' => '获取班级列表失败:' . $e->getMessage() |
|||
]; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取教练列表 |
|||
* @param array $data |
|||
* @return array |
|||
*/ |
|||
public function getCoachList(array $data) |
|||
{ |
|||
try { |
|||
$campus_id = $data['campus_id'] ?? 0; |
|||
$include_all = $data['include_all'] ?? false; |
|||
|
|||
$coaches = $this->getCoachListData($campus_id, $include_all, $data); |
|||
|
|||
return [ |
|||
'code' => 1, |
|||
'data' => $coaches |
|||
]; |
|||
} catch (\Exception $e) { |
|||
return [ |
|||
'code' => 0, |
|||
'msg' => '获取教练列表失败:' . $e->getMessage() |
|||
]; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取场地列表 |
|||
* @param array $data |
|||
* @return array |
|||
*/ |
|||
public function getVenueList(array $data) |
|||
{ |
|||
try { |
|||
$campus_id = $data['campus_id'] ?? 0; |
|||
$include_all = $data['include_all'] ?? false; |
|||
|
|||
$venues = $this->getVenueListData($campus_id, $include_all, $data); |
|||
|
|||
return [ |
|||
'code' => 1, |
|||
'data' => $venues |
|||
]; |
|||
} catch (\Exception $e) { |
|||
return [ |
|||
'code' => 0, |
|||
'msg' => '获取场地列表失败:' . $e->getMessage() |
|||
]; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取课程数据 |
|||
* @param int $campus_id |
|||
* @param bool $include_all |
|||
* @param array $filters |
|||
* @return array |
|||
*/ |
|||
private function getCourseListData(int $campus_id, bool $include_all, array $filters = []) |
|||
{ |
|||
$query = Course::where('deleted_at', 0) |
|||
->where('status', $filters['status'] ?? 1) |
|||
->field('id,course_name,course_type,duration,session_count,price,status'); |
|||
|
|||
// 如果有关键词搜索 |
|||
if (!empty($filters['keyword'])) { |
|||
$query->where('course_name', 'like', '%' . $filters['keyword'] . '%'); |
|||
} |
|||
|
|||
// 如果有课程类型筛选 |
|||
if (!empty($filters['course_type'])) { |
|||
$query->where('course_type', $filters['course_type']); |
|||
} |
|||
|
|||
// TODO: 课程表暂时没有campus_id字段,后续需要添加 |
|||
// 课程通常是全局的,不按校区过滤,但可以通过其他关联表来实现校区过滤 |
|||
|
|||
$courses = $query->order('id desc')->select()->toArray(); |
|||
|
|||
return $courses; |
|||
} |
|||
|
|||
/** |
|||
* 获取班级数据 |
|||
* @param int $campus_id |
|||
* @param bool $include_all |
|||
* @param array $filters |
|||
* @return array |
|||
*/ |
|||
private function getClassListData(int $campus_id, bool $include_all, array $filters = []) |
|||
{ |
|||
$query = SchoolClass::where('deleted_at', 0) |
|||
->where('status', $filters['status'] ?? 1) |
|||
->field('id,campus_id,campus_name,class_name,head_coach,age_group,class_type,assistant_coach,status,sort_order'); |
|||
|
|||
// 校区过滤:如果当前登录人有校区且不是获取全部数据,则只获取该校区的数据 |
|||
if (!$include_all && $campus_id > 0) { |
|||
$query->where('campus_id', $campus_id); |
|||
} |
|||
|
|||
// 如果有关键词搜索 |
|||
if (!empty($filters['keyword'])) { |
|||
$query->where('class_name', 'like', '%' . $filters['keyword'] . '%'); |
|||
} |
|||
|
|||
// 如果有班级类型筛选 |
|||
if (!empty($filters['class_type'])) { |
|||
$query->where('class_type', $filters['class_type']); |
|||
} |
|||
|
|||
$classes = $query->order('sort_order asc, id desc')->select()->toArray(); |
|||
|
|||
return $classes; |
|||
} |
|||
|
|||
/** |
|||
* 获取教练数据 |
|||
* @param int $campus_id |
|||
* @param bool $include_all |
|||
* @param array $filters |
|||
* @return array |
|||
*/ |
|||
private function getCoachListData(int $campus_id, bool $include_all, array $filters = []) |
|||
{ |
|||
// 通过角色关联表获取教练 |
|||
$query = SchoolPersonnel::alias('p') |
|||
->where('p.deleted_at', 0) |
|||
->where('p.status', $filters['status'] ?? 1) |
|||
->field('p.id,p.name,p.head_img,p.gender,p.phone,p.email,p.account_type,p.status'); |
|||
|
|||
// 校区过滤:通过角色关联表过滤 |
|||
if (!$include_all && $campus_id > 0) { |
|||
$query->join('school_campus_person_role r', 'p.id = r.person_id') |
|||
->where('r.campus_id', $campus_id) |
|||
->where('r.deleted_at', 0); |
|||
} |
|||
|
|||
// 获取教练类型的人员(teacher类型的人员可以作为教练) |
|||
$query->where('p.account_type', 'like', '%teacher%'); |
|||
|
|||
// 如果有关键词搜索 |
|||
if (!empty($filters['keyword'])) { |
|||
$query->where('p.name', 'like', '%' . $filters['keyword'] . '%'); |
|||
} |
|||
|
|||
$coaches = $query->order('p.id desc')->select()->toArray(); |
|||
|
|||
return $coaches; |
|||
} |
|||
|
|||
/** |
|||
* 获取场地数据 |
|||
* @param int $campus_id |
|||
* @param bool $include_all |
|||
* @param array $filters |
|||
* @return array |
|||
*/ |
|||
private function getVenueListData(int $campus_id, bool $include_all, array $filters = []) |
|||
{ |
|||
$query = SchoolVenue::where('deleted_at', 0) |
|||
->where('availability_status', $filters['availability_status'] ?? 1) |
|||
->field('id,campus_id,venue_name,capacity,availability_status,time_range_type,time_range_start,time_range_end'); |
|||
|
|||
// 校区过滤:如果当前登录人有校区且不是获取全部数据,则只获取该校区的数据 |
|||
if (!$include_all && $campus_id > 0) { |
|||
$query->where('campus_id', $campus_id); |
|||
} |
|||
|
|||
// 如果有关键词搜索 |
|||
if (!empty($filters['keyword'])) { |
|||
$query->where('venue_name', 'like', '%' . $filters['keyword'] . '%'); |
|||
} |
|||
|
|||
$venues = $query->order('id desc')->select()->toArray(); |
|||
|
|||
return $venues; |
|||
} |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
/** |
|||
* 排课选项Mock数据 |
|||
* 提供与API响应结构一致的测试数据 |
|||
*/ |
|||
|
|||
// 课程Mock数据
|
|||
const mockCourses = [ |
|||
{ id: 1, course_name: "基础篮球课", course_type: "1", duration: 1, session_count: 1, price: "100.00", status: 1 }, |
|||
{ id: 2, course_name: "中级篮球课", course_type: "2", duration: 1, session_count: 1, price: "150.00", status: 1 }, |
|||
{ id: 3, course_name: "高级篮球课", course_type: "3", duration: 1, session_count: 1, price: "200.00", status: 1 }, |
|||
{ id: 4, course_name: "私教课程", course_type: "3", duration: 1, session_count: 1, price: "300.00", status: 1 } |
|||
]; |
|||
|
|||
// 班级Mock数据
|
|||
const mockClasses = [ |
|||
{ id: 1, campus_id: 1, campus_name: "测试校区", class_name: "幼儿班", head_coach: "张教练", age_group: "3-5", class_type: "1", assistant_coach: "李助教", status: 1, sort_order: 1 }, |
|||
{ id: 2, campus_id: 1, campus_name: "测试校区", class_name: "少儿班", head_coach: "王教练", age_group: "6-8", class_type: "2", assistant_coach: "赵助教", status: 1, sort_order: 2 }, |
|||
{ id: 3, campus_id: 1, campus_name: "测试校区", class_name: "青少年班", head_coach: "刘教练", age_group: "9-12", class_type: "3", assistant_coach: "钱助教", status: 1, sort_order: 3 } |
|||
]; |
|||
|
|||
// 教练Mock数据
|
|||
const mockCoaches = [ |
|||
{ id: 1, name: "张教练", head_img: "", gender: 1, phone: "13800001001", email: "zhang@test.com", account_type: "teacher", status: 1 }, |
|||
{ id: 2, name: "王教练", head_img: "", gender: 0, phone: "13800001002", email: "wang@test.com", account_type: "teacher", status: 1 }, |
|||
{ id: 3, name: "刘教练", head_img: "", gender: 1, phone: "13800001003", email: "liu@test.com", account_type: "teacher", status: 1 }, |
|||
{ id: 4, name: "李助教", head_img: "", gender: 1, phone: "13800001004", email: "li@test.com", account_type: "teacher", status: 1 } |
|||
]; |
|||
|
|||
// 场地Mock数据
|
|||
const mockVenues = [ |
|||
{ id: 1, campus_id: 1, venue_name: "一号篮球场", capacity: 20, availability_status: 1, time_range_type: "all", time_range_start: null, time_range_end: null }, |
|||
{ id: 2, campus_id: 1, venue_name: "二号篮球场", capacity: 15, availability_status: 1, time_range_type: "range", time_range_start: "08:00", time_range_end: "18:00" }, |
|||
{ id: 3, campus_id: 1, venue_name: "多功能厅", capacity: 30, availability_status: 1, time_range_type: "fixed", time_range_start: null, time_range_end: null } |
|||
]; |
|||
|
|||
// 统一选项Mock响应
|
|||
export const mockAllScheduleOptions = { |
|||
code: 1, |
|||
msg: "获取成功", |
|||
data: { |
|||
courses: mockCourses, |
|||
classes: mockClasses, |
|||
coaches: mockCoaches, |
|||
venues: mockVenues, |
|||
campus_info: { |
|||
campus_id: 1, |
|||
include_all: false |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// 单独选项Mock响应
|
|||
export const mockCourseList = { |
|||
code: 1, |
|||
msg: "获取成功", |
|||
data: mockCourses |
|||
}; |
|||
|
|||
export const mockClassList = { |
|||
code: 1, |
|||
msg: "获取成功", |
|||
data: mockClasses |
|||
}; |
|||
|
|||
export const mockCoachList = { |
|||
code: 1, |
|||
msg: "获取成功", |
|||
data: mockCoaches |
|||
}; |
|||
|
|||
export const mockVenueList = { |
|||
code: 1, |
|||
msg: "获取成功", |
|||
data: mockVenues |
|||
}; |
|||
|
|||
export default { |
|||
mockAllScheduleOptions, |
|||
mockCourseList, |
|||
mockClassList, |
|||
mockCoachList, |
|||
mockVenueList |
|||
}; |
|||
Loading…
Reference in new issue