diff --git a/SCHEDULE_FIXES_SUMMARY.md b/SCHEDULE_FIXES_SUMMARY.md deleted file mode 100644 index 825df57a..00000000 --- a/SCHEDULE_FIXES_SUMMARY.md +++ /dev/null @@ -1,198 +0,0 @@ -# 定时任务修复总结 - -## 修复概述 - -本次修复主要解决了系统中4个定时任务的关键逻辑问题和性能问题,并创建了统一的执行锁机制基类。 - -## 修复的问题 - -### 1. 资源自动分配逻辑问题 ✅ -**文件**: `niucloud/app/job/transfer/schedule/ResourceAutoAllocation.php` - -**问题**: -- 资源分配时创建新记录而不是更新现有记录,导致重复分配 -- 缺乏执行锁机制,可能并发执行 - -**修复**: -- 改为更新现有记录而非创建新记录 -- 添加执行锁机制(5分钟锁定时间) -- 改进分配统计和日志记录 -- 继承统一的 `BaseScheduleJob` 基类 - -### 2. 自动排课重复执行问题 ✅ -**文件**: `niucloud/app/job/transfer/schedule/CourseScheduleJob.php` - -**问题**: -- 每天执行时重复创建未来30天的课程 -- 缺乏重复执行控制机制 - -**修复**: -- 添加执行锁机制(10分钟锁定时间) -- 添加每日执行标记,防止重复执行 -- 改进模板数据获取逻辑,使用最近的有效数据作为模板 -- 优化日志记录和结果返回 - -### 3. 绩效计算重复和事务问题 ✅ -**文件**: `niucloud/app/job/transfer/schedule/PerformanceCalculation.php` - -**问题**: -- `performanceService` 初始化为 null 导致调用失败 -- 多人介入订单处理逻辑混乱 -- 缺乏完整的重复检查机制 -- 事务处理不完善 - -**修复**: -- 修复 `performanceService` 初始化问题 -- 添加执行锁机制(30分钟锁定时间) -- 重构保存逻辑,按订单分组处理避免重复更新 -- 完善事务处理和错误处理 -- 改进统计和日志记录 - -### 4. 课程状态批量更新性能问题 ✅ -**文件**: `niucloud/app/job/schedule/HandleCourseSchedule.php` - -**问题**: -- 在循环中逐条更新,性能极差 -- 缺乏事务保护 -- 可能重复更新相同记录 - -**修复**: -- 改为批量更新操作 -- 添加事务保护 -- 添加执行锁机制(5分钟锁定时间) -- 避免重复更新已完成的课程 -- 改进错误处理和统计 - -### 5. 统一执行锁机制 ✅ -**文件**: `niucloud/core/base/BaseScheduleJob.php` - -**新增功能**: -- 创建定时任务基类 `BaseScheduleJob` -- 提供统一的执行锁机制 -- 支持每日执行标记 -- 统一的日志记录格式 -- 自动清理过期标记文件 -- 标准化的结果返回格式 - -## 修复效果 - -### 性能提升 -- **课程状态更新**: 从逐条更新改为批量更新,性能提升约90% -- **绩效计算**: 优化事务处理和重复检查,减少数据库锁定时间 -- **资源分配**: 改进分配逻辑,避免重复记录创建 - -### 数据一致性 -- 所有定时任务都添加了事务保护 -- 完善的错误处理和回滚机制 -- 避免重复执行和数据重复 - -### 系统稳定性 -- 统一的执行锁机制防止任务冲突 -- 每日执行标记避免重复处理 -- 完善的异常处理和日志记录 - -## 技术改进 - -### 1. 执行锁机制 -- 文件锁防止任务重复执行 -- 可配置的锁定时间 -- 自动清理机制 - -### 2. 每日执行控制 -- 标记文件防止重复执行 -- 自动清理过期标记 -- 适用于每日执行一次的任务 - -### 3. 统一基类设计 -- `BaseScheduleJob` 提供通用功能 -- 子类只需实现具体业务逻辑 -- 标准化的错误处理和日志 - -### 4. 改进的事务处理 -- 合理的事务边界 -- 完善的回滚机制 -- 按业务单元分组处理 - -## 使用方法 - -### 启动定时任务服务 -```bash -# 启动定时任务服务 -docker exec niucloud_php php think cron:schedule start - -# 检查服务状态 -docker exec niucloud_php php think cron:schedule status - -# 停止服务 -docker exec niucloud_php php think cron:schedule stop -``` - -### 手动执行单个任务 -```bash -# 测试资源分配任务 -docker exec niucloud_php php think queue:work --queue resource_auto_allocation - -# 测试自动排课任务 -docker exec niucloud_php php think queue:work --queue course_schedule_job -``` - -### 创建新的定时任务 -继承 `BaseScheduleJob` 基类: - -```php -getSuccessResult(['processed' => 100]); - } -} -``` - -## 监控和维护 - -### 日志文件位置 -- 定时任务日志: `niucloud/runtime/log/` -- 锁文件位置: `niucloud/runtime/` -- 执行标记: `niucloud/runtime/` - -### 关键监控指标 -- 任务执行时间 -- 成功/失败率 -- 数据处理量 -- 锁文件状态 - -### 故障排查 -1. 检查日志文件中的错误信息 -2. 查看锁文件是否存在异常 -3. 验证数据库连接和权限 -4. 检查系统资源使用情况 - -## 后续建议 - -1. **添加监控告警**: 对关键任务失败进行告警 -2. **性能监控**: 记录任务执行时间和资源使用 -3. **数据备份**: 在重要操作前添加数据备份 -4. **测试环境验证**: 定期在测试环境验证任务逻辑 -5. **文档更新**: 保持文档与代码同步更新 - -## 风险控制 - -所有修复都已通过以下验证: -- ✅ PHP语法检查通过 -- ✅ 数据库操作事务完整 -- ✅ 错误处理机制完善 -- ✅ 日志记录详细 -- ✅ 向后兼容性保持 - -修复后的定时任务更加稳定、高效,并且具有更好的可维护性。 \ No newline at end of file diff --git a/admin/README.md b/admin/README.md deleted file mode 100644 index ef72fd52..00000000 --- a/admin/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Vue 3 + TypeScript + Vite - -This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` \ No newline at end of file diff --git a/gift_table_documentation.md b/gift_table_documentation.md deleted file mode 100644 index 28bbe001..00000000 --- a/gift_table_documentation.md +++ /dev/null @@ -1,79 +0,0 @@ -# 赠品表设计文档 - -## 表结构说明 - -### 表名:`gift` -**用途**:存储系统中的赠品信息,包括赠课和代金券等赠品类型 - -### 字段说明 - -| 字段名 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `id` | int(11) | AUTO_INCREMENT | 赠品主键ID | -| `gift_name` | varchar(255) | '' | 赠品名称 | -| `gift_type` | varchar(50) | '' | 赠品类型:course(赠课),voucher(代金券) | -| `gift_time` | int(11) | 0 | 赠送时间(时间戳) | -| `giver_id` | int(11) | 0 | 赠送来源人员ID | -| `resource_id` | int(11) | 0 | 赠品归属资源ID | -| `order_id` | int(11) | 0 | 赠品使用的订单ID(0表示未使用) | -| `gift_status` | tinyint(4) | 1 | 赠品状态:1=未使用,2=已使用,3=已过期,4=已作废 | -| `use_time` | int(11) | 0 | 赠品使用时间(时间戳) | -| `create_time` | int(11) | 0 | 创建时间(时间戳) | -| `update_time` | int(11) | 0 | 更新时间(时间戳) | -| `delete_time` | int(11) | 0 | 删除时间(时间戳,0表示未删除) | - -### 索引设计 - -#### 主键索引 -- `PRIMARY KEY (id)` - 主键索引,自动创建 - -#### 普通索引 -1. `IDX_gift_giver_id` - 赠送人员索引 - - **用途**:根据赠送人员ID查询赠品 - - **场景**:统计某个人员赠送的所有赠品 - -2. `IDX_gift_resource_id` - 资源ID索引 - - **用途**:根据资源ID查询相关赠品 - - **场景**:查询某个资源相关的所有赠品 - -3. `IDX_gift_order_id` - 订单ID索引 - - **用途**:根据订单ID查询使用的赠品 - - **场景**:查询某个订单中使用了哪些赠品 - -4. `IDX_gift_status` - 状态索引 - - **用途**:根据赠品状态快速筛选 - - **场景**:查询未使用、已使用、已过期等状态的赠品 - -5. `IDX_gift_type` - 类型索引 - - **用途**:根据赠品类型快速筛选 - - **场景**:分别查询赠课或代金券 - -6. `IDX_gift_time` - 赠送时间索引 - - **用途**:根据赠送时间范围查询 - - **场景**:统计某个时间段的赠品发放情况 - -### 业务逻辑说明 - -#### 赠品状态流转 -1. **未使用(1)** → **已使用(2)**:用户使用赠品时更新 -2. **未使用(1)** → **已过期(3)**:系统定时任务检查过期 -3. **未使用(1)** → **已作废(4)**:管理员手动作废 -4. **已使用(2)**:终态,不可再变更 - -#### 关键业务场景 -1. **赠品发放**:创建记录,设置 `gift_status=1` -2. **赠品使用**:更新 `order_id`、`use_time`、`gift_status=2` -3. **赠品过期**:定时任务更新 `gift_status=3` -4. **赠品作废**:管理员操作更新 `gift_status=4` - -### 性能优化建议 - -1. **复合索引考虑**: - - 如果经常按状态+类型查询,可考虑创建复合索引 `(gift_status, gift_type)` - - 如果经常按时间范围+状态查询,可考虑创建复合索引 `(gift_time, gift_status)` - -2. **分区表考虑**: - - 如果数据量很大,可考虑按时间分区 - -3. **归档策略**: - - 定期归档已删除或过期的赠品数据 \ No newline at end of file diff --git a/niucloud/README.md b/niucloud/README.md deleted file mode 100644 index a8c4d1cd..00000000 --- a/niucloud/README.md +++ /dev/null @@ -1,56 +0,0 @@ -ThinkPHP 6.0 -=============== - -> 运行环境要求PHP7.2+,兼容PHP8.1 - -[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api) - -ThinkPHPV6.0版本由[亿速云](https://www.yisu.com/)独家赞助发布。 - -## 主要新特性 - -* 采用`PHP7`强类型(严格模式) -* 支持更多的`PSR`规范 -* 原生多应用支持 -* 更强大和易用的查询 -* 全新的事件系统 -* 模型事件和数据库事件统一纳入事件系统 -* 模板引擎分离出核心 -* 内部功能中间件化 -* SESSION/Cookie机制改进 -* 对Swoole以及协程支持改进 -* 对IDE更加友好 -* 统一和精简大量用法 - -## 安装 - -~~~ -composer create-project topthink/think tp 6.0.* -~~~ - -如果需要更新框架使用 -~~~ -composer update topthink/framework -~~~ - -## 文档 - -[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content) - -## 参与开发 - -请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)。 - -## 版权信息 - -ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 - -本项目包含的第三方源码和二进制文件之版权信息另行标注。 - -版权所有Copyright © 2006-2021 by ThinkPHP (http://thinkphp.cn) - -All rights reserved。 - -ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 - -更多细节参阅 [LICENSE.txt](LICENSE.txt) diff --git a/niucloud/app/api/controller/apiController/Course.php b/niucloud/app/api/controller/apiController/Course.php index ff4cd30f..1c303f4e 100644 --- a/niucloud/app/api/controller/apiController/Course.php +++ b/niucloud/app/api/controller/apiController/Course.php @@ -107,7 +107,11 @@ class Course extends BaseApiService ["person_type",''], ["schedule_id",''], ["course_date",''], - ["time_slot",''] + ["time_slot",''], + ["schedule_type", 1], // 1=正式位, 2=等待位 + ["course_type", 1], // 1=正式课, 2=体验课, 3=等待位 + ["position", ''], // 位置信息 + ["remark", ''] // 备注 ]); return (new CourseService())->addSchedule($data); } diff --git a/niucloud/app/api/controller/apiController/StudentCourse.php b/niucloud/app/api/controller/apiController/StudentCourse.php index 1aa63a48..11460423 100644 --- a/niucloud/app/api/controller/apiController/StudentCourse.php +++ b/niucloud/app/api/controller/apiController/StudentCourse.php @@ -13,6 +13,7 @@ namespace app\api\controller\apiController; use app\Request; use app\service\api\apiService\StudentCourseService; +use app\service\api\apiService\ServiceService; use core\base\BaseApiService; /** @@ -64,6 +65,36 @@ class StudentCourse extends BaseApiService } } + /** + * 获取学员服务记录 + * @param Request $request + * @return \think\Response + */ + public function getServiceList(Request $request) + { + $student_id = $request->param('student_id', ''); + + // 如果没有传student_id,尝试从当前登录用户获取 + if (empty($student_id)) { + $student_id = $this->getResourceIdByMemberId($this->member_id); + } + + if (empty($student_id)) { + return fail('学员ID不能为空'); + } + + try { + $res = (new ServiceService())->getStudentServiceList((int)$student_id); + if (!$res['code']) { + return fail($res['msg']); + } + + return success($res['data']); + } catch (\Exception $e) { + return fail('获取服务记录失败:' . $e->getMessage()); + } + } + /** * 根据会员ID获取资源ID * @param int $member_id diff --git a/niucloud/app/api/route/route.php b/niucloud/app/api/route/route.php index 73989880..2c80ee52 100644 --- a/niucloud/app/api/route/route.php +++ b/niucloud/app/api/route/route.php @@ -524,6 +524,8 @@ Route::group(function () { //学生端-课程详情 Route::get('xy/course/detail', 'apiController.StudentCourse/courseDetail'); + //学生端-服务记录列表 + Route::get('xy/service/list', 'apiController.StudentCourse/getServiceList'); /***************************************************** 字典批量获取 ****************************************************/ // 批量获取字典数据 diff --git a/niucloud/app/service/api/apiService/CourseService.php b/niucloud/app/service/api/apiService/CourseService.php index 9dcb5f5b..4a96c3ff 100644 --- a/niucloud/app/service/api/apiService/CourseService.php +++ b/niucloud/app/service/api/apiService/CourseService.php @@ -445,6 +445,10 @@ class CourseService extends BaseApiService '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=等待位 + 'position' => $data['position'] ?? '', // 位置信息 + 'remark' => $data['remark'] ?? '' // 备注 ]); $CourseSchedule->where(['id' => $data['schedule_id']])->dec("available_capacity")->update(); return success("添加成功"); diff --git a/niucloud/app/service/api/apiService/CustomerResourcesService.php b/niucloud/app/service/api/apiService/CustomerResourcesService.php index da16667f..dbc88b62 100644 --- a/niucloud/app/service/api/apiService/CustomerResourcesService.php +++ b/niucloud/app/service/api/apiService/CustomerResourcesService.php @@ -89,7 +89,7 @@ class CustomerResourcesService extends BaseApiService $model = $model->where('name', 'like', "%{$where['name']}%"); } if(!empty($where['phone_number'])){ - $model = $model->where('phone_number', $where['phone_number']); + $model = $model->where('phone_number', 'like', "%{$where['phone_number']}%"); } $data = $model->field($field) ->with([ diff --git a/niucloud/app/service/api/apiService/ServiceService.php b/niucloud/app/service/api/apiService/ServiceService.php index b105d16b..bd1bf4c4 100644 --- a/niucloud/app/service/api/apiService/ServiceService.php +++ b/niucloud/app/service/api/apiService/ServiceService.php @@ -157,4 +157,116 @@ class ServiceService extends BaseApiService return ['code' => 0, 'msg' => '更新失败:' . $e->getMessage()]; } } + + /** + * 获取学员服务记录列表 + * @param int $studentId 学员ID + * @return array + */ + public function getStudentServiceList(int $studentId) + { + try { + // 查询SQL:关联服务基础信息、课程信息、员工信息 + $list = $this->model->alias('sl') + ->join('school_service s', 'sl.service_id = s.id') + ->leftJoin('school_course c', 'sl.course_id = c.id') + ->leftJoin('school_personnel p', 'sl.staff_id = p.id') + ->where('sl.resource_id', $studentId) + ->where('s.deleted_at', 0) + ->field([ + // 服务基础信息 + 's.id as service_id', + 's.service_name', + 's.preview_image_url', + 's.description', + 's.service_type', + 's.status as service_status', + // 服务记录信息 + 'sl.id as log_id', + 'sl.status as log_status', + 'sl.score', + 'sl.feedback', + 'sl.service_remark', + 'sl.created_at as service_time', + 'sl.feedback_time', + 'sl.updated_at', + // 课程信息 + 'c.course_name', + // 员工信息 + 'p.name as staff_name' + ]) + ->order('sl.created_at desc, sl.status asc') + ->select() + ->toArray(); + + // 处理数据格式,按服务分组 + $serviceMap = []; + foreach ($list as $item) { + $serviceId = $item['service_id']; + + if (!isset($serviceMap[$serviceId])) { + // 初始化服务信息 + $serviceMap[$serviceId] = [ + 'id' => $serviceId, + 'service_name' => $item['service_name'], + 'preview_image_url' => $item['preview_image_url'], + 'description' => $item['description'], + 'service_type' => $item['service_type'], + 'status' => $this->mapServiceStatus($item['service_status']), + 'logs' => [], + 'total_count' => 0, + 'completed_count' => 0 + ]; + } + + // 添加服务记录 + if ($item['log_id']) { + $log = [ + 'id' => $item['log_id'], + 'status' => $item['log_status'], + 'service_content' => $item['service_remark'], + 'service_staff' => $item['staff_name'], + 'service_time' => $item['service_time'] ?: '', + 'duration' => $item['updated_at'] ?: '', + 'customer_feedback' => $item['feedback'], + 'service_rating' => $item['score'] && $item['score'] <= 5 ? $item['score'] : null, + 'remark' => $item['service_remark'], + 'course_name' => $item['course_name'], + 'updated_at' => $item['updated_at'] ?: '' + ]; + + $serviceMap[$serviceId]['logs'][] = $log; + $serviceMap[$serviceId]['total_count']++; + + if ($item['log_status'] == 1) { + $serviceMap[$serviceId]['completed_count']++; + } + } + } + + return ['code' => 1, 'data' => array_values($serviceMap), 'msg' => '获取成功']; + + } catch (\Exception $e) { + return ['code' => 0, 'data' => [], 'msg' => '获取失败:' . $e->getMessage()]; + } + } + + /** + * 映射服务状态 + * @param int $status + * @return string + */ + private function mapServiceStatus($status) + { + switch ($status) { + case 1: + return 'active'; + case 0: + return 'expired'; + case 2: + return 'suspended'; + default: + return 'expired'; + } + } } diff --git a/niucloud/课程安排资料.md b/niucloud/课程安排资料.md deleted file mode 100644 index 6d8a4d26..00000000 --- a/niucloud/课程安排资料.md +++ /dev/null @@ -1,173 +0,0 @@ -school_campus(校区表) -CREATE TABLE `school_campus` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', -`campus_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '校区名称', -`campus_address` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '校区地址', -`campus_preview_image` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '校区预览图,存储图片路径', -`campus_coordinates` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '校区坐标,格式为经度,纬度', -`campus_introduction` text COLLATE utf8mb4_general_ci COMMENT '校区介绍', -`campus_status` tinyint DEFAULT '1' COMMENT '校区状态:0-禁用,1-启用', -`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '校区创建时间', -`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '校区更新时间', -`delete_time` int NOT NULL DEFAULT '0' COMMENT '逻辑删除字段,0表示未删除,非空表示已删除', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='校区表'; -做为基础数据,下面一级就是场地。 - -school_venue(场地表) -CREATE TABLE `school_venue` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '场地编号', -`campus_id` int NOT NULL COMMENT '校区ID', -`venue_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '场地名称', -`capacity` int NOT NULL COMMENT '场地可容纳人数上限', -`availability_status` tinyint(1) NOT NULL COMMENT '场地可用状态: 1-可用, 0-不可用', -`time_range_type` enum('range','fixed','all') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '场地可用时间范围类型: range-范围类型, fixed-固定时间范围类型', -`time_range_start` varchar(8) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '范围类型的开始时间', -`time_range_end` varchar(8) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '范围类型的结束时间', -`fixed_time_ranges` json DEFAULT NULL COMMENT '固定时间范围类型的可用时间, 存储为JSON数组', -`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', -`deleted_at` int DEFAULT '0' COMMENT '逻辑删除时间', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='场地表'; -场地表做为课程的容器,主要是用来限制人数,时间,和可用状态。如果场地被设置为不可用,那么该场地下的所有课程都会被取消。其中time_range_type字段决定这个时间范围是范围类型还是固定时间类型。 -这个字段配合time_range_start,time_range_end,fixed_time_ranges这三个字段,可以确定这个场地可用的时间范围。 - -school_course(课程表) -CREATE TABLE `school_course` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '课程编号', -`course_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '课程名称', -`course_type` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '课程类型', -`duration` int NOT NULL COMMENT '课程时长', -`session_count` int NOT NULL COMMENT '课时数量', -`single_session_count` int NOT NULL DEFAULT '0' COMMENT '单次消课数量', -`gift_session_count` int NOT NULL DEFAULT '0' COMMENT '赠送课时数量', -`price` decimal(10,2) NOT NULL COMMENT '课程价格', -`internal_reminder` int NOT NULL COMMENT '内部提醒课时', -`customer_reminder` int NOT NULL COMMENT '客户提醒课时', -`remarks` text COLLATE utf8mb4_general_ci COMMENT '课程备注', -`created_at` int DEFAULT '0' COMMENT '创建时间', -`updated_at` int DEFAULT '0' COMMENT '更新时间', -`deleted_at` int DEFAULT '0' COMMENT '逻辑删除时间', -`contract_id` int DEFAULT NULL, -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='课程表'; -课程表主要是用户上课的内容,在排课阶段主要是看用户排的是什么课在哪个课程安排里展示。课程表和课程安排表是一对多的关系,一个课程可以有多个课程安排。但是在一个周期范围内,这个安排的数量始终是不会超过课程表的课时数量的。 -举例来说single_session_count字段表示一次课程安排要消耗多少课时,如果值为 2,session_count课时数量是 10,那么这次课程周期一个用户只能排 5 次课程安排。 - -school_course_schedule(课程安排表) -CREATE TABLE `school_course_schedule` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '课程安排编号', -`campus_id` int NOT NULL COMMENT '校区ID', -`venue_id` int NOT NULL COMMENT '场地ID', -`course_date` date NOT NULL COMMENT '上课日期', -`time_slot` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '上课时段', -`course_id` int NOT NULL COMMENT '课程ID', -`coach_id` int NOT NULL COMMENT '上课教练ID', -`participants` json DEFAULT NULL COMMENT '参与人员列表,存储为JSON数组,包含学员ID和来源信息', -`student_ids` json DEFAULT NULL COMMENT '上课学生ID列表,存储为JSON数组', -`available_capacity` int DEFAULT NULL COMMENT '根据场地容量判断的可安排学员位置数量', -`status` enum('pending','upcoming','ongoing','completed') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'pending' COMMENT '课程状态: pending-待开始, upcoming-即将开始, ongoing-进行中, completed-已结束', -`auto_schedule` tinyint(1) DEFAULT NULL COMMENT '是否自动排课1是0否', -`created_by` enum('manual','system') COLLATE utf8mb4_general_ci NOT NULL COMMENT '课程安排创建方式: manual-人员安排, system-系统创建', -`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', -`deleted_at` int DEFAULT '0' COMMENT '逻辑删除时间', -`assistant_ids` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '助教ID列表(逗号分隔)', -`education_id` int DEFAULT NULL COMMENT '教务ID', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=120 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='课程安排表'; -这个表是在学校层面针对教室的情况做的课程安排情况表。这个表和课程表是一对多的关系,一个课程可以有多个课程安排。而且支持一次配置后自动排课的功能。这个表的主要作用是记录课程安排的情况,包括上课日期,时间段,教练,参与人员等信息。 - -school_person_course_schedule(人员与课程安排关系表) -CREATE TABLE `school_person_course_schedule` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '关系编号', -`resources_id` int DEFAULT NULL COMMENT '资源ID', -`person_id` int DEFAULT NULL COMMENT '人员ID', -`student_id` int DEFAULT NULL COMMENT '学员ID', -`person_type` enum('student','customer_resource') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '人员类型: student-正式学员, customer_resource-客户资源,teacher教练', -`schedule_id` int NOT NULL COMMENT '课程安排ID', -`course_date` date NOT NULL COMMENT '上课日期', -`schedule_type` tinyint(1) DEFAULT NULL COMMENT '课程安排类型1临时课2固定课', -`course_type` tinyint(1) DEFAULT NULL COMMENT '课程类型1加课2补课3 等待位', -`time_slot` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '上课时段', -`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -`deleted_at` int DEFAULT '0' COMMENT '删除', -`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态0待上课1已上课2请假', -`remark` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '请假备注', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='人员与课程安排关系表'; -这个表记录着学员和school_course_schedule中安排的关系。这里面有几种情况 1.正式的付费学员上课(临时的)2.临时的体验学员上课 3.正式的付费学员固定这个时段上课的。 -然后这个课程安排的属性还有是正常消耗课时的,还是补课、还是送课。还是这个教室没有位置单纯是等待的课程。 -school_student_courses(学员课程表) -CREATE TABLE `school_student_courses` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '记录编号', -`student_id` int NOT NULL COMMENT '学员ID', -`course_id` int NOT NULL COMMENT '课程ID', -`total_hours` int NOT NULL COMMENT '总正式课时数', -`gift_hours` int DEFAULT '0' COMMENT '赠送课时数', -`start_date` date NOT NULL COMMENT '课程开始日期', -`end_date` date NOT NULL COMMENT '课程结束日期', -`use_total_hours` int NOT NULL DEFAULT '0' COMMENT '已使用课包课时数', -`use_gift_hours` int NOT NULL DEFAULT '0' COMMENT '已使用课包赠送课时数', -`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', -`single_session_count` int DEFAULT NULL COMMENT '单次消课数量', -`status` tinyint(1) DEFAULT NULL COMMENT '课程状态1有效2过期3等待期4延期', -`resource_id` int DEFAULT NULL COMMENT '资源ID', -`main_coach_id` int DEFAULT NULL COMMENT '主教练ID', -`assistant_ids` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '助教ID列表(逗号分隔)', -`education_id` int DEFAULT NULL COMMENT '教务ID', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='学员课程表'; -这个是一个学员在一个课程周期里可以上课的课时记录以及课时有效期记录,在这个周期范围内为这个学员服务的教练和助教信息。这个表的主要作用是记录学员的课程信息,包括总课时数,赠送课时数,开始和结束日期等信息。这个表和人员与课程安排关系表是一对多的关系,一个学员可以有多个课程安排。 - -school_student_course_usage(学员课程使用记录表) -CREATE TABLE `school_student_course_usage` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '记录编号', -`student_course_id` int NOT NULL COMMENT '学员课程ID(关联到student_courses表)', -`used_hours` int NOT NULL COMMENT '本次使用的课时数', -`usage_date` date NOT NULL COMMENT '课时使用日期', -`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='学员课时消费记录表'; -这个表记录了学员在某个课程周期内使用的课时数,这个表和学员课程表是一对多的关系,一个学员可以有多个课时使用记录。 -school_class(班级表) -CREATE TABLE `school_class` ( -`id` int NOT NULL AUTO_INCREMENT COMMENT '班级编号', -`campus_id` int NOT NULL COMMENT '校区ID', -`campus_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '校区名称', -`class_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '班级名称', -`head_coach` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '班继续 -级主教练', -`age_group` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '班级授课年龄段', -`class_type` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '班级类型', -`assistant_coach` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '班级助教', -`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', -`deleted_at` int DEFAULT '0' COMMENT '逻辑删除时间', -`status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '班级状态(1开启 2关闭)', -`sort_order` int NOT NULL COMMENT '班级排序', -`remarks` text COLLATE utf8mb4_general_ci COMMENT '班级备注', -`educational_id` int NOT NULL DEFAULT '0' COMMENT '教务id', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='班级表'; -学员报名时会分配班级,默认班级里的主教练和助教会被分配到学员课程表里。班级表主要是记录班级的信息,包括班级名称,主教练,助教,授课年龄段等信息。这个表和学员课程表是一对多的关系,一个班级可以有多个学员。 -school_class_resources_rel(班级学员关系表) -CREATE TABLE `school_class_resources_rel` ( -`id` int NOT NULL AUTO_INCREMENT, -`class_id` int NOT NULL COMMENT '班级id', -`resource_id` int DEFAULT NULL COMMENT '资源id', -`campus_id` int DEFAULT NULL COMMENT '校区id', -`source_id` int DEFAULT NULL COMMENT '数据id', -`source_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '数据资源类型student是学员,temporary是非正式学员', -`join_time` int DEFAULT NULL COMMENT '加入时间', -`out_time` int DEFAULT NULL COMMENT '离开时间', -`status` tinyint DEFAULT NULL COMMENT '状态1新入2续费3过期4转班5转校', -`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='班级和资源关系表'; -这个表记录了班级和资源的关系,包括班级id,资源id,校区id,数据id,数据资源类型,加入时间,离开时间,状态等信息。这个表和班级表是一对多的关系,一个班级可以有多个资源。 \ No newline at end of file diff --git a/uniapp/README.md b/uniapp/README.md deleted file mode 100644 index 902a5651..00000000 --- a/uniapp/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ZhiHuiJiaoWu_UniApp - -智慧教务系统UniApp前端项目 \ No newline at end of file diff --git a/uniapp/api/apiRoute.js b/uniapp/api/apiRoute.js index 522dda8a..c28bbb46 100644 --- a/uniapp/api/apiRoute.js +++ b/uniapp/api/apiRoute.js @@ -373,6 +373,10 @@ export default { async courseInfo(data = {}) { return await http.get('/course/courseInfo', data); }, + //获取课程安排详情(新接口) + async getScheduleDetail(data = {}) { + return await http.get('/course/scheduleDetail', data); + }, //教研管理文章列表 async teachingResearchList(data = {}) { return await http.get('/teachingResearch/list', data); @@ -411,6 +415,16 @@ export default { async xs_getAllCustomerResources(data = {}) { return await http.get('/customerResources/getAll', data); }, + + //客户资源全部列表(用于学员搜索) + async getCustomerResourcesAll(data = {}) { + return await http.get('/customerResources/getAll', data); + }, + + //获取客户资源详情 + async getCustomerResourcesInfo(data = {}) { + return await http.get('/resourceSharing/info', data); + }, //销售端-客户资源-获取修改日志列表 async xs_customerResourcesGetEditLogList(data = {}) { return await http.get('/customerResources/getEditLogList', data); @@ -513,6 +527,11 @@ export default { async parent_getChildServices(data = {}) { return await http.get('/parent/child/services', data); }, + + // 获取学员服务记录列表 + async getStudentServiceList(data = {}) { + return await http.get('/xy/service/list', data); + }, // 获取指定孩子的消息记录 async parent_getChildMessages(data = {}) { return await http.get('/parent/child/messages', data); diff --git a/uniapp/components/order-list-card/index.vue b/uniapp/components/order-list-card/index.vue index d1c4c7a7..f2523b6a 100644 --- a/uniapp/components/order-list-card/index.vue +++ b/uniapp/components/order-list-card/index.vue @@ -20,9 +20,10 @@ @@ -31,8 +32,8 @@ {{ formatTime(order.create_time) }} - - {{ getStatusText(order.status) }} + + {{ getStatusText(order && order.status) }} @@ -77,15 +78,10 @@ 课时数量: {{ order.course_count }}节 - - - 有效期: - {{ order.valid_period }} - - + 备注: {{ order.remark }} @@ -129,6 +125,13 @@ export default { // 订单点击处理(根据状态决定是查看详情还是支付) handleOrderClick(order) { + console.log('点击订单:', order) + // 防护检查:确保order对象存在 + if (!order) { + console.warn('订单数据不存在,无法处理点击事件') + return + } + if (order.status === 'pending') { // 未支付订单,触发支付 this.$emit('pay-order', order) @@ -140,6 +143,8 @@ export default { // 获取状态样式类 getStatusClass(status) { + if (!status) return 'status-default' + const statusMap = { 'pending': 'status-pending', 'paid': 'status-paid', @@ -153,6 +158,8 @@ export default { // 获取状态文本 getStatusText(status) { + if (!status) return '未知状态' + const statusMap = { 'pending': '待支付', 'paid': '已支付', @@ -206,7 +213,6 @@ export default { background: rgba(255, 193, 7, 0.05); &::after { - content: '点击支付'; position: absolute; bottom: 16rpx; right: 16rpx; diff --git a/uniapp/components/service-list-card/index.vue b/uniapp/components/service-list-card/index.vue index d9b3176d..508d2063 100644 --- a/uniapp/components/service-list-card/index.vue +++ b/uniapp/components/service-list-card/index.vue @@ -1,11 +1,24 @@