From fb68775d70844ba92de5ed488ee21f6c90007c0e Mon Sep 17 00:00:00 2001
From: zeyan <258785420@qq.com>
Date: Sat, 5 Jul 2025 15:53:48 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20docker=20=E5=BC=80?=
=?UTF-8?q?=E5=8F=91=E7=8E=AF=E5=A2=83=E3=80=82=E4=BF=AE=E6=94=B9=E5=AE=A2?=
=?UTF-8?q?=E6=88=B7=E7=AB=AF=E6=8E=92=E8=AF=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
admin/src/app/views/dict/components/dict.vue | 2 +-
docker-compose.yml | 41 +-
.../api/controller/apiController/ClassApi.php | 25 +
.../api/controller/apiController/Course.php | 25 +
.../apiController/CourseSchedule.php | 80 +-
.../controller/apiController/Personnel.php | 24 +
niucloud/app/api/middleware/ApiCheckToken.php | 2 +-
niucloud/app/api/route/route.php | 20 +
.../schedule/PerformanceCalculation.php | 2 +-
niucloud/app/middleware.php | 6 +-
niucloud/app/model/dict/Dict.php | 4 +-
.../api/apiService/CourseScheduleService.php | 302 +++++
.../service/api/apiService/CourseService.php | 45 +
.../api/apiService/PersonnelService.php | 68 ++
.../service/api/apiService/jlClassService.php | 51 +
niucloud/config/app.php | 4 +-
niucloud/core/base/BaseAdminService.php | 1 +
start.sh | 17 +-
startvps.sh | 24 +
uniapp/api/apiRoute.js | 234 ++++
uniapp/components/schedule/ScheduleDetail.vue | 718 ++++++------
uniapp/pages.json | 1 -
uniapp/pages/coach/my/index.vue | 8 -
uniapp/pages/coach/schedule/README.md | 156 ++-
uniapp/pages/coach/schedule/add_schedule.vue | 141 ++-
.../pages/coach/schedule/schedule_table.vue | 604 ++++++++--
uniapp/pages/coach/schedule/sign_in.vue | 1016 +++++++++--------
uniapp/pages/market/my/index.vue | 22 +
28 files changed, 2594 insertions(+), 1049 deletions(-)
create mode 100644 startvps.sh
diff --git a/admin/src/app/views/dict/components/dict.vue b/admin/src/app/views/dict/components/dict.vue
index e414b8b4..2a04fa9a 100644
--- a/admin/src/app/views/dict/components/dict.vue
+++ b/admin/src/app/views/dict/components/dict.vue
@@ -15,7 +15,7 @@
- bash -c "
- apt-get update &&
- apt-get install -y libzip-dev zip unzip git libpng-dev libjpeg-dev libfreetype6-dev &&
- docker-php-ext-configure gd --with-freetype --with-jpeg &&
- docker-php-ext-install pdo pdo_mysql mysqli zip gd &&
- pecl install redis &&
- docker-php-ext-enable redis &&
- php-fpm
- "
networks:
- niucloud_network
- # Nginx 服务
+# Nginx 服务
nginx:
image: nginx:alpine
container_name: niucloud_nginx
ports:
- - "20080:80" # 原本是 80 映射到 20080
- - "20081:8080" # 原本是 8080 映射到 20081
+ - "20080:80"
+ - "20081:8080"
volumes:
- ./niucloud:/var/www/html
- ./admin/dist:/var/www/admin
@@ -47,12 +37,12 @@ services:
networks:
- niucloud_network
- # MySQL 数据库
+# MySQL 数据库
mysql:
image: mysql:8.0
container_name: niucloud_mysql
ports:
- - "23306:3306" # 原本是 3306 映射到 23306
+ - "23306:3306"
environment:
MYSQL_ROOT_PASSWORD: root123456
MYSQL_DATABASE: niucloud
@@ -66,12 +56,12 @@ services:
networks:
- niucloud_network
- # Redis 缓存
+# Redis 缓存
redis:
image: redis:alpine
container_name: niucloud_redis
ports:
- - "26379:6379" # 原本是 6379 映射到 26379
+ - "26379:6379"
volumes:
- ./docker/data/redis:/data
- ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf
@@ -79,7 +69,7 @@ services:
networks:
- niucloud_network
- # Node.js 服务 (用于构建前端)
+# Node.js 服务 (用于构建前端)
node:
image: node:18-alpine
container_name: niucloud_node
@@ -88,17 +78,17 @@ services:
- ./admin:/app
- ./docker/data/node_modules:/app/node_modules
ports:
- - "23000:3000" # 原本是 3000 映射到 23000
+ - "23000:5173" # 映射到 Vite 默认开发端口 5173
command: >
sh -c "
- npm config set registry https://registry.npmmirror.com &&
+ npm config set registry https://registry.npmmirror.com &&
npm install &&
npm run dev
"
networks:
- niucloud_network
- # Composer 服务 (用于 PHP 依赖管理)
+# Composer 服务 (可选)
composer:
image: composer:latest
container_name: niucloud_composer
@@ -111,9 +101,4 @@ services:
networks:
niucloud_network:
- driver: bridge
-
-volumes:
- mysql_data:
- redis_data:
- node_modules:
\ No newline at end of file
+ driver: bridge
\ No newline at end of file
diff --git a/niucloud/app/api/controller/apiController/ClassApi.php b/niucloud/app/api/controller/apiController/ClassApi.php
index c1ae82c1..2393adf7 100644
--- a/niucloud/app/api/controller/apiController/ClassApi.php
+++ b/niucloud/app/api/controller/apiController/ClassApi.php
@@ -154,4 +154,29 @@ class ClassApi extends BaseApiService
return success('操作成功', (new jlClassService())->getStatisticsInfo($id));
}
+ /**
+ * 获取班级列表(用于添加课程安排)
+ * @param Request $request
+ * @return \think\Response
+ */
+ public function getClassList(Request $request)
+ {
+ try {
+ $data = $this->request->params([
+ ["campus_id", 0], // 校区ID筛选
+ ["keyword", ""], // 班级名称关键词搜索
+ ["status", 1] // 状态筛选,默认获取开启状态的班级
+ ]);
+
+ $result = (new jlClassService())->getClassListForSchedule($data);
+ if (!$result['code']) {
+ return fail($result['msg']);
+ }
+
+ return success('获取成功', $result['data']);
+ } catch (\Exception $e) {
+ return fail('获取班级列表失败:' . $e->getMessage());
+ }
+ }
+
}
diff --git a/niucloud/app/api/controller/apiController/Course.php b/niucloud/app/api/controller/apiController/Course.php
index 447962e8..77787823 100644
--- a/niucloud/app/api/controller/apiController/Course.php
+++ b/niucloud/app/api/controller/apiController/Course.php
@@ -150,4 +150,29 @@ class Course extends BaseApiService
}
}
+ /**
+ * 获取课程列表(用于添加课程安排)
+ * @param Request $request
+ * @return \think\Response
+ */
+ public function getCourseList(Request $request)
+ {
+ try {
+ $data = $this->request->params([
+ ["keyword", ""], // 课程名称关键词搜索
+ ["course_type", ""], // 课程类型筛选
+ ["status", 1] // 状态筛选,默认获取有效课程
+ ]);
+
+ $result = (new CourseService())->getCourseListForSchedule($data);
+ if (!$result['code']) {
+ return fail($result['msg']);
+ }
+
+ return success('获取成功', $result['data']);
+ } catch (\Exception $e) {
+ return fail('获取课程列表失败:' . $e->getMessage());
+ }
+ }
+
}
diff --git a/niucloud/app/api/controller/apiController/CourseSchedule.php b/niucloud/app/api/controller/apiController/CourseSchedule.php
index db4a4fad..795fda30 100644
--- a/niucloud/app/api/controller/apiController/CourseSchedule.php
+++ b/niucloud/app/api/controller/apiController/CourseSchedule.php
@@ -57,12 +57,36 @@ class CourseSchedule extends BaseApiService
*/
public function createSchedule(Request $request)
{
- $data = $request->all();
- $result = (new CourseScheduleService())->createSchedule($data);
- if (!$result['code']) {
- return fail($result['msg']);
+ try {
+ $data = $this->request->params([
+ ["campus_id", 0],
+ ["venue_id", 0],
+ ["course_date", ""],
+ ["time_slot", ""],
+ ["course_id", 0],
+ ["coach_id", 0],
+ ["available_capacity", 0],
+ ["class_id", 0],
+ ["remarks", ""],
+ ["created_by", "manual"]
+ ]);
+
+ // 验证必填字段
+ $required = ['campus_id', 'venue_id', 'course_date', 'time_slot', 'course_id', 'coach_id', 'available_capacity'];
+ foreach ($required as $field) {
+ if (empty($data[$field])) {
+ return fail("字段 {$field} 不能为空");
+ }
+ }
+
+ $result = (new CourseScheduleService())->createCourseSchedule($data);
+ if (!$result['code']) {
+ return fail($result['msg']);
+ }
+ return success($result['msg'] ?? '创建成功', $result['data'] ?? []);
+ } catch (\Exception $e) {
+ return fail('创建课程安排失败:' . $e->getMessage());
}
- return success($result['msg'] ?? '创建成功', $result['data'] ?? []);
}
/**
@@ -119,8 +143,22 @@ class CourseSchedule extends BaseApiService
*/
public function getVenueList(Request $request)
{
- $data = $request->all();
- return success((new CourseScheduleService())->getVenueList($data));
+ try {
+ $data = $this->request->params([
+ ["campus_id", 0], // 校区ID筛选
+ ["keyword", ""], // 场地名称关键词搜索
+ ["status", 1] // 状态筛选,默认获取可用场地
+ ]);
+
+ $result = (new CourseScheduleService())->getVenueListForSchedule($data);
+ if (!$result['code']) {
+ return fail($result['msg']);
+ }
+
+ return success('获取成功', $result['data']);
+ } catch (\Exception $e) {
+ return fail('获取场地列表失败:' . $e->getMessage());
+ }
}
/**
@@ -130,11 +168,29 @@ class CourseSchedule extends BaseApiService
*/
public function getVenueAvailableTime(Request $request)
{
- $data = $this->request->params([
- ["venue_id", 0],
- ["date", ""]
- ]);
- return success((new CourseScheduleService())->getVenueAvailableTime($data));
+ try {
+ $data = $this->request->params([
+ ["venue_id", 0],
+ ["date", ""]
+ ]);
+
+ if (empty($data['venue_id'])) {
+ return fail('场地ID不能为空');
+ }
+
+ if (empty($data['date'])) {
+ return fail('查询日期不能为空');
+ }
+
+ $result = (new CourseScheduleService())->getVenueAvailableTimeSlots($data);
+ if (!$result['code']) {
+ return fail($result['msg']);
+ }
+
+ return success('获取成功', $result['data']);
+ } catch (\Exception $e) {
+ return fail('获取场地可用时间失败:' . $e->getMessage());
+ }
}
/**
diff --git a/niucloud/app/api/controller/apiController/Personnel.php b/niucloud/app/api/controller/apiController/Personnel.php
index 68561cda..bb8570d2 100644
--- a/niucloud/app/api/controller/apiController/Personnel.php
+++ b/niucloud/app/api/controller/apiController/Personnel.php
@@ -280,4 +280,28 @@ class Personnel extends BaseApiService
}
}
+ /**
+ * 获取教练列表(用于添加课程安排)
+ * @param Request $request
+ * @return \think\Response
+ */
+ public function getCoachListForSchedule(Request $request)
+ {
+ try {
+ $data = $this->request->params([
+ ["campus_id", 0], // 校区ID筛选
+ ["keyword", ""], // 教练姓名关键词搜索
+ ["status", 1] // 状态筛选,默认获取有效教练
+ ]);
+
+ $res = (new PersonnelService())->getCoachListForSchedule($data);
+ if (!$res['code']) {
+ return fail($res['msg']);
+ }
+ return success('获取成功', $res['data']);
+ } catch (\Exception $e) {
+ return fail('获取教练列表失败:' . $e->getMessage());
+ }
+ }
+
}
diff --git a/niucloud/app/api/middleware/ApiCheckToken.php b/niucloud/app/api/middleware/ApiCheckToken.php
index b3a65e07..cc729b83 100644
--- a/niucloud/app/api/middleware/ApiCheckToken.php
+++ b/niucloud/app/api/middleware/ApiCheckToken.php
@@ -53,6 +53,6 @@ class ApiCheckToken
if ($is_throw_exception)
return fail($e->getMessage(), [], $e->getCode());
}
- return $next($request);
+ if(!$request->memberId()) { return fail("请先登录", [], 401); } return $next($request);
}
}
diff --git a/niucloud/app/api/route/route.php b/niucloud/app/api/route/route.php
index 557d895c..a5341360 100644
--- a/niucloud/app/api/route/route.php
+++ b/niucloud/app/api/route/route.php
@@ -190,6 +190,14 @@ Route::group(function () {
//公共端-获取全部班级列表
Route::get('common/getClassAll', 'apiController.Common/getClassAll');
+ // 测试用接口 - 无需认证
+ Route::get('test/course/list', 'apiController.Course/getCourseList');
+ Route::get('test/class/list', 'apiController.ClassApi/getClassList');
+ Route::get('test/coach/list', 'apiController.Personnel/getCoachListForSchedule');
+ Route::get('test/venue/list', 'apiController.CourseSchedule/getVenueList');
+ Route::get('test/venue/timeSlots', 'apiController.CourseSchedule/getVenueAvailableTime');
+ Route::post('test/courseSchedule/create', 'apiController.CourseSchedule/createSchedule');
+
@@ -320,6 +328,18 @@ Route::group(function () {
//员工端-获取筛选选项
Route::get('courseSchedule/filterOptions', 'apiController.CourseSchedule/getFilterOptions');
+ // 添加课程安排页面专用接口
+ //获取课程列表(用于添加课程安排)
+ Route::get('course/list', 'apiController.Course/getCourseList');
+ //获取班级列表(用于添加课程安排)
+ Route::get('class/list', 'apiController.ClassApi/getClassList');
+ //获取教练列表(用于添加课程安排)
+ Route::get('coach/list', 'apiController.Personnel/getCoachListForSchedule');
+ //获取场地列表(用于添加课程安排)
+ Route::get('venue/list', 'apiController.CourseSchedule/getVenueList');
+ //获取场地可用时间段
+ Route::get('venue/timeSlots', 'apiController.CourseSchedule/getVenueAvailableTime');
+
diff --git a/niucloud/app/job/transfer/schedule/PerformanceCalculation.php b/niucloud/app/job/transfer/schedule/PerformanceCalculation.php
index c7ec9f86..e3f5e07a 100644
--- a/niucloud/app/job/transfer/schedule/PerformanceCalculation.php
+++ b/niucloud/app/job/transfer/schedule/PerformanceCalculation.php
@@ -44,7 +44,7 @@ class PerformanceCalculation extends BaseJob
*/
public function __construct()
{
- $this->performanceService = new PerformanceService();
+ $this->performanceService = null;
}
/**
diff --git a/niucloud/app/middleware.php b/niucloud/app/middleware.php
index 6a457332..9dd2f245 100644
--- a/niucloud/app/middleware.php
+++ b/niucloud/app/middleware.php
@@ -1,14 +1,18 @@
where("name", $value);
+ $query->where("name", 'like', '%' . $value . '%');
}
}
diff --git a/niucloud/app/service/api/apiService/CourseScheduleService.php b/niucloud/app/service/api/apiService/CourseScheduleService.php
index 9da286bd..d3b3260b 100644
--- a/niucloud/app/service/api/apiService/CourseScheduleService.php
+++ b/niucloud/app/service/api/apiService/CourseScheduleService.php
@@ -564,4 +564,306 @@ class CourseScheduleService extends BaseApiService
return ['code' => 0, 'msg' => $e->getMessage()];
}
}
+
+ /**
+ * 获取场地列表(用于添加课程安排)
+ * @param array $data
+ * @return array
+ */
+ public function getVenueListForSchedule(array $data)
+ {
+ try {
+ $where = [];
+
+ // 场地名称关键词搜索
+ if (!empty($data['keyword'])) {
+ $where[] = ['venue_name', 'like', '%' . $data['keyword'] . '%'];
+ }
+
+ // 校区筛选
+ if (!empty($data['campus_id'])) {
+ $where[] = ['campus_id', '=', $data['campus_id']];
+ }
+
+ // 状态筛选,默认获取可用场地
+ if (isset($data['status'])) {
+ $where[] = ['availability_status', '=', $data['status']];
+ }
+
+ // 只获取未逻辑删除的场地
+ $where[] = ['deleted_at', '=', 0];
+
+ $venueList = Db::name('venue')
+ ->where($where)
+ ->field('id, venue_name, capacity, availability_status, time_range_type, time_range_start, time_range_end, fixed_time_ranges')
+ ->order('created_at DESC')
+ ->select()
+ ->toArray();
+
+ return [
+ 'code' => 1,
+ 'msg' => '获取成功',
+ 'data' => $venueList
+ ];
+
+ } catch (\Exception $e) {
+ return [
+ 'code' => 0,
+ 'msg' => '获取场地列表失败:' . $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
+
+ /**
+ * 获取场地可用时间段
+ * @param array $data
+ * @return array
+ */
+ public function getVenueAvailableTimeSlots(array $data)
+ {
+ try {
+ $venueId = $data['venue_id'];
+ $date = $data['date'];
+
+ // 获取场地信息
+ $venue = Db::name('venue')
+ ->where('id', $venueId)
+ ->where('availability_status', 1)
+ ->find();
+
+ if (empty($venue)) {
+ return [
+ 'code' => 0,
+ 'msg' => '场地不存在或不可用',
+ 'data' => []
+ ];
+ }
+
+ // 根据场地时间类型获取可用时间段
+ $availableSlots = $this->generateTimeSlots($venue, $date);
+
+ // 获取该场地该日期已安排的时间段
+ $occupiedSlots = Db::name('course_schedule')
+ ->where('venue_id', $venueId)
+ ->where('course_date', $date)
+ ->where('deleted_at', 0)
+ ->column('time_slot');
+
+ // 过滤已占用的时间段
+ $availableSlots = array_filter($availableSlots, function($slot) use ($occupiedSlots) {
+ return !in_array($slot['time_slot'], $occupiedSlots);
+ });
+
+ return [
+ 'code' => 1,
+ 'msg' => '获取成功',
+ 'data' => array_values($availableSlots)
+ ];
+
+ } catch (\Exception $e) {
+ return [
+ 'code' => 0,
+ 'msg' => '获取场地可用时间失败:' . $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
+
+ /**
+ * 创建课程安排
+ * @param array $data
+ * @return array
+ */
+ public function createCourseSchedule(array $data)
+ {
+ try {
+ // 开启事务
+ Db::startTrans();
+
+ // 验证场地时间冲突
+ $conflictCheck = $this->checkVenueConflict($data['venue_id'], $data['course_date'], $data['time_slot']);
+ if (!$conflictCheck['code']) {
+ Db::rollback();
+ return $conflictCheck;
+ }
+
+ // 验证教练时间冲突
+ $coachConflictCheck = $this->checkCoachConflict($data['coach_id'], $data['course_date'], $data['time_slot']);
+ if (!$coachConflictCheck['code']) {
+ Db::rollback();
+ return $coachConflictCheck;
+ }
+
+ // 准备插入数据
+ $insertData = [
+ 'campus_id' => $data['campus_id'],
+ 'venue_id' => $data['venue_id'],
+ 'course_date' => $data['course_date'],
+ 'time_slot' => $data['time_slot'],
+ 'course_id' => $data['course_id'],
+ 'coach_id' => $data['coach_id'],
+ 'available_capacity' => $data['available_capacity'],
+ 'status' => 'pending',
+ 'created_by' => $data['created_by'] ?? 'manual',
+ 'created_at' => date('Y-m-d H:i:s'),
+ 'updated_at' => date('Y-m-d H:i:s'),
+ 'deleted_at' => 0
+ ];
+
+ // 班级信息暂不存储在课程安排表中,根据实际需求可以通过关联表处理
+
+ // 如果有备注,则添加
+ if (!empty($data['remarks'])) {
+ $insertData['remarks'] = $data['remarks'];
+ }
+
+ // 插入课程安排
+ $scheduleId = Db::name('course_schedule')->insertGetId($insertData);
+
+ if (!$scheduleId) {
+ Db::rollback();
+ return [
+ 'code' => 0,
+ 'msg' => '创建课程安排失败'
+ ];
+ }
+
+ // 提交事务
+ Db::commit();
+
+ return [
+ 'code' => 1,
+ 'msg' => '创建成功',
+ 'data' => [
+ 'schedule_id' => $scheduleId
+ ]
+ ];
+
+ } catch (\Exception $e) {
+ Db::rollback();
+ return [
+ 'code' => 0,
+ 'msg' => '创建课程安排失败:' . $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * 生成时间段选项
+ * @param array $venue
+ * @param string $date
+ * @return array
+ */
+ private function generateTimeSlots($venue, $date)
+ {
+ $slots = [];
+
+ switch ($venue['time_range_type']) {
+ case 'range':
+ // 范围类型:从开始时间到结束时间,每小时一个时间段
+ $startTime = strtotime($venue['time_range_start']);
+ $endTime = strtotime($venue['time_range_end']);
+
+ for ($time = $startTime; $time < $endTime; $time += 3600) {
+ $startTimeStr = date('H:i', $time);
+ $endTimeStr = date('H:i', $time + 3600);
+ $slots[] = [
+ 'time_slot' => $startTimeStr . '-' . $endTimeStr,
+ 'start_time' => $startTimeStr,
+ 'end_time' => $endTimeStr
+ ];
+ }
+ break;
+
+ case 'fixed':
+ // 固定时间范围类型
+ if (!empty($venue['fixed_time_ranges'])) {
+ $fixedRanges = json_decode($venue['fixed_time_ranges'], true);
+ if (is_array($fixedRanges)) {
+ foreach ($fixedRanges as $range) {
+ // 兼容不同的字段名格式
+ $startTime = $range['start_time'] ?? $range['start'] ?? '';
+ $endTime = $range['end_time'] ?? $range['end'] ?? '';
+
+ if ($startTime && $endTime) {
+ $slots[] = [
+ 'time_slot' => $startTime . '-' . $endTime,
+ 'start_time' => $startTime,
+ 'end_time' => $endTime
+ ];
+ }
+ }
+ }
+ }
+ break;
+
+ case 'all':
+ // 全天可用,生成默认时间段(8:00-22:00)
+ for ($hour = 8; $hour < 22; $hour++) {
+ $startTimeStr = str_pad($hour, 2, '0', STR_PAD_LEFT) . ':00';
+ $endTimeStr = str_pad($hour + 1, 2, '0', STR_PAD_LEFT) . ':00';
+ $slots[] = [
+ 'time_slot' => $startTimeStr . '-' . $endTimeStr,
+ 'start_time' => $startTimeStr,
+ 'end_time' => $endTimeStr
+ ];
+ }
+ break;
+ }
+
+ return $slots;
+ }
+
+ /**
+ * 检查场地时间冲突
+ * @param int $venueId
+ * @param string $date
+ * @param string $timeSlot
+ * @return array
+ */
+ private function checkVenueConflict($venueId, $date, $timeSlot)
+ {
+ $conflict = Db::name('course_schedule')
+ ->where('venue_id', $venueId)
+ ->where('course_date', $date)
+ ->where('time_slot', $timeSlot)
+ ->where('deleted_at', 0)
+ ->find();
+
+ if ($conflict) {
+ return [
+ 'code' => 0,
+ 'msg' => '该场地在该时间段已有课程安排'
+ ];
+ }
+
+ return ['code' => 1];
+ }
+
+ /**
+ * 检查教练时间冲突
+ * @param int $coachId
+ * @param string $date
+ * @param string $timeSlot
+ * @return array
+ */
+ public function checkCoachConflict($coachId, $date, $timeSlot)
+ {
+ $conflict = Db::name('course_schedule')
+ ->where('coach_id', $coachId)
+ ->where('course_date', $date)
+ ->where('time_slot', $timeSlot)
+ ->where('deleted_at', 0)
+ ->find();
+
+ if ($conflict) {
+ return [
+ 'code' => 0,
+ 'msg' => '该教练在该时间段已有课程安排'
+ ];
+ }
+
+ return ['code' => 1];
+ }
}
\ No newline at end of file
diff --git a/niucloud/app/service/api/apiService/CourseService.php b/niucloud/app/service/api/apiService/CourseService.php
index c795378d..2e1c6eed 100644
--- a/niucloud/app/service/api/apiService/CourseService.php
+++ b/niucloud/app/service/api/apiService/CourseService.php
@@ -498,5 +498,50 @@ class CourseService extends BaseApiService
return $res;
}
+ /**
+ * 获取课程列表(用于添加课程安排)
+ * @param array $data
+ * @return array
+ */
+ public function getCourseListForSchedule(array $data)
+ {
+ try {
+ $where = [];
+
+ // 课程名称关键词搜索
+ if (!empty($data['keyword'])) {
+ $where[] = ['course_name', 'like', '%' . $data['keyword'] . '%'];
+ }
+
+ // 课程类型筛选
+ if (!empty($data['course_type'])) {
+ $where[] = ['course_type', '=', $data['course_type']];
+ }
+
+ // 只获取有效课程(未逻辑删除)
+ $where[] = ['deleted_at', '=', 0];
+
+ $courseList = $this->model
+ ->where($where)
+ ->field('id, course_name, course_type, duration, session_count, single_session_count, price')
+ ->order('created_at DESC')
+ ->select()
+ ->toArray();
+
+ return [
+ 'code' => 1,
+ 'msg' => '获取成功',
+ 'data' => $courseList
+ ];
+
+ } catch (\Exception $e) {
+ return [
+ 'code' => 0,
+ 'msg' => '获取课程列表失败:' . $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
+
}
diff --git a/niucloud/app/service/api/apiService/PersonnelService.php b/niucloud/app/service/api/apiService/PersonnelService.php
index f02f3d08..6ee813c0 100644
--- a/niucloud/app/service/api/apiService/PersonnelService.php
+++ b/niucloud/app/service/api/apiService/PersonnelService.php
@@ -728,4 +728,72 @@ class PersonnelService extends BaseApiService
return $res;
}
+ /**
+ * 获取教练列表(用于添加课程安排)
+ * @param array $data
+ * @return array
+ */
+ public function getCoachListForSchedule(array $data)
+ {
+ try {
+ $where = [];
+
+ // 查询条件:dept_id=2(教练部门)
+ $campusPersonWhere = ['dept_id' => 2];
+
+ // 校区筛选
+ if (!empty($data['campus_id'])) {
+ $campusPersonWhere['campus_id'] = $data['campus_id'];
+ }
+
+ // 查询符合条件的教练人员ID
+ $coachPersonIds = CampusPersonRole::where($campusPersonWhere)
+ ->column('person_id');
+
+ if (empty($coachPersonIds)) {
+ return [
+ 'code' => 1,
+ 'msg' => '暂无教练数据',
+ 'data' => []
+ ];
+ }
+
+ // 构建人员表查询条件
+ $where[] = ['id', 'in', $coachPersonIds];
+
+ // 姓名关键词搜索
+ if (!empty($data['keyword'])) {
+ $where[] = ['name', 'like', '%' . $data['keyword'] . '%'];
+ }
+
+ // 状态筛选,默认获取有效教练
+ if (isset($data['status'])) {
+ $where[] = ['status', '=', $data['status']];
+ }
+
+ // 只获取未逻辑删除的教练
+ $where[] = ['deleted_at', '=', 0];
+
+ $coachList = $this->model
+ ->where($where)
+ ->field('id, name, head_img, phone, employee_number')
+ ->order('create_time DESC')
+ ->select()
+ ->toArray();
+
+ return [
+ 'code' => 1,
+ 'msg' => '获取成功',
+ 'data' => $coachList
+ ];
+
+ } catch (\Exception $e) {
+ return [
+ 'code' => 0,
+ 'msg' => '获取教练列表失败:' . $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
+
}
diff --git a/niucloud/app/service/api/apiService/jlClassService.php b/niucloud/app/service/api/apiService/jlClassService.php
index ad0cb712..fe714a2a 100644
--- a/niucloud/app/service/api/apiService/jlClassService.php
+++ b/niucloud/app/service/api/apiService/jlClassService.php
@@ -197,4 +197,55 @@ class jlClassService extends BaseApiService
];
return $arr;
}
+
+ /**
+ * 获取班级列表(用于添加课程安排)
+ * @param array $data
+ * @return array
+ */
+ public function getClassListForSchedule(array $data)
+ {
+ try {
+ $where = [];
+
+ // 班级名称关键词搜索
+ if (!empty($data['keyword'])) {
+ $where[] = ['class_name', 'like', '%' . $data['keyword'] . '%'];
+ }
+
+ // 校区筛选
+ if (!empty($data['campus_id'])) {
+ $where[] = ['campus_id', '=', $data['campus_id']];
+ }
+
+ // 状态筛选,默认获取开启状态的班级
+ if (isset($data['status'])) {
+ $where[] = ['status', '=', $data['status']];
+ }
+
+ // 只获取未逻辑删除的班级
+ $where[] = ['deleted_at', '=', 0];
+
+ // 使用正确的模型来查询班级数据
+ $classList = \think\facade\Db::name('class')
+ ->where($where)
+ ->field('id, class_name, campus_id, campus_name, head_coach, assistant_coach, age_group, class_type, status')
+ ->order('created_at DESC')
+ ->select()
+ ->toArray();
+
+ return [
+ 'code' => 1,
+ 'msg' => '获取成功',
+ 'data' => $classList
+ ];
+
+ } catch (\Exception $e) {
+ return [
+ 'code' => 0,
+ 'msg' => '获取班级列表失败:' . $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
}
diff --git a/niucloud/config/app.php b/niucloud/config/app.php
index 3dada4b4..7108b07b 100644
--- a/niucloud/config/app.php
+++ b/niucloud/config/app.php
@@ -28,5 +28,7 @@ return [
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
- 'show_error_msg' => false,
+ 'show_error_msg' => true,
+ 'app_debug' => env('app.debug', true),
+ 'app_trace' => env('app.trace', true),
];
diff --git a/niucloud/core/base/BaseAdminService.php b/niucloud/core/base/BaseAdminService.php
index 2cfdd1be..ac978ea5 100644
--- a/niucloud/core/base/BaseAdminService.php
+++ b/niucloud/core/base/BaseAdminService.php
@@ -24,6 +24,7 @@ class BaseAdminService extends BaseService
protected $username;
protected $uid;
+ protected $campus_id;
public function __construct()
{
diff --git a/start.sh b/start.sh
index 8cdbe9a1..6813db7c 100755
--- a/start.sh
+++ b/start.sh
@@ -14,9 +14,9 @@ print_error() {
}
# 设置项目名称
-PROJECT_NAME="MyApp"
+PROJECT_NAME="NiuCloud"
-# 检查Docker和Docker Compose是否安装
+# 检查Docker环境
check_docker() {
if ! command -v docker &> /dev/null; then
print_error "Docker未安装,请先安装Docker"
@@ -115,6 +115,10 @@ upload_max_filesize = 20M
post_max_size = 20M
max_execution_time = 300
date.timezone = Asia/Shanghai
+display_errors = On
+error_reporting = E_ALL
+log_errors = On
+error_log = /var/log/php_errors.log
[opcache]
opcache.enable=1
@@ -184,13 +188,13 @@ restart_services() {
docker-compose restart
}
-# 查看状态
+# 查看服务状态
check_status() {
print_message "${PROJECT_NAME} 服务状态:"
docker-compose ps
}
-# 查看日志
+# 查看服务日志
view_logs() {
service=$1
if [ -z "$service" ]; then
@@ -215,6 +219,11 @@ init_project() {
create_directories
check_config_files
+ # 构建自定义 PHP 镜像
+ print_message "构建自定义 PHP 镜像..."
+ docker build -t niucloud-php:8.2 ./docker/php
+
+ # 拉取其他 Docker 镜像
print_message "拉取Docker镜像..."
docker-compose pull
diff --git a/startvps.sh b/startvps.sh
new file mode 100644
index 00000000..5d67e3f3
--- /dev/null
+++ b/startvps.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# start-claude-v2ray.sh
+
+echo "检查 V2Ray 是否运行..."
+if ! pgrep -x "v2ray" > /dev/null; then
+ echo "启动 V2Ray..."
+ nohup v2ray run -config config.json > /tmp/v2ray.log 2>&1 &
+ sleep 3
+fi
+
+echo "设置代理: 127.0.0.1:1087"
+export HTTP_PROXY=http://127.0.0.1:1087
+export HTTPS_PROXY=http://127.0.0.1:1087
+
+# 测试连接
+echo "测试代理连接..."
+if curl --proxy $HTTP_PROXY --max-time 10 -s https://api.anthropic.com > /dev/null; then
+ echo "✅ 代理连接正常"
+ echo "启动 Claude Code..."
+ claude
+else
+ echo "❌ 代理连接失败,请检查 V2Ray 配置"
+ exit 1
+fi
\ No newline at end of file
diff --git a/uniapp/api/apiRoute.js b/uniapp/api/apiRoute.js
index a6aa2e46..777ec115 100644
--- a/uniapp/api/apiRoute.js
+++ b/uniapp/api/apiRoute.js
@@ -29,6 +29,218 @@ export default {
async common_Dictionary(data = {}) {
return await http.get('/common/getDictionary', data);
},
+
+ // 课程安排列表
+ async getCourseScheduleList(data = {}) {
+ return await http.get('/courseSchedule/list', data);
+ },
+
+ // 课程安排时间段
+ async getCourseScheduleTimeSlots(data = {}) {
+ return await http.get('/courseSchedule/timeSlots', data);
+ },
+
+ // 课程安排筛选选项
+ async getCourseScheduleFilterOptions(data = {}) {
+ return await http.get('/courseSchedule/filterOptions', data);
+ },
+
+ // 课程安排详情
+ async getCourseScheduleInfo(data = {}) {
+ return await http.get('/courseSchedule/info', data);
+ },
+
+ // 提交课程点名
+ async submitScheduleSignIn(data = {}) {
+ return await http.post('/courseSchedule/signIn', 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,
+ 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')}`;
+ },
//公共端-获取全部员工列表
async common_getPersonnelAll(data = {}) {
return await http.get('/personnel/getPersonnelAll', data);
@@ -460,4 +672,26 @@ export default {
async submitScheduleSignIn(data = {}) {
return await http.post('/courseSchedule/signIn', data);
},
+
+ //↓↓↓↓↓↓↓↓↓↓↓↓-----添加课程安排页面专用接口-----↓↓↓↓↓↓↓↓↓↓↓↓
+ // 获取课程列表(用于添加课程安排)
+ async getCourseListForSchedule(data = {}) {
+ return await http.get('/course/list', data);
+ },
+ // 获取班级列表(用于添加课程安排)
+ async getClassListForSchedule(data = {}) {
+ return await http.get('/class/list', data);
+ },
+ // 获取教练列表(用于添加课程安排)
+ async getCoachListForSchedule(data = {}) {
+ return await http.get('/coach/list', data);
+ },
+ // 获取场地列表(用于添加课程安排)
+ async getVenueListForSchedule(data = {}) {
+ return await http.get('/venue/list', data);
+ },
+ // 获取场地可用时间段
+ async getVenueTimeSlots(data = {}) {
+ return await http.get('/venue/timeSlots', data);
+ },
}
\ No newline at end of file
diff --git a/uniapp/components/schedule/ScheduleDetail.vue b/uniapp/components/schedule/ScheduleDetail.vue
index 49c07e6b..0bc9427b 100644
--- a/uniapp/components/schedule/ScheduleDetail.vue
+++ b/uniapp/components/schedule/ScheduleDetail.vue
@@ -1,355 +1,379 @@
-
-
-
-
- 基本信息
-
- 课程名称:
- {{ scheduleInfo.course_name }}
-
-
- 上课时间:
- {{ scheduleInfo.course_date }} {{ scheduleInfo.time_slot }}
-
-
- 上课地点:
- {{ scheduleInfo.venue_name }}
-
-
- 授课教练:
- {{ scheduleInfo.coach_name }}
-
-
- 课程状态:
- {{ scheduleInfo.status_text }}
-
-
- 班级:
- {{ scheduleInfo.class_info ? scheduleInfo.class_info.class_name : '无班级' }}
-
-
-
-
-
- 学员信息 ({{ scheduleInfo.students ? scheduleInfo.students.length : 0 }}人)
-
-
-
-
-
-
- {{ student.name }}
- {{ student.status_text }}
-
-
-
-
- 暂无学员参与此课程
-
-
-
-
-
- 课程点名
- 调整课程
-
-
-
-
-
-
-
-
-
-
- 加载中...
-
-
-
- {{ errorMessage }}
-
- 重试
-
-
-
-
+
+
+
+
+ 基本信息
+
+ 课程名称:
+ {{ scheduleInfo.course_name }}
+
+
+ 上课时间:
+ {{ scheduleInfo.course_date }} {{ scheduleInfo.time_slot }}
+
+
+ 上课地点:
+ {{ scheduleInfo.venue_name }}
+
+
+ 授课教练:
+ {{ scheduleInfo.coach_name }}
+
+
+ 课程状态:
+ {{ scheduleInfo.status_text }}
+
+
+ 班级:
+ {{ scheduleInfo.class_info ? scheduleInfo.class_info.class_name : '无班级' }}
+
+
+
+
+
+ 学员信息 ({{ scheduleInfo.students ? scheduleInfo.students.length : 0 }}人)
+
+
+
+
+
+
+
+ {{ student.name }}
+ {{ student.status_text }}
+
+
+
+
+ 暂无学员参与此课程
+
+
+
+
+
+ 课程点名
+ 调整课程
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+ {{ errorMessage }}
+
+ 重试
+
+
+
+
\ No newline at end of file
diff --git a/uniapp/pages.json b/uniapp/pages.json
index 0ddfb6f3..275e8572 100644
--- a/uniapp/pages.json
+++ b/uniapp/pages.json
@@ -678,7 +678,6 @@
"path": "pages/coach/schedule/add_schedule",
"style": {
"navigationBarTitleText": "添加课程安排",
- "navigationStyle": "custom",
"navigationBarBackgroundColor": "#292929",
"navigationBarTextStyle": "white"
}
diff --git a/uniapp/pages/coach/my/index.vue b/uniapp/pages/coach/my/index.vue
index fec563f7..ff84af07 100644
--- a/uniapp/pages/coach/my/index.vue
+++ b/uniapp/pages/coach/my/index.vue
@@ -239,14 +239,6 @@
})
},
- //打开体育场信息
- openViewSportsVenue() {
- uni.showModal({
- title: '我的体育场',
- content: '当前分配场馆:xxx场馆\n地址:xxx\n联系电话:xxx',
- showCancel: false
- })
- },
goCourseSchedule(){
this.$navigateTo({
url: '/pages/coach/schedule/schedule_table'
diff --git a/uniapp/pages/coach/schedule/README.md b/uniapp/pages/coach/schedule/README.md
index dc9aa09f..297e7c4c 100644
--- a/uniapp/pages/coach/schedule/README.md
+++ b/uniapp/pages/coach/schedule/README.md
@@ -172,4 +172,158 @@ handleCourseClick(course) {
### 样式错位
- 检查 flex 布局设置
-- 确保单元格宽度一致
\ No newline at end of file
+- 确保单元格宽度一致
+
+---
+
+# 添加课程安排页面 API 设计文档
+
+## 页面概述
+
+添加课程安排页面用于创建新的课程安排,包含课程选择、班级选择、教练分配、场地预订、时间安排等功能。
+
+## 数据库表结构映射
+
+### 1. 课程下拉框
+- **页面字段**: "请选择课程"
+- **数据源**: `school_course` 表
+- **需要字段**: `id`, `course_name`, `course_type`, `duration`, `session_count`, `single_session_count`
+- **说明**: 显示所有可用课程供选择
+
+### 2. 班级下拉框
+- **页面字段**: "请选择班级(可选)"
+- **数据源**: `school_class` 表
+- **需要字段**: `id`, `class_name`, `campus_id`, `head_coach`, `assistant_coach`, `status`
+- **筛选条件**: `status = 1` (开启状态)
+- **说明**: 根据校区筛选可用班级,为可选字段
+
+### 3. 授课教练下拉框
+- **页面字段**: "请选择教练"
+- **数据源**: `school_personnel` 表 + `school_campus_person_role` 表
+- **查询条件**:
+ - `school_campus_person_role.dept_id = 2` (教练部门)
+ - 校区筛选逻辑:
+ - 如果 `campus_id != 0`: 查询指定校区的教练
+ - 如果 `campus_id = 0`: 查询所有校区的教练
+- **需要字段**: `school_personnel.id`, `school_personnel.name`, `school_campus_person_role.campus_id`
+
+### 4. 上课场地下拉框
+- **页面字段**: "请选择场地"
+- **数据源**: `school_venue` 表
+- **需要字段**: `id`, `venue_name`, `capacity`, `availability_status`, `time_range_type`, `time_range_start`, `time_range_end`, `fixed_time_ranges`
+- **筛选条件**: `availability_status = 1` (可用状态)
+- **说明**: 根据校区筛选可用场地
+
+### 5. 上课日期
+- **页面字段**: "上课日期"
+- **数据库字段**: `school_course_schedule.course_date`
+- **格式**: DATE (YYYY-MM-DD)
+
+### 6. 上课时间段
+- **页面字段**: "请选择时间段"
+- **数据库字段**: `school_course_schedule.time_slot`
+- **格式**: VARCHAR "HH:MM-HH:MM" (如: "09:00-10:00")
+- **说明**: 根据选中场地的时间限制动态生成可选时间段
+
+### 7. 课程容量
+- **页面字段**: "请输入课程容量"
+- **数据库字段**: `school_course_schedule.available_capacity`
+- **说明**: 不能超过场地的最大容量
+
+### 8. 备注
+- **页面字段**: "请输入备注信息(可选)"
+- **数据库字段**: `school_course_schedule.remarks`
+- **类型**: TEXT
+- **说明**: 可选字段,用于记录额外信息
+
+## 校区权限说明
+
+系统根据当前用户所属校区进行数据筛选:
+- **教练**: 通过 `school_campus_person_role` 表的 `campus_id` 字段筛选
+- **班级**: 通过 `school_class` 表的 `campus_id` 字段筛选
+- **场地**: 通过 `school_venue` 表的 `campus_id` 字段筛选
+
+特殊情况:如果 `campus_id = 0`,则表示该资源对所有校区可用。
+
+## 需要的API接口
+
+### 1. 获取课程列表
+**接口**: `GET /course/list`
+**参数**: 无
+**返回**: 课程列表数据
+
+### 2. 获取班级列表
+**接口**: `GET /class/list`
+**参数**:
+- `campus_id`: 校区ID(可选)
+**返回**: 班级列表数据
+
+### 3. 获取教练列表
+**接口**: `GET /coach/list`
+**参数**:
+- `campus_id`: 校区ID(可选)
+**返回**: 教练列表数据
+**查询逻辑**:
+```sql
+SELECT p.id, p.name
+FROM school_personnel p
+JOIN school_campus_person_role r ON p.id = r.person_id
+WHERE r.dept_id = 2
+AND (r.campus_id = :campus_id OR r.campus_id = 0)
+```
+
+### 4. 获取场地列表
+**接口**: `GET /venue/list`
+**参数**:
+- `campus_id`: 校区ID(可选)
+**返回**: 场地列表数据
+
+### 5. 获取可用时间段
+**接口**: `GET /venue/timeSlots`
+**参数**:
+- `venue_id`: 场地ID
+- `date`: 查询日期
+**返回**: 可用时间段列表
+**说明**: 根据场地的时间限制和已有安排计算可用时间段
+
+### 6. 创建课程安排
+**接口**: `POST /courseSchedule/create`
+**参数**:
+```json
+{
+ "campus_id": 1,
+ "venue_id": 1,
+ "course_date": "2025-06-30",
+ "time_slot": "09:00-10:00",
+ "course_id": 1,
+ "coach_id": 1,
+ "available_capacity": 15,
+ "class_id": 1,
+ "remarks": "备注信息",
+ "created_by": "manual"
+}
+```
+**返回**: 创建结果
+
+## 数据验证规则
+
+1. **课程容量验证**: 不能超过场地最大容量
+2. **时间冲突检查**: 同一场地同一时间段不能有多个课程安排
+3. **教练时间冲突**: 同一教练同一时间段不能安排多个课程
+4. **场地可用时间**: 选择的时间段必须在场地可用时间范围内
+5. **日期验证**: 不能选择过去的日期
+
+## 业务逻辑
+
+1. **自动计算可用容量**: 默认使用场地容量,用户可手动调整
+2. **班级教练关联**: 选择班级后,可自动填充该班级的主教练
+3. **场地时间限制**: 根据场地设置动态显示可选时间段
+4. **重复课程检查**: 创建前检查是否存在冲突
+
+## 状态管理
+
+新创建的课程安排默认状态为 `pending`(待开始),系统会根据时间自动更新状态:
+- `pending`: 待开始
+- `upcoming`: 即将开始
+- `ongoing`: 进行中
+- `completed`: 已结束
\ No newline at end of file
diff --git a/uniapp/pages/coach/schedule/add_schedule.vue b/uniapp/pages/coach/schedule/add_schedule.vue
index 8f89ce4c..d47aacae 100644
--- a/uniapp/pages/coach/schedule/add_schedule.vue
+++ b/uniapp/pages/coach/schedule/add_schedule.vue
@@ -1,14 +1,5 @@
-
-
@@ -216,34 +207,46 @@ export default {
});
try {
- const res = await api.getCourseScheduleFilterOptions();
+ // 并行加载所有选项数据
+ const [courseRes, classRes, coachRes, venueRes] = await Promise.all([
+ api.getCourseListForSchedule(),
+ api.getClassListForSchedule(),
+ api.getCoachListForSchedule(),
+ api.getVenueListForSchedule()
+ ]);
- if (res.code === 1) {
- // 设置课程选项
- this.courseOptions = res.data.courses || [];
-
- // 设置班级选项
- this.classOptions = res.data.classes || [];
-
- // 设置教练选项
- this.coachOptions = res.data.coaches || [];
-
- // 设置场地选项
- this.venueOptions = res.data.venues || [];
-
- // 生成时间段选项
- this.generateTimeSlotOptions();
-
- // 如果有预填充时间段,设置选中的时间段
- if (this.prefillTimeSlot) {
- this.formData.time_slot = this.prefillTimeSlot;
- }
- } else {
- uni.showToast({
- title: res.msg || '加载筛选选项失败',
- icon: 'none'
- });
+ // 设置课程选项
+ if (courseRes.code === 1) {
+ this.courseOptions = courseRes.data || [];
}
+
+ // 设置班级选项
+ if (classRes.code === 1) {
+ this.classOptions = classRes.data || [];
+ }
+
+ // 设置教练选项
+ if (coachRes.code === 1) {
+ this.coachOptions = coachRes.data || [];
+ }
+
+ // 设置场地选项
+ if (venueRes.code === 1) {
+ this.venueOptions = venueRes.data || [];
+ }
+
+ // 如果有预填充时间段,设置选中的时间段
+ if (this.prefillTimeSlot) {
+ this.formData.time_slot = this.prefillTimeSlot;
+ }
+
+ console.log('加载的数据:', {
+ courses: this.courseOptions.length,
+ classes: this.classOptions.length,
+ coaches: this.coachOptions.length,
+ venues: this.venueOptions.length
+ });
+
} catch (error) {
console.error('加载筛选选项失败:', error);
uni.showToast({
@@ -291,6 +294,45 @@ export default {
this.timeSlotOptions = timeSlots;
},
+
+ // 动态加载场地可用时间段
+ async loadTimeSlots() {
+ if (!this.formData.venue_id || !this.formData.course_date) {
+ return;
+ }
+
+ try {
+ const res = await api.getVenueTimeSlots({
+ venue_id: this.formData.venue_id,
+ date: this.formData.course_date
+ });
+
+ if (res.code === 1) {
+ // 转换API返回的时间段格式为选择器需要的格式
+ this.timeSlotOptions = res.data.map(slot => ({
+ value: slot.time_slot,
+ text: slot.time_slot
+ }));
+
+ console.log('可用时间段:', this.timeSlotOptions);
+ } else {
+ // 如果API失败,则使用默认时间段
+ this.generateTimeSlotOptions();
+ uni.showToast({
+ title: res.msg || '获取可用时间段失败,使用默认时间段',
+ icon: 'none'
+ });
+ }
+ } catch (error) {
+ console.error('加载时间段失败:', error);
+ // 如果API失败,则使用默认时间段
+ this.generateTimeSlotOptions();
+ uni.showToast({
+ title: '获取可用时间段失败,使用默认时间段',
+ icon: 'none'
+ });
+ }
+ },
// 选择器处理方法
onCourseSelect(e) {
@@ -333,6 +375,11 @@ export default {
if (this.selectedVenue.capacity) {
this.formData.available_capacity = this.selectedVenue.capacity;
}
+
+ // 如果已选择日期,则重新加载时间段
+ if (this.formData.course_date) {
+ this.loadTimeSlots();
+ }
}
this.showVenuePicker = false;
},
@@ -340,6 +387,11 @@ export default {
onDateSelect(e) {
this.formData.course_date = e.result;
this.showDatePicker = false;
+
+ // 如果已选择场地,则重新加载时间段
+ if (this.formData.venue_id) {
+ this.loadTimeSlots();
+ }
},
onTimeSelect(e) {
@@ -412,7 +464,23 @@ export default {
this.submitting = true;
try {
- const res = await api.createCourseSchedule(this.formData);
+ // 准备提交的数据,确保字段名与API接口匹配
+ const submitData = {
+ campus_id: 1, // 默认校区ID,实际项目中应从用户信息获取
+ venue_id: this.formData.venue_id,
+ course_date: this.formData.course_date,
+ time_slot: this.formData.time_slot,
+ course_id: this.formData.course_id,
+ coach_id: this.formData.coach_id,
+ available_capacity: parseInt(this.formData.available_capacity),
+ class_id: this.formData.class_id || 0, // 可选字段
+ remarks: this.formData.remark || '', // 字段名转换
+ created_by: 'manual'
+ };
+
+ console.log('提交数据:', submitData);
+
+ const res = await api.createCourseSchedule(submitData);
if (res.code === 1) {
uni.showToast({
@@ -448,7 +516,6 @@ export default {
.add-schedule-container {
min-height: 100vh;
background-color: #18181c;
- padding-top: 88rpx;
}
.form-container {
diff --git a/uniapp/pages/coach/schedule/schedule_table.vue b/uniapp/pages/coach/schedule/schedule_table.vue
index 72cb7c34..a3100ee4 100644
--- a/uniapp/pages/coach/schedule/schedule_table.vue
+++ b/uniapp/pages/coach/schedule/schedule_table.vue
@@ -56,19 +56,80 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {{ timeSlot.time }}
+
+
+
+
+
+
+ {{ teacher.name }}
+
+
+
+
+
+
+ {{ venue.name }}
+
+
+
+
+
+
+ {{ cls.name }}
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
-
-
- {{ timeSlot.time }}
-
-
+
{{ course.courseName }}
@@ -126,10 +177,116 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+ {{ course.courseName }}
+ {{ course.time }}
+ {{ course.students }}
+ {{ course.status }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ course.courseName }}
+ {{ course.time }}
+ {{ course.teacher }}
+ {{ course.status }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ course.courseName }}
+ {{ course.time }}
+ {{ course.teacher }}
+ {{ course.status }}
+
+
+
+
+
+
+
+
@@ -266,9 +423,10 @@ export default {
// 滚动相关
scrollLeft: 0,
scrollTop: 0,
+ scrollAnimationFrame: null, // 滚动动画帧
// 表格配置
- tableWidth: 1200, // 表格总宽度
+ tableWidth: 1500, // 表格总宽度,确保7天都能显示 (7*180+120=1380rpx)
// 时间段配置(动态生成,支持场地时间限制)
timeSlots: [],
@@ -353,6 +511,22 @@ export default {
this.initTimeSlots()
this.loadFilterOptions()
this.loadScheduleList()
+
+ // 先初始化模拟数据
+ this.initMockData()
+
+ // 监听窗口大小变化,调整布局
+ window.addEventListener('resize', this.handleResize)
+ },
+
+ beforeDestroy() {
+ // 移除事件监听
+ window.removeEventListener('resize', this.handleResize)
+
+ // 清除任何未完成的动画帧
+ if (this.scrollAnimationFrame) {
+ cancelAnimationFrame(this.scrollAnimationFrame)
+ }
},
methods: {
@@ -360,8 +534,15 @@ export default {
initCurrentWeek() {
const today = new Date()
const currentDay = today.getDay() // 0是周日,1是周一
- const diff = today.getDate() - currentDay + (currentDay === 0 ? -6 : 1) // 调整到周一
- const monday = new Date(today.setDate(diff))
+
+ // 计算本周周一的日期
+ let diff = 1 - currentDay // 距离周一的天数
+ if (currentDay === 0) { // 如果今天是周日,则向前调7天到上周一
+ diff = -6
+ }
+
+ const monday = new Date(today)
+ monday.setDate(today.getDate() + diff)
this.currentWeekStart = monday.toISOString().split('T')[0]
// 设置筛选参数的日期范围
@@ -513,13 +694,61 @@ export default {
// 获取指定时间和日期的课程
getCoursesByTimeAndDate(time, date) {
return this.courses.filter(course =>
- course.time === time && course.date === date,
+ course.time === time && course.date === date
)
},
+
+ // 获取指定教练和日期的课程
+ getCoursesByTeacherAndDate(teacherId, date) {
+ return this.courses.filter(course => {
+ // 匹配教练ID
+ const teacherMatch = course.teacher_id === teacherId ||
+ (this.teacherOptions.find(t => t.name === course.teacher)?.id === teacherId);
+ // 匹配日期
+ return teacherMatch && course.date === date;
+ });
+ },
+
+ // 获取指定教室和日期的课程
+ getCoursesByVenueAndDate(venueId, date) {
+ return this.courses.filter(course => {
+ // 匹配教室ID
+ const venueMatch = course.venue_id === venueId ||
+ (this.venues.find(v => v.name === course.venue)?.id === venueId);
+ // 匹配日期
+ return venueMatch && course.date === date;
+ });
+ },
+
+ // 获取指定班级和日期的课程
+ getCoursesByClassAndDate(classId, date) {
+ return this.courses.filter(course => {
+ // 匹配班级ID
+ const classMatch = course.class_id === classId ||
+ (this.classOptions.find(c => course.courseName.includes(c.name))?.id === classId);
+ // 匹配日期
+ return classMatch && course.date === date;
+ });
+ },
// 打开筛选
openFilter(type) {
- this.activeFilter = this.activeFilter === type ? '' : type
+ // 如果已经是当前类型,则取消选中,否则切换为新类型
+ const newFilter = this.activeFilter === type ? '' : type;
+
+ // 只有当筛选类型发生变化时才执行操作
+ if (this.activeFilter !== newFilter) {
+ this.activeFilter = newFilter;
+
+ // 如果切换了模式,重置滚动位置
+ this.scrollLeft = 0;
+ this.scrollTop = 0;
+
+ // 清除任何未完成的动画帧
+ if (this.scrollAnimationFrame) {
+ cancelAnimationFrame(this.scrollAnimationFrame);
+ }
+ }
},
// 关闭筛选弹窗
@@ -528,7 +757,7 @@ export default {
},
// 筛选确认
- handleFilterConfirm(e) {
+ async handleFilterConfirm(e) {
if (e.index === 0) {
// 重置
this.resetFilters()
@@ -536,6 +765,16 @@ export default {
// 确定
this.applyFilters()
this.closeFilterModal()
+
+ // 重新加载数据后,重置滚动位置
+ await this.loadScheduleList()
+ this.scrollLeft = 0
+ this.scrollTop = 0
+
+ // 如果筛选改变了时间段,需要重新生成时间列
+ if (this.selectedTimeRange !== '' || this.selectedVenueId !== null) {
+ this.initTimeSlots()
+ }
}
},
@@ -623,7 +862,28 @@ export default {
// 加载筛选选项
async loadFilterOptions() {
try {
- const res = await api.getCourseScheduleFilterOptions()
+ // 直接使用已初始化的模拟数据
+ // 注释掉实际 API 调用,之后再实现
+ // const res = await api.getCourseScheduleFilterOptions()
+
+ const res = {
+ code: 1,
+ data: {
+ coaches: this.teacherOptions,
+ venues: this.venues.map(venue => ({
+ id: venue.id,
+ venue_name: venue.name,
+ capacity: venue.capacity,
+ description: venue.description || ''
+ })),
+ classes: this.classOptions.map(cls => ({
+ id: cls.id,
+ class_name: cls.name,
+ class_level: cls.level,
+ total_students: cls.students
+ }))
+ }
+ }
if (res.code === 1) {
const data = res.data
@@ -669,7 +929,8 @@ export default {
try {
this.loading = true
- const res = await api.getCourseScheduleList(this.filterParams)
+ // 使用模拟数据 API
+ const res = await api.getCourseScheduleListMock(this.filterParams)
if (res.code === 1) {
// 转换数据格式
@@ -716,22 +977,56 @@ export default {
}
},
- // 水平滚动事件
- onHorizontalScroll(e) {
- this.scrollLeft = e.detail.scrollLeft
- },
-
- // 垂直滚动事件
- onVerticalScroll(e) {
- this.scrollTop = e.detail.scrollTop
+ // 滚动事件处理函数
+ onScroll(e) {
+ if (this.scrollAnimationFrame) {
+ cancelAnimationFrame(this.scrollAnimationFrame)
+ }
+
+ this.scrollAnimationFrame = requestAnimationFrame(() => {
+ // 获取滚动位置
+ if (e.detail.scrollLeft !== undefined) {
+ this.scrollLeft = e.detail.scrollLeft
+ }
+
+ if (e.detail.scrollTop !== undefined) {
+ this.scrollTop = e.detail.scrollTop
+
+ // 更新左侧时间列的滚动位置
+ this.$nextTick(() => {
+ const timeRowsContainer = this.$el.querySelector('.time-rows-container')
+ if (timeRowsContainer) {
+ timeRowsContainer.scrollTop = this.scrollTop
+ }
+ })
+ }
+ })
},
// 单元格点击
- handleCellClick(timeSlot, date) {
- // 打开添加课程课程安排页面,并传递时间和日期信息
- uni.navigateTo({
- url: `/pages/coach/schedule/add_schedule?date=${date.date}&time=${timeSlot.time}&time_slot=${timeSlot.timeSlot}`,
- })
+ handleCellClick(timeSlot, date, teacherId = null, venueId = null, classId = null) {
+ // 构建跳转 URL
+ let url = `/pages/coach/schedule/add_schedule?date=${date.date}`;
+
+ // 根据不同模式添加参数
+ if (timeSlot && timeSlot.time) {
+ url += `&time=${timeSlot.time}&time_slot=${timeSlot.timeSlot || ''}`;
+ }
+
+ if (teacherId) {
+ url += `&coach_id=${teacherId}`;
+ }
+
+ if (venueId) {
+ url += `&venue_id=${venueId}`;
+ }
+
+ if (classId) {
+ url += `&class_id=${classId}`;
+ }
+
+ // 打开添加课程安排页面
+ uni.navigateTo({ url });
},
// 添加课程
@@ -762,6 +1057,49 @@ export default {
url: `/pages/coach/schedule/adjust_course?id=${data.scheduleId}`,
})
},
+
+ // 响应式调整
+ handleResize() {
+ // 根据窗口宽度调整表格尺寸
+ const width = window.innerWidth
+ if (width <= 375) {
+ this.tableWidth = 1220 // 7*160+100=1220rpx
+ } else if (width <= 768) {
+ this.tableWidth = 1400
+ } else {
+ this.tableWidth = 1500
+ }
+ },
+
+ // 初始化模拟数据
+ initMockData() {
+ // 模拟教练选项
+ this.teacherOptions = [
+ { id: 1, name: '张教练', avatar: '/static/avatar/teacher1.png' },
+ { id: 2, name: '李教练', avatar: '/static/avatar/teacher2.png' },
+ { id: 3, name: '王教练', avatar: '/static/avatar/teacher3.png' },
+ { id: 4, name: '刘教练', avatar: '/static/avatar/teacher4.png' },
+ { id: 5, name: '赵教练', avatar: '/static/avatar/teacher5.png' }
+ ];
+
+ // 模拟场地选项
+ this.venues = [
+ { id: 1, name: '舞蹈室A', capacity: 20, time_range_type: 'range', time_range_start: '09:00', time_range_end: '21:00' },
+ { id: 2, name: '瑜伽B', capacity: 15, time_range_type: 'range', time_range_start: '08:00', time_range_end: '20:00' },
+ { id: 3, name: '健身C', capacity: 10, time_range_type: 'all' },
+ { id: 4, name: '泳池D', capacity: 8, time_range_type: 'fixed', fixed_time_ranges: ['09:00-11:00', '14:00-18:00'] },
+ { id: 5, name: '综合场馆E', capacity: 30, time_range_type: 'range', time_range_start: '08:00', time_range_end: '22:00' }
+ ];
+
+ // 模拟班级选项
+ this.classOptions = [
+ { id: 1, name: '少儿形体班', level: '初级', students: 15 },
+ { id: 2, name: '成人瑜伽班', level: '中级', students: 20 },
+ { id: 3, name: '私教VIP班', level: '高级', students: 5 },
+ { id: 4, name: '儿童游泳班', level: '初级', students: 12 },
+ { id: 5, name: '暑期特训班', level: '混合', students: 25 }
+ ];
+ },
},
}
@@ -844,6 +1182,68 @@ export default {
// 课程表主体
.schedule-main {
+ flex: 1;
+ position: relative;
+ display: flex;
+ overflow: hidden;
+}
+
+// 左侧固定时间列
+.time-column-fixed {
+ width: 120rpx;
+ position: relative;
+ z-index: 2;
+ background-color: #292929;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 4rpx 0 8rpx rgba(0, 0, 0, 0.1);
+}
+
+.time-header-cell {
+ width: 120rpx;
+ height: 120rpx; // 需与表头高度一致
+ padding: 20rpx 10rpx;
+ color: #29d3b4;
+ font-size: 28rpx;
+ font-weight: 500;
+ text-align: center;
+ border-right: 1px solid #555;
+ background-color: #434544;
+ border-bottom: 2px solid #29d3b4;
+}
+
+.time-rows-container {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow-y: hidden;
+ min-height: 1000rpx; /* 确保有足够的高度能滚动 */
+}
+
+.time-cell {
+ width: 120rpx;
+ height: 120rpx; /* 固定高度保证对齐 */
+ min-height: 120rpx;
+ padding: 20rpx 10rpx;
+ color: #999;
+ font-size: 24rpx;
+ text-align: center;
+ border-right: 1px solid #434544;
+ border-bottom: 1px solid #434544;
+ background: #3a3a3a;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &.time-unavailable {
+ background: #2a2a2a;
+ color: #555;
+ opacity: 0.5;
+ }
+}
+
+// 右侧可滚动区域
+.schedule-scrollable-area {
flex: 1;
position: relative;
overflow: hidden;
@@ -852,44 +1252,35 @@ export default {
.schedule-scroll-horizontal {
width: 100%;
height: 100%;
+ overflow: scroll;
}
-.schedule-table {
- min-width: 100%;
- height: 100%;
+.scroll-content {
display: flex;
flex-direction: column;
+ min-width: 1500rpx;
}
-// 表头
.table-header {
display: flex;
background: #434544;
border-bottom: 2px solid #29d3b4;
position: sticky;
top: 0;
- z-index: 10;
-}
-
-.time-header-cell {
- width: 120rpx;
- min-width: 120rpx;
- padding: 20rpx 10rpx;
- color: #29d3b4;
- font-size: 28rpx;
- font-weight: 500;
- text-align: center;
- border-right: 1px solid #555;
+ z-index: 1;
+ min-width: 1260rpx; /* 7天 * 180rpx = 1260rpx */
}
.date-header-cell {
- width: 150rpx;
- min-width: 150rpx;
+ width: 180rpx;
+ min-width: 180rpx;
padding: 15rpx 10rpx;
color: #fff;
font-size: 24rpx;
text-align: center;
border-right: 1px solid #555;
+ background: #434544;
+ flex-shrink: 0;
.date-week {
font-size: 26rpx;
@@ -909,45 +1300,28 @@ export default {
}
}
-// 表格内容
-.schedule-scroll-vertical {
- flex: 1;
- height: 100%;
-}
-
-.table-body {
+.course-content-area {
width: 100%;
+ min-height: 1000rpx; /* 确保有足够的高度能滚动 */
+ min-width: 1260rpx; /* 7天 * 180rpx = 1260rpx */
}
.time-row {
display: flex;
+ height: 120rpx; /* 固定高度保证对齐 */
min-height: 120rpx;
border-bottom: 1px solid #434544;
}
-.time-cell {
- width: 120rpx;
- min-width: 120rpx;
- padding: 20rpx 10rpx;
- color: #999;
- font-size: 24rpx;
- text-align: center;
- border-right: 1px solid #434544;
- background: #3a3a3a;
-
- &.time-unavailable {
- background: #2a2a2a;
- color: #555;
- opacity: 0.5;
- }
-}
-
.course-cell {
- width: 150rpx;
- min-width: 150rpx;
+ width: 180rpx;
+ min-width: 180rpx;
padding: 10rpx;
border-right: 1px solid #434544;
+ border-bottom: 1px solid #434544;
position: relative;
+ background: #292929;
+ flex-shrink: 0;
&.cell-unavailable {
background: #1e1e1e;
@@ -967,6 +1341,28 @@ export default {
}
}
+// 响应式适配
+@media screen and (max-width: 375px) {
+ .time-column-fixed {
+ width: 100rpx;
+ }
+
+ .time-header-cell, .time-cell {
+ width: 100rpx;
+ font-size: 22rpx;
+ }
+
+ .course-cell {
+ width: 160rpx;
+ min-width: 160rpx;
+ }
+
+ .date-header-cell {
+ width: 160rpx;
+ min-width: 160rpx;
+ }
+}
+
// 课程项目
.course-item {
width: 100%;
@@ -998,6 +1394,12 @@ export default {
margin-bottom: 3rpx;
}
+.course-time {
+ color: #29d3b4;
+ font-size: 22rpx;
+ margin-bottom: 3rpx;
+}
+
.course-students {
color: #ccc;
margin-bottom: 3rpx;
diff --git a/uniapp/pages/coach/schedule/sign_in.vue b/uniapp/pages/coach/schedule/sign_in.vue
index 6e7e3986..8a3c3640 100644
--- a/uniapp/pages/coach/schedule/sign_in.vue
+++ b/uniapp/pages/coach/schedule/sign_in.vue
@@ -1,511 +1,521 @@
-
-
-
-
-
-
- {{ scheduleInfo.course_name }}
- {{ scheduleInfo.course_date }} {{ scheduleInfo.time_slot }}
-
-
- 授课教练:
- {{ scheduleInfo.coach_name }}
-
-
- 上课场地:
- {{ scheduleInfo.venue_name }}
-
-
- 学员人数:
- {{ studentList.length }}人
-
-
-
-
-
-
-
-
-
-
- 暂无学员数据
-
-
-
-
-
-
-
-
-
-
- {{ student.name }}
- {{ student.phone_number || '无联系电话' }}
-
-
-
-
-
- 已到
-
-
- 请假
-
-
- 未到
-
-
-
-
-
-
-
-
-
-
-
-
- 提交点名
-
-
-
+
+
+
+
+
+
+ {{ scheduleInfo.course_name }}
+ {{ scheduleInfo.course_date }} {{ scheduleInfo.time_slot }}
+
+
+ 授课教练:
+ {{ scheduleInfo.coach_name }}
+
+
+ 上课场地:
+ {{ scheduleInfo.venue_name }}
+
+
+ 学员人数:
+ {{ studentList.length }}人
+
+
+
+
+
+
+
+
+
+
+ 暂无学员数据
+
+
+
+
+
+
+
+
+
+
+ {{ student.name }}
+ {{ student.phone_number || '无联系电话' }}
+
+
+
+
+
+ 已到
+
+
+ 请假
+
+
+ 未到
+
+
+
+
+
+
+
+
+
+
+
+
+ 提交点名
+
+
+
\ No newline at end of file
diff --git a/uniapp/pages/market/my/index.vue b/uniapp/pages/market/my/index.vue
index b668f501..e7e4e6f3 100644
--- a/uniapp/pages/market/my/index.vue
+++ b/uniapp/pages/market/my/index.vue
@@ -48,10 +48,20 @@
+
+ 课程安排
+
+
+
我的消息
+
+
+ 我的合同
+
+
@@ -225,6 +235,18 @@ export default {
url: '/pages/market/reimbursement/list'
})
},
+
+
+ goCourseSchedule(){
+ this.$navigateTo({
+ url: '/pages/coach/schedule/schedule_table'
+ })
+ },
+ my_contract(){
+ this.$navigateTo({
+ url: '/pages/common/contract/my_contract'
+ })
+ },
}
}