消息通知

This commit is contained in:
fthvgb1 2018-01-27 18:35:56 +08:00
parent ad94cc05dd
commit ed8ce10700
13 changed files with 284 additions and 5 deletions

View 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'));
}
}

View File

@ -7,7 +7,7 @@ class Topic extends Model
protected $fillable = ['title', 'category_id', 'body', 'excerpt', 'slug']; 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)); return route('topics.show', array_merge([$this->id, $this->slug], $params));
} }

View File

@ -4,10 +4,13 @@ namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Auth;
class User extends Authenticatable class User extends Authenticatable
{ {
use Notifiable; use Notifiable {
notify as protected laravelNotify;
}
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@ -46,4 +49,20 @@ class User extends Authenticatable
{ {
return $this->hasMany(Topic::class); 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();
}
} }

View 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 [
//
];
}
}

View File

@ -3,6 +3,7 @@
namespace App\Observers; namespace App\Observers;
use App\Models\Reply; use App\Models\Reply;
use App\Notifications\TopicReplied;
// creating, created, updating, updated, saving, // creating, created, updating, updated, saving,
// saved, deleting, deleted, restoring, restored // saved, deleting, deleted, restoring, restored
@ -21,6 +22,10 @@ class ReplyObserver
public function created(Reply $reply) public function created(Reply $reply)
{ {
$topic = $reply->topic;
$reply->topic->increment('reply_count', 1); $reply->topic->increment('reply_count', 1);
if (!$reply->user->isAuthorOf($topic)) {
$topic->user->notify(new TopicReplied($reply));
}
} }
} }

View File

@ -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');
}
}

View File

@ -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
View File

@ -8975,5 +8975,15 @@ body {
color: #b3b3b3; 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;
}

View File

@ -174,4 +174,14 @@ body {
} }
} }
/* Topic Index Page */ .notifications-badge {
margin-top: -1;
.badge-fade {
background-color: #EBE8E8;
}
.badge-hint {
background-color: #d15b47 !important;;
}
}

View File

@ -45,6 +45,15 @@
</a> </a>
</li> </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"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"> <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;"> <span class="user-avatar pull-left" style="margin-right:8px; margin-top:-5px;">
@ -68,6 +77,9 @@
</a> </a>
</li> </li>
<li> <li>
<form hidden id="logout-form" action="{{route('logout')}}" method="post">
{{csrf_field()}}
</form>
<a href="{{ route('logout') }}" <a href="{{ route('logout') }}"
onclick="event.preventDefault(); onclick="event.preventDefault();
document.getElementById('logout-form').submit();"> document.getElementById('logout-form').submit();">

View 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

View 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>

View File

@ -38,4 +38,5 @@ Route::resource('categories', 'CategoriesController', ['only' => ['show']]);
Route::post('upload_image', 'TopicsController@uploadImage')->name('topics.upload_image'); 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');