From 26d68ac7305a600feda7fef268ec97bbe9547838 Mon Sep 17 00:00:00 2001 From: lion <120344285@qq.com> Date: Wed, 29 Jul 2026 17:12:12 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=BE=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Admin/CourseController.php | 22 ++- app/Models/Course.php | 145 ++++++++++-------- 2 files changed, 102 insertions(+), 65 deletions(-) diff --git a/app/Http/Controllers/Admin/CourseController.php b/app/Http/Controllers/Admin/CourseController.php index cc2bb78..c3b27eb 100755 --- a/app/Http/Controllers/Admin/CourseController.php +++ b/app/Http/Controllers/Admin/CourseController.php @@ -306,17 +306,29 @@ class CourseController extends BaseController $model->fill($all); $model->save(); DB::commit(); - // 更改状态 + } catch (\Exception $exception) { + DB::rollBack(); + return $this->fail([$exception->getCode(), $exception->getMessage()]); + } + + // 提交后再更新状态;微信小程序码失败不应影响保存成功 + try { $model = Course::updateSignStatus($model->id); $model = Course::updateStatus($model->id); if ($model->status == 1 && $model->start_date) { CourseAppointmentTotal::addByCourse($model->id); } - return $this->success($model); - } catch (\Exception $exception) { - DB::rollBack(); - return $this->fail([$exception->getCode(), $exception->getMessage()]); + } catch (\Throwable $e) { + \Log::warning('course save post-process failed', [ + 'course_id' => $model->id ?? null, + 'message' => $e->getMessage(), + ]); } + + $model = Course::find($model->id); + // 保存接口不强制生成小程序码,避免 Failed to cache access token 误报为保存失败 + $model->setAppends(array_values(array_diff($model->getAppends(), ['qrcode']))); + return $this->success($model); } /** diff --git a/app/Models/Course.php b/app/Models/Course.php index f93e62d..9b586c2 100755 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -5,7 +5,9 @@ namespace App\Models; use EasyWeChat\Factory; +use EasyWeChat\Kernel\Http\StreamResponse; use Illuminate\Filesystem\Filesystem; +use Illuminate\Support\Facades\Log; class Course extends SoftDeletesModel { @@ -30,59 +32,70 @@ class Course extends SoftDeletesModel public function getStatusTextAttribute() { $array = [0 => '待发布', 1 => '已发布']; - return $array[$this->attributes['status']]; + return $array[$this->attributes['status'] ?? 0] ?? ''; } public function getIsFeeTextAttribute() { $array = [0 => '免费', 1 => '收费']; - return $array[$this->attributes['is_fee']]; + return $array[$this->attributes['is_fee'] ?? 0] ?? ''; } public function getIsArrangeTextAttribute() { $array = [0 => '否', 1 => '是']; - return $array[$this->attributes['is_arrange']]; + return $array[$this->attributes['is_arrange'] ?? 0] ?? ''; } public function getShowTxlTextAttribute() { $array = [0 => '否', 1 => '是']; - return $array[$this->attributes['show_txl']]; + return $array[$this->attributes['show_txl'] ?? 0] ?? ''; } public function getShowMobileTextAttribute() { $array = [0 => '否', 1 => '是']; - return $array[$this->attributes['show_mobile']]; + return $array[$this->attributes['show_mobile'] ?? 0] ?? ''; } public function getAutoSchoolmateTextAttribute() { $array = [0 => '否', 1 => '是']; - return $array[$this->attributes['auto_schoolmate']]; + return $array[$this->attributes['auto_schoolmate'] ?? 0] ?? ''; } public function getFreeEnterSchoolmateTextAttribute() { $array = [0 => '否', 1 => '是']; - return $array[$this->attributes['free_enter_schoolmate'] ?? 0]; + return $array[$this->attributes['free_enter_schoolmate'] ?? 0] ?? ''; } public function getIsVirtualTextAttribute() { $array = [0 => '否', 1 => '是']; - return $array[$this->attributes['is_virtual']]; + return $array[$this->attributes['is_virtual'] ?? 0] ?? ''; } public function getQrcodeAttribute($value) { - return $this->getCourseQrcode($this->attributes['id']); + try { + return $this->getCourseQrcode($this->attributes['id']); + } catch (\Throwable $e) { + Log::warning('course qrcode append failed', [ + 'course_id' => $this->attributes['id'] ?? null, + 'message' => $e->getMessage(), + ]); + return ''; + } } public function getTeacherDetailAttribute($value) { + if (empty($this->teacher_id)) { + return collect(); + } $teacherIds = explode(',', $this->teacher_id); return Teacher::whereIn('id', $teacherIds)->get(); } @@ -228,25 +241,14 @@ class Course extends SoftDeletesModel public function getCourseQrcode($courseId) { $course = Course::find($courseId); - $path = config('filesystems.disks.public.root') . '/course_qrcode/' . $course->id . '.png'; - $url = config('filesystems.disks.public.url') . '/course_qrcode/' . $course->id . '.png'; - $fileSys = new Filesystem(); - if ($fileSys->exists($path)) { - return $url; + if (empty($course)) { + return ''; } - $config = [ - 'app_id' => \config('app.applet_appid'), - 'secret' => \config('app.applet_secret') - ]; - $app = Factory::miniProgram($config); - $tmp = $app->app_code->get('packages/course/detail?' . 'id=' . $courseId, [ - 'env_version' => "release" // 正式版 - // 'env_version' => "trial" // 体验版 - ]); - $dir = dirname($path); - $fileSys->ensureDirectoryExists($dir, 0755, true); - $fileSys->put($path, $tmp); - return $url; + return $this->resolveMiniProgramQrcode( + 'course_qrcode/' . $course->id . '.png', + 'packages/course/detail?id=' . $courseId, + ['course_id' => $courseId] + ); } /** @@ -255,24 +257,14 @@ class Course extends SoftDeletesModel public function getCourseCheckQrcode($courseId) { $course = Course::find($courseId); - $path = config('filesystems.disks.public.root') . '/course_check_qrcode/' . $course->id . '.png'; - $url = config('filesystems.disks.public.url') . '/course_check_qrcode/' . $course->id . '.png'; - $fileSys = new Filesystem(); - if ($fileSys->exists($path)) { - return $url; + if (empty($course)) { + return ''; } - $config = [ - 'app_id' => \config('app.applet_appid'), - 'secret' => \config('app.applet_secret') - ]; - $app = Factory::miniProgram($config); - $tmp = $app->app_code->get('packages/sign/course?course_id=' . $courseId, [ - 'env_version' => "release" // 正式版 - ]); - $dir = dirname($path); - $fileSys->ensureDirectoryExists($dir, 0755, true); - $fileSys->put($path, $tmp); - return $url; + return $this->resolveMiniProgramQrcode( + 'course_check_qrcode/' . $course->id . '.png', + 'packages/sign/course?course_id=' . $courseId, + ['course_id' => $courseId] + ); } /** @@ -281,26 +273,59 @@ class Course extends SoftDeletesModel public function getEvaluationQrcode($id) { $courseContentEvaluation = CourseContentEvaluation::find($id); - $path = config('filesystems.disks.public.root') . '/course_evaluation_qrcode/' . $courseContentEvaluation->id . '.png'; - $url = config('filesystems.disks.public.url') . '/course_evaluation_qrcode/' . $courseContentEvaluation->id . '.png'; + if (empty($courseContentEvaluation)) { + return ''; + } + return $this->resolveMiniProgramQrcode( + 'course_evaluation_qrcode/' . $courseContentEvaluation->id . '.png', + 'packages/surveyFill/index?id=' . $id, + ['evaluation_id' => $id] + ); + } + + /** + * 读取或生成小程序码;微信/缓存失败时返回空字符串,避免列表接口 500 + */ + protected function resolveMiniProgramQrcode(string $relativePath, string $page, array $context = []): string + { + $path = config('filesystems.disks.public.root') . '/' . $relativePath; + $url = config('filesystems.disks.public.url') . '/' . $relativePath; $fileSys = new Filesystem(); if ($fileSys->exists($path)) { return $url; } - $config = [ - 'app_id' => \config('app.applet_appid'), - 'secret' => \config('app.applet_secret') - ]; - $app = Factory::miniProgram($config); - $tmp = $app->app_code->get('packages/surveyFill/index?id=' . $id, [ - // todo:: 版本切换 - 'env_version' => "release" // 正式版 - // 'env_version' => "trial" // 体验版 - ]); - $dir = dirname($path); - $fileSys->ensureDirectoryExists($dir, 0755, true); - $fileSys->put($path, $tmp); - return $url; + + $appId = (string) config('app.applet_appid'); + $secret = (string) config('app.applet_secret'); + if ($appId === '' || $secret === '') { + Log::warning('mini program qrcode skipped: missing appid/secret', $context); + return ''; + } + + try { + $app = Factory::miniProgram([ + 'app_id' => $appId, + 'secret' => $secret, + ]); + $tmp = $app->app_code->get($page, [ + 'env_version' => 'release', + ]); + $content = $tmp instanceof StreamResponse ? $tmp->getBodyContents() : (string) $tmp; + if ($content === '' || str_starts_with(ltrim($content), '{')) { + Log::warning('mini program qrcode invalid response', $context + [ + 'body' => substr($content, 0, 300), + ]); + return ''; + } + $fileSys->ensureDirectoryExists(dirname($path), 0755, true); + $fileSys->put($path, $content); + return $url; + } catch (\Throwable $e) { + Log::warning('mini program qrcode failed', $context + [ + 'message' => $e->getMessage(), + ]); + return ''; + } } /**