Laravel Eloquent表关联开发:通知确认与取消按钮功能实现
没问题,咱们一步步来实现这个需求,从创建数据表到关联模型再到视图按钮,都给你安排明白:
完整实现步骤
1. 创建确认记录表的迁移与模型
首先用Artisan命令生成迁移文件,用来创建notice_confirmed_student表:
php artisan make:migration create_notice_confirmed_student_table
打开生成的迁移文件(在database/migrations目录下),编写表结构:
public function up() { Schema::create('notice_confirmed_student', function (Blueprint $table) { $table->id(); $table->foreignId('notice_id')->constrained()->onDelete('cascade'); // 关联通知表,删除通知时同步删除确认记录 $table->foreignId('student_id')->constrained(); // 关联学生表,你可以根据实际业务调整字段名 $table->timestamps(); // 加个唯一约束,防止同一学生重复确认同一条通知 $table->unique(['notice_id', 'student_id']); }); } public function down() { Schema::dropIfExists('notice_confirmed_student'); }
接着生成对应的模型:
php artisan make:model NoticeConfirmedStudent
打开app/Models/NoticeConfirmedStudent.php,配置可填充字段和关联关系:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class NoticeConfirmedStudent extends Model { // 允许批量赋值的字段 protected $fillable = ['notice_id', 'student_id']; // 关联Notice模型(多对一) public function notice(): BelongsTo { return $this->belongsTo(Notice::class); } // 如果有Student模型,添加关联(可选,根据你的业务) public function student(): BelongsTo { return $this->belongsTo(Student::class); } }
最后运行迁移创建表:
php artisan migrate
2. 配置Notice模型的Eloquent关联
打开现有的app/Models/Notice.php,添加和确认记录的一对多关联,再写个辅助方法方便判断当前用户是否已确认:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; class Notice extends Model { // 原有的代码(比如$fillable)保持不变 // 关联确认记录(一对多) public function confirmedStudents(): HasMany { return $this->hasMany(NoticeConfirmedStudent::class); } // 辅助方法:判断指定学生是否已确认该通知 public function isConfirmedBy($studentId): bool { return $this->confirmedStudents()->where('student_id', $studentId)->exists(); } }
3. 添加路由与控制器处理逻辑
先在routes/web.php里添加两个POST路由,分别处理确认和取消确认的请求:
use App\Http\Controllers\NoticeController; Route::post('/notices/{notice}/confirm', [NoticeController::class, 'confirm'])->name('notices.confirm'); Route::post('/notices/{notice}/cancel-confirm', [NoticeController::class, 'cancelConfirm'])->name('notices.cancel-confirm');
然后在NoticeController里新增两个方法:
namespace App\Http\Controllers; use App\Models\Notice; use App\Models\NoticeConfirmedStudent; use Illuminate\Http\Request; class NoticeController extends Controller { // 原有的获取通知列表的方法(比如index)保持不变 // 处理确认通知请求 public function confirm(Request $request, Notice $notice) { // 这里假设当前登录用户是学生,用auth()->id()获取用户ID,你可以根据实际调整 $studentId = auth()->id(); // 用firstOrCreate避免重复提交 NoticeConfirmedStudent::firstOrCreate( ['notice_id' => $notice->id, 'student_id' => $studentId] ); return back()->with('success', '已成功确认该通知'); } // 处理取消确认请求 public function cancelConfirm(Request $request, Notice $notice) { $studentId = auth()->id(); // 删除当前用户对该通知的确认记录 $notice->confirmedStudents()->where('student_id', $studentId)->delete(); return back()->with('success', '已取消该通知的确认'); } }
4. 更新视图,添加确认/取消按钮
在遍历通知的循环里,根据当前用户是否已确认,显示对应的按钮:
@foreach($notices as $notice) <div class="notice-container"> <p>{{ $notice->notice }}</p> @if($notice->isConfirmedBy(auth()->id())) <!-- 已确认时显示取消按钮 --> <form action="{{ route('notices.cancel-confirm', $notice) }}" method="POST"> @csrf <button type="submit" class="btn btn-outline-secondary">取消确认</button> </form> @else <!-- 未确认时显示确认按钮 --> <form action="{{ route('notices.confirm', $notice) }}" method="POST"> @csrf <button type="submit" class="btn btn-primary">确认</button> </form> @endif </div> @endforeach
如果想要无刷新的体验,可以改成AJAX提交(用jQuery举例):
@foreach($notices as $notice) <div class="notice-container"> <p>{{ $notice->notice }}</p> <div class="action-btn"> @if($notice->isConfirmedBy(auth()->id())) <button class="btn btn-outline-secondary cancel-btn" data-id="{{ $notice->id }}">取消确认</button> @else <button class="btn btn-primary confirm-btn" data-id="{{ $notice->id }}">确认</button> @endif </div> </div> @endforeach <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> // 确认按钮逻辑 $('.confirm-btn').click(function() { let noticeId = $(this).data('id'); let btn = $(this); $.post(`/notices/${noticeId}/confirm`, { _token: '{{ csrf_token() }}' }, function() { btn.replaceWith(`<button class="btn btn-outline-secondary cancel-btn" data-id="${noticeId}">取消确认</button>`); alert('确认成功'); }); }); // 取消确认按钮逻辑 $('.cancel-btn').click(function() { let noticeId = $(this).data('id'); let btn = $(this); $.post(`/notices/${noticeId}/cancel-confirm`, { _token: '{{ csrf_token() }}' }, function() { btn.replaceWith(`<button class="btn btn-primary confirm-btn" data-id="${noticeId}">确认</button>`); alert('已取消确认'); }); }); </script>
内容的提问来源于stack exchange,提问作者Fokrule
相关产品推荐
相关产品推荐

