This commit is contained in:
2023-03-08 09:16:04 +08:00
commit e78454540f
1318 changed files with 210569 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
<?php
namespace Modules\Notification\Channels;
use Illuminate\Notifications\Notification;
class AppChannel
{
/**
* APP 推送渠道
*
* @param mixed $notifiable
* @param Notification $notification
* @return void
*/
public function send($notifiable, Notification $notification)
{
// $uapi = new GTUserApi();
// $uapi->bindAlias();
// $api = new GTClient("https://restapi.getui.com", "APPKEY", "APPID", "MASTERSECRET");
// 设置推送参数
// $push = new \GTPushRequest();
// $push->setRequestId(uniqid());
// $message = new GTPushMessage();
// $notify = new GTNotification();
// $notify->setTitle("设置通知标题");
// $notify->setBody("设置通知内容");
// // 点击通知后续动作,目前支持以下后续动作:
// // 1、intent打开应用内特定页面url打开网页地址。
// // 2、payload自定义消息内容启动应用。
// // 3、payload_custom自定义消息内容不启动应用。
// // 4、startapp打开应用首页。
// // 5、none纯通知无后续动作
// $notify->setClickType("none");
// $message->setNotification($notify);
// $push->setPushMessage($message);
// $push->setCid("CID");
// //处理返回结果
// $result = $api->pushApi()->pushToSingleByCid($push);
$notification->toApp($notifiable);
}
}

View File

