diff --git a/app/Http/Controllers/Admin/ScheduleOverviewController.php b/app/Http/Controllers/Admin/ScheduleOverviewController.php new file mode 100644 index 0000000..7c84fa4 --- /dev/null +++ b/app/Http/Controllers/Admin/ScheduleOverviewController.php @@ -0,0 +1,395 @@ +systemModel = new ScheduleOverviewSystem(); + $this->courseModel = new ScheduleOverviewCourse(); + $this->scheduleModel = new ScheduleOverviewSchedule(); + } + + public function overview() + { + $year = request('year', date('Y')); + + return $this->success([ + 'systems' => $this->getSystems(), + 'courses' => $this->getCourses(), + 'schedules' => $this->getSchedules($year), + ]); + } + + public function systemIndex() + { + return $this->success($this->getSystems()); + } + + public function systemShow() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'id' => 'required', + ], [ + 'id.required' => '体系ID必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $detail = $this->systemModel->with('courses')->find($all['id']); + if (empty($detail)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '体系不存在']); + } + + return $this->success($detail); + } + + public function systemSave() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'name' => 'required|string|max:255', + 'sort' => 'nullable|integer', + ], [ + 'name.required' => '体系名称必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + if (!empty($all['id'])) { + $model = $this->systemModel->find($all['id']); + if (empty($model)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '体系不存在']); + } + } else { + $model = new ScheduleOverviewSystem(); + $model->admin_id = $this->getUserId(); + $model->department_id = optional($this->getUser())->department_id; + } + + DB::beginTransaction(); + try { + $model->name = $all['name']; + $model->sort = (int) ($all['sort'] ?? 0); + $model->save(); + + DB::commit(); + return $this->success($model); + } catch (\Throwable $throwable) { + DB::rollBack(); + return $this->fail([ResponseCode::ERROR_INSIDE, $throwable->getMessage()]); + } + } + + public function systemDestroy() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'id' => 'required', + ], [ + 'id.required' => '体系ID必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $model = $this->systemModel->find($all['id']); + if (empty($model)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '体系不存在']); + } + + DB::beginTransaction(); + try { + $courseIds = $this->courseModel->where('system_id', $model->id)->pluck('id')->toArray(); + $this->scheduleModel->where('system_id', $model->id)->delete(); + if (!empty($courseIds)) { + $this->scheduleModel->whereIn('course_id', $courseIds)->delete(); + $this->courseModel->whereIn('id', $courseIds)->delete(); + } + $model->delete(); + + DB::commit(); + return $this->success('删除成功'); + } catch (\Throwable $throwable) { + DB::rollBack(); + return $this->fail([ResponseCode::ERROR_INSIDE, $throwable->getMessage()]); + } + } + + public function courseIndex() + { + return $this->success($this->getCourses()); + } + + public function courseShow() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'id' => 'required', + ], [ + 'id.required' => '课程ID必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $detail = $this->courseModel->with('system')->find($all['id']); + if (empty($detail)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '课程不存在']); + } + + return $this->success($detail); + } + + public function courseSave() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'system_id' => 'required|integer', + 'name' => 'required|string|max:255', + 'sort' => 'nullable|integer', + ], [ + 'system_id.required' => '所属体系必填', + 'name.required' => '课程名称必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $system = $this->systemModel->find($all['system_id']); + if (empty($system)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '所属体系不存在']); + } + + if (!empty($all['id'])) { + $model = $this->courseModel->find($all['id']); + if (empty($model)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '课程不存在']); + } + } else { + $model = new ScheduleOverviewCourse(); + $model->admin_id = $this->getUserId(); + $model->department_id = optional($this->getUser())->department_id; + } + + DB::beginTransaction(); + try { + $originSystemId = $model->system_id; + $model->system_id = (int) $all['system_id']; + $model->name = $all['name']; + $model->sort = (int) ($all['sort'] ?? 0); + $model->save(); + + if (!empty($originSystemId) && (int) $originSystemId !== (int) $model->system_id) { + $this->scheduleModel->where('course_id', $model->id)->update([ + 'system_id' => $model->system_id, + ]); + } + + DB::commit(); + return $this->success($model->load('system')); + } catch (\Throwable $throwable) { + DB::rollBack(); + return $this->fail([ResponseCode::ERROR_INSIDE, $throwable->getMessage()]); + } + } + + public function courseDestroy() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'id' => 'required', + ], [ + 'id.required' => '课程ID必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $model = $this->courseModel->find($all['id']); + if (empty($model)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '课程不存在']); + } + + DB::beginTransaction(); + try { + $this->scheduleModel->where('course_id', $model->id)->delete(); + $model->delete(); + + DB::commit(); + return $this->success('删除成功'); + } catch (\Throwable $throwable) { + DB::rollBack(); + return $this->fail([ResponseCode::ERROR_INSIDE, $throwable->getMessage()]); + } + } + + public function scheduleIndex() + { + $year = request('year', date('Y')); + + return $this->success($this->getSchedules($year)); + } + + public function scheduleShow() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'id' => 'required', + ], [ + 'id.required' => '编排ID必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $detail = $this->scheduleModel->with(['system', 'course'])->find($all['id']); + if (empty($detail)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '编排不存在']); + } + + return $this->success($detail); + } + + public function scheduleSave() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'year' => 'required|string|size:4', + 'system_id' => 'required|integer', + 'course_id' => 'required|integer', + 'month' => 'required|integer|min:1|max:12', + 'title' => 'required|string|max:255', + 'owner' => 'required|string|max:255', + 'location' => 'required|string|max:255', + 'count_text' => 'nullable|string|max:255', + ], [ + 'year.required' => '年份必填', + 'system_id.required' => '体系必填', + 'course_id.required' => '课程必填', + 'month.required' => '月份必填', + 'title.required' => '编排标题必填', + 'owner.required' => '负责人必填', + 'location.required' => '地点必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $system = $this->systemModel->find($all['system_id']); + if (empty($system)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '体系不存在']); + } + + $course = $this->courseModel->find($all['course_id']); + if (empty($course)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '课程不存在']); + } + + if ((int) $course->system_id !== (int) $system->id) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '课程不属于当前体系']); + } + + if (!empty($all['id'])) { + $model = $this->scheduleModel->find($all['id']); + if (empty($model)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '编排不存在']); + } + } else { + $model = new ScheduleOverviewSchedule(); + $model->admin_id = $this->getUserId(); + $model->department_id = optional($this->getUser())->department_id; + } + + DB::beginTransaction(); + try { + $model->year = $all['year']; + $model->system_id = (int) $all['system_id']; + $model->course_id = (int) $all['course_id']; + $model->month = (int) $all['month']; + $model->title = $all['title']; + $model->owner = $all['owner']; + $model->location = $all['location']; + $model->count_text = $all['count_text'] ?? ''; + $model->save(); + + DB::commit(); + return $this->success($model->load(['system', 'course'])); + } catch (\Throwable $throwable) { + DB::rollBack(); + return $this->fail([ResponseCode::ERROR_INSIDE, $throwable->getMessage()]); + } + } + + public function scheduleDestroy() + { + $all = request()->all(); + $validator = Validator::make($all, [ + 'id' => 'required', + ], [ + 'id.required' => '编排ID必填', + ]); + + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + + $model = $this->scheduleModel->find($all['id']); + if (empty($model)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '编排不存在']); + } + + $model->delete(); + return $this->success('删除成功'); + } + + protected function getSystems() + { + return $this->systemModel + ->orderBy('sort') + ->orderBy('id') + ->get(); + } + + protected function getCourses() + { + return $this->courseModel + ->with('system') + ->orderBy('sort') + ->orderBy('id') + ->get(); + } + + protected function getSchedules($year) + { + return $this->scheduleModel + ->with(['system', 'course']) + ->where('year', $year) + ->orderBy('month') + ->orderBy('id') + ->get(); + } +} diff --git a/app/Models/ScheduleOverviewCourse.php b/app/Models/ScheduleOverviewCourse.php new file mode 100644 index 0000000..9caf75c --- /dev/null +++ b/app/Models/ScheduleOverviewCourse.php @@ -0,0 +1,18 @@ +belongsTo(ScheduleOverviewSystem::class, 'system_id', 'id'); + } + + public function schedules() + { + return $this->hasMany(ScheduleOverviewSchedule::class, 'course_id', 'id'); + } +} diff --git a/app/Models/ScheduleOverviewSchedule.php b/app/Models/ScheduleOverviewSchedule.php new file mode 100644 index 0000000..32fc00b --- /dev/null +++ b/app/Models/ScheduleOverviewSchedule.php @@ -0,0 +1,18 @@ +belongsTo(ScheduleOverviewSystem::class, 'system_id', 'id'); + } + + public function course() + { + return $this->belongsTo(ScheduleOverviewCourse::class, 'course_id', 'id'); + } +} diff --git a/app/Models/ScheduleOverviewSystem.php b/app/Models/ScheduleOverviewSystem.php new file mode 100644 index 0000000..11e355a --- /dev/null +++ b/app/Models/ScheduleOverviewSystem.php @@ -0,0 +1,18 @@ +hasMany(ScheduleOverviewCourse::class, 'system_id', 'id')->orderBy('sort')->orderBy('id'); + } + + public function schedules() + { + return $this->hasMany(ScheduleOverviewSchedule::class, 'system_id', 'id'); + } +} diff --git a/database/migrations/2026_03_13_160000_create_schedule_overview_tables.php b/database/migrations/2026_03_13_160000_create_schedule_overview_tables.php new file mode 100644 index 0000000..157c9a6 --- /dev/null +++ b/database/migrations/2026_03_13_160000_create_schedule_overview_tables.php @@ -0,0 +1,67 @@ +id(); + $table->string('name')->comment('体系名称'); + $table->integer('sort')->default(0)->comment('排序'); + $table->bigInteger('admin_id')->nullable()->comment('创建管理员'); + $table->bigInteger('department_id')->nullable()->comment('部门ID'); + $table->timestamps(); + $table->softDeletes(); + }); + + Schema::create('schedule_overview_courses', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('system_id')->comment('所属体系ID'); + $table->string('name')->comment('课程名称'); + $table->integer('sort')->default(0)->comment('排序'); + $table->bigInteger('admin_id')->nullable()->comment('创建管理员'); + $table->bigInteger('department_id')->nullable()->comment('部门ID'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('system_id'); + }); + + Schema::create('schedule_overview_schedules', function (Blueprint $table) { + $table->id(); + $table->string('year', 4)->comment('年份'); + $table->unsignedBigInteger('system_id')->comment('体系ID'); + $table->unsignedBigInteger('course_id')->comment('课程ID'); + $table->unsignedTinyInteger('month')->comment('月份'); + $table->string('title')->comment('编排标题'); + $table->string('owner')->comment('负责人'); + $table->string('location')->comment('地点'); + $table->string('count_text')->nullable()->comment('显示说明'); + $table->bigInteger('admin_id')->nullable()->comment('创建管理员'); + $table->bigInteger('department_id')->nullable()->comment('部门ID'); + $table->timestamps(); + $table->softDeletes(); + + $table->index(['year', 'month']); + $table->index('system_id'); + $table->index('course_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('schedule_overview_schedules'); + Schema::dropIfExists('schedule_overview_courses'); + Schema::dropIfExists('schedule_overview_systems'); + } +}; diff --git a/e6c3dd54ed7f22db16bafaf65efac481.png b/e6c3dd54ed7f22db16bafaf65efac481.png new file mode 100644 index 0000000..f3b74db Binary files /dev/null and b/e6c3dd54ed7f22db16bafaf65efac481.png differ diff --git a/routes/api.php b/routes/api.php index a7e8ef7..24b0bd7 100755 --- a/routes/api.php +++ b/routes/api.php @@ -80,6 +80,21 @@ Route::group(["namespace" => "Admin", "prefix" => "admin"], function () { Route::post('course-types/excel-show', [\App\Http\Controllers\Admin\CourseTypeController::class, "excelShow"]); Route::post('course-types/import', [\App\Http\Controllers\Admin\CourseTypeController::class, "import"]); + // 课程排期总览 + Route::get('schedule-overview/overview', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "overview"]); + Route::get('schedule-overview/systems/index', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "systemIndex"]); + Route::get('schedule-overview/systems/show', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "systemShow"]); + Route::post('schedule-overview/systems/save', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "systemSave"]); + Route::get('schedule-overview/systems/destroy', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "systemDestroy"]); + Route::get('schedule-overview/courses/index', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "courseIndex"]); + Route::get('schedule-overview/courses/show', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "courseShow"]); + Route::post('schedule-overview/courses/save', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "courseSave"]); + Route::get('schedule-overview/courses/destroy', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "courseDestroy"]); + Route::get('schedule-overview/schedules/index', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "scheduleIndex"]); + Route::get('schedule-overview/schedules/show', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "scheduleShow"]); + Route::post('schedule-overview/schedules/save', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "scheduleSave"]); + Route::get('schedule-overview/schedules/destroy', [\App\Http\Controllers\Admin\ScheduleOverviewController::class, "scheduleDestroy"]); + // 通讯录 Route::get('users/index', [\App\Http\Controllers\Admin\UserController::class, "index"]); Route::get('users/study', [\App\Http\Controllers\Admin\UserController::class, "study"]); diff --git a/shangxueyuan.code-workspace b/shangxueyuan.code-workspace new file mode 100644 index 0000000..d5e682c --- /dev/null +++ b/shangxueyuan.code-workspace @@ -0,0 +1,13 @@ +{ + "folders": [ + { + "name": "后端 (wx.sstbc.com)", + "path": "." + }, + { + "name": "后台前端 (shangxueyuan-admin)", + "path": "/Users/apple/www/fronted/shangxueyuan-admin" + } + ], + "settings": {} +}