消息通知
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'];
|
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
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;
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
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>
|
</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();">
|
||||||
|
|
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::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