消息通知
This commit is contained in:
parent
ad94cc05dd
commit
ed8ce10700
13
app/Http/Controllers/NotificationsController.php
Normal file
13
app/Http/Controllers/NotificationsController.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
class NotificationsController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$notifications = \Auth::user()->notifications()->paginate(20);
|
||||
\Auth::user()->markAsRead();
|
||||
return view('notifications.index', compact('notifications'));
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ class Topic extends Model
|
|||
protected $fillable = ['title', 'category_id', 'body', 'excerpt', 'slug'];
|
||||
|
||||
|
||||
public function link($params = [])
|
||||
public function link(...$params)
|
||||
{
|
||||
return route('topics.show', array_merge([$this->id, $this->slug], $params));
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use Notifiable;
|
||||
use Notifiable {
|
||||
notify as protected laravelNotify;
|
||||
}
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
@ -46,4 +49,20 @@ class User extends Authenticatable
|
|||
{
|
||||
return $this->hasMany(Topic::class);
|
||||
}
|
||||
|
||||
public function notify($instance)
|
||||
{
|
||||
if ($this->id == Auth::id()) {
|
||||
return;
|
||||
}
|
||||
$this->increment('notification_count');
|
||||
$this->laravelNotify($instance);
|
||||
}
|
||||
|
||||
public function markAsRead()
|
||||
{
|
||||
$this->notification_count = 0;
|
||||
$this->save();
|
||||
$this->unreadNotifications->markAsRead();
|
||||
}
|
||||
}
|
||||
|
|
81
app/Notifications/TopicReplied.php
Normal file
81
app/Notifications/TopicReplied.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Reply;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class TopicReplied extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $replay;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
* @param Reply $reply
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Reply $reply)
|
||||
{
|
||||
$this->replay = $reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['database'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->line('The introduction to the notification.')
|
||||
->action('Notification Action', url('/'))
|
||||
->line('Thank you for using our application!');
|
||||
}
|
||||
|
||||
public function toDataBase($notifiable)
|
||||
{
|
||||
$topic = $this->replay->topic;
|
||||
|
||||
$link = $topic->link('#reply', $this->replay->id);
|
||||
|
||||
return [
|
||||
'reply_id' => $this->replay->id,
|
||||
'reply_content' => $this->replay->content,
|
||||
'user_id' => $this->replay->user->id,
|
||||
'user_name' => $this->replay->user->name,
|
||||
'user_avatar' => $this->replay->user->avatar,
|
||||
'topic_link' => $link,
|
||||
'topic_id' => $topic->id,
|
||||
'topic_title' => $topic->title
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Observers;
|
||||
|
||||
use App\Models\Reply;
|
||||
use App\Notifications\TopicReplied;
|
||||
|
||||
// creating, created, updating, updated, saving,
|
||||
// saved, deleting, deleted, restoring, restored
|
||||
|
@ -21,6 +22,10 @@ class ReplyObserver
|
|||
|
||||
public function created(Reply $reply)
|
||||
{
|
||||
$topic = $reply->topic;
|
||||
$reply->topic->increment('reply_count', 1);
|
||||
if (!$reply->user->isAuthorOf($topic)) {
|
||||
$topic->user->notify(new TopicReplied($reply));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateNotificationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddNotificationCoutToUsersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->integer('notification_count')->unsigned()->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('notification_count');
|
||||
});
|
||||
}
|
||||
}
|
12
public/css/app.css
vendored
12
public/css/app.css
vendored
|
@ -8975,5 +8975,15 @@ body {
|
|||
color: #b3b3b3;
|
||||
}
|
||||
|
||||
/* Topic Index Page */
|
||||
.notifications-badge {
|
||||
margin-top: -1;
|
||||
}
|
||||
|
||||
.notifications-badge .badge-fade {
|
||||
background-color: #EBE8E8;
|
||||
}
|
||||
|
||||
.notifications-badge .badge-hint {
|
||||
background-color: #d15b47 !important;
|
||||
}
|
||||
|
||||
|
|
12
resources/assets/sass/app.scss
vendored
12
resources/assets/sass/app.scss
vendored
|
@ -174,4 +174,14 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
/* Topic Index Page */
|
||||
.notifications-badge {
|
||||
margin-top: -1;
|
||||
|
||||
.badge-fade {
|
||||
background-color: #EBE8E8;
|
||||
}
|
||||
|
||||
.badge-hint {
|
||||
background-color: #d15b47 !important;;
|
||||
}
|
||||
}
|
|
@ -45,6 +45,15 @@
|
|||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="{{route('notifications.index')}}" class="notifications-badge" style="margin-top:-2px;">
|
||||
<span class="badge badge-{{Auth::user()->notification_count>0 ? 'hint':'fade'}}"
|
||||
title="消息提醒">
|
||||
{{Auth::user()->notification_count}}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
||||
<span class="user-avatar pull-left" style="margin-right:8px; margin-top:-5px;">
|
||||
|
@ -68,6 +77,9 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<form hidden id="logout-form" action="{{route('logout')}}" method="post">
|
||||
{{csrf_field()}}
|
||||
</form>
|
||||
<a href="{{ route('logout') }}"
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
|
|
34
resources/views/notifications/index.blade.php
Normal file
34
resources/views/notifications/index.blade.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title','你的通知')
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<div class="panel panel-default">
|
||||
|
||||
<div class="panel-body">
|
||||
|
||||
<h3 class="text-center">
|
||||
<span class="glyphicon glyphicon-bell" aria-hidden="true"></span> 我的通知
|
||||
</h3>
|
||||
<hr>
|
||||
|
||||
@if ($notifications->count())
|
||||
|
||||
<div class="notification-list">
|
||||
@foreach ($notifications as $notification)
|
||||
@include('notifications.types._' . snake_case(class_basename($notification->type)))
|
||||
@endforeach
|
||||
|
||||
{!! $notifications->render() !!}
|
||||
</div>
|
||||
|
||||
@else
|
||||
<div class="empty-block">没有消息通知!</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
27
resources/views/notifications/types/_topic_replied.blade.php
Normal file
27
resources/views/notifications/types/_topic_replied.blade.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<div class="media">
|
||||
<div class="avatar pull-left">
|
||||
<a href="{{route('users.show',$notification->data['user_id'])}}">
|
||||
<img class="media-object img-thumbnail" alt="{{ $notification->data['user_name'] }}"
|
||||
src="{{ $notification->data['user_avatar'] }}" style="width:48px;height:48px;"/>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
<div class="infos">
|
||||
<div class="media-heading">
|
||||
<a href="{{ route('users.show', $notification->data['user_id']) }}">{{ $notification->data['user_name'] }}</a>
|
||||
评论了
|
||||
<a href="{{ $notification->data['topic_link'] }}">{{ $notification->data['topic_title'] }}</a>
|
||||
|
||||
{{-- 回复删除按钮 --}}
|
||||
<span class="meta pull-right" title="{{ $notification->created_at }}">
|
||||
<span class="glyphicon glyphicon-clock" aria-hidden="true"></span>
|
||||
{{ $notification->created_at->diffForHumans() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="reply-content">
|
||||
{!! $notification->data['reply_content'] !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
|
@ -38,4 +38,5 @@ Route::resource('categories', 'CategoriesController', ['only' => ['show']]);
|
|||
Route::post('upload_image', 'TopicsController@uploadImage')->name('topics.upload_image');
|
||||
|
||||
|
||||
Route::resource('replies', 'RepliesController', ['only' => ['store', 'destroy']]);
|
||||
Route::resource('replies', 'RepliesController', ['only' => ['store', 'destroy']]);
|
||||
Route::resource('notifications', 'NotificationsController', ['only' => ['index']])->middleware('auth');
|
Loading…
Reference in New Issue
Block a user