You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
9.8 KiB

1 year ago
<?php
namespace App\Models;
use EasyWeChat\Factory;
1 day ago
use EasyWeChat\Kernel\Http\StreamResponse;
1 year ago
use Illuminate\Filesystem\Filesystem;
1 day ago
use Illuminate\Support\Facades\Log;
1 year ago
class Course extends SoftDeletesModel
{
11 months ago
protected $appends = [
7 months ago
'date_status',
'publicize',
'sign_date_status',
1 day ago
// qrcode 不自动 append列表/关联序列化时会调微信,易导致接口 500
7 months ago
'teacher_detail',
'status_text',
'is_fee_text',
'is_arrange_text',
'show_txl_text',
'show_mobile_text',
'auto_schoolmate_text',
4 months ago
'free_enter_schoolmate_text',
7 months ago
'is_virtual_text'
11 months ago
];
1 year ago
protected $casts = ['publicize_ids' => 'json'];
11 months ago
public function getStatusTextAttribute()
{
$array = [0 => '待发布', 1 => '已发布'];
1 day ago
return $array[$this->attributes['status'] ?? 0] ?? '';
11 months ago
}
public function getIsFeeTextAttribute()
{
$array = [0 => '免费', 1 => '收费'];
1 day ago
return $array[$this->attributes['is_fee'] ?? 0] ?? '';
11 months ago
}
public function getIsArrangeTextAttribute()
{
$array = [0 => '否', 1 => '是'];
1 day ago
return $array[$this->attributes['is_arrange'] ?? 0] ?? '';
11 months ago
}
public function getShowTxlTextAttribute()
{
$array = [0 => '否', 1 => '是'];
1 day ago
return $array[$this->attributes['show_txl'] ?? 0] ?? '';
11 months ago
}
public function getShowMobileTextAttribute()
{
$array = [0 => '否', 1 => '是'];
1 day ago
return $array[$this->attributes['show_mobile'] ?? 0] ?? '';
11 months ago
}
public function getAutoSchoolmateTextAttribute()
{
$array = [0 => '否', 1 => '是'];
1 day ago
return $array[$this->attributes['auto_schoolmate'] ?? 0] ?? '';
11 months ago
}
11 months ago
4 months ago
public function getFreeEnterSchoolmateTextAttribute()
{
$array = [0 => '否', 1 => '是'];
1 day ago
return $array[$this->attributes['free_enter_schoolmate'] ?? 0] ?? '';
4 months ago
}
11 months ago
public function getIsVirtualTextAttribute()
{
$array = [0 => '否', 1 => '是'];
1 day ago
return $array[$this->attributes['is_virtual'] ?? 0] ?? '';
11 months ago
}
11 months ago
1 year ago
public function getQrcodeAttribute($value)
{
1 day ago
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 '';
}
1 year ago
}
public function getTeacherDetailAttribute($value)
{
1 day ago
if (empty($this->teacher_id)) {
return collect();
}
1 year ago
$teacherIds = explode(',', $this->teacher_id);
return Teacher::whereIn('id', $teacherIds)->get();
}
public function getPublicizeAttribute($value)
{
7 months ago
if (empty($this->publicize_ids))
return [];
1 year ago
return Upload::whereIn('id', $this->publicize_ids)->get();
}
public function getDateStatusAttribute()
{
$text = '课程未开始';
if ($this->course_status == 10) {
$text = '课程进行中';
}
if ($this->course_status == 40) {
$text = '课程已结束';
}
return $text;
}
public function getSignDateStatusAttribute()
{
$text = '未开始';
if ($this->sign_status == 10) {
$text = '进行中';
}
if ($this->sign_status == 40) {
$text = '已结束';
}
return $text;
}
public function typeDetail()
{
return $this->hasOne(CourseType::class, 'id', 'type');
}
public function courseForms()
{
return $this->hasMany(CourseForm::class, 'course_id', 'id');
}
public function teacher()
{
return $this->hasOne(Teacher::class, 'id', 'teacher_id');
}
public function courseSettings()
{
return $this->hasMany(CourseSetting::class, 'course_id', 'id');
}
public function coursePeriods()
{
return $this->hasMany(CoursePeriod::class, 'course_id', 'id');
}
public function courseSigns()
{
return $this->hasMany(CourseSign::class, 'course_id', 'id');
}
public function image()
{
return $this->hasOne(Upload::class, 'id', 'image_id');
}
public function qunImage()
{
return $this->hasOne(Upload::class, 'id', 'qun_image_id');
}
12 months ago
public function courseContents()
{
return $this->hasMany(CourseContent::class, 'course_id', 'id');
}
12 months ago
public function courseContentEvaluation()
{
11 months ago
return $this->hasMany(CourseContentEvaluation::class, 'course_id', 'id');
12 months ago
}
1 year ago
/**
* 更新课程报名状态
*/
public static function updateSignStatus($courseId)
{
// 进行中-未开始-已结束
$now = date('Y-m-d');
$course = Course::find($courseId);
// 默认未开始
$sign_status = 30;
if ($course->sign_start_date && $now < $course->sign_start_date) {
// 未开始
$sign_status = 20;
}
if ($course->sign_start_date && $now >= $course->sign_start_date) {
// 进行中
$sign_status = 10;
}
if ($course->sign_end_date && $now > $course->sign_end_date) {
// 已结束
$sign_status = 40;
}
$course->sign_status = $sign_status;
$course->save();
return $course;
}
/**
* 更新课程状态
*/
public static function updateStatus($courseId)
{
// 进行中-未开始-已结束
$now = date('Y-m-d');
$course = Course::find($courseId);
// 默认待定
$course_status = 30;
if ($course->start_date && $now < $course->start_date) {
// 未开始
$course_status = 20;
}
if ($course->start_date && $now >= $course->start_date) {
// 进行中
$course_status = 10;
}
if ($course->end_date && $now > $course->end_date) {
// 已结束
$course_status = 40;
}
$course->course_status = $course_status;
$course->save();
return $course;
}
/**
* 获取课程详情小程序码
1 day ago
* @param mixed $courseId
* @param bool $generate 是否在文件不存在时尝试生成
1 year ago
*/
1 day ago
public function getCourseQrcode($courseId, $generate = true)
1 year ago
{
$course = Course::find($courseId);
1 day ago
if (empty($course)) {
return '';
1 year ago
}
1 day ago
return $this->resolveMiniProgramQrcode(
'course_qrcode/' . $course->id . '.png',
'packages/course/detail?id=' . $courseId,
1 day ago
['course_id' => $courseId],
$generate
1 day ago
);
1 year ago
}
12 months ago
/**
* 获取课程报名小程序码
*/
1 day ago
public function getCourseCheckQrcode($courseId, $generate = true)
12 months ago
{
$course = Course::find($courseId);
1 day ago
if (empty($course)) {
return '';
12 months ago
}
1 day ago
return $this->resolveMiniProgramQrcode(
'course_check_qrcode/' . $course->id . '.png',
'packages/sign/course?course_id=' . $courseId,
1 day ago
['course_id' => $courseId],
$generate
1 day ago
);
12 months ago
}
11 months ago
/**
* 获取问卷小程序码
*/
1 day ago
public function getEvaluationQrcode($id, $generate = true)
11 months ago
{
11 months ago
$courseContentEvaluation = CourseContentEvaluation::find($id);
1 day ago
if (empty($courseContentEvaluation)) {
return '';
}
return $this->resolveMiniProgramQrcode(
'course_evaluation_qrcode/' . $courseContentEvaluation->id . '.png',
'packages/surveyFill/index?id=' . $id,
1 day ago
['evaluation_id' => $id],
$generate
1 day ago
);
}
/**
* 读取或生成小程序码;微信/缓存失败时返回空字符串,避免列表接口 500
*/
1 day ago
protected function resolveMiniProgramQrcode(string $relativePath, string $page, array $context = [], bool $generate = true): string
1 day ago
{
$path = config('filesystems.disks.public.root') . '/' . $relativePath;
$url = config('filesystems.disks.public.url') . '/' . $relativePath;
11 months ago
$fileSys = new Filesystem();
if ($fileSys->exists($path)) {
return $url;
}
1 day ago
1 day ago
if (!$generate) {
return '';
}
1 day ago
$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 '';
}
11 months ago
}
7 months ago
/**
* 获取课程统计项元数据
* 返回每个统计项的计算逻辑和验证方法说明
7 months ago
* 从 statistics_metadata 表中读取
7 months ago
* @return array
*/
public static function getStatisticsMetadata()
{
7 months ago
return StatisticsMetadata::getAllAsArray();
7 months ago
}
1 year ago
}