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.
228 lines
7.4 KiB
228 lines
7.4 KiB
|
2 weeks ago
|
<?php
|
||
|
|
|
||
|
|
namespace App\Http\Controllers\Miniapp;
|
||
|
|
|
||
|
|
use App\Http\Controllers\Miniapp\BaseController;
|
||
|
|
use App\Models\Course;
|
||
|
|
use App\Models\CourseSignup;
|
||
|
|
use App\Models\MiniappUser;
|
||
|
|
use App\Support\ApiResponse;
|
||
|
|
use App\Support\Miniapp\MiniappPresenter;
|
||
|
|
use Illuminate\Http\JsonResponse;
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
|
||
|
|
class CourseController extends BaseController
|
||
|
|
{
|
||
|
|
use ApiResponse;
|
||
|
|
|
||
|
|
public function index(Request $request): JsonResponse
|
||
|
|
{
|
||
|
|
$user = $this->optionalUser($request);
|
||
|
|
$query = $this->publishedQuery($request);
|
||
|
|
|
||
|
|
$paginator = $query
|
||
|
|
->orderByDesc('teach_start_date')
|
||
|
|
->orderByDesc('id')
|
||
|
|
->paginate((int) $request->query('page_size', 20))
|
||
|
|
->withQueryString();
|
||
|
|
|
||
|
|
$paginator->getCollection()->transform(
|
||
|
|
fn (Course $course) => MiniappPresenter::serializeCourseList($course, $user)
|
||
|
|
);
|
||
|
|
|
||
|
|
return $this->paginated($paginator);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function hot(): JsonResponse
|
||
|
|
{
|
||
|
|
$items = Course::query()
|
||
|
|
->with(['courseSystemItem', 'coverMedia', 'promoMedia'])
|
||
|
|
->withCount('signups')
|
||
|
|
->where('published', 1)
|
||
|
|
->whereIn('progress_status', [1, 2])
|
||
|
|
->orderByDesc('signups_count')
|
||
|
|
->orderByDesc('id')
|
||
|
|
->limit(3)
|
||
|
|
->get()
|
||
|
|
->map(fn (Course $course) => MiniappPresenter::serializeCourseList($course))
|
||
|
|
->values()
|
||
|
|
->all();
|
||
|
|
|
||
|
|
return $this->ok(['items' => $items]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function latest(): JsonResponse
|
||
|
|
{
|
||
|
|
$items = Course::query()
|
||
|
|
->with(['courseSystemItem', 'coverMedia', 'promoMedia'])
|
||
|
|
->withCount('signups')
|
||
|
|
->where('published', 1)
|
||
|
|
->orderByRaw('teach_start_date IS NULL')
|
||
|
|
->orderByDesc('teach_start_date')
|
||
|
|
->orderByDesc('id')
|
||
|
|
->limit(3)
|
||
|
|
->get()
|
||
|
|
->map(fn (Course $course) => MiniappPresenter::serializeCourseList($course))
|
||
|
|
->values()
|
||
|
|
->all();
|
||
|
|
|
||
|
|
return $this->ok(['items' => $items]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function show(Request $request, int $course): JsonResponse
|
||
|
|
{
|
||
|
|
$user = $this->optionalUser($request);
|
||
|
|
$model = Course::query()
|
||
|
|
->with(['courseSystemItem', 'coverMedia', 'promoMedia'])
|
||
|
|
->withCount('signups')
|
||
|
|
->where('published', 1)
|
||
|
|
->findOrFail($course);
|
||
|
|
|
||
|
|
return $this->ok(MiniappPresenter::serializeCourseList($model, $user));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function signup(Request $request, int $course): JsonResponse
|
||
|
|
{
|
||
|
|
/** @var MiniappUser $user */
|
||
|
|
$user = $request->user();
|
||
|
|
$model = Course::query()->withCount('signups')->where('published', 1)->findOrFail($course);
|
||
|
|
|
||
|
|
if (CourseSignup::query()->where('course_id', $course)->where('miniapp_user_id', $user->id)->exists()) {
|
||
|
|
return $this->fail('您已报名该课程', 422);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! MiniappPresenter::canSignupCourse($model, (int) $model->signups_count)) {
|
||
|
|
return $this->fail('当前不可报名', 422);
|
||
|
|
}
|
||
|
|
|
||
|
|
$data = $request->validate([
|
||
|
|
'name' => ['required', 'string', 'max:64'],
|
||
|
|
'mobile' => ['required', 'string', 'max:32'],
|
||
|
|
'company' => ['nullable', 'string', 'max:128'],
|
||
|
|
]);
|
||
|
|
|
||
|
|
CourseSignup::query()->create([
|
||
|
|
'course_id' => $course,
|
||
|
|
'miniapp_user_id' => $user->id,
|
||
|
|
'name' => $data['name'],
|
||
|
|
'mobile' => $data['mobile'],
|
||
|
|
'company' => $data['company'] ?? null,
|
||
|
|
'signed_up_at' => now(),
|
||
|
|
'status' => 1,
|
||
|
|
]);
|
||
|
|
|
||
|
|
if (! $user->name) {
|
||
|
|
$user->name = $data['name'];
|
||
|
|
}
|
||
|
|
if (! $user->mobile) {
|
||
|
|
$user->mobile = $data['mobile'];
|
||
|
|
}
|
||
|
|
if (! $user->company && ! empty($data['company'])) {
|
||
|
|
$user->company = $data['company'];
|
||
|
|
}
|
||
|
|
$user->save();
|
||
|
|
|
||
|
|
return $this->ok(null, '报名成功');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function mySignups(Request $request): JsonResponse
|
||
|
|
{
|
||
|
|
/** @var MiniappUser $user */
|
||
|
|
$user = $request->user();
|
||
|
|
|
||
|
|
$courseIds = CourseSignup::query()
|
||
|
|
->where('miniapp_user_id', $user->id)
|
||
|
|
->pluck('course_id');
|
||
|
|
|
||
|
|
$items = Course::query()
|
||
|
|
->with(['courseSystemItem', 'coverMedia', 'promoMedia'])
|
||
|
|
->withCount('signups')
|
||
|
|
->whereIn('id', $courseIds)
|
||
|
|
->orderByDesc('teach_start_date')
|
||
|
|
->orderByDesc('id')
|
||
|
|
->get()
|
||
|
|
->map(fn (Course $course) => MiniappPresenter::serializeCourseList($course, $user))
|
||
|
|
->values()
|
||
|
|
->all();
|
||
|
|
|
||
|
|
return $this->ok(['items' => $items]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function calendar(Request $request): JsonResponse
|
||
|
|
{
|
||
|
|
/** @var MiniappUser $user */
|
||
|
|
$user = $request->user();
|
||
|
|
$data = $request->validate([
|
||
|
|
'month' => ['required', 'date_format:Y-m'],
|
||
|
|
]);
|
||
|
|
|
||
|
|
$courseIds = CourseSignup::query()
|
||
|
|
->where('miniapp_user_id', $user->id)
|
||
|
|
->pluck('course_id');
|
||
|
|
|
||
|
|
$courses = Course::query()
|
||
|
|
->with(['courseSystemItem'])
|
||
|
|
->withCount('signups')
|
||
|
|
->whereIn('id', $courseIds)
|
||
|
|
->get();
|
||
|
|
|
||
|
|
[$year, $month] = array_map('intval', explode('-', $data['month']));
|
||
|
|
$monthStart = sprintf('%04d-%02d-01', $year, $month);
|
||
|
|
$monthEnd = date('Y-m-t', strtotime($monthStart));
|
||
|
|
|
||
|
|
$events = $courses->map(function (Course $course) {
|
||
|
|
return [
|
||
|
|
'id' => $course->id,
|
||
|
|
'title' => $course->title,
|
||
|
|
'start_date' => $course->teach_start_date?->toDateString(),
|
||
|
|
'end_date' => $course->teach_end_date?->toDateString(),
|
||
|
|
'time_range' => MiniappPresenter::timeRange(
|
||
|
|
MiniappPresenter::formatTimeValue($course->teach_start_time),
|
||
|
|
MiniappPresenter::formatTimeValue($course->teach_end_time)
|
||
|
|
),
|
||
|
|
'location' => $course->location,
|
||
|
|
'progress_status' => (int) $course->progress_status,
|
||
|
|
'progress_status_label' => MiniappPresenter::progressStatusLabel((int) $course->progress_status),
|
||
|
|
];
|
||
|
|
})->filter(function (array $event) use ($monthStart, $monthEnd) {
|
||
|
|
if (! $event['start_date']) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
$start = $event['start_date'];
|
||
|
|
$end = $event['end_date'] ?: $start;
|
||
|
|
|
||
|
|
return $start <= $monthEnd && $end >= $monthStart;
|
||
|
|
})->values();
|
||
|
|
|
||
|
|
return $this->ok([
|
||
|
|
'month' => $data['month'],
|
||
|
|
'events' => $events,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function publishedQuery(Request $request)
|
||
|
|
{
|
||
|
|
$query = Course::query()
|
||
|
|
->with(['courseSystemItem', 'coverMedia', 'promoMedia'])
|
||
|
|
->withCount('signups')
|
||
|
|
->where('published', 1);
|
||
|
|
|
||
|
|
if ($kw = $request->query('keyword')) {
|
||
|
|
$query->where(function ($q) use ($kw) {
|
||
|
|
$q->where('title', 'like', "%{$kw}%")
|
||
|
|
->orWhere('location', 'like', "%{$kw}%");
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($request->filled('course_system_dict_item_id')) {
|
||
|
|
$query->where('course_system_dict_item_id', (int) $request->query('course_system_dict_item_id'));
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($request->filled('progress_status')) {
|
||
|
|
$query->where('progress_status', (int) $request->query('progress_status'));
|
||
|
|
}
|
||
|
|
|
||
|
|
return $query;
|
||
|
|
}
|
||
|
|
}
|