基本 通知功能

This commit is contained in:
iVampireSP.com 2022-12-31 18:04:28 +08:00
parent 98e42bb9a6
commit 6131da2cf5
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
7 changed files with 354 additions and 0 deletions

View File

@ -0,0 +1,88 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Jobs\SendCommonNotificationsJob;
use App\Models\Host;
use App\Models\Module;
use App\Models\User;
use GeneaLabs\LaravelModelCaching\CachedBuilder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class NotificationController extends Controller
{
/**
* Show the form for creating a new resource.
*
* @return View
*/
public function create(Request $request)
{
$modules = Module::all();
$users = $this->query($request)->paginate(20)->withQueryString();
return view('admin.notifications.create', compact('modules', 'users'));
}
/**
* Store a newly created resource in storage.
*
* @param Request $request
*
* @return RedirectResponse
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required',
'content' => 'required',
'user_id' => 'nullable',
'module_id' => 'nullable',
'user' => 'nullable',
]);
dispatch(new SendCommonNotificationsJob($request->toArray(), $request->input('title'), $request->input('content')));
return back()->with('success', '通知发送成功。')->withInput();
}
public function query(Request|array $request): User|CachedBuilder
{
if ($request instanceof Request) {
$request = $request->all();
}
if (!empty($request['user_id'])) {
$users = User::where('id', $request['user_id']);
} else {
$users = User::query();
if (!empty($request['user'])) {
$user = $request['user'];
if ($user == 'active') {
// 寻找有 host 的用户
$users = $users->whereHas('hosts');
} else if ($user == 'normal') {
$users = $users->whereNull('banned_at');
} else if ($user == 'banned') {
$users = $users->whereNotNull('banned_at');
}
}
}
if (!empty($request['module_id'])) {
// 从 hosts 中找到 module_id然后找到拥有此 host 的用户
$users = $users->whereHas('hosts', function ($query) use ($request) {
$query->where('module_id', $request['module_id']);
});
}
return $users;
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Jobs;
use App\Http\Controllers\Admin\NotificationController;
use App\Models\User;
use App\Notifications\CommonNotification;
use GeneaLabs\LaravelModelCaching\CachedBuilder;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class SendCommonNotificationsJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected array $requests;
protected User|CachedBuilder $users;
protected string $title, $content;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(array $requests, $title, $content)
{
$this->requests = $requests;
$this->title = $title;
$this->content = $content;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(): void
{
//
$notificationController = new NotificationController();
$users = $notificationController->query($this->requests);
// chunk
$users->chunk(100, function ($users) {
foreach ($users as $user) {
$user->notify(new CommonNotification($this->title, $this->content));
}
});
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
class CommonNotification extends Notification implements ShouldQueue
{
use Queueable;
public string $title;
public string $content;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct(string $title, string $content)
{
$this->title = $title;
$this->content = $content;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return MailMessage
*/
public function toMail($notifiable): MailMessage
{
return (new MailMessage)->subject($this->title)->markdown('mail.common', [
'title' => $this->title,
'content' => $this->content,
]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable): array
{
return [
//
];
}
}

View File

@ -0,0 +1,127 @@
@extends('layouts.admin')
@section('title', '通知')
@section('content')
<h3>通知</h3>
@if (Request::isNotFilled('user_id'))
<h5>首先,我们得先筛选出要通知哪些用户。</h5>
<form action="#" method="get">
<div class="form-group">
<label for="user">用户</label>
<select name="user" id="user" class="form-control">
<option value="all" @if(Request::get('user') == 'all') selected @endif>全部</option>
<option value="normal" @if(Request::get('user') == 'normal') selected @endif>正常没有被封禁的用户
</option>
<option value="active" @if(Request::get('user') == 'active') selected @endif>有主机的用户</option>
<option value="banned" @if(Request::get('user') == 'banned') selected @endif>封禁的用户</option>
</select>
</div>
<div class="form-group">
<label for="module_id">在哪些模块拥有主机的</label>
<select name="module_id" id="module_id" class="form-control">
<option value=""></option>
@foreach ($modules as $module)
<option value="{{ $module->id }}"
@if(Request::get('module_id') == $module->id) selected @endif>{{ $module->name }}</option>
@endforeach
</select>
</div>
<p>这两个搜搜条件只能二选一。</p>
<button type="submit" class="btn btn-primary mt-1">筛选并确定条件</button>
</form>
@endif
@if (count($users))
<h5 class="mt-4">筛选出的用户,接下来我们得选择通知方式。</h5>
{{-- 用户列表 --}}
<div class="overflow-auto mt-3">
<table class="table table-hover">
<thead>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
<th>余额</th>
<th>用户组</th>
<th>注册时间</th>
<th>操作</th>
</thead>
<tbody>
@foreach ($users as $user)
<tr>
<td>
<a href="{{ route('admin.users.show', $user) }}" title="切换到 {{ $user->name }}">
{{ $user->id }}
</a>
</td>
<td>
<a href="{{ route('admin.users.edit', $user) }}"
title="显示和编辑 {{ $user->name }} 的资料">
{{ $user->name }}
</a>
</td>
<td>
{{ $user->email }}
</td>
<td>
{{ $user->balance }}
</td>
<td>
@if ($user->user_group_id)
<a href="{{ route('admin.user-groups.show', $user->user_group_id) }}">
{{ $user->user_group->name }}
</a>
@else
@endif
</td>
<td>
{{ $user->created_at }}
</td>
<td>
<a href="{{ route('admin.users.edit', $user) }}" class="btn btn-primary btn-sm">编辑</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
{{-- 分页 --}}
{{ $users->links() }}
@endif
<form method="POST" action="{{ route('admin.notifications.store')}}">
@csrf
<input type="hidden" name="user" value="{{ Request::get('user') }}">
<input type="hidden" name="module_id" value="{{ Request::get('module_id') }}">
<input type="hidden" name="user_id" value="{{ Request::get('user_id') }}">
<div class="form-group">
<label for="title">标题</label>
<input type="text" name="title" id="title" class="form-control" value="{{ old('title') }}">
</div>
{{-- 通知内容 --}}
<div class="form-group mt-4">
<label for="content">通知内容 支持 Markdown</label>
<textarea name="content" id="content" class="form-control" rows="10">{{ old('content') }}</textarea>
</div>
<button type="submit" class="btn btn-primary mt-3">发送</button>
<span class="text-muted d-block">通知一旦发送,将无法撤销!</span>
</form>
@endsection

View File

@ -49,6 +49,9 @@
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.transactions') }}">交易记录</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.notifications.create') }}">通知</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.admins.index') }}">管理员</a>
</li>

View File

@ -0,0 +1,7 @@
@component('mail::message')
# {{ $title }}
{{ $content }}
<br />
@endcomponent

View File

@ -7,6 +7,7 @@
use App\Http\Controllers\Admin\HomeController;
use App\Http\Controllers\Admin\HostController;
use App\Http\Controllers\Admin\ModuleController;
use App\Http\Controllers\Admin\NotificationController;
use App\Http\Controllers\Admin\UserController;
use App\Http\Controllers\Admin\UserGroupController;
use App\Http\Controllers\Admin\WorkOrderController;
@ -45,6 +46,8 @@
Route::resource('devices', DeviceController::class)->only(['index', 'destroy']);
Route::resource('notifications', NotificationController::class)->only(['create', 'store']);
Route::view('commands', 'admin.commands')->name('commands');