@@ -0,0 +1,34 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| 模块名称
|--------------------------------------------------------------------------
*/
'name' => 'Notification',
/*
|--------------------------------------------------------------------------
| 消息分类
|--------------------------------------------------------------------------
*/
'types' => [
'App\\Notifications\\SystemOpenVip' => [
'name' => '开通会员',
'icon' => 'http://api.siyuankunlun.com/storage/materials/2022/08/09/newsIcon_04.jpg',
],
'App\\Notifications\\SystemOrderDelivered' => [
'name' => '发货',
'icon' => 'http://api.siyuankunlun.com/storage/materials/2022/08/09/newsIcon_02.png',
],
'App\\Notifications\\SystemRemindUserSign' => [
'name' => '打卡',
'icon' => 'http://api.siyuankunlun.com/storage/materials/2022/08/09/newsIcon_01.png',
],
'App\\Notifications\\SystemUpdateCase' => [
'name' => '上传报告',
'icon' => 'http://api.siyuankunlun.com/storage/materials/2022/08/09/newsIcon_05.png',
],
],
];

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateNotificationTemplatesTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('notification_templates', function (Blueprint $table) {
$table->id();
$table->string('title')->comment('模板标题');
$table->string('slug')->unique()->comment('唯一标识');
$table->text('content')->comment('模板内容');
$table->boolean('status')->unsigned()->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('notification_templates');
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Modules\Notification\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\Linker\Traits\WithLinker;
use Modules\Notification\Models\Template;
class IndexController extends AdminController
{
use WithLinker;
protected $title = '消息模板';
public function grid(): Grid
{
$grid = new Grid(new Template());
$grid->column('title', '模板标题');
$grid->column('slug', '调用标识');
$grid->column('status', '状态')->bool();
$grid->column('created_at', '创建时间');
return $grid;
}
public function form(): Form
{
$form = new Form((new Template())->disableModelCaching());
$form->text('title', '模板标题')
->required();
$form->text('slug', '调用标识')
->required();
$form->textarea('content', '模板内容')
->required();
$form->switch('status', '状态');
$this->withUrl($form);
return $form;
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Modules\Notification\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
class SettingController extends AdminController
{
protected $title = '消息设置';
public function grid()
{
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace Modules\Notification\Http\Controllers\Api;
use App\Api\Controllers\Controller;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Notifications\DatabaseNotification;
use Illuminate\Support\Str;
use Jason\Api\Api;
use Modules\Notification\Http\Resources\NotificationCollection;
use Modules\Notification\Http\Resources\NotificationResource;
use Modules\User\Models\User;
class IndexController extends Controller
{
/**
* Notes : 分类消息数量
*
* @Date : 2021/6/21 9:30 上午
* @Author : <Jason.C>
* @return JsonResponse
*/
public function index(): JsonResponse
{
$user = Api::user();
$result = [];
foreach (config('notification.types') as $type => $name) {
$result[] = [
'type' => Str::remove('App\\Notifications\\', $type),
'icon' => $name['icon'],
'name' => $name['name'],
'count' => $user->unreadNotifications()->where('type', $type)->count(),
'title' => data_get($user->unreadNotifications()->where('type', $type)->latest()->value('data'),
'title') ?? '',
];
}
return $this->success($result);
}
/**
* Notes : 未读消息数量
*
* @Date : 2021/5/20 12:10 下午
* @Author : <Jason.C>
*/
public function counts(): JsonResponse
{
$user = Api::user();
if ($user) {
$count = $user->unreadNotifications()->count();
} else {
$count = 0;
}
return $this->success($count);
}
/**
* Notes : 分类读取消息
*
* @Date : 2021/5/18 3:12 下午
* @Author : <Jason.C>
* @param string $type
* @return JsonResponse
*/
public function type(string $type): JsonResponse
{
$list = DatabaseNotification::query()
->whereHasMorph(
'notifiable',
User::class,
function (Builder $query) {
$query->where('id', Api::userId());
}
)
->where('type', 'like', "%$type")
->orderBy('read_at')
->orderByDesc('created_at')->paginate();
return $this->success(new NotificationCollection($list));
}
/**
* Notes : 消息详情,自动标记已读
*
* @Date : 2021/5/18 3:17 下午
* @Author : <Jason.C>
* @param string $id
* @return JsonResponse
*/
public function show(string $id): JsonResponse
{
$notification = DatabaseNotification::findOrFail($id);
$notification->markAsRead();
return $this->success(new NotificationResource($notification));
}
/**
* Notes : 全部标记已读
*
* @Date : 2021/5/18 3:22 下午
* @Author : <Jason.C>
*/
public function markAsRead(string $type = null): JsonResponse
{
$user = Api::user();
$user->unreadNotifications()->when($type, function ($query) use ($type) {
$query->where('type', 'like', "%$type");
})->update(['read_at' => now()]);
return $this->success('');
}
/**
* Notes : 清空消息
*
* @Date : 2021/5/18 5:49 下午
* @Author : <Jason.C>
* @param string|null $type
* @return JsonResponse
*/
public function clean(string $type = null): JsonResponse
{
$user = Api::user();
$user->notifications()->when($type, function ($query) use ($type) {
$query->where('type', 'like', "%$type");
})->delete();
return $this->success('');
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Modules\Notification\Http\Resources;
use App\Api\Resources\BaseCollection;
class NotificationCollection extends BaseCollection
{
public function toArray($request): array
{
return [
'data' => $this->collection->map(function ($notification) {
return new NotificationResource($notification);
}),
'page' => $this->page(),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Modules\Notification\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Str;
class NotificationResource extends JsonResource
{
public function toArray($request): array
{
return [
'notification_id' => $this->id,
'type' => Str::remove('App\\Notifications\\', $this->type),
'title' => $this->data['title'] ?? '',
'content' => $this->data['content'] ?? '',
'read_at' => (string) $this->read_at,
'created_at' => (string) $this->created_at,
];
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Modules\Notification\Models;
use App\Models\Model;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Modules\Linker\Traits\HasLinker;
class Template extends Model
{
use Cachable,
HasLinker;
protected $table = 'notification_templates';
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Modules\Notification;
use Illuminate\Support\Facades\Artisan;
class Notification
{
protected static string $mainTitle = '通知消息';
/**
* Notes : 模块初始化要做的一些操作
*
* @Date : 2021/3/12 11:34 上午
* @Author : <Jason.C>
*/
public static function install()
{
Artisan::call('migrate', [
'--path' => 'modules/Notification/Database/Migrations',
]);
self::createAdminMenu();
}
protected static function createAdminMenu()
{
$menu = config('admin.database.menu_model');
$main = $menu::create([
'parent_id' => 0,
'order' => 40,
'title' => self::$mainTitle,
'icon' => 'fa-commenting-o',
]);
$main->children()->createMany([
[
'order' => 1,
'title' => '消息模板',
'icon' => 'fa-dashboard',
'uri' => 'notifications/templates',
],
[
'order' => 2,
'title' => '消息设置',
'icon' => 'fa-cogs',
'uri' => 'notifications/settings',
],
]);
}
/**
* Notes : 卸载模块的一些操作
*
* @Date : 2021/3/12 11:35 上午
* @Author : <Jason.C>
*/
public static function uninstall()
{
$menu = config('admin.database.menu_model');
$mains = $menu::where('title', self::$mainTitle)->get();
foreach ($mains as $main) {
$main->delete();
}
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Modules\Notification\Providers;
use Illuminate\Support\ServiceProvider;
class NotificationServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected string $moduleName = 'Notification';
/**
* @var string $moduleNameLower
*/
protected string $moduleNameLower = 'notification';
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerConfig();
$this->app->register(RouteServiceProvider::class);
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig()
{
$this->publishes([
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower.'.php'),
], 'config');
$this->mergeConfigFrom(
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
);
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides(): array
{
return [];
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Modules\Notification\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected string $moduleName = 'Notification';
/**
* The module namespace to assume when generating URLs to actions.
*
* @var string
*/
protected string $moduleNamespace = 'Modules\Notification\Http\Controllers';
/**
* Called before routes are registered.
* Register any model bindings or pattern based filters.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapAdminRoutes();
$this->mapApiRoutes();
}
protected function mapApiRoutes()
{
Route::as(config('api.route.as'))
->domain(config('api.route.domain'))
->middleware(config('api.route.middleware'))
->namespace($this->moduleNamespace)
->prefix(config('api.route.prefix'))
->group(module_path($this->moduleName, 'Routes/api.php'));
}
protected function mapAdminRoutes()
{
Route::as(config('admin.route.as'))
->domain(config('admin.route.domain'))
->middleware(config('admin.route.middleware'))
->namespace($this->moduleNamespace)
->prefix(config('admin.route.prefix'))
->group(module_path($this->moduleName, 'Routes/admin.php'));
}
}

View File

@@ -0,0 +1,154 @@
# Notification
通知模块
## 1. 安装
```shell
composer require getuilaboratory/getui-pushapi-php-client-v2
```
## 2. 接口文档
### 1. 获取未读消息数量不登陆返回0
> GET: /api/notifications/counts
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": 16
}
```
### 2. 消息主页
> GET: /api/notifications
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": [
{
"type": "SystemNotification",
"icon": "",
"name": "系统通知",
"count": 16,
"title": "登录成功"
},
{
"type": "OrderNotification",
"icon": "",
"name": "订单通知",
"count": 0,
"title": ""
},
{
"type": "ActivityNotification",
"icon": "",
"name": "活动通知",
"count": 0,
"title": ""
}
]
}
```
### 3. 分类消息的列表
> GET: /api/notifications/{type}/list
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": {
"data": [
{
"notification_id": "91e31d1e-95e1-40ff-88d8-8049df974860",
"type": "SystemNotification",
"title": "登录成功",
"content": "您于北京时间2021-07-02 15:31:03通过【账号密码】渠道在IP1.190.203.218成功登录系统。请注意保管好您的账号密码。",
"read_at": "",
"created_at": "2021-07-02 15:31:03"
}
],
"page": {
"current": 1,
"total_page": 2,
"per_page": 15,
"has_more": true,
"total": 16
}
}
}
```
### 4. 消息详情
> GET: /api/notifications/{notification_id}
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": {
"notification_id": "91e31d1e-95e1-40ff-88d8-8049df974860",
"type": "SystemNotification",
"title": "登录成功",
"content": "您于北京时间2021-07-02 15:31:03通过【账号密码】渠道在IP1.190.203.218成功登录系统。请注意保管好您的账号密码。",
"read_at": "2021-07-02 16:27:07",
"created_at": "2021-07-02 15:31:03"
}
}
```
### 5. 全部标记已读
> PUT: /api/notifications
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": ""
}
```
### 6. 全部标记已读(分类)
> PUT: /api/notifications/{type}
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": ""
}
```
### 7. 清空全部消息
> DELETE: /api/notifications
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": ""
}
```
### 8. 清空分类消息
> DELETE: /api/notifications/{type}
```json
{
"status": "SUCCESS",
"status_code": 200,
"data": ""
}
```

View File

@@ -0,0 +1,13 @@
<?php
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
Route::group([
'prefix' => 'notifications',
'namespace' => 'Admin',
'as' => 'notification.',
], function (Router $router) {
$router->resource('templates', 'IndexController');
$router->get('settings', 'SettingController@index');
});

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
Route::group([
'prefix' => 'notifications',
'namespace' => 'Api',
'middleware' => config('api.route.middleware_guess'),
], function (Router $router) {
// 用户未读消息数量不登陆返回0
$router->get('counts', 'IndexController@counts');
});
Route::group([
'prefix' => 'notifications',
'namespace' => 'Api',
'middleware' => config('api.route.middleware_auth'),
], function (Router $router) {
$router->get('', 'IndexController@index');
$router->get('{type}/list', 'IndexController@type');
$router->put('{type?}', 'IndexController@markAsRead');
$router->delete('{type?}', 'IndexController@clean');
$router->get('{id}', 'IndexController@show');
});

View File

@@ -0,0 +1,23 @@
{
"name": "uztech/notification-module",
"description": "",
"type": "laravel-module",
"authors": [
{
"name": "Jason.Chen",
"email": "chenjxlg@163.com"
}
],
"require": {
"genealabs/laravel-model-caching": "^0.11.3",
"getuilaboratory/getui-pushapi-php-client-v2": "dev-master"
},
"extra": {
"module-dir": "modules"
},
"autoload": {
"psr-4": {
"Modules\\Notification\\": ""
}
}
}

View File

@@ -0,0 +1,17 @@
{
"name": "Notification",
"alias": "notification",
"description": "消息通知管理模块",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\Notification\\Providers\\NotificationServiceProvider"
],
"aliases": {},
"files": [],
"requires": [
"Linker"
],
"version": "1.0.0",
"author": "Jason.Chen"
}