diff --git a/app/Console/Commands/PushCourses.php b/app/Console/Commands/PushCourses.php index d998d6c..0e01337 100755 --- a/app/Console/Commands/PushCourses.php +++ b/app/Console/Commands/PushCourses.php @@ -44,9 +44,12 @@ class PushCourses extends Command public function handle() { $today = date('Y-m-d'); - $courses = Course::where('sign_end_date', $today)->whereHas('typeDetail', function ($query) { + $courses = Course::whereHas('typeDetail', function ($query) { $query->where('is_push', 1); - })->get(); + }) + ->where('sign_end_date', $today) + ->where('is_push', 1) + ->get(); if ($courses->isEmpty()) { $this->info('没有可推送的课程'); return; @@ -55,13 +58,17 @@ class PushCourses extends Command foreach ($courses as $course) { // 所有报名审核成功的用户id $userIds = $course->courseSigns()->where('status', 1)->pluck('user_id'); - $users = User::whereIn('id', $userIds)->whereNotNull('company_id')->get(); + $users = User::whereIn('id', $userIds)->whereHas('company', function ($query) { + $query->whereNotNull('credit_code'); + })->groupBy('company_id')->get(); foreach ($users as $user) { - $result = $YuanheRepository->pushCourses($course, $user); + $result = $YuanheRepository->pushCourses($course, $user, $out); if ($result) { + $user->is_push = 1; + $user->save(); $this->info("推送成功:{$course->name}-{$user->name}"); } else { - $this->info("推送失败:{$course->name}-{$user->name}"); + $this->info("推送失败:{$course->name}-{$user->name}-{$out}"); } } } diff --git a/app/Console/Commands/TestEmailCommand.php b/app/Console/Commands/TestEmailCommand.php new file mode 100644 index 0000000..3be822e --- /dev/null +++ b/app/Console/Commands/TestEmailCommand.php @@ -0,0 +1,59 @@ +info("开始测试邮件发送功能..."); + $this->info("收件人: {$to}"); + $this->info("主题: {$subject}"); + + try { + + // 使用 Laravel 的 Mail 门面发送邮件 + Mail::raw($content, function ($message) use ($to, $subject) { + $message->to($to)->subject($subject); + }); + + $this->info("✅ 邮件发送成功!"); + $this->info("邮件已记录到日志文件中,请检查 storage/logs/laravel.log"); + + return Command::SUCCESS; + + } catch (\Exception $e) { + $this->error("❌ 邮件发送失败!"); + $this->error("错误信息: " . $e->getMessage()); + return Command::FAILURE; + } + } +} diff --git a/app/Console/Commands/UpdateCourseSignDoor.php b/app/Console/Commands/UpdateCourseSignDoor.php new file mode 100755 index 0000000..ef8c938 --- /dev/null +++ b/app/Console/Commands/UpdateCourseSignDoor.php @@ -0,0 +1,64 @@ +whereIn('id', [97, 99]) + ->get(); + foreach ($courses as $course) { + $courseSigns = CourseSign::where('course_id', $course->id)->where('status', 1)->get(); + foreach ($courseSigns as $courseSign) { + dispatch((new SendCourseDoor($courseSign))); + $this->info('更新学员' . $courseSign->user->name . '的门禁权限'); + } + } + return $this->info('更新完成'); + } + + +} diff --git a/app/Http/Controllers/Admin/CalendarsController.php b/app/Http/Controllers/Admin/CalendarsController.php index 777662d..ba5cea1 100644 --- a/app/Http/Controllers/Admin/CalendarsController.php +++ b/app/Http/Controllers/Admin/CalendarsController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Exports\BaseExport; +use App\Exports\CommonExport; use App\Helpers\ResponseCode; use App\Models\AppointmentType; use App\Models\Book; @@ -35,6 +36,9 @@ class CalendarsController extends BaseController * tags={"日历管理"}, * summary="列表", * description="", + * @OA\Parameter(name="is_export", in="query", @OA\Schema(type="string"), required=false, description="是否导出0否1是"), + * @OA\Parameter(name="export_fields", in="query", @OA\Schema(type="string"), required=false, description="需要导出的字段数组"), + * @OA\Parameter(name="file_name", in="query", @OA\Schema(type="string"), required=false, description="导出文件名"), * @OA\Parameter(name="month", in="query", @OA\Schema(type="string"), required=true, description="月份"), * @OA\Response( * response="200", @@ -55,6 +59,10 @@ class CalendarsController extends BaseController return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } $list = Calendar::with('course', 'courseContent')->where('start_time', 'like', $all['month'] . '%')->orderBy('date')->get(); + if (isset($all['is_export']) && $all['is_export'] == 1) { + $list = $list->toArray(); + return Excel::download(new CommonExport($list, $all['export_fields'] ?? ''), ($all['file_name'] ?? '') . date('YmdHis') . '.xlsx'); + } return $this->success($list); } diff --git a/app/Http/Controllers/Admin/CourseSignController.php b/app/Http/Controllers/Admin/CourseSignController.php index b9c5e6c..e686103 100755 --- a/app/Http/Controllers/Admin/CourseSignController.php +++ b/app/Http/Controllers/Admin/CourseSignController.php @@ -7,7 +7,6 @@ use App\Helpers\ResponseCode; use App\Helpers\StarterResponseCode; use App\Jobs\SendCourseCar; use App\Jobs\SendCourseDoor; -use App\Models\AppointmentTotalLog; use App\Models\Course; use App\Models\CourseAppointmentTotal; use App\Models\CourseForm; @@ -451,7 +450,7 @@ class CourseSignController extends BaseController $list[$key]['status'] = 0; $list[$key]['status_name'] = '待审核'; } - $list[$key] = array_merge($list[$key], ['course_id' => $course_id, 'from' => '跟班学员']); + $list[$key] = array_merge($list[$key], ['course_id' => $course_id]); } return $this->success($list); } @@ -731,7 +730,7 @@ class CourseSignController extends BaseController if (empty($model)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '数据不存在']); } - $model = $this->model->witg('course')->find($all['id']); + $model = $this->model->with('course')->find($all['id']); $course = $model->course; // 执行预约 // 执行预约操作 diff --git a/app/Http/Controllers/Admin/OtherController.php b/app/Http/Controllers/Admin/OtherController.php index 7ec00f0..cccfe54 100755 --- a/app/Http/Controllers/Admin/OtherController.php +++ b/app/Http/Controllers/Admin/OtherController.php @@ -303,10 +303,9 @@ class OtherController extends CommonController public function test() { - $model = Appointment::find(293); - // 取消预约 - dispatch((new CancelAppointMeet($model, 'a0f75f36213a48f59ce860e679a77c5b'))); - + $model = new DoorRepository(); + $result = $model->getAllDoorInfo(); + dd(json_encode($result,JSON_UNESCAPED_UNICODE)); } diff --git a/app/Http/Controllers/Admin/TeacherController.php b/app/Http/Controllers/Admin/TeacherController.php index 4a0a8e8..beb6333 100755 --- a/app/Http/Controllers/Admin/TeacherController.php +++ b/app/Http/Controllers/Admin/TeacherController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Exports\BaseExport; +use App\Exports\CommonExport; use App\Helpers\ResponseCode; use App\Models\CustomForm; use App\Models\CustomFormField; @@ -38,6 +39,7 @@ class TeacherController extends BaseController * @OA\Parameter(name="sort_type", in="query", @OA\Schema(type="string"), required=false, description="排序类型"), * @OA\Parameter(name="theme", in="query", @OA\Schema(type="string"), required=false, description="主题"), * @OA\Parameter(name="direction", in="query", @OA\Schema(type="string"), required=false, description="方向"), + * @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=true, description="搜索关键词"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", @@ -108,24 +110,69 @@ class TeacherController extends BaseController } } })->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc'); + // 应用与列表一致的筛选 + if (isset($all['theme']) || isset($all['direction'])) { + $list = $list->whereHas('courseContents', function ($query) use ($all) { + if (isset($all['theme'])) { + $query->where('theme', $all['theme']); + } + if (isset($all['direction'])) { + $query->where('direction', $all['direction']); + } + }); + } + if (isset($all['keyword'])) { + $list = $list->where(function ($query) use ($all) { + $query->whereHas('courseContents', function ($query) use ($all) { + $query->where('direction', 'like', '%' . $all['keyword'] . '%'); + })->orWhere('name', 'like', '%' . $all['keyword'] . '%'); + }); + } if (isset($all['is_export']) && !empty($all['is_export'])) { - $list = $list->get()->toArray(); - $export_fields = $all['export_fields'] ?? []; - // 导出文件名字 - $tableName = $this->model->getTable(); - $filename = (new CustomForm())->getTableComment($tableName); - return Excel::download(new BaseExport($export_fields, $list, $tableName), $filename . date('YmdHis') . '.xlsx'); - } else { - if (isset($all['theme']) || isset($all['direction'])) { - $list = $list->whereHas('courseContents', function ($query) use ($all) { - if (isset($all['theme'])) { - $query->where('theme', $all['theme']); - } - if (isset($all['direction'])) { - $query->where('direction', $all['direction']); + // 导出 + // 取数并展开为“老师 x 课程”的多行 + $teachers = $list->limit(5000)->get(); + $rows = []; + foreach ($teachers as $teacher) { + $hasCourses = $teacher->courseContents && $teacher->courseContents->count() > 0; + if ($hasCourses) { + foreach ($teacher->courseContents as $content) { + $rows[] = [ + 'teacher_name' => $teacher->name ?? '', + 'introduce' => $teacher->introduce ?? '', + 'sex' => $teacher->sex ?? '', + 'mobile' => $teacher->mobile ?? '', + 'course_name' => optional($content->course)->name ?? '', + 'theme' => $content->theme ?? '', + 'direction' => $content->direction ?? '', + ]; } - }); + } else { + // 无课程时也导出一行,课程相关列留空 + $rows[] = [ + 'teacher_name' => $teacher->name ?? '', + 'introduce' => $teacher->introduce ?? '', + 'sex' => $teacher->sex ?? '', + 'mobile' => $teacher->mobile ?? '', + 'course_name' => '', + 'theme' => '', + 'direction' => '', + ]; + } } + // 列映射与顺序 + $exportFields = [ + 'teacher_name' => '授课老师', + 'introduce' => '老师简介', + 'sex' => '性别', + 'mobile' => '联系方式', + 'course_name' => '课程名称', + 'theme' => '课程主题', + 'direction' => '课程方向', + ]; + $fileName = ($all['file_name'] ?? '老师课程_') . date('YmdHis') . '.xlsx'; + return Excel::download(new CommonExport($rows, $exportFields), $fileName); + } else { // 输出 $list = $list->paginate($all['page_size'] ?? 20); } diff --git a/app/Http/Controllers/Mobile/UserController.php b/app/Http/Controllers/Mobile/UserController.php index eb3b85b..f5d37a1 100755 --- a/app/Http/Controllers/Mobile/UserController.php +++ b/app/Http/Controllers/Mobile/UserController.php @@ -16,6 +16,7 @@ use App\Models\CourseSign; use App\Models\RelatedModel; use App\Models\ScoreLog; use App\Models\ThirdAppointmentLog; +use App\Models\Sms; use App\Models\User; use App\Repositories\DoorRepository; use App\Repositories\YuanheRepository; @@ -163,7 +164,7 @@ class UserController extends CommonController */ public function updateUser() { - $all = \request()->all(); + $all = \request()->except(['id','mobile','openid']); $model = User::find($this->getUserId()); if (isset($all['password'])) { // 判断旧密码是否正确 @@ -202,7 +203,8 @@ class UserController extends CommonController ->where('plate', $plate) ->where('plate_status', 1) ->first(); - if ($has) continue; + if ($has) + continue; // 车辆预约 dispatch((new SendAppointCar($appointment, $plate))); } @@ -226,11 +228,15 @@ class UserController extends CommonController public function getUserInfo() { $user = User::with('appointments') - ->withCount(['appointments as pass_appointments' => function ($query) { - $query->whereIn('status', [0, 1]); - }])->with(['courseSigns' => function ($query) { - $query->whereHas('course')->with('course.typeDetail')->where('status', 1)->where('fee_status', 1); - }])->find($this->getUserId()); + ->withCount([ + 'appointments as pass_appointments' => function ($query) { + $query->whereIn('status', [0, 1]); + } + ])->with([ + 'courseSigns' => function ($query) { + $query->whereHas('course')->with('course.typeDetail')->where('status', 1)->where('fee_status', 1); + } + ])->find($this->getUserId()); $doorRepository = new DoorRepository(); $door_appointments = Appointment::where('user_id', $this->getUserId()) @@ -249,7 +255,6 @@ class UserController extends CommonController })->first(); if ($course_signs) { $course_signs->qrcode = $doorRepository->getEmpQrCodeByCourse($course_signs, $out); - $course_signs->qrcode = ''; } // 是否有资格进入校友库 $enter_schoolmate = User::whereHas('courseSigns', function ($query) { @@ -325,6 +330,14 @@ class UserController extends CommonController public function bindMobile() { $all = \request()->all(); + $clientIp = request()->ip(); + + // 检查IP锁定状态 + $lockCheck = Sms::checkIpLock($clientIp, 'bind_mobile'); + if ($lockCheck['locked']) { + return $this->fail([ResponseCode::ERROR_BUSINESS, $lockCheck['message']]); + } + $messages = [ 'mobile.required' => '手机号必填', 'mobile.numeric' => '手机号格式错误', @@ -339,15 +352,29 @@ class UserController extends CommonController if ($validator->fails()) { return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } + $key = 'sms_' . $all['mobile']; $check = Cache::get($key); - if (empty($check)) return $this->fail([ResponseCode::ERROR_BUSINESS, '请先发送验证码']); - if ($check['code'] != $all['code']) return $this->fail([ResponseCode::ERROR_BUSINESS, '验证码错误']); + if (empty($check)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '请先发送验证码']); + } + if ($check['code'] != $all['code']) { + $errorResult = Sms::recordError($clientIp, 'bind_mobile'); + return $this->fail([ResponseCode::ERROR_BUSINESS, $errorResult['message']]); + } + + // 验证码正确,清除错误计数 + Sms::clearError($clientIp, 'bind_mobile'); + + // 删除验证码缓存 + Cache::forget($key); + // 判断手机号是否存在 $hasMobile = User::where('mobile', $all['mobile'])->where('id', '!=', $this->getUserId())->first(); if ($hasMobile) { return $this->fail([ResponseCode::ERROR_BUSINESS, '手机号已存在']); } + $model = User::find($this->getUserId()); if ($all['is_bind']) { $model->mobile = $all['mobile']; @@ -374,6 +401,14 @@ class UserController extends CommonController public function checkMobile() { $all = \request()->all(); + $clientIp = request()->ip(); + + // 检查IP锁定状态 + $lockCheck = Sms::checkIpLock($clientIp, 'check_mobile'); + if ($lockCheck['locked']) { + return $this->fail([ResponseCode::ERROR_BUSINESS, $lockCheck['message']]); + } + $messages = [ 'mobile.required' => '手机号必填', 'mobile.numeric' => '手机号格式错误', @@ -386,10 +421,24 @@ class UserController extends CommonController if ($validator->fails()) { return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } + $key = 'sms_' . $all['mobile']; $check = Cache::get($key); - if (empty($check)) return $this->fail([ResponseCode::ERROR_BUSINESS, '请先发送验证码']); - if ($check['code'] != $all['code']) return $this->fail([ResponseCode::ERROR_BUSINESS, '验证码错误']); + if (empty($check)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '请先发送验证码']); + } + + if ($check['code'] != $all['code']) { + $errorResult = Sms::recordError($clientIp, 'check_mobile'); + return $this->fail([ResponseCode::ERROR_BUSINESS, $errorResult['message']]); + } + + // 验证码正确,清除错误计数 + Sms::clearError($clientIp, 'check_mobile'); + + // 删除验证码缓存 + Cache::forget($key); + // 判断手机号是否存在 $hasMobile = User::where('mobile', $all['mobile'])->first(); if ($hasMobile) { @@ -444,7 +493,7 @@ class UserController extends CommonController if (isset($check) && time() - $check['time'] <= 60) { return $this->fail([ResponseCode::ERROR_BUSINESS, '请勿频繁发送']); } - $code = rand(1000, 9999); + $code = rand(100000, 999999); $smsSign = Config::getValueByKey('sms_sign'); $content = "{$smsSign}您的验证码是:{$code},验证码五分钟内有效,如非本人操作,请忽略。"; $result = ymSms($all['mobile'], $content); @@ -541,6 +590,14 @@ class UserController extends CommonController public function mobileLogin() { $all = \request()->all(); + $clientIp = request()->ip(); + + // 检查IP锁定状态 + $lockCheck = Sms::checkIpLock($clientIp, 'mobile_login'); + if ($lockCheck['locked']) { + return $this->fail([ResponseCode::ERROR_BUSINESS, $lockCheck['message']]); + } + $messages = [ 'code.required' => 'code必填', 'mobile.required' => '手机号必填' @@ -552,10 +609,24 @@ class UserController extends CommonController if ($validator->fails()) { return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } + $key = 'sms_login_' . $all['mobile']; $check = Cache::get($key); - if (empty($check)) return $this->fail([ResponseCode::ERROR_BUSINESS, '请先发送验证码']); - if ($check['code'] != $all['code']) return $this->fail([ResponseCode::ERROR_BUSINESS, '验证码错误']); + if (empty($check)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '请先发送验证码']); + } + + if ($check['code'] != $all['code']) { + $errorResult = Sms::recordError($clientIp, 'mobile_login'); + return $this->fail([ResponseCode::ERROR_BUSINESS, $errorResult['message']]); + } + + // 验证码正确,清除错误计数 + Sms::clearError($clientIp, 'mobile_login'); + + // 删除验证码缓存 + Cache::forget($key); + $user = User::where('mobile', $all['mobile'])->first(); $token = $user->createToken("mobile-token")->plainTextToken; return $this->success(compact('token')); @@ -621,7 +692,7 @@ class UserController extends CommonController if (isset($check) && time() - $check['time'] <= 60) { return $this->fail([ResponseCode::ERROR_BUSINESS, '请勿频繁发送']); } - $code = rand(1000, 9999); + $code = rand(100000, 999999); $smsSign = Config::getValueByKey('sms_sign'); $content = "{$smsSign}您的验证码是:{$code},验证码五分钟内有效,如非本人操作,请忽略。"; $result = ymSms($all['mobile'], $content); diff --git a/app/Jobs/SendCourseDoor.php b/app/Jobs/SendCourseDoor.php index dfe43eb..9beda6c 100755 --- a/app/Jobs/SendCourseDoor.php +++ b/app/Jobs/SendCourseDoor.php @@ -38,8 +38,11 @@ class SendCourseDoor implements ShouldQueue */ public function handle() { - $door = Config::getValueByKey('course_sign_door'); + $doors = Config::getValueByKey('course_sign_door'); + $doors = json_decode($doors, true); $doorRepository = new DoorRepository(); - $doorRepository->generateEmpAuthorSet1ByCourse($this->courseSignsModel, $door, $out); + foreach ($doors as $door) { + $doorRepository->generateEmpAuthorSet1ByCourse($this->courseSignsModel, $door, $out); + } } } diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php index 6abc56e..172b6ba 100755 --- a/app/Models/Calendar.php +++ b/app/Models/Calendar.php @@ -9,6 +9,19 @@ use Illuminate\Support\Facades\Cache; class Calendar extends SoftDeletesModel { + protected $appends = ['is_publish_text','type_text']; + + public function getIsPublishTextAttribute() + { + return $this->attributes['is_publish'] == 1 ? '是' : '否'; + } + + public function getTypeTextAttribute() + { + $array = [1=>'课程', 3=>'自定义事件', 4=>'资讯']; + return $array[$this->attributes['type']] ?? ''; + } + public function course() { return $this->hasOne(Course::class, 'id', 'course_id'); diff --git a/app/Models/Sms.php b/app/Models/Sms.php index 9c42cb9..9e8286c 100755 --- a/app/Models/Sms.php +++ b/app/Models/Sms.php @@ -1,15 +1,76 @@ bool, 'message' => string] + */ + public static function checkIpLock($ip, $type = 'bind_mobile') + { + $ipLockKey = 'sms_ip_lock_' . $type . '_' . $ip; + + if (Cache::has($ipLockKey)) { + $lockTime = Cache::get($ipLockKey); + $remainingTime = $lockTime - time(); + + if ($remainingTime > 0) { + $minutes = ceil($remainingTime / 60); + return [ + 'locked' => true, + 'message' => "访问过于频繁,请{$minutes}分钟后再试" + ]; + } + } - public function belongs() { - return $this->morphTo(); + return ['locked' => false, 'message' => '']; } -} + /** + * 记录验证码错误 + * + * @param string $ip 客户端IP地址 + * @param string $type 方法类型 (bind_mobile/check_mobile) + * @return array ['locked' => bool, 'message' => string] + */ + public static function recordError($ip, $type = 'bind_mobile') + { + $errorKey = 'sms_error_count_' . $type . '_' . $ip; + $ipLockKey = 'sms_ip_lock_' . $type . '_' . $ip; + + $errorCount = Cache::get($errorKey, 0) + 1; + Cache::put($errorKey, $errorCount, 3600); // 1小时过期 + + // 如果错误次数达到10次,锁定IP + if ($errorCount >= 10) { + Cache::put($ipLockKey, time() + 3600, 3600); // 锁定1小时 + Cache::forget($errorKey); // 清除错误计数 + + return [ + 'locked' => true, + 'message' => '验证码错误次数过多,请1小时后再试' + ]; + } + + return ['locked' => false, 'message' => '验证码错误']; + } + + /** + * 清除错误计数 + * + * @param string $ip 客户端IP地址 + * @param string $type 方法类型 (bind_mobile/check_mobile) + */ + public static function clearError($ip, $type = 'bind_mobile') + { + $errorKey = 'sms_error_count_' . $type . '_' . $ip; + Cache::forget($errorKey); + } +} diff --git a/app/Repositories/DoorRepository.php b/app/Repositories/DoorRepository.php index 43d1af0..3709bd5 100755 --- a/app/Repositories/DoorRepository.php +++ b/app/Repositories/DoorRepository.php @@ -286,7 +286,9 @@ class DoorRepository */ public function generateEmpAuthorSet1ByCourse($model, $door, &$out) { - $door = json_decode($door, true); + if (!is_array($door)) { + $door = json_decode($door, true); + } if (!isset($door['doorName'])) { $out = '门禁信息不存在'; return false; @@ -310,7 +312,7 @@ class DoorRepository 'timestamp' => time() ]; // 预约开始时间需大于当前时间两分钟 - if (date('Y-m-d', strtotime($courseModel->start_date)) == date('Y-m-d')) { + if (date('Y-m-d', strtotime($courseModel->start_date)) <= date('Y-m-d')) { $params['startTime'] = date('Y-m-d H:i:s', time() + 200); } $params['sign'] = $this->sign($params); diff --git a/app/Repositories/YuanheRepository.php b/app/Repositories/YuanheRepository.php index 8313255..ade2cb4 100755 --- a/app/Repositories/YuanheRepository.php +++ b/app/Repositories/YuanheRepository.php @@ -83,15 +83,15 @@ class YuanheRepository /** * 数据推送 */ - public function pushCourses(Course $course, User $user) + public function pushCourses(Course $course, User $user,&$out) { if (empty($user->company)) { return false; } $params = [ - 'classTeacher' => $course->teacher->name, + 'classTeacher' => $course->teacher->name??'', 'courseName' => $course->name, - 'description' => $user->company->businessScope, + 'description' => $user->company->businessScope??'', 'enterpriseName' => $user->company->company_name, 'creditCode' => $user->company->credit_code, 'groupId' => '1030004', @@ -106,9 +106,11 @@ class YuanheRepository if ($result['code'] == 200) { return true; } else { + $out = $result['msg']; return false; } } catch (\Exception $e) { + $out = $e->getMessage(); return false; } } diff --git a/database/migrations/2025_10_13_153610_alert_courses_table.php b/database/migrations/2025_10_13_153610_alert_courses_table.php new file mode 100644 index 0000000..5e93acd --- /dev/null +++ b/database/migrations/2025_10_13_153610_alert_courses_table.php @@ -0,0 +1,33 @@ +boolean('is_push')->default(true)->comment('是否推送0否1是'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('courses', function (Blueprint $table) { + // + }); + } +}; diff --git a/database/migrations/2025_10_13_162135_alert_users_table.php b/database/migrations/2025_10_13_162135_alert_users_table.php new file mode 100644 index 0000000..16969a3 --- /dev/null +++ b/database/migrations/2025_10_13_162135_alert_users_table.php @@ -0,0 +1,32 @@ +boolean('is_push')->default(false)->comment('是否推送过0否1是'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + // + }); + } +}; diff --git a/public/admin.zip b/public/admin.zip new file mode 100644 index 0000000..c0da2e1 Binary files /dev/null and b/public/admin.zip differ diff --git a/public/wx-icon/bbg.png b/public/wx-icon/bbg.png new file mode 100755 index 0000000..168860b Binary files /dev/null and b/public/wx-icon/bbg.png differ diff --git a/public/wx-icon/book-top.png b/public/wx-icon/book-top.png index 71ff3e7..8005df6 100755 Binary files a/public/wx-icon/book-top.png and b/public/wx-icon/book-top.png differ diff --git a/public/wx-icon/btips.png b/public/wx-icon/btips.png new file mode 100755 index 0000000..f701593 Binary files /dev/null and b/public/wx-icon/btips.png differ diff --git a/public/wx-icon/course-top1.png b/public/wx-icon/course-top1.png new file mode 100755 index 0000000..ea623a1 Binary files /dev/null and b/public/wx-icon/course-top1.png differ diff --git a/public/wx-icon/hr1.png b/public/wx-icon/hr1.png new file mode 100755 index 0000000..e742337 Binary files /dev/null and b/public/wx-icon/hr1.png differ diff --git a/public/wx-icon/index_icon5.png b/public/wx-icon/index_icon5.png new file mode 100755 index 0000000..96708ce Binary files /dev/null and b/public/wx-icon/index_icon5.png differ diff --git a/public/wx-icon/index_icon6.png b/public/wx-icon/index_icon6.png new file mode 100755 index 0000000..069e8a9 Binary files /dev/null and b/public/wx-icon/index_icon6.png differ diff --git a/public/wx-icon/index_icon7.png b/public/wx-icon/index_icon7.png new file mode 100755 index 0000000..275299a Binary files /dev/null and b/public/wx-icon/index_icon7.png differ diff --git a/public/wx-icon/index_icon8.png b/public/wx-icon/index_icon8.png new file mode 100755 index 0000000..cf58a14 Binary files /dev/null and b/public/wx-icon/index_icon8.png differ diff --git a/public/wx-icon/logo-add.png b/public/wx-icon/logo-add.png new file mode 100755 index 0000000..c59bf3d Binary files /dev/null and b/public/wx-icon/logo-add.png differ diff --git a/public/wx-icon/logo-user.png b/public/wx-icon/logo-user.png new file mode 100755 index 0000000..1cd3053 Binary files /dev/null and b/public/wx-icon/logo-user.png differ diff --git a/public/wx-icon/type1.png b/public/wx-icon/type1.png new file mode 100755 index 0000000..f0a641c Binary files /dev/null and b/public/wx-icon/type1.png differ diff --git a/public/wx-icon/type2.png b/public/wx-icon/type2.png new file mode 100755 index 0000000..4469b47 Binary files /dev/null and b/public/wx-icon/type2.png differ diff --git a/public/wx-icon/type3.png b/public/wx-icon/type3.png new file mode 100755 index 0000000..3a61a9a Binary files /dev/null and b/public/wx-icon/type3.png differ diff --git a/public/wx-icon/type4.png b/public/wx-icon/type4.png new file mode 100755 index 0000000..2a0846b Binary files /dev/null and b/public/wx-icon/type4.png differ diff --git a/public/wx-icon/urlbtn.png b/public/wx-icon/urlbtn.png new file mode 100755 index 0000000..896ed39 Binary files /dev/null and b/public/wx-icon/urlbtn.png differ diff --git a/public/wx-icon/xy1.png b/public/wx-icon/xy1.png new file mode 100755 index 0000000..c5e6898 Binary files /dev/null and b/public/wx-icon/xy1.png differ diff --git a/public/wx-icon/xy2.png b/public/wx-icon/xy2.png new file mode 100755 index 0000000..7ad80a3 Binary files /dev/null and b/public/wx-icon/xy2.png differ diff --git a/public/wx-icon/xy3.png b/public/wx-icon/xy3.png new file mode 100755 index 0000000..40f5dd3 Binary files /dev/null and b/public/wx-icon/xy3.png differ diff --git a/public/wx-icon/xy4.png b/public/wx-icon/xy4.png new file mode 100755 index 0000000..9f2e1f3 Binary files /dev/null and b/public/wx-icon/xy4.png differ diff --git a/public/wx-icon/xy5.png b/public/wx-icon/xy5.png new file mode 100755 index 0000000..c0ddee1 Binary files /dev/null and b/public/wx-icon/xy5.png differ