fisrt
This commit is contained in:
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
37
.env.example
Normal file
37
.env.example
Normal file
@@ -0,0 +1,37 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=1
|
||||
REDIS_CACHE_DB=1
|
||||
|
||||
FILESYSTEM_DRIVER=public
|
||||
OSS_ACCESS_KEY=
|
||||
OSS_SECRET_KEY=
|
||||
OSS_ENDPOINT=
|
||||
OSS_BUCKET=
|
||||
OSS_IS_CNAME=false
|
||||
OSS_CDN_HOST=
|
||||
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
* text=auto
|
||||
*.css linguist-vendored
|
||||
*.scss linguist-vendored
|
||||
*.js linguist-vendored
|
||||
CHANGELOG.md export-ignore
|
||||
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/node_modules
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.phpunit.result.cache
|
||||
docker-compose.override.yml
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.idea
|
||||
.DS_Store
|
||||
13
.styleci.yml
Normal file
13
.styleci.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
php:
|
||||
preset: laravel
|
||||
disabled:
|
||||
- no_unused_imports
|
||||
finder:
|
||||
not-name:
|
||||
- index.php
|
||||
- server.php
|
||||
js:
|
||||
finder:
|
||||
not-name:
|
||||
- webpack.mix.js
|
||||
css: true
|
||||
122
README.md
Normal file
122
README.md
Normal file
@@ -0,0 +1,122 @@
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
|
||||
|
||||
# UzTech.Laravel
|
||||
|
||||
> Jason.Chen , 为了构建一个健壮的底层。
|
||||
|
||||
[TOC]
|
||||
|
||||
## 1.安装
|
||||
|
||||
```shell
|
||||
git pull http://git.yuzhankeji.cn/UzTech/laravel.git
|
||||
```
|
||||
|
||||
```shell
|
||||
# 生成 laravel 密钥
|
||||
php artisan key:generate --ansi
|
||||
|
||||
# 数据库迁移
|
||||
php artisan migrate
|
||||
|
||||
# 数据填充
|
||||
php artisan db:seed --class=AdminPanelSeeder
|
||||
|
||||
# api 密钥
|
||||
php artisan jwt:secret
|
||||
```
|
||||
|
||||
手动导入 initial.sql 后台数据基础文件
|
||||
|
||||
## 包含的基础组件
|
||||
|
||||
> OSS文件管理包
|
||||
>
|
||||
> "jasonc/flysystem-oss": "^2.0"
|
||||
>
|
||||
> 模块化工具
|
||||
>
|
||||
> "nwidart/laravel-modules": "^8.2"
|
||||
>
|
||||
> 模块安装工具
|
||||
>
|
||||
> "joshbrw/laravel-module-installer": "^2.0"
|
||||
>
|
||||
> API 管理工具
|
||||
>
|
||||
> "jasonc/api": "^3.3"
|
||||
>
|
||||
> 后台模板
|
||||
>
|
||||
> "encore/laravel-admin": "^1.8"
|
||||
|
||||
## 模块安装
|
||||
|
||||
> 模块安装完毕之后,要执行 composer dump-autoload
|
||||
|
||||
### 1.
|
||||
|
||||
## 模块开发
|
||||
|
||||
### 1. 创建新模块
|
||||
|
||||
```shell
|
||||
|
||||
php artisan make:module ModuleName
|
||||
|
||||
```
|
||||
|
||||
### 2. 模块目录的一些规范
|
||||
|
||||
```
|
||||
modules/
|
||||
├── Blog/
|
||||
├── Config/ 配置目录,使用 Config::get('module_name.') 调用
|
||||
├── Console/ 控制台命令
|
||||
├── Kernel.php 执行定时任务
|
||||
├── Database/ 数据库
|
||||
├── Migrations/ 数据表单迁移
|
||||
├── Seeders/ 数据填充文件
|
||||
├── Events/ 事件目录
|
||||
├── Http/
|
||||
├── Controllers/ 控制器
|
||||
├── Admin/
|
||||
├── Api/
|
||||
├── Middleware/ 中间件目录
|
||||
├── Requests/ 请求验证
|
||||
├── Resources API接口资源
|
||||
├── Jobs/ 队列
|
||||
├── Listeners/ 监听器
|
||||
├── Models/ 模型
|
||||
├── Traits/ 模块内部模型使用的traits
|
||||
├── Providers/
|
||||
├── BlogServiceProvider.php
|
||||
├── RouteServiceProvider.php
|
||||
├── Resources/ 静态资源目录
|
||||
├── assets/
|
||||
├── js/
|
||||
├── app.js
|
||||
├── sass/
|
||||
├── app.scss
|
||||
├── lang/
|
||||
├── views/
|
||||
├── Routes/ 路由
|
||||
├── admin.php
|
||||
├── api.php
|
||||
├── Service/ 内部服务
|
||||
├── Traits/ 对外的traits
|
||||
├── composer.json
|
||||
├── module.json
|
||||
├── README.md
|
||||
```
|
||||
### 3. 定时任务相关说明
|
||||
|
||||
```
|
||||
定时任务命令在ServiceProvider中加载
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([]);
|
||||
}
|
||||
定时任务的执行
|
||||
在模型文件夹 Console 建立 Kernel 类,类中 runCommand 执行定时任务
|
||||
$schedule->command(**)->everyMinute();
|
||||
```
|
||||
20
app/Admin/Actions/LinkCreateAddress.php
Normal file
20
app/Admin/Actions/LinkCreateAddress.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions;
|
||||
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
|
||||
class LinkCreateAddress extends RowAction
|
||||
{
|
||||
|
||||
public $name = '添加收货地址';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function href(): string
|
||||
{
|
||||
return admin_url("mall/addresses/create?user_id=".$this->row->id);
|
||||
}
|
||||
|
||||
}
|
||||
20
app/Admin/Actions/LinkStockOrderDeliver.php
Normal file
20
app/Admin/Actions/LinkStockOrderDeliver.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions;
|
||||
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
|
||||
class LinkStockOrderDeliver extends RowAction
|
||||
{
|
||||
|
||||
public $name = '发货';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function href(): string
|
||||
{
|
||||
return admin_url('mall/stock_orders?user_id='.$this->row->user->id);
|
||||
}
|
||||
|
||||
}
|
||||
20
app/Admin/Actions/LinkVipOrderRefund.php
Normal file
20
app/Admin/Actions/LinkVipOrderRefund.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions;
|
||||
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
|
||||
class LinkVipOrderRefund extends RowAction
|
||||
{
|
||||
|
||||
public $name = '体验官退款';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function href(): string
|
||||
{
|
||||
return admin_url("platform/vip_orders?user[username]=".$this->row->user->username);
|
||||
}
|
||||
|
||||
}
|
||||
10
app/Admin/Controllers/AuthController.php
Normal file
10
app/Admin/Controllers/AuthController.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Encore\Admin\Controllers\AuthController as BaseAuthController;
|
||||
|
||||
class AuthController extends BaseAuthController
|
||||
{
|
||||
|
||||
}
|
||||
259
app/Admin/Controllers/HomeController.php
Normal file
259
app/Admin/Controllers/HomeController.php
Normal file
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Encore\Admin\Auth\Permission;
|
||||
use Encore\Admin\Facades\Admin;
|
||||
use Encore\Admin\Layout\Column;
|
||||
use Encore\Admin\Layout\Content;
|
||||
use Encore\Admin\Layout\Row;
|
||||
use Encore\Admin\Widgets\InfoBox;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Modules\Mall\Models\Order;
|
||||
use Modules\Mall\Models\OrderItem;
|
||||
use Modules\User\Models\User;
|
||||
use Modules\User\Models\UserStock;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* Notes : 数据看板
|
||||
*
|
||||
* @Date : 2021/3/10 5:12 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param Content $content
|
||||
* @return Content
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
$this->content = $content->title('数据看板')->description('Description...');
|
||||
$admin = Admin::user();
|
||||
if ($admin->id == 1) {
|
||||
$this->getUserData();
|
||||
$this->getUserStockData();
|
||||
$this->getUserStockOrderData();
|
||||
} else {
|
||||
$this->content->row($this->setDivider('您没有权限查看数据'));
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取用户数据
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date : 2021/11/17 11:24
|
||||
*/
|
||||
public function getUserData()
|
||||
{
|
||||
$this->content->row($this->setDivider('用户统计'));
|
||||
|
||||
$users = [
|
||||
'all' => [
|
||||
'name' => '用户总数',
|
||||
'color' => 'blue',
|
||||
'count' => User::count()
|
||||
],
|
||||
'ty' => [
|
||||
'name' => '月卡',
|
||||
'color' => 'green',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 2);
|
||||
})->count()
|
||||
],
|
||||
'jk' => [
|
||||
'name' => '季卡用户数',
|
||||
'color' => 'red',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 3);
|
||||
})->count()
|
||||
],
|
||||
'nk' => [
|
||||
'name' => '年卡用户数',
|
||||
'color' => 'yellow',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 4);
|
||||
})->count(),
|
||||
],
|
||||
];
|
||||
|
||||
$this->content->row(function (Row $row) use ($users) {
|
||||
foreach ($users as $user) {
|
||||
$row->column(2, function (Column $column) use ($user) {
|
||||
$column->append(new InfoBox(
|
||||
$user['name'],
|
||||
'users',
|
||||
$user['color'],
|
||||
'/admin/users',
|
||||
$user['count'],
|
||||
));
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 用户水数量
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/1 13:35
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserStockData()
|
||||
{
|
||||
$this->content->row($this->setDivider('会员水库存数'));
|
||||
|
||||
$all = UserStock::query()->sum('stock');
|
||||
$holds = UserStock::query()->sum('hold');
|
||||
$sy = bcsub($all, $holds);
|
||||
|
||||
$users = [
|
||||
'all' => [
|
||||
'name' => '总数',
|
||||
'color' => 'blue',
|
||||
'count' => UserStock::query()->sum('stock')
|
||||
],
|
||||
'stock' => [
|
||||
'name' => '已提货数',
|
||||
'color' => 'green',
|
||||
'count' => UserStock::query()->sum('hold')
|
||||
],
|
||||
'sy' => [
|
||||
'name' => '待提货数',
|
||||
'color' => 'green',
|
||||
'count' => $sy
|
||||
],
|
||||
];
|
||||
|
||||
$this->content->row(function (Row $row) use ($users) {
|
||||
foreach ($users as $user) {
|
||||
$row->column(2, function (Column $column) use ($user) {
|
||||
$column->append(new InfoBox(
|
||||
$user['name'],
|
||||
'goods',
|
||||
$user['color'],
|
||||
'/admin/stocks',
|
||||
$user['count'],
|
||||
));
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 提货订单数量
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/1 13:51
|
||||
*/
|
||||
public function getUserStockOrderData()
|
||||
{
|
||||
$this->content->row($this->setDivider('会员提货订单'));
|
||||
|
||||
|
||||
$deliver = OrderItem::query()
|
||||
->whereHas('order', function ($q) {
|
||||
$q->paid();
|
||||
})->sum('qty');
|
||||
|
||||
$deliverd = OrderItem::query()
|
||||
->whereHas('order', function ($q) {
|
||||
$q->whereIn('state', [
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_DELIVERED,
|
||||
]);
|
||||
})->sum('qty');
|
||||
|
||||
$users = [
|
||||
'all' => [
|
||||
'name' => '订单总数',
|
||||
'color' => 'blue',
|
||||
'count' => Order::query()->where('type', Order::TYPE_SAMPLE)->count()
|
||||
],
|
||||
'deliver' => [
|
||||
'name' => '待发货',
|
||||
'color' => 'green',
|
||||
'count' => Order::query()
|
||||
->where('type', Order::TYPE_SAMPLE)
|
||||
->paid()
|
||||
->count()
|
||||
],
|
||||
'deliverd' => [
|
||||
'name' => '已发货',
|
||||
'color' => 'green',
|
||||
'count' => Order::query()
|
||||
->where('type', Order::TYPE_SAMPLE)
|
||||
->whereIn('state', [
|
||||
Order::STATUS_DELIVERED,
|
||||
])
|
||||
->count(),
|
||||
],
|
||||
'signed' => [
|
||||
'name' => '已签收',
|
||||
'color' => 'green',
|
||||
'count' => Order::query()
|
||||
->where('type', Order::TYPE_SAMPLE)
|
||||
->whereIn('state', [
|
||||
Order::STATUS_SIGNED,
|
||||
])
|
||||
->count()
|
||||
],
|
||||
];
|
||||
|
||||
$this->content->row(function (Row $row) use ($users) {
|
||||
foreach ($users as $user) {
|
||||
$row->column(2, function (Column $column) use ($user) {
|
||||
$column->append(new InfoBox(
|
||||
$user['name'],
|
||||
'goods',
|
||||
$user['color'],
|
||||
'/admin/stocks',
|
||||
$user['count'],
|
||||
));
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 清理模型缓存
|
||||
*
|
||||
* @Date : 2021/6/8 10:51 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
public function cleanCache(): string
|
||||
{
|
||||
Artisan::call('modelCache:clear');
|
||||
|
||||
return '缓存清理成功';
|
||||
}
|
||||
|
||||
public function setDivider($title)
|
||||
{
|
||||
return <<<HTML
|
||||
<div style="height: 20px; border-bottom: 1px solid #eee; text-align: center;margin-top: 20px;margin-bottom: 20px;">
|
||||
<span style="font-size: 18px; padding: 0 10px;">
|
||||
{$title}
|
||||
</span>
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
|
||||
}
|
||||
17
app/Admin/Controllers/LeadyController.php
Normal file
17
app/Admin/Controllers/LeadyController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Bouns;
|
||||
use Modules\User\Models\Order;
|
||||
|
||||
class LeadyController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$order = Order::find(1);
|
||||
Bouns::addBouns($order, $order->price);
|
||||
dd(111);
|
||||
}
|
||||
}
|
||||
54
app/Admin/Controllers/Material/IndexController.php
Normal file
54
app/Admin/Controllers/Material/IndexController.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\Material;
|
||||
|
||||
use App\Models\Material;
|
||||
use Encore\Admin\Controllers\AdminController;
|
||||
use Encore\Admin\Form;
|
||||
use Encore\Admin\Grid;
|
||||
|
||||
class IndexController extends AdminController
|
||||
{
|
||||
|
||||
/**
|
||||
* Title for current resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '物料/素材';
|
||||
|
||||
/**
|
||||
* Make a grid builder.
|
||||
*
|
||||
* @return Grid
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new Material());
|
||||
|
||||
$grid->column('id', '编号');
|
||||
$grid->column('title', '名称');
|
||||
$grid->column('地址')->display(function () {
|
||||
return $this->cover_url;
|
||||
});
|
||||
$grid->column('created_at', '创建时间');
|
||||
|
||||
return $grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a form builder.
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
protected function form(): Form
|
||||
{
|
||||
$form = new Form(new Material());
|
||||
$form->text('title', '名称');
|
||||
|
||||
$form->image('cover', '图片1')->move('materials/'.date('Y/m/d'));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
100
app/Admin/Controllers/ModuleController.php
Normal file
100
app/Admin/Controllers/ModuleController.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Models\Module;
|
||||
use Encore\Admin\Controllers\AdminController;
|
||||
use Encore\Admin\Grid;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Nwidart\Modules\Facades\Module as ModuleManager;
|
||||
|
||||
class ModuleController extends AdminController
|
||||
{
|
||||
|
||||
protected $title = '模块管理';
|
||||
|
||||
protected function grid(): Grid
|
||||
{
|
||||
$grid = new Grid(new Module());
|
||||
|
||||
$grid->disableBatchActions();
|
||||
$grid->disableFilter();
|
||||
$grid->disableCreateButton();
|
||||
$grid->disablePagination();
|
||||
$grid->disableActions();
|
||||
|
||||
$grid->column('name', '模块名称');
|
||||
$grid->column('alias', '别名');
|
||||
$grid->column('version', '版本');
|
||||
$grid->column('author', '作者');
|
||||
$grid->column('description', '模块简介');
|
||||
$grid->column('enabled', '状态')->bool();
|
||||
$grid->column('id', '操作')->display(function () {
|
||||
if ($this->enabled) {
|
||||
return sprintf('<a href="%s">%s</a>', route('admin.module.disable', $this->name), '禁用');
|
||||
} else {
|
||||
return sprintf('<a href="%s">%s</a>', route('admin.module.enable', $this->name), '启用');
|
||||
}
|
||||
});
|
||||
|
||||
return $grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 禁用模块
|
||||
* @Date : 2021/3/11 1:13 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param $name
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function disable($name): RedirectResponse
|
||||
{
|
||||
try {
|
||||
$module = ModuleManager::find($name);
|
||||
|
||||
$module->disable();
|
||||
|
||||
$class = sprintf('\\%s\\%s\\%s', config('modules.namespace'), $module->getName(), $module->getName());
|
||||
|
||||
if (class_exists($class)) {
|
||||
call_user_func([$class, 'uninstall']);
|
||||
}
|
||||
|
||||
admin_success('Success', $name . '模块禁用成功');
|
||||
} catch (\Exception $exception) {
|
||||
admin_error('Error', $exception->getMessage());
|
||||
}
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 启用模块
|
||||
* @Date : 2021/3/11 1:13 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param $name
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function enable($name): RedirectResponse
|
||||
{
|
||||
try {
|
||||
$module = ModuleManager::find($name);
|
||||
|
||||
$module->enable();
|
||||
|
||||
$class = sprintf('\\%s\\%s\\%s', config('modules.namespace'), $module->getName(), $module->getName());
|
||||
|
||||
if (class_exists($class)) {
|
||||
call_user_func([$class, 'install']);
|
||||
}
|
||||
|
||||
admin_success('Success', $name . '模块启用成功');
|
||||
} catch (\Exception $exception) {
|
||||
admin_error('Error', $exception->getMessage());
|
||||
}
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
}
|
||||
291
app/Admin/Controllers/Platform/DashboardController.php
Normal file
291
app/Admin/Controllers/Platform/DashboardController.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\Platform;
|
||||
|
||||
use Encore\Admin\Layout\Column;
|
||||
use Encore\Admin\Layout\Content;
|
||||
use Encore\Admin\Layout\Row;
|
||||
use Encore\Admin\Widgets\InfoBox;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Modules\Mall\Models\Order;
|
||||
use Modules\Mall\Models\OrderItem;
|
||||
use Modules\User\Models\User;
|
||||
use Modules\User\Models\UserChannel;
|
||||
use Modules\User\Models\UserStock;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function index(Content $content): Content
|
||||
{
|
||||
$this->content = $content->title('数据看板')->description('Description...');
|
||||
$this->getVipUserData();
|
||||
$this->getUserStockData();
|
||||
// $this->getChannelData();
|
||||
return $this->content;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取用户数据
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date : 2021/11/17 11:24
|
||||
*/
|
||||
public function getVipUserData(): Content
|
||||
{
|
||||
$this->content->row($this->setDivider('会员统计'));
|
||||
$users = [
|
||||
'all' => [
|
||||
'name' => '总会员量',
|
||||
'color' => 'blue',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', '>', 1);
|
||||
})->count()
|
||||
],
|
||||
'mo' => [
|
||||
'name' => '月卡会员量',
|
||||
'color' => 'red',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 2);
|
||||
})->count()
|
||||
],
|
||||
'jk' => [
|
||||
'name' => '季卡会员量',
|
||||
'color' => 'red',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 3);
|
||||
})->count()
|
||||
],
|
||||
'nk' => [
|
||||
'name' => '年卡会员量',
|
||||
'color' => 'yellow',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 4);
|
||||
})->count(),
|
||||
],
|
||||
'onlone' => [
|
||||
'name' => '在线会员数',
|
||||
'color' => 'red',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', '>', 1);
|
||||
})
|
||||
->where('status', User::STATUS_INIT)
|
||||
->count(),
|
||||
],
|
||||
'refund' => [
|
||||
'name' => '退费会员数',
|
||||
'color' => 'maroon',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', '>', 1);
|
||||
})
|
||||
->where('status', User::STATUS_REFUND)
|
||||
->count(),
|
||||
],
|
||||
];
|
||||
|
||||
$this->content->row(function (Row $row) use ($users) {
|
||||
foreach ($users as $user) {
|
||||
$row->column(2, function (Column $column) use ($user) {
|
||||
$column->append(new InfoBox(
|
||||
$user['name'],
|
||||
'users',
|
||||
$user['color'],
|
||||
'/admin/platform/vips',
|
||||
$user['count'],
|
||||
));
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取渠道数据
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/10/14 13:55
|
||||
*/
|
||||
public function getChannelData()
|
||||
{
|
||||
$this->content->row($this->setDivider('渠道数据'));
|
||||
$channels = UserChannel::query()->get();
|
||||
|
||||
$users = [
|
||||
'all' => [
|
||||
'name' => '总会员量',
|
||||
'color' => 'blue',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', '>', 2);
|
||||
})
|
||||
],
|
||||
'jk' => [
|
||||
'name' => '季卡会员量',
|
||||
'color' => 'red',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 3);
|
||||
})
|
||||
],
|
||||
'nk' => [
|
||||
'name' => '年卡会员量',
|
||||
'color' => 'yellow',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 4);
|
||||
}),
|
||||
],
|
||||
'cs' => [
|
||||
'name' => '创始会员量',
|
||||
'color' => 'aqua',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 5);
|
||||
}),
|
||||
],
|
||||
'hh' => [
|
||||
'name' => '合伙人量',
|
||||
'color' => 'navy',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 6);
|
||||
}),
|
||||
],
|
||||
// 'onlone' => [
|
||||
// 'name' => '在线会员数',
|
||||
// 'color' => 'red',
|
||||
// 'count' => User::query()
|
||||
// ->whereHas('identities', function ($q) {
|
||||
// $q->where('id', '>', 2);
|
||||
// })
|
||||
// ->where('status', User::STATUS_INIT),
|
||||
// ],
|
||||
'refund' => [
|
||||
'name' => '退费会员数',
|
||||
'color' => 'maroon',
|
||||
'count' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', '>', 2);
|
||||
})
|
||||
->where('status', User::STATUS_REFUND),
|
||||
],
|
||||
];
|
||||
foreach ($channels as $channel) {
|
||||
$this->channel_id = $channel->id;
|
||||
$this->content->row(function (Row $row) use ($channel, $users) {
|
||||
foreach ($users as $user) {
|
||||
$row->column(2, function (Column $column) use ($channel, $user) {
|
||||
$column->append(new InfoBox(
|
||||
$channel->name.'-'.$user['name'],
|
||||
'users',
|
||||
$user['color'],
|
||||
'/admin/platform/vips?channel_id='.$channel->id,
|
||||
(clone $user['count'])->where('channel_id', $channel->id)->count(),
|
||||
));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 用户水数量
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/1 13:35
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserStockData()
|
||||
{
|
||||
$this->content->row($this->setDivider('会员库存数'));
|
||||
|
||||
$all = UserStock::query()->sum('stock');
|
||||
$holds = UserStock::query()->sum('hold');
|
||||
$sy = bcsub($all, $holds);
|
||||
|
||||
$users = [
|
||||
'all' => [
|
||||
'name' => '累计总箱数',
|
||||
'color' => 'blue',
|
||||
'count' => $all
|
||||
],
|
||||
'stock' => [
|
||||
'name' => '累计提货数',
|
||||
'color' => 'green',
|
||||
'count' => $holds
|
||||
],
|
||||
'sy' => [
|
||||
'name' => '累计剩余',
|
||||
'color' => 'green',
|
||||
'count' => $sy
|
||||
],
|
||||
'online' => [
|
||||
'name' => '线上发货',
|
||||
'color' => 'green',
|
||||
'count' => OrderItem::query()
|
||||
->whereHas('order', function ($q) {
|
||||
$q->where('type', Order::TYPE_SAMPLE)
|
||||
->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
])->where('channel', Order::CHANNEL_USER);
|
||||
})
|
||||
->sum('qty')
|
||||
],
|
||||
'offline' => [
|
||||
'name' => '线下发货',
|
||||
'color' => 'green',
|
||||
'count' => OrderItem::query()
|
||||
->whereHas('order', function ($q) {
|
||||
$q->where('type', Order::TYPE_SAMPLE)
|
||||
->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
])->where('channel', Order::CHANNEL_SYSTEM);
|
||||
})
|
||||
->sum('qty')
|
||||
],
|
||||
];
|
||||
|
||||
$this->content->row(function (Row $row) use ($users) {
|
||||
foreach ($users as $user) {
|
||||
$row->column(2, function (Column $column) use ($user) {
|
||||
$column->append(new InfoBox(
|
||||
$user['name'],
|
||||
'goods',
|
||||
$user['color'],
|
||||
'/admin/users/stocks',
|
||||
$user['count'],
|
||||
));
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setDivider($title)
|
||||
{
|
||||
return <<<HTML
|
||||
<div style="height: 20px; border-bottom: 1px solid #eee; text-align: center;margin-top: 20px;margin-bottom: 20px;">
|
||||
<span style="font-size: 18px; padding: 0 10px;">
|
||||
{$title}
|
||||
</span>
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
|
||||
}
|
||||
140
app/Admin/Controllers/Platform/ExperienceController.php
Normal file
140
app/Admin/Controllers/Platform/ExperienceController.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\Platform;
|
||||
|
||||
use App\Admin\Actions\LinkStockOrderDeliver;
|
||||
use App\Admin\Actions\LinkVipOrderRefund;
|
||||
use Encore\Admin\Controllers\AdminController;
|
||||
use Encore\Admin\Grid;
|
||||
use Modules\Gout\Http\Controllers\Admin\Action\Audit;
|
||||
use Modules\Gout\Models\GoutCase;
|
||||
use Modules\Gout\Renderable\CaseData;
|
||||
use Modules\Gout\Renderable\CaseSymptoms;
|
||||
use Modules\User\Models\User;
|
||||
use Modules\User\Models\UserStock;
|
||||
|
||||
class ExperienceController extends AdminController
|
||||
{
|
||||
|
||||
protected $title = '体验官审核';
|
||||
|
||||
public function grid(): Grid
|
||||
{
|
||||
$grid = new Grid(new GoutCase());
|
||||
$grid->disableCreateButton();
|
||||
$grid->model()->with(['symptoms', 'user', 'user.sign', 'user.userStock'])
|
||||
->withCount(['logs', 'surveys'])
|
||||
->where('type', GoutCase::TYPE_TY);
|
||||
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$actions->disableEdit();
|
||||
$actions->disableDelete();
|
||||
$actions->disableView();
|
||||
|
||||
if ($actions->row->canAudit()) {
|
||||
$actions->add(new Audit());
|
||||
}
|
||||
|
||||
if ($actions->row->manage_status == GoutCase::MANAGE_STATUS_DELIVER) {
|
||||
$actions->add(new LinkStockOrderDeliver());
|
||||
}
|
||||
if ($actions->row->manage_status == GoutCase::MANAGE_STATUS_REFUND) {
|
||||
$actions->add(new LinkVipOrderRefund());
|
||||
}
|
||||
});
|
||||
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->column(1 / 2, function (Grid\Filter $filter) {
|
||||
$filter->like('name', '姓名');
|
||||
$filter->equal('mobile', '手机号');
|
||||
});
|
||||
$filter->column(1 / 2, function (Grid\Filter $filter) {
|
||||
$filter->equal('status', '状态')->select((new GoutCase())->status_map);
|
||||
});
|
||||
});
|
||||
|
||||
$grid->column('id', '#ID#');
|
||||
$grid->column('name', '姓名');
|
||||
$grid->column('mobile', '手机号');
|
||||
$grid->column('建档信息')
|
||||
->display(function ($title, $column) {
|
||||
return '查看';
|
||||
})->modal('建档信息', CaseData::class);
|
||||
|
||||
$grid->column('报告数据')
|
||||
->display(function ($title, $column) {
|
||||
return '查看';
|
||||
})->modal('亚健康数据', CaseSymptoms::class);
|
||||
|
||||
$grid->column('symptoms', '症状')
|
||||
->display(function () {
|
||||
return $this->symptoms->pluck('title');
|
||||
})->label();
|
||||
$grid->column('是否关注')
|
||||
->display(function () {
|
||||
return $this->user->isOfficialSubscribe();
|
||||
})
|
||||
->bool();
|
||||
//
|
||||
$grid->column('缴纳保证金')
|
||||
->display(function () {
|
||||
return $this->user->isExperiencePrice() ? '已缴' : '待缴';
|
||||
})
|
||||
->label([
|
||||
'已缴' => 'primary',
|
||||
'待缴' => 'success',
|
||||
]);
|
||||
|
||||
$grid->column('是否收货')
|
||||
->display(function () {
|
||||
return $this->user->userStock->stock_order_status_text;
|
||||
})
|
||||
->label(UserStock::STOCK_ORDER_STATUS_MAP);
|
||||
|
||||
$grid->column('is_coupon', '是否发券')
|
||||
->using(GoutCase::COUPONS)
|
||||
->label(GoutCase::COUPONS_MAP);
|
||||
|
||||
$grid->column('喝水打卡')
|
||||
->display(function () {
|
||||
return $this->user->sign->counts;
|
||||
});
|
||||
//
|
||||
$grid->column('完结报告')
|
||||
->display(function () {
|
||||
return $this->logs_count > 1 ? '已上传' : '待上传';
|
||||
})
|
||||
->label([
|
||||
'已上传' => 'primary',
|
||||
'待上传' => 'success',
|
||||
]);
|
||||
//
|
||||
$grid->column('是否退保')
|
||||
->display(function () {
|
||||
return $this->user->isExperiencePriceRefund() ? '是' : '否';
|
||||
})
|
||||
->label([
|
||||
'是' => 'primary',
|
||||
'否' => 'success',
|
||||
]);
|
||||
$grid->column('好转反馈')
|
||||
->display(function () {
|
||||
return $this->surveys_count;
|
||||
});
|
||||
|
||||
$grid->column('manage_status', '状态')
|
||||
->using((new GoutCase())->manage_status_map)
|
||||
->label([
|
||||
GoutCase::MANAGE_STATUS_INIT => 'primary',
|
||||
GoutCase::MANAGE_STATUS_DELIVER => 'success',
|
||||
GoutCase::MANAGE_STATUS_REFUND => 'danger',
|
||||
GoutCase::MANAGE_STATUS_PASS => 'info',
|
||||
GoutCase::MANAGE_STATUS_FINISH => 'warning',
|
||||
]);
|
||||
|
||||
$grid->column('created_at', '创建时间');
|
||||
|
||||
return $grid;
|
||||
}
|
||||
|
||||
}
|
||||
257
app/Admin/Controllers/Platform/VipController.php
Normal file
257
app/Admin/Controllers/Platform/VipController.php
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\Platform;
|
||||
|
||||
use App\Admin\Actions\LinkCreateAddress;
|
||||
use Carbon\Carbon;
|
||||
use Encore\Admin\Controllers\AdminController;
|
||||
use Encore\Admin\Facades\Admin;
|
||||
use Encore\Admin\Form;
|
||||
use Encore\Admin\Grid;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Modules\User\Http\Controllers\Admin\Actions\AddUserRemark;
|
||||
use Modules\User\Http\Controllers\Admin\Actions\JoinIdentity;
|
||||
use Modules\User\Http\Controllers\Admin\Actions\UserStatusInit;
|
||||
use Modules\User\Http\Controllers\Admin\Actions\UserStatusRefund;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\IdentityLog;
|
||||
use Modules\User\Models\IdentityMiddle;
|
||||
use Modules\User\Models\User;
|
||||
use Modules\User\Models\UserChannel;
|
||||
use Modules\User\Renderable\UserLog;
|
||||
|
||||
class VipController extends AdminController
|
||||
{
|
||||
|
||||
protected $title = '会员管理';
|
||||
|
||||
/**
|
||||
* Notes : 用户管理列表
|
||||
*
|
||||
* @Date : 2021/3/11 1:59 下午
|
||||
* @Author : <Jason.C>
|
||||
* @return Grid
|
||||
*/
|
||||
public function grid(): Grid
|
||||
{
|
||||
$grid = new Grid(new User());
|
||||
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$actions->disableEdit();
|
||||
$actions->disableDelete();
|
||||
$actions->disableView();
|
||||
if ($actions->row->status == User::STATUS_INIT) {
|
||||
$actions->add(new UserStatusRefund());
|
||||
}
|
||||
if ($actions->row->status == User::STATUS_REFUND) {
|
||||
$actions->add(new UserStatusInit());
|
||||
}
|
||||
|
||||
$actions->add(new JoinIdentity());
|
||||
$actions->add(new AddUserRemark());
|
||||
$actions->add(new LinkCreateAddress());
|
||||
|
||||
});
|
||||
|
||||
$grid->quickSearch('username')->placeholder('快速搜索用户名');
|
||||
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->column(1 / 3, function (Grid\Filter $filter) {
|
||||
$filter->like('username', '用户名');
|
||||
$filter->equal('channel_id', '渠道')->select(UserChannel::pluck('name', 'id'));
|
||||
});
|
||||
|
||||
$filter->column(1 / 3, function (Grid\Filter $filter) {
|
||||
$filter->like('info.nickname', '用户昵称');
|
||||
});
|
||||
$filter->column(1 / 3, function (Grid\Filter $filter) {
|
||||
$filter->equal('identities.id', '身份')
|
||||
->select(Identity::query()->where('id', '>', 1)->pluck('name', 'id'));
|
||||
});
|
||||
});
|
||||
|
||||
$grid->model()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', '>', 1);
|
||||
})
|
||||
->withCount(['addresses', 'logs'])
|
||||
->with(['info', 'parent', 'identities', 'addresses', 'vipOrders', 'userStock', 'logs']);
|
||||
|
||||
//序号 姓名 手机号 会员类型 会员编号 缴费金额 加入时间 状态(正常,退费) 用箱数 提货箱数 剩余箱数
|
||||
$grid->column('id', '序号');
|
||||
$grid->column('username', '手机号');
|
||||
$grid->column('identities', '会员类型')
|
||||
->display(function () {
|
||||
$data = [];
|
||||
foreach ($this->identities as $identity) {
|
||||
$data[] = $identity->name;
|
||||
}
|
||||
return $data;
|
||||
})
|
||||
->label();
|
||||
$grid->column('serial', '会员编号')
|
||||
->display(function () {
|
||||
$data = [];
|
||||
foreach ($this->identities as $identity) {
|
||||
$data[] = $identity->serial_prefix.$identity->getOriginal('pivot_serial');
|
||||
}
|
||||
return $data;
|
||||
})
|
||||
->label();
|
||||
|
||||
$grid->column('price', '缴费金额')
|
||||
->display(function () {
|
||||
return $this->getOpenVipPrices();
|
||||
})
|
||||
->label();
|
||||
|
||||
$grid->column('created_at', '加入时间');
|
||||
$grid->column('status', '状态')
|
||||
->using(User::STATUS)
|
||||
->label();
|
||||
$grid->column('userStock.stock', '总箱数');
|
||||
$grid->column('userStock.hold', '提货箱数');
|
||||
$grid->column('userStock.residue', '剩余箱数');
|
||||
$grid->column('addresses_count', '收货地址')
|
||||
->link(function () {
|
||||
return route('admin.mall.addresses.index', ['user_id' => $this->id]);
|
||||
}, '_self');
|
||||
$grid->column('logs_count', '备注')
|
||||
->modal('备注信息', UserLog::class);
|
||||
|
||||
$grid->disableExport(false);
|
||||
$grid->export(function ($export) {
|
||||
$export->column('identities', function ($value, $original) {
|
||||
return strip_tags($value);
|
||||
});
|
||||
$export->column('serial', function ($value, $original) {
|
||||
return strip_tags($value);
|
||||
});
|
||||
$export->column('price', function ($value, $original) {
|
||||
return strip_tags($value);
|
||||
});
|
||||
$export->column('status', function ($value, $original) {
|
||||
return strip_tags($value);
|
||||
});
|
||||
|
||||
// $export->column('use_way', function ($value, $original) {
|
||||
// return strip_tags($value);
|
||||
// });
|
||||
// $export->column('所属用户', function ($value, $original) {
|
||||
// return iconv('gb2312//ignore', 'utf-8',
|
||||
// iconv('utf-8', 'gb2312//ignore', strip_tags(str_replace(" ", " ", $value))));
|
||||
// });
|
||||
//
|
||||
// $export->column('couponGrant.code', function ($value, $original) {
|
||||
// return $value."\n";
|
||||
// });
|
||||
|
||||
$export->except(['addresses_count', 'logs_count']);
|
||||
|
||||
$export->filename($this->title.date("YmdHis"));
|
||||
});
|
||||
|
||||
return $grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 编辑表单
|
||||
*
|
||||
* @Date : 2021/7/15 5:09 下午
|
||||
* @Author : <Jason.C>
|
||||
* @return Form
|
||||
* @throws Exception
|
||||
*/
|
||||
public function form(): Form
|
||||
{
|
||||
// if (! config('user.create_user_by_admin')) {
|
||||
// throw new Exception('不运允许操作用户');
|
||||
// }
|
||||
|
||||
Admin::script(" $(document.body).append(`<script src='/vendor/js/setStock.js'>`); ");
|
||||
$form = new Form(new User());
|
||||
|
||||
//姓名 手机号 身份 编号 (数字从1开始) 缴费金额 加入日期(当天) 总箱数
|
||||
$form->text('info.nickname', '姓名')->required();
|
||||
$form->text('username', '手机号')
|
||||
->required()
|
||||
->rules(['phone:CN,mobile', 'unique:users,username,{{id}}'], [
|
||||
'phone' => '手机号格式错误'
|
||||
]);
|
||||
$form->select('join_identity_id', '加入身份')
|
||||
->options(Identity::where('order', '>', 2)->pluck('name', 'id'))
|
||||
->required();
|
||||
$form->text('serial', '编号')->value($form->model()->getNewSerial(8))->required();
|
||||
$form->number('price', '缴费金额')
|
||||
->default(1)
|
||||
->required();
|
||||
|
||||
$form->date('join_at', '加入时间')->default(now())->required();
|
||||
$form->number('stock', '总箱数')
|
||||
->default(0)
|
||||
->setLabelClass(['identity_stock'])
|
||||
->required();
|
||||
|
||||
$form->ignore(['join_at', 'price', 'serial', 'stock', 'join_identity_id']);
|
||||
|
||||
$form->saving(function (Form $form) {
|
||||
$exists = IdentityMiddle::query()->where('serial', $form->serial)->first();
|
||||
if ($exists) {
|
||||
$error = new MessageBag([
|
||||
'title' => '错误',
|
||||
'message' => '编号已经存在',
|
||||
]);
|
||||
|
||||
return back()->withInput()->with(compact('error'));
|
||||
}
|
||||
});
|
||||
|
||||
$form->saved(function (Form $form) {
|
||||
$user = $form->model();
|
||||
$user->update([
|
||||
'created_at' => Carbon::parse(request()->jion_at)->startOfDay()
|
||||
]);
|
||||
$user->createOrder(request()->join_identity_id, 1, request()->price, request()->stock, [
|
||||
'serial' => request()->serial,
|
||||
'channel' => IdentityLog::CHANNEL_SYSTEM,
|
||||
]);//创建订单
|
||||
});
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : User 列表选择, 这里没有判断,用户是否已经有店铺了,如果判断的情况,可能导致当前用户 无法被选中
|
||||
*
|
||||
* @Date : 2021/5/6 4:35 下午
|
||||
* @Author : <Jason.C>
|
||||
*/
|
||||
public function ajax(Request $request)
|
||||
{
|
||||
$q = $request->get('q');
|
||||
|
||||
return User::leftJoin('user_infos as info', 'users.id', '=', 'info.user_id')
|
||||
->where('username', 'like', "%$q%")
|
||||
->orWhere('info.nickname', 'like', "%$q%")
|
||||
->select('id', DB::raw('CONCAT(username, " [", info.nickname, "]") as text'))
|
||||
->paginate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取库存
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/7 15:23
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function stock(Request $request)
|
||||
{
|
||||
$q = $request->get('q');
|
||||
$identity = Identity::find($q);
|
||||
return ['status_code' => 200, 'value' => $identity->stock];
|
||||
}
|
||||
|
||||
}
|
||||
85
app/Admin/Controllers/Platform/VipOrderController.php
Normal file
85
app/Admin/Controllers/Platform/VipOrderController.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\Platform;
|
||||
|
||||
use Encore\Admin\Controllers\AdminController;
|
||||
use Encore\Admin\Form;
|
||||
use Encore\Admin\Grid;
|
||||
use Exception;
|
||||
use Modules\User\Http\Controllers\Admin\Actions\Pay;
|
||||
use Modules\User\Http\Controllers\Admin\Actions\Refund;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\Order;
|
||||
|
||||
class VipOrderController extends AdminController
|
||||
{
|
||||
|
||||
protected $title = '体验官退款';
|
||||
|
||||
/**
|
||||
* Notes: 升级订单
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date : 2021/6/7 15:19
|
||||
* @return Grid
|
||||
*/
|
||||
public function grid(): Grid
|
||||
{
|
||||
try {
|
||||
trait_exists('Modules\Payment\Traits\WithPayments');
|
||||
$grid = new Grid(new Order());
|
||||
$grid->model()
|
||||
->whereHas('identity', function ($q) {
|
||||
$q->ty();
|
||||
})
|
||||
->whereIn('state',[Order::STATE_SUCCESS,Order::STATE_REFUND])
|
||||
->latest();
|
||||
|
||||
$grid->disableCreateButton();
|
||||
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$actions->disableEdit();
|
||||
$actions->disableDelete();
|
||||
$actions->disableView();
|
||||
if ($actions->row->canRefund()) {
|
||||
$actions->add(new Refund());
|
||||
}
|
||||
});
|
||||
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->column(1 / 2, function (Grid\Filter $filter) {
|
||||
$filter->like('user.username', '用户名');
|
||||
});
|
||||
|
||||
$filter->column(1 / 2, function (Grid\Filter $filter) {
|
||||
$filter->equal('state', '状态')->select(Order::STATES);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$grid->column('id', '用户ID');
|
||||
$grid->column('升级用户')->display(function () {
|
||||
return $this->user->username."({$this->user->info->nickname})";
|
||||
});
|
||||
$grid->column('identity.name', '身份');
|
||||
$grid->column('price', '金额');
|
||||
$grid->column('state', '状态')->using(Order::STATES)->label();
|
||||
$grid->column('type', '类型')->using(Order::TYPES)->label();
|
||||
$grid->column('created_at', '升级时间');
|
||||
|
||||
return $grid;
|
||||
} catch (Exception $exception) {
|
||||
dd('Payment 模块不存在,无法加载订单数据');
|
||||
}
|
||||
}
|
||||
|
||||
public function form(): Form
|
||||
{
|
||||
$form = new Form(new Order());
|
||||
|
||||
$form->decimal('price', '金额')->required();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
123
app/Admin/Controllers/TestController.php
Normal file
123
app/Admin/Controllers/TestController.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Bonus\IdentityBonus;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Liuhelong\LaravelAdmin\Wechat\Models\WechatOffiaccountUser;
|
||||
use Modules\Coupon\Models\Coupon;
|
||||
use Modules\Coupon\Traits\WithCoupon;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\Order;
|
||||
use Modules\User\Models\UserInvite;
|
||||
use Modules\User\Models\UserStockLog;
|
||||
use Modules\User\Models\UserWechat;
|
||||
use Modules\User\Models\UserWechatOfficial;
|
||||
use Modules\User\Traits\RankDataTrait;
|
||||
use Modules\User\Traits\WechatTrait;
|
||||
use Vinkla\Hashids\Facades\Hashids;
|
||||
|
||||
class TestController extends Controller
|
||||
{
|
||||
use WithCoupon, WechatTrait, RankDataTrait;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$identities= Identity::all();
|
||||
dd($identities->toArray());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 清空数据表的操作,为了测试用的
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/11/23 4:54 下午
|
||||
*/
|
||||
public function truncate(Request $request)
|
||||
{
|
||||
$name = $request->name;
|
||||
$is_test = config('app.is_test');
|
||||
dump('is_test'.$is_test);
|
||||
|
||||
if ($name != 'skyxu') {
|
||||
dd('name不对');
|
||||
}
|
||||
|
||||
if (! $is_test) {
|
||||
dd('不是测试环境');
|
||||
}
|
||||
|
||||
$tables = [
|
||||
'admin_operation_log',
|
||||
'bouns',
|
||||
'bouns_orders',
|
||||
'bouns_user_perves',
|
||||
'coupon_grants',
|
||||
'coupon_item_use_logs',
|
||||
'coupon_use_logs',
|
||||
'failed_jobs',
|
||||
'gout_case_log_symptoms',
|
||||
'gout_case_logs',
|
||||
'gout_case_timelines',
|
||||
'gout_case_symptom',
|
||||
'gout_cases',
|
||||
'gout_surveys',
|
||||
'gout_votes',
|
||||
'jobs',
|
||||
'linker_relations',
|
||||
'linkers',
|
||||
'mall_addresses',
|
||||
'mall_order_expresses',
|
||||
'mall_order_items',
|
||||
'mall_orders',
|
||||
'mall_carts',
|
||||
'mall_refund_items',
|
||||
'mall_refund_logs',
|
||||
'mall_refunds',
|
||||
'mall_refund_expresses',
|
||||
'notifications',
|
||||
'payment_refunds',
|
||||
'payments',
|
||||
'user_account_logs',
|
||||
'user_accounts',
|
||||
'user_identity',
|
||||
'user_identity_logs',
|
||||
'user_identity_coupons',
|
||||
'user_infos',
|
||||
'user_invites',
|
||||
'user_logs',
|
||||
'user_orders',
|
||||
'user_perves',
|
||||
'user_relations',
|
||||
'user_sign_logs',
|
||||
'user_signs',
|
||||
'user_sms',
|
||||
'user_stock_logs',
|
||||
'user_stocks',
|
||||
'user_wechat_apps',
|
||||
'user_wechat_minis',
|
||||
'user_wechat_officials',
|
||||
'user_wechats',
|
||||
'users',
|
||||
'versions',
|
||||
'wechat_offiaccount_event_logs',
|
||||
'withdraw_alipay_accounts',
|
||||
'withdraw_bank_accounts',
|
||||
'withdraw_logs',
|
||||
'withdraws',
|
||||
'personal_access_tokens',
|
||||
];
|
||||
foreach ($tables as $table) {
|
||||
DB::table($table)->truncate();
|
||||
}
|
||||
dd('清理成功');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
29
app/Admin/Extensions/CleanCache.php
Normal file
29
app/Admin/Extensions/CleanCache.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Extensions;
|
||||
|
||||
class CleanCache
|
||||
{
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$url = route('admin.cleanCache');
|
||||
|
||||
return <<<HTML
|
||||
<li data-toggle="tooltip" data-placement="bottom" title="清除缓存">
|
||||
<a href="javascript:void(0);" class="clean-cache">
|
||||
<i class="fa fa-trash-o"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<script>
|
||||
$('.clean-cache').click(function () {
|
||||
$.get('{$url}', function (data) {
|
||||
toastr.success(data)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
HTML;
|
||||
}
|
||||
|
||||
}
|
||||
10
app/Admin/Routes/material.php
Normal file
10
app/Admin/Routes/material.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
|
||||
Route::group([
|
||||
'namespace' => 'Material',
|
||||
], function (Router $router) {
|
||||
$router->resource('materials', 'IndexController');
|
||||
|
||||
});
|
||||
12
app/Admin/Routes/modules.php
Normal file
12
app/Admin/Routes/modules.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group([
|
||||
'prefix' => 'modules',
|
||||
], function (Router $router) {
|
||||
$router->get('', 'ModuleController@index');
|
||||
$router->get('{name}/disable', 'ModuleController@disable')->name('module.disable');
|
||||
$router->get('{name}/enable', 'ModuleController@enable')->name('module.enable');
|
||||
});
|
||||
15
app/Admin/Routes/platform.php
Normal file
15
app/Admin/Routes/platform.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
|
||||
Route::group([
|
||||
'namespace' => 'Platform',
|
||||
'prefix' => 'platform',
|
||||
], function (Router $router) {
|
||||
$router->resource('experiences', 'ExperienceController');//体验官审核
|
||||
$router->resource('vip_orders', 'VipOrderController');//体验官审核
|
||||
$router->resource('vips', 'VipController');//会员管理
|
||||
$router->get('identity_stock', 'VipController@stock')->name('platform.identity_stock');;//会员管理
|
||||
$router->get('dashboard', 'DashboardController@index');
|
||||
|
||||
});
|
||||
12
app/Admin/Routes/test.php
Normal file
12
app/Admin/Routes/test.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group([
|
||||
'prefix' => 'test',
|
||||
], function (Router $router) {
|
||||
$router->get('', 'TestController@index');
|
||||
$router->get('truncate', 'TestController@truncate');
|
||||
$router->get('leady', 'LeadyController@index');
|
||||
});
|
||||
103
app/Admin/Traits/WithUploads.php
Normal file
103
app/Admin/Traits/WithUploads.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Traits;
|
||||
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
|
||||
trait WithUploads
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 单张封面图上传
|
||||
*
|
||||
* @Date : 2021/4/25 2:06 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param \Encore\Admin\Form $form
|
||||
* @param string $filed
|
||||
* @param string $label
|
||||
*/
|
||||
public function cover(Renderable $form, string $filed = 'cover', string $label = '封面图片')
|
||||
{
|
||||
$cover = $form->image($filed, $label)
|
||||
->move('images/'.date('Y/m/d'))
|
||||
->uniqueName()
|
||||
->removable()
|
||||
->retainable();
|
||||
|
||||
$waterConfig = config('admin.image_water');
|
||||
|
||||
if (! empty($waterConfig)) {
|
||||
$cover->insert(...$waterConfig);
|
||||
}
|
||||
|
||||
$coverThumb = config('admin.cover_thumb');
|
||||
|
||||
if (! empty($coverThumb)) {
|
||||
$cover->thumbnail($coverThumb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 上传视频
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/30 9:44
|
||||
* @param Renderable $form
|
||||
* @param string $filed
|
||||
* @param string $label
|
||||
*/
|
||||
public function video(Renderable $form, string $filed = 'path', string $label = '视频')
|
||||
{
|
||||
$form->file($filed, $label)
|
||||
->move('videos/'.date('Y/m/d'))
|
||||
->uniqueName()
|
||||
->removable()
|
||||
->downloadable()
|
||||
->retainable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 统一的多图上传
|
||||
*
|
||||
* @Date : 2021/4/25 2:06 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param \Encore\Admin\Form $form
|
||||
* @param string $filed
|
||||
* @param string $label
|
||||
*/
|
||||
public function pictures(Renderable $form, string $filed = 'pictures', string $label = '多图轮播')
|
||||
{
|
||||
$pictures = $form->multipleImage($filed, $label)
|
||||
->move('images/'.date('Y/m/d'))
|
||||
->uniqueName()
|
||||
->removable()
|
||||
->retainable();
|
||||
|
||||
// 多图如果开启排序的话,会报错,暂时没由解决办法 ->sortable()
|
||||
$waterConfig = config('admin.image_water');
|
||||
|
||||
if (! empty($waterConfig)) {
|
||||
$pictures->insert(...$waterConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 统一的附件上传
|
||||
*
|
||||
* @Date : 2021/4/25 3:03 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param \Illuminate\Contracts\Support\Renderable $form
|
||||
* @param string $filed
|
||||
* @param string $label
|
||||
*/
|
||||
public function attachments(Renderable $form, string $filed = 'attachments', string $label = '内容附件')
|
||||
{
|
||||
$form->multipleFile($filed, $label)
|
||||
->move('attachments/'.date('Y/m/d'))
|
||||
->uniqueName()
|
||||
->removable()
|
||||
->retainable()
|
||||
->sortable();
|
||||
}
|
||||
|
||||
}
|
||||
62
app/Admin/bootstrap.php
Normal file
62
app/Admin/bootstrap.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Laravel-admin - admin builder based on Laravel.
|
||||
* @author z-song <https://github.com/z-song>
|
||||
* Bootstraper for Admin.
|
||||
* Here you can remove builtin form field:
|
||||
* Encore\Admin\Form::forget(['map', 'editor']);
|
||||
* Or extend custom form field:
|
||||
* Encore\Admin\Form::extend('php', PHPEditor::class);
|
||||
* Or require js and css assets:
|
||||
* Admin::css('/packages/prettydocs/css/styles.css');
|
||||
* Admin::js('/packages/prettydocs/js/main.js');
|
||||
*/
|
||||
|
||||
use App\Admin\Extensions\CleanCache;
|
||||
use Encore\Admin\Facades\Admin;
|
||||
use Encore\Admin\Form;
|
||||
use Encore\Admin\Grid;
|
||||
use Encore\Admin\Show;
|
||||
use Encore\Admin\Widgets\Navbar;
|
||||
|
||||
Form::forget(['map', 'editor']);
|
||||
|
||||
Admin::navbar(function (Navbar $navbar) {
|
||||
$navbar->right(new CleanCache());
|
||||
$navbar->right(new Navbar\Fullscreen());
|
||||
});
|
||||
|
||||
Form::init(function (Form $form) {
|
||||
$form->disableEditingCheck();
|
||||
$form->disableCreatingCheck();
|
||||
$form->disableViewCheck();
|
||||
|
||||
$form->tools(function (Form\Tools $tools) {
|
||||
$tools->disableView();
|
||||
// $tools->disableDelete();
|
||||
// $tools->disableList();
|
||||
});
|
||||
});
|
||||
|
||||
Show::init(function (Show $show) {
|
||||
$show->panel()
|
||||
->tools(function ($tools) {
|
||||
// $tools->disableEdit();
|
||||
// $tools->disableList();
|
||||
$tools->disableDelete();
|
||||
});;
|
||||
});
|
||||
|
||||
Grid::init(function (Grid $grid) {
|
||||
$grid->disableExport();
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$actions->disableView();
|
||||
});
|
||||
$grid->disableBatchActions();
|
||||
$grid->filter(function ($filter) {
|
||||
$filter->disableIdFilter();
|
||||
});
|
||||
// $grid->expandFilter();
|
||||
});
|
||||
|
||||
24
app/Admin/routes.php
Normal file
24
app/Admin/routes.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Encore\Admin\Facades\Admin;
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Admin::routes();
|
||||
|
||||
Route::group([
|
||||
'prefix' => config('admin.route.prefix'),
|
||||
'namespace' => config('admin.route.namespace'),
|
||||
'middleware' => config('admin.route.middleware'),
|
||||
'as' => config('admin.route.as'),
|
||||
], function (Router $router) {
|
||||
|
||||
$router->get('/', 'HomeController@index')->name('home');
|
||||
|
||||
$router->get('clean_cache', 'HomeController@cleanCache')->name('cleanCache');
|
||||
|
||||
foreach (glob(admin_path('Routes') . '/*.php') as $routeFile) {
|
||||
require $routeFile;
|
||||
}
|
||||
|
||||
});
|
||||
12
app/Api/Controllers/Controller.php
Normal file
12
app/Api/Controllers/Controller.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Controllers;
|
||||
|
||||
use Jason\Api\Traits\ApiResponse;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
|
||||
use ApiResponse;
|
||||
}
|
||||
159
app/Api/Controllers/Data/IndexController.php
Normal file
159
app/Api/Controllers/Data/IndexController.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Controllers\Data;
|
||||
|
||||
use App\Api\Controllers\Controller;
|
||||
use App\Api\Resources\Order\OrderDataCollection;
|
||||
use App\Api\Resources\User\UserDataCollection;
|
||||
use App\Api\Resources\User\UserDataResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Coupon\Http\Resources\User\UserBaseResource;
|
||||
use Modules\Mall\Models\Order;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class IndexController extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
$all = 1000;
|
||||
$sold = Order::query()
|
||||
->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])
|
||||
->count();
|
||||
$donate = (new User())->getALlJzCount();
|
||||
|
||||
$orderQuery = Order::query()->where('type', Order::TYPE_NORMAL);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
$amount = (clone $orderQuery)->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])->sum('amount');
|
||||
|
||||
$data = [
|
||||
'activities' => [
|
||||
'all' => $all,
|
||||
'donate' => $donate,
|
||||
'residue' => bcsub($all, $donate),
|
||||
],
|
||||
'orders' => [
|
||||
'users' => User::query()->whereHas('orders', function ($q) {
|
||||
$q->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])->where('type', Order::TYPE_NORMAL);
|
||||
})->count(),
|
||||
|
||||
'all' => (clone $orderQuery)
|
||||
->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])->count(),
|
||||
'paid' => (clone $orderQuery)->where('state', Order::STATUS_PAID)->count(),
|
||||
'delivered' => (clone $orderQuery)->where('state', Order::STATUS_DELIVERED)->count(),
|
||||
'signed' => (clone $orderQuery)->where('state', Order::STATUS_SIGNED)->count(),
|
||||
'completed' => (clone $orderQuery)->where('state', Order::STATUS_COMPLETED)->count(),
|
||||
'amount' => floatval($amount),
|
||||
],
|
||||
'users' => [
|
||||
'all' => User::count(),
|
||||
'yk' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 2);
|
||||
})->count(),
|
||||
'jk' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 3);
|
||||
})->count(),
|
||||
'nk' => User::query()
|
||||
->whereHas('identities', function ($q) {
|
||||
$q->where('id', 4);
|
||||
})->count(),
|
||||
]
|
||||
];
|
||||
|
||||
return $this->success($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: description
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2023/1/5 13:50
|
||||
*/
|
||||
public function orders(Request $request)
|
||||
{
|
||||
$status = $request->status ?? 'all';
|
||||
|
||||
$orders = Order::query()
|
||||
->where('type', Order::TYPE_NORMAL)
|
||||
->when($status !== 'all', function ($q) use ($status) {
|
||||
$q->where('state', $status);
|
||||
}, function ($q) {
|
||||
$q->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
]);
|
||||
})
|
||||
->paginate();
|
||||
|
||||
return $this->success(new OrderDataCollection($orders));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: description
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2023/1/5 14:13
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
$users = User::query()
|
||||
->withCount([
|
||||
'orders' => function ($q) {
|
||||
$q->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
]);
|
||||
}
|
||||
])
|
||||
->withSum([
|
||||
'orders' => function ($q) {
|
||||
$q->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
]);
|
||||
}
|
||||
], 'amount')
|
||||
->whereHas('orders', function ($q) {
|
||||
$q->whereIn('state', [
|
||||
Order::STATUS_PAID,
|
||||
Order::STATUS_DELIVERED,
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])->where('type', Order::TYPE_NORMAL);
|
||||
})
|
||||
->paginate();
|
||||
return $this->success(new UserDataCollection($users));
|
||||
|
||||
}
|
||||
}
|
||||
12
app/Api/Controllers/IndexController.php
Normal file
12
app/Api/Controllers/IndexController.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Controllers;
|
||||
|
||||
class IndexController extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
return $this->success('Json Api is ready');
|
||||
}
|
||||
}
|
||||
63
app/Api/Controllers/Wechat/IndexController.php
Normal file
63
app/Api/Controllers/Wechat/IndexController.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Controllers\Wechat;
|
||||
|
||||
use App\Api\WechatHandlers\EventMessageHandler;
|
||||
use App\Api\WechatHandlers\FileMessageHandler;
|
||||
use App\Api\WechatHandlers\ImageMessageHandler;
|
||||
use App\Api\WechatHandlers\LinkMessageHandler;
|
||||
use App\Api\WechatHandlers\LocationMessageHandler;
|
||||
use App\Api\WechatHandlers\ShortVideoMessageHandler;
|
||||
use App\Api\WechatHandlers\TextMessageHandler;
|
||||
use App\Api\WechatHandlers\TransferMessageHandler;
|
||||
use App\Api\WechatHandlers\VideoMessageHandler;
|
||||
use App\Api\WechatHandlers\VoiceMessageHandler;
|
||||
use EasyWeChat\Kernel\Messages\Message;
|
||||
use Overtrue\LaravelWeChat\Controllers\Controller;
|
||||
|
||||
class IndexController extends Controller
|
||||
{
|
||||
|
||||
public function serve()
|
||||
{
|
||||
$app = app('wechat.official_account');
|
||||
|
||||
$app->server->push(function ($message) {
|
||||
switch ($message['MsgType']) {
|
||||
case 'event':
|
||||
return '收到事件消息';
|
||||
break;
|
||||
case 'text':
|
||||
return '收到文字消息';
|
||||
break;
|
||||
case 'image':
|
||||
return '收到图片消息';
|
||||
break;
|
||||
case 'voice':
|
||||
return '收到语音消息';
|
||||
break;
|
||||
case 'video':
|
||||
return '收到视频消息';
|
||||
break;
|
||||
case 'location':
|
||||
return '收到坐标消息';
|
||||
break;
|
||||
case 'link':
|
||||
return '收到链接消息';
|
||||
break;
|
||||
case 'file':
|
||||
return '收到文件消息';
|
||||
// ... 其它消息
|
||||
default:
|
||||
return '收到其它消息';
|
||||
break;
|
||||
}
|
||||
|
||||
// ...
|
||||
});
|
||||
|
||||
$app->server->push(EventMessageHandler::class, Message::EVENT);
|
||||
|
||||
return $app->server->serve();
|
||||
}
|
||||
}
|
||||
21
app/Api/Resources/BaseCollection.php
Normal file
21
app/Api/Resources/BaseCollection.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class BaseCollection extends ResourceCollection
|
||||
{
|
||||
|
||||
protected function page(): array
|
||||
{
|
||||
return [
|
||||
'current' => $this->currentPage(),
|
||||
'total_page' => $this->lastPage(),
|
||||
'per_page' => $this->perPage(),
|
||||
'has_more' => $this->hasMorePages(),
|
||||
'total' => $this->total(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
32
app/Api/Resources/Order/OrderDataCollection.php
Normal file
32
app/Api/Resources/Order/OrderDataCollection.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Resources\Order;
|
||||
|
||||
use App\Api\Resources\BaseCollection;
|
||||
use App\Api\Resources\User\UserBaseResource;
|
||||
use Modules\Mall\Http\Resources\Api\Order\OrderExpressResource;
|
||||
|
||||
class OrderDataCollection extends BaseCollection
|
||||
{
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection->map(function ($order) {
|
||||
return [
|
||||
'order_no' => $order->order_no,
|
||||
'user' => new UserBaseResource($order->user),
|
||||
'express' => new OrderExpressResource($order->express),
|
||||
'qty' => $order->items()->sum('qty'),
|
||||
'amount' => $order->amount,
|
||||
'freight' => $order->freight,
|
||||
'total' => $order->total,
|
||||
'type' => $order->type_text,
|
||||
'state' => $order->state_text,
|
||||
];
|
||||
}),
|
||||
'page' => $this->page(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
20
app/Api/Resources/User/UserBaseResource.php
Normal file
20
app/Api/Resources/User/UserBaseResource.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Resources\User;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserBaseResource extends JsonResource
|
||||
{
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'user_id' => $this->id,
|
||||
'username' => $this->username,
|
||||
'nickname' => $this->info->nickname,
|
||||
'avatar' => $this->info->avatar ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
20
app/Api/Resources/User/UserDataCollection.php
Normal file
20
app/Api/Resources/User/UserDataCollection.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Resources\User;
|
||||
|
||||
use App\Api\Resources\BaseCollection;
|
||||
|
||||
class UserDataCollection extends BaseCollection
|
||||
{
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection->map(function ($info) {
|
||||
return new UserDataResource($info);
|
||||
}),
|
||||
'page' => $this->page(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
22
app/Api/Resources/User/UserDataResource.php
Normal file
22
app/Api/Resources/User/UserDataResource.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\Resources\User;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserDataResource extends JsonResource
|
||||
{
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'user_id' => $this->id,
|
||||
'username' => $this->username,
|
||||
'nickname' => $this->info->nickname,
|
||||
'orders_count' => $this->orders_count,
|
||||
'orders_sum_amount' => $this->orders_sum_amount,
|
||||
'avatar' => $this->info->avatar ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
14
app/Api/Routes/data.php
Normal file
14
app/Api/Routes/data.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group([
|
||||
'namespace' => 'Data',
|
||||
'middleware' => config('api.route.middleware'),
|
||||
], function (Router $router) {
|
||||
$router->get('data', 'IndexController@index');
|
||||
$router->get('data/orders', 'IndexController@orders');
|
||||
$router->get('data/users', 'IndexController@users');
|
||||
});
|
||||
|
||||
12
app/Api/Routes/wechat.php
Normal file
12
app/Api/Routes/wechat.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group([
|
||||
'namespace' => 'Wechat',
|
||||
'middleware' => config('api.route.middleware'),
|
||||
], function (Router $router) {
|
||||
$router->any('wechat', 'IndexController@serve')->name('wechat');
|
||||
});
|
||||
|
||||
142
app/Api/WechatHandlers/EventMessageHandler.php
Normal file
142
app/Api/WechatHandlers/EventMessageHandler.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
use EasyWeChat\Kernel\Messages\Text;
|
||||
use Modules\User\Models\UserWechat;
|
||||
use Modules\User\Models\UserWechatOfficial;
|
||||
use Modules\User\Traits\WechatTrait;
|
||||
|
||||
class EventMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
use WechatTrait;
|
||||
|
||||
private $payload;
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
if (method_exists($this, $payload->Event)) {
|
||||
$this->payload = $payload;
|
||||
return call_user_func_array([$this, $payload->Event], []);
|
||||
} else {
|
||||
// return '暂不支持的消息类型';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 关注事件
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/27 9:41
|
||||
*/
|
||||
private function subscribe()
|
||||
{
|
||||
$app = app('wechat.official_account');
|
||||
$user = $app->user->get($this->payload->FromUserName);
|
||||
|
||||
if ($user->unionid) {
|
||||
$wechatUsers = UserWechat::query()
|
||||
->where('unionid', $user->unionid)
|
||||
->get();
|
||||
if ($wechatUsers->isNotEmpty()) {
|
||||
foreach ($wechatUsers as $wechatUser) {
|
||||
if ($wechatUser->official) {
|
||||
if ($wechatUser->official->subscribe != 1) {
|
||||
$wechatUser->official->update([
|
||||
'subscribe' => 1,
|
||||
'subscribed_at' => Carbon::parse($user->subscribe_time)->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$wechatUser->official()->create([
|
||||
'openid' => $this->payload->FromUserName,
|
||||
'subscribe' => 1,
|
||||
'subscribed_at' => Carbon::parse($user->subscribe_time)->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//插入关注数据
|
||||
$this->setUserSubscribe($user->unionid, $this->payload->FromUserName, 1);
|
||||
|
||||
} else {
|
||||
// 先查找用户是否存在,不存在再注册
|
||||
$officialUsers = UserWechatOfficial::query()
|
||||
->where('openid', $this->payload->FromUserName)
|
||||
->get();
|
||||
|
||||
//设置总表uniond
|
||||
if ($officialUsers->isNotEmpty()) {
|
||||
foreach ($officialUsers as $officialUser) {
|
||||
if (! $officialUser->userWechat->unionid && $user->unionid) {
|
||||
$officialUser->userWechat->update([
|
||||
'unionid' => $user->unionid
|
||||
]);
|
||||
}
|
||||
|
||||
if ($officialUser->subscribe != 1) {
|
||||
$officialUser->update([
|
||||
'subscribe' => 1,
|
||||
'subscribed_at' => Carbon::parse($user->subscribe_time)->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->firstSubscribeMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 取消关注事件
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/27 9:41
|
||||
*/
|
||||
private function unsubscribe()
|
||||
{
|
||||
$officialUsers = UserWechatOfficial::where('openid', $this->payload->FromUserName)->get();
|
||||
if ($officialUsers->isNotEmpty()) {
|
||||
foreach ($officialUsers as $officialUser) {
|
||||
$officialUser->update([
|
||||
'subscribe' => 0,
|
||||
'subscribed_at' => null,
|
||||
]);
|
||||
|
||||
//设置取消关注
|
||||
if ($officialUser->userWechat) {
|
||||
$this->setUserSubscribe($officialUser->userWechat->unionid, $officialUser->openid, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 关注返回的消息
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/2 11:37
|
||||
* @return Text
|
||||
*/
|
||||
private function firstSubscribeMessage()
|
||||
{
|
||||
$officialUser = UserWechatOfficial::where('openid', $this->payload->FromUserName)->first();
|
||||
$text = new Text('扎西德勒!感谢关注锶源昆仑。锶源昆仑天然饮用水,水源地位于海拔4300米的昆仑山,水中富含镁离子、锶元素、钙元素等微量元素且氘含量低,稀世罕见,仅供30000人饮用。
|
||||
参与打卡“锶享体验官”活动,请点击公众号菜单上的按钮“锶享体验官”进入活动,来申请喝水体验官吧!');
|
||||
if ($officialUser && $officialUser->userWechat) {
|
||||
$nickname = $officialUser->userWechat->nickname;
|
||||
$text = new Text('扎西德勒!'.$nickname.',感谢关注锶源昆仑。锶源昆仑天然饮用水,水源地位于海拔4300米的昆仑山,水中富含镁离子、锶元素、钙元素等微量元素且氘含量低,稀世罕见,仅供30000人饮用。
|
||||
参与打卡“锶享体验官”活动,请点击公众号菜单上的按钮“锶享体验官”进入活动,来申请喝水体验官吧!');
|
||||
}
|
||||
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
}
|
||||
27
app/Api/WechatHandlers/FileMessageHandler.php
Normal file
27
app/Api/WechatHandlers/FileMessageHandler.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class FileMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
$payload->ToUserName;
|
||||
$payload->FromUserName;
|
||||
$payload->CreateTime;
|
||||
$payload->MsgId;
|
||||
|
||||
$payload->Title;
|
||||
$payload->Description;
|
||||
$payload->FileKey;
|
||||
$payload->FileMd5;
|
||||
$payload->FileTotalLen;
|
||||
|
||||
return '文件消息';
|
||||
}
|
||||
|
||||
}
|
||||
24
app/Api/WechatHandlers/ImageMessageHandler.php
Normal file
24
app/Api/WechatHandlers/ImageMessageHandler.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class ImageMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
// $payload->ToUserName;
|
||||
// $payload->FromUserName;
|
||||
// $payload->CreateTime;
|
||||
// $payload->MsgId;
|
||||
//
|
||||
// $payload->MediaId;
|
||||
// $payload->PicUrl;
|
||||
|
||||
return '图片消息';
|
||||
}
|
||||
|
||||
}
|
||||
25
app/Api/WechatHandlers/LinkMessageHandler.php
Normal file
25
app/Api/WechatHandlers/LinkMessageHandler.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class LinkMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
$payload->ToUserName;
|
||||
$payload->FromUserName;
|
||||
$payload->CreateTime;
|
||||
$payload->MsgId;
|
||||
|
||||
$payload->Title;
|
||||
$payload->Description;
|
||||
$payload->Url;
|
||||
|
||||
return '链接消息';
|
||||
}
|
||||
|
||||
}
|
||||
25
app/Api/WechatHandlers/LocationMessageHandler.php
Normal file
25
app/Api/WechatHandlers/LocationMessageHandler.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class LocationMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
$payload->ToUserName;
|
||||
$payload->FromUserName;
|
||||
$payload->CreateTime;
|
||||
$payload->MsgId;
|
||||
|
||||
$payload->Latitude;
|
||||
$payload->Longitude;
|
||||
$payload->Precision;
|
||||
|
||||
return '上报位置消息';
|
||||
}
|
||||
|
||||
}
|
||||
24
app/Api/WechatHandlers/ShortVideoMessageHandler.php
Normal file
24
app/Api/WechatHandlers/ShortVideoMessageHandler.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class ShortVideoMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
$payload->ToUserName;
|
||||
$payload->FromUserName;
|
||||
$payload->CreateTime;
|
||||
$payload->MsgId;
|
||||
|
||||
$payload->MediaId;
|
||||
$payload->ThumbMediaId;
|
||||
|
||||
return '短视频消息';
|
||||
}
|
||||
|
||||
}
|
||||
16
app/Api/WechatHandlers/TextMessageHandler.php
Normal file
16
app/Api/WechatHandlers/TextMessageHandler.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
use function AlibabaCloud\Client\json;
|
||||
|
||||
class TextMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
return '您的留言已经收到';
|
||||
}
|
||||
|
||||
}
|
||||
15
app/Api/WechatHandlers/TransferMessageHandler.php
Normal file
15
app/Api/WechatHandlers/TransferMessageHandler.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class TransferMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
return '客服消息'.json_encode($payload);
|
||||
}
|
||||
|
||||
}
|
||||
24
app/Api/WechatHandlers/VideoMessageHandler.php
Normal file
24
app/Api/WechatHandlers/VideoMessageHandler.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class VideoMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
$payload->ToUserName;
|
||||
$payload->FromUserName;
|
||||
$payload->CreateTime;
|
||||
$payload->MsgId;
|
||||
|
||||
$payload->MediaId;
|
||||
$payload->ThumbMediaId;
|
||||
|
||||
return '视频消息';
|
||||
}
|
||||
|
||||
}
|
||||
25
app/Api/WechatHandlers/VoiceMessageHandler.php
Normal file
25
app/Api/WechatHandlers/VoiceMessageHandler.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Api\WechatHandlers;
|
||||
|
||||
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
|
||||
|
||||
class VoiceMessageHandler implements EventHandlerInterface
|
||||
{
|
||||
|
||||
public function handle($payload = null)
|
||||
{
|
||||
|
||||
$payload->ToUserName;
|
||||
$payload->FromUserName;
|
||||
$payload->CreateTime;
|
||||
$payload->MsgId;
|
||||
|
||||
$payload->MediaId;
|
||||
$payload->Format;
|
||||
$payload->Recognition;
|
||||
|
||||
return '语音消息';
|
||||
}
|
||||
|
||||
}
|
||||
1
app/Api/bootstrap.php
Normal file
1
app/Api/bootstrap.php
Normal file
@@ -0,0 +1 @@
|
||||
<?php
|
||||
25
app/Api/routes.php
Normal file
25
app/Api/routes.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
//Route::get('/', 'IndexController@index')->name('home');
|
||||
|
||||
/**
|
||||
* 分组的路由示例
|
||||
*/
|
||||
Route::group([
|
||||
// 'as' => '',
|
||||
// 'domain' => '',
|
||||
// 'middleware' => '',
|
||||
// 'namespace' => '',
|
||||
// 'prefix' => '',
|
||||
], function (Router $router) {
|
||||
$router->get('/', 'IndexController@index')->name('home');
|
||||
});
|
||||
/**
|
||||
* 文件夹引入的示例
|
||||
*/
|
||||
foreach (glob(app_path('Api/Routes').'/*.php') as $routeFile) {
|
||||
require $routeFile;
|
||||
}
|
||||
305
app/Bonus/IdentityBonus.php
Normal file
305
app/Bonus/IdentityBonus.php
Normal file
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
namespace App\Bonus;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Modules\Coupon\Models\Coupon;
|
||||
use Modules\Coupon\Models\CouponGrant;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\Order;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class IdentityBonus
|
||||
{
|
||||
|
||||
/**
|
||||
* 开通身份
|
||||
*
|
||||
* @param User $user
|
||||
* @param Order $order
|
||||
* @param array $source
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function BuyIdentity(User $user, Order $order, array $source = [])
|
||||
{
|
||||
dd(1);
|
||||
try {
|
||||
$identity = $order->identity;
|
||||
$parent = $user->parent;
|
||||
$parentIdentity = $parent ? $user->parent->identityFirst() : '';
|
||||
|
||||
//开通赠送水滴
|
||||
$crystal = $order->identity->getRule('give_crystal', '0');
|
||||
if ($crystal > 0) {
|
||||
$user->account->rule('open_identity_score', $crystal, true, array_merge($source, [
|
||||
'user_order_id' => $order->id
|
||||
]));
|
||||
}
|
||||
//发券
|
||||
self::grantCoupon($user, $order, $parent, $parentIdentity);
|
||||
|
||||
//是否有上级
|
||||
if ($parent && $parentIdentity && $order->price > 0) {
|
||||
//增加业绩
|
||||
$parent->addPerf($order->price, $order);
|
||||
//开通的是季卡
|
||||
if ($identity->job == Identity::JOB_JK) {
|
||||
|
||||
|
||||
//直推季卡获得水滴
|
||||
$hasRecommend_jk_score = $parentIdentity->getRule('recommend_jk_score', '');
|
||||
if ($hasRecommend_jk_score) {
|
||||
$user->parent->account->rule(
|
||||
'recommend_jk_score',
|
||||
$hasRecommend_jk_score,
|
||||
false,
|
||||
array_merge($source, [
|
||||
'user_order_id' => $order->id
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
//合伙人推荐奖励
|
||||
self::setHhRecommendJk($hasRecommend_jk_score, $user, $order, $source);
|
||||
}
|
||||
|
||||
//开通的是年卡
|
||||
if ($identity->job == Identity::JOB_NK) {
|
||||
//直推年卡获得水滴
|
||||
$hasRecommend_nk_score = $parentIdentity->getRule('recommend_nk_score', '');
|
||||
if ($hasRecommend_nk_score) {
|
||||
$user->parent->account->rule(
|
||||
'recommend_nk_score',
|
||||
$hasRecommend_nk_score,
|
||||
false,
|
||||
array_merge($source, [
|
||||
'user_order_id' => $order->id
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
//合伙人推荐奖励
|
||||
self::setHhRecommendNk($hasRecommend_nk_score, $user, $order, $source);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (\Exception $exception) {
|
||||
return $exception->getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 发券
|
||||
* 推荐会员得优惠券 季卡 年卡 创始
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/31 13:53
|
||||
*/
|
||||
public static function grantCoupon($user, $order, $parent, $parentIdentity)
|
||||
{
|
||||
if ($parent && $parentIdentity->job !== Identity::JOB_HH) {
|
||||
$jkIdentity = Identity::query()->Jk()->first();
|
||||
$openJkCount = $parent->getOpenJkCount();//开通季卡次数
|
||||
$recommendUserCoupunCount = $parent->getRecommendUserCouponCount();//推荐季卡得优惠券数
|
||||
$recommend_coupon = $parentIdentity->getRule('recommend_coupon', null);//是否有推荐奖励
|
||||
|
||||
//推荐季卡得优惠券
|
||||
if ($recommend_coupon && $order->type == Order::TYPE_OPEN && $openJkCount > $recommendUserCoupunCount) {
|
||||
$coupon = Coupon::query()
|
||||
->whereHas('items', function ($q) use ($jkIdentity) {
|
||||
$q->withGoods($jkIdentity);
|
||||
})
|
||||
->first();
|
||||
|
||||
$ended_at = Carbon::parse($parentIdentity->pivot->ended_at);
|
||||
if ($coupon && $ended_at->gt(now())) {
|
||||
$days = $ended_at->addMonth()->diffInDays(now());
|
||||
#TODO 推季卡会员得优惠券
|
||||
// $user->parent->getCoupon($coupon->id, CouponGrant::CHANNEL_EXPAND, $days);
|
||||
$user->parent->getCoupon($coupon->id, CouponGrant::CHANNEL_EXPAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 合伙人推荐季卡
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/19 15:11
|
||||
*/
|
||||
public static function setHhRecommendJk($score, $user, $order, $source)
|
||||
{
|
||||
$hhUsers = $user->getParentHh();//获取所有合伙人
|
||||
$hhIdentity = Identity::query()->where('job', Identity::JOB_HH)->first();
|
||||
$rule_name = 'recommend_indirect_jk_balance';
|
||||
if ($hhIdentity && ! empty($hhUsers)) {
|
||||
//有人获得了推荐水滴就是间推
|
||||
|
||||
$i = 1;
|
||||
foreach ($hhUsers as $hhUser) {
|
||||
$jkChildren = $hhUser->getJkChildrenCount();
|
||||
$amount = 0;
|
||||
|
||||
if ($i > 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
//间接
|
||||
if ($score) {
|
||||
if ($jkChildren > 10) {
|
||||
$rateName = 'recommend_rate_indirect_jk_balance_gt';
|
||||
} else {
|
||||
$rateName = 'recommend_rate_indirect_jk_balance_lte';
|
||||
}
|
||||
} else {//直接
|
||||
if ($jkChildren > 10) {
|
||||
$rateName = 'recommend_rate_jk_balance_gt';
|
||||
} else {
|
||||
$rateName = 'recommend_rate_jk_balance_lte';
|
||||
}
|
||||
|
||||
$rule_name = 'recommend_jk_balance';
|
||||
}
|
||||
|
||||
$hasRate = $hhIdentity->getRule($rateName, 0);//获取比例
|
||||
$rateData = self::getNonZeroRate($hasRate);
|
||||
$amount = bcmul($order->price, $rateData, 2);
|
||||
|
||||
if ($amount) {
|
||||
//执行分润
|
||||
$hhUser->account->rule(
|
||||
$rule_name,
|
||||
$amount,
|
||||
false,
|
||||
array_merge($source, [
|
||||
'user_order_id' => $order->id,
|
||||
'rate' => $rateData
|
||||
])
|
||||
);
|
||||
//培育津贴
|
||||
self::allowance($hhUser, $amount, $source);
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
info('没有找到合伙人');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 合伙人间推季卡
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/19 15:13
|
||||
*/
|
||||
public static function setHhRecommendNk($score, $user, $order, $source)
|
||||
{
|
||||
$hhUsers = $user->getParentHh();//获取所有合伙人
|
||||
$hhIdentity = Identity::query()->where('job', Identity::JOB_HH)->first();
|
||||
$rule_name = 'recommend_indirect_nk_balance';
|
||||
if ($hhIdentity && ! empty($hhUsers)) {
|
||||
//有人获得了推荐水滴就是间推
|
||||
$i = 1;
|
||||
foreach ($hhUsers as $hhUser) {
|
||||
$nkChildren = $hhUser->getNkChildrenCount();
|
||||
$amount = 0;
|
||||
if ($i > 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
//间接
|
||||
if ($score) {
|
||||
if ($nkChildren > 10) {
|
||||
$rateName = 'recommend_rate_indirect_nk_balance_gt';
|
||||
} else {
|
||||
$rateName = 'recommend_rate_indirect_nk_balance_lte';
|
||||
}
|
||||
} else {//直接
|
||||
if ($nkChildren > 10) {
|
||||
$rateName = 'recommend_rate_nk_balance_gt';
|
||||
} else {
|
||||
$rateName = 'recommend_rate_nk_balance_lte';
|
||||
}
|
||||
|
||||
$rule_name = 'recommend_nk_balance';
|
||||
}
|
||||
$hasRate = $hhIdentity->getRule($rateName, 0);//获取比例
|
||||
$rateData = self::getNonZeroRate($hasRate);
|
||||
$amount = bcmul($order->price, $rateData, 2);
|
||||
|
||||
|
||||
if ($amount > 0) {
|
||||
//执行分润
|
||||
$hhUser->account->rule(
|
||||
$rule_name,
|
||||
$amount,
|
||||
false,
|
||||
array_merge($source, [
|
||||
'user_order_id' => $order->id,
|
||||
'rate' => $rateData
|
||||
])
|
||||
);
|
||||
|
||||
//培育津贴
|
||||
self::allowance($hhUser, $amount, $source);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 获取百分比数据
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/19 14:56
|
||||
* @param $rate
|
||||
* @param $decimals
|
||||
* @return int|string|null
|
||||
*/
|
||||
public static function getNonZeroRate($rate, $decimals = 2)
|
||||
{
|
||||
return $rate > 0 ? bcdiv($rate, 100, $decimals) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 培育津贴
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/30 14:32
|
||||
*/
|
||||
public static function allowance(User $user, $amount, $source)
|
||||
{
|
||||
$UserIdentity = $user->identityFirst();
|
||||
$hasRate = $UserIdentity->getRule('recommend_rate_allowance', 0);//获取培育津贴比例
|
||||
if ($UserIdentity->job == Identity::JOB_HH && $hasRate) {
|
||||
$hhUsers = $user->getParentHh();//获取所有合伙人
|
||||
$rateData = self::getNonZeroRate($hasRate);
|
||||
$amount = bcmul($amount, $rateData, 2);
|
||||
|
||||
$i = 1;
|
||||
if (! empty($hhUsers)) {
|
||||
foreach ($hhUsers as $hhUser) {
|
||||
if ($i > 1) {
|
||||
break;
|
||||
}
|
||||
$hhUser->account->rule(
|
||||
'allowance_balance',
|
||||
$amount,
|
||||
false,
|
||||
$source
|
||||
);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
15
app/Channels/WechatMiniChannel.php
Normal file
15
app/Channels/WechatMiniChannel.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Channels;
|
||||
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class WechatMiniChannel
|
||||
{
|
||||
|
||||
public function send($notifiable, Notification $notification)
|
||||
{
|
||||
$notification->toWeChat($notifiable);
|
||||
}
|
||||
|
||||
}
|
||||
36
app/Console/Commands/MonthPerfCommand.php
Normal file
36
app/Console/Commands/MonthPerfCommand.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\Bonus\MonthPerfJob;
|
||||
use Illuminate\Console\Command;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class MonthPerfCommand extends Command
|
||||
{
|
||||
protected $signature = 'Bonus:MonthPerf {last?}';
|
||||
|
||||
protected $description = '分红:计算用户月度业绩';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$last = $this->argument('last') ?: 0;
|
||||
|
||||
User::whereHas('identities', function ($query) {
|
||||
$query->where('id', 6);
|
||||
})
|
||||
->whereHas('identityMiddle', function ($query) {
|
||||
$query->where('star', '>', 0);
|
||||
})
|
||||
->chunkById(100, function ($users) use ($last) {
|
||||
foreach ($users as $user) {
|
||||
MonthPerfJob::dispatch($user, $last);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
57
app/Console/Commands/StartBounsCommand.php
Normal file
57
app/Console/Commands/StartBounsCommand.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\Bonus\SendBounsJob;
|
||||
use App\Models\Bouns;
|
||||
use App\Models\BounsUserPerf;
|
||||
use Illuminate\Console\Command;
|
||||
use Exception;
|
||||
|
||||
class StartBounsCommand extends Command
|
||||
{
|
||||
protected $signature = 'Bonus:StartMonth {star} {last?}';
|
||||
|
||||
protected $description = '分红:开始分红 {1-5} {last?}';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$star = $this->argument('star') ?: 0;
|
||||
if (!in_array($star, Bouns::TYPEARRAY)) {
|
||||
throw new Exception('星级参数不正确');
|
||||
}
|
||||
$last = $this->argument('last') ?: 0;
|
||||
|
||||
$time = now()->startOfMonth()->toDateTimeString();
|
||||
if ($last) {
|
||||
$time = now()->subMonth()->startOfMonth()->toDateTimeString();
|
||||
}
|
||||
$bouns = Bouns::where('date', $time)
|
||||
->where('type', $star)
|
||||
->where('status', Bouns::STATUS_INIT)
|
||||
->first();
|
||||
if (!$bouns) {
|
||||
throw new Exception('分红内容不存在或状态不正确');
|
||||
}
|
||||
$bounsUserPerf = BounsUserPerf::where('date', $bouns->date)
|
||||
->where('star', '>=', $bouns->type)
|
||||
->get();
|
||||
if ($bounsUserPerf->count() > 0) {
|
||||
$allOld = bcmul($bounsUserPerf->sum('old_perf'), 0.3, 4);//累计业绩
|
||||
$allNew = bcmul($bounsUserPerf->sum('new_perf'), 0.7, 4);//新增业绩
|
||||
$allPerf = bcadd($allOld, $allNew, 4);//总业绩
|
||||
$price = bcdiv($bouns->total, $allPerf, 6);//单价
|
||||
$bouns->doIng();
|
||||
foreach ($bounsUserPerf as $bounsPerf) {
|
||||
SendBounsJob::dispatch($bounsPerf, $price, $bouns);
|
||||
}
|
||||
} else {
|
||||
$bouns->doEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
app/Console/Kernel.php
Normal file
66
app/Console/Kernel.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use Nwidart\Modules\Facades\Module as ModuleManager;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
|
||||
/**
|
||||
* The Artisan commands provided by your application.
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// $schedule->command('inspire')->hourly();
|
||||
$schedule->command('Bonus:MonthPerf 1')->monthlyOn(1, '00:01');
|
||||
$schedule->command('Bonus:StartMonth 1 1')->monthlyOn(1, '00:10');
|
||||
$schedule->command('Bonus:StartMonth 2 1')->monthlyOn(1, '00:15');
|
||||
$schedule->command('Bonus:StartMonth 3 1')->monthlyOn(1, '00:20');
|
||||
$schedule->command('Bonus:StartMonth 4 1')->monthlyOn(1, '00:25');
|
||||
$schedule->command('Bonus:StartMonth 5 1')->monthlyOn(1, '00:30');
|
||||
$this->modules($schedule);
|
||||
}
|
||||
|
||||
/**
|
||||
* 要执行任务的位置增加Console\Kernel类
|
||||
* 类中 runCommand(Schedule $schedule)
|
||||
* 模型中的command在模型的ServiceProvider自行注册
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
*/
|
||||
protected function modules(Schedule $schedule)
|
||||
{
|
||||
$data = ModuleManager::toCollection();
|
||||
foreach ($data as $name => $module) {
|
||||
$nameSpace = "\\Modules\\$name\\Console\\Kernel";
|
||||
if (class_exists($nameSpace)) {
|
||||
$runKernel = resolve($nameSpace);
|
||||
$runKernel->runCommand($schedule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
* @return void
|
||||
*/
|
||||
protected function commands()
|
||||
{
|
||||
$this->load(__DIR__.'/Commands');
|
||||
|
||||
// require base_path('routes/console.php');
|
||||
}
|
||||
|
||||
}
|
||||
43
app/Exceptions/Handler.php
Normal file
43
app/Exceptions/Handler.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Jason\Api\Traits\ApiException;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
|
||||
use ApiException;
|
||||
|
||||
/**
|
||||
* A list of the exception types that are not reported.
|
||||
* @var array
|
||||
*/
|
||||
protected $dontReport = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* A list of the inputs that are never flashed for validation exceptions.
|
||||
* @var array
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
29
app/Http/Controllers/Controller.php
Normal file
29
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Jason\Api\Traits\ApiResponse;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
|
||||
use ApiResponse;
|
||||
|
||||
/**
|
||||
* Notes : 授权token返回格式
|
||||
* @Date : 2021/3/16 5:00 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param string $token
|
||||
* @return array
|
||||
*/
|
||||
protected function respondWithToken(string $token): array
|
||||
{
|
||||
return [
|
||||
'access_token' => $token,
|
||||
'token_type' => 'Bearer',
|
||||
'expires_in' => auth('api')->factory()->getTTL() * 60,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
18
app/Http/Controllers/ImageController.php
Normal file
18
app/Http/Controllers/ImageController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Material;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ImageController extends Controller
|
||||
{
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$name = $request->name;
|
||||
$img = Material::query()->where('title', $name)->first();
|
||||
|
||||
return view('image', compact('img'));
|
||||
}
|
||||
}
|
||||
66
app/Http/Kernel.php
Normal file
66
app/Http/Kernel.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
/**
|
||||
* The application's global HTTP middleware stack.
|
||||
*
|
||||
* These middleware are run during every request to your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware groups.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
// 'throttle:api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware.
|
||||
*
|
||||
* These middleware may be assigned to groups or used individually.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
];
|
||||
}
|
||||
21
app/Http/Middleware/Authenticate.php
Normal file
21
app/Http/Middleware/Authenticate.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
|
||||
class Authenticate extends Middleware
|
||||
{
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
return route('login');
|
||||
}
|
||||
}
|
||||
}
|
||||
17
app/Http/Middleware/EncryptCookies.php
Normal file
17
app/Http/Middleware/EncryptCookies.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||
|
||||
class EncryptCookies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the cookies that should not be encrypted.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
17
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
17
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
|
||||
|
||||
class PreventRequestsDuringMaintenance extends Middleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be reachable while maintenance mode is enabled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
32
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
32
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null ...$guards
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, ...$guards)
|
||||
{
|
||||
$guards = empty($guards) ? [null] : $guards;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
19
app/Http/Middleware/TrimStrings.php
Normal file
19
app/Http/Middleware/TrimStrings.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||
|
||||
class TrimStrings extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the attributes that should not be trimmed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
}
|
||||
20
app/Http/Middleware/TrustHosts.php
Normal file
20
app/Http/Middleware/TrustHosts.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Middleware\TrustHosts as Middleware;
|
||||
|
||||
class TrustHosts extends Middleware
|
||||
{
|
||||
/**
|
||||
* Get the host patterns that should be trusted.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function hosts()
|
||||
{
|
||||
return [
|
||||
$this->allSubdomainsOfApplicationUrl(),
|
||||
];
|
||||
}
|
||||
}
|
||||
23
app/Http/Middleware/TrustProxies.php
Normal file
23
app/Http/Middleware/TrustProxies.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array|string|null
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
17
app/Http/Middleware/VerifyCsrfToken.php
Normal file
17
app/Http/Middleware/VerifyCsrfToken.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||
|
||||
class VerifyCsrfToken extends Middleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be excluded from CSRF verification.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'wechat'
|
||||
];
|
||||
}
|
||||
43
app/Jobs/Bonus/BuyIdentityJob.php
Normal file
43
app/Jobs/Bonus/BuyIdentityJob.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Bonus;
|
||||
|
||||
use App\Bonus\IdentityBonus;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Modules\User\Models\Order;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class BuyIdentityJob implements ShouldQueue
|
||||
{
|
||||
|
||||
use Dispatchable, InteractsWithQueue;
|
||||
|
||||
public $queue = 'BONUS';
|
||||
|
||||
public $delay = 0;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public $timeout = 30;
|
||||
|
||||
protected $user; //bonus
|
||||
|
||||
protected $order; //bonus
|
||||
|
||||
protected $source;//bonus
|
||||
|
||||
public function __construct(User $user, Order $order, array $source = [])
|
||||
{
|
||||
$this->user = $user->fresh();
|
||||
$this->order = $order->fresh();
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
IdentityBonus::BuyIdentity($this->user, $this->order, $this->source);
|
||||
}
|
||||
|
||||
}
|
||||
57
app/Jobs/Bonus/MonthPerfJob.php
Normal file
57
app/Jobs/Bonus/MonthPerfJob.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Bonus;
|
||||
|
||||
use App\Models\BounsUserPerf;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class MonthPerfJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue;
|
||||
|
||||
public $queue = 'BONUS';
|
||||
|
||||
public $delay = 0;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public $timeout = 30;
|
||||
|
||||
protected $user; //bonus
|
||||
|
||||
protected $last; //bonus
|
||||
|
||||
/**
|
||||
* @param User $user 用户
|
||||
* @param bool $last 是否上个月
|
||||
*/
|
||||
public function __construct(User $user, bool $last)
|
||||
{
|
||||
$this->user = $user->fresh();
|
||||
$this->last = $last;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$time = [now()->startOfMonth()->toDateTimeString(), now()->endOfMonth()->toDateTimeString()];
|
||||
if ($this->last) {
|
||||
$time = [
|
||||
now()->subMonth()->startOfMonth()->toDateTimeString(),
|
||||
now()->subMonth()->endOfMonth()->toDateTimeString()
|
||||
];
|
||||
}
|
||||
$old = $this->user->allPerf();
|
||||
$new = $this->user->allPerf($time);
|
||||
BounsUserPerf::updateOrCreate([
|
||||
'user_id' => $this->user->id,
|
||||
'date' => $time[0],
|
||||
], [
|
||||
'star' => $this->user->identityFirst()->pivot->star,
|
||||
'old_perf' => $old,
|
||||
'new_perf' => $new,
|
||||
]);
|
||||
}
|
||||
}
|
||||
55
app/Jobs/Bonus/SendBounsJob.php
Normal file
55
app/Jobs/Bonus/SendBounsJob.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Bonus;
|
||||
|
||||
use App\Models\Bouns;
|
||||
use App\Models\BounsUserPerf;
|
||||
use App\Models\Job;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class SendBounsJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue;
|
||||
|
||||
public $queue = 'BONUS';
|
||||
|
||||
public $delay = 0;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public $timeout = 30;
|
||||
|
||||
protected BounsUserPerf $bounsPerf; //BounsUserPerf
|
||||
protected float $price;//单价
|
||||
protected Bouns $bouns;//单价
|
||||
|
||||
public function __construct(BounsUserPerf $bounsPerf, float $price, Bouns $bouns)
|
||||
{
|
||||
$this->bounsPerf = $bounsPerf->fresh();
|
||||
$this->price = $price;
|
||||
$this->bouns = $bouns;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
$perf = bcadd(bcmul($this->bounsPerf->old_perf, 0.3, 4),
|
||||
bcmul($this->bounsPerf->new_perf, 0.7, 4), 4);
|
||||
|
||||
$this->bounsPerf->price = $this->price;
|
||||
$this->bounsPerf->amount = $this->price * $perf;
|
||||
$this->bounsPerf->user->account->rule('star_balance', $this->bounsPerf->amount, false, [
|
||||
'remark' => Bouns::TYPES[$this->bouns->type],
|
||||
'star' => $this->bouns->type,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->bounsPerf->status = BounsUserPerf::STATUS_ERROR;
|
||||
}
|
||||
$this->bounsPerf->save();
|
||||
if (Job::where('queue', 'BONUS')->where('payload', 'like', '%SendBounsJob%')->count() <= 1) {
|
||||
$this->bouns->doEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
app/Listeners/PaymentPaidListener.php
Normal file
15
app/Listeners/PaymentPaidListener.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Modules\Payment\Events\Paid;
|
||||
|
||||
class PaymentPaidListener implements ShouldQueue
|
||||
{
|
||||
public function handle(Paid $event): void
|
||||
{
|
||||
$payment = $event->payment;
|
||||
|
||||
}
|
||||
}
|
||||
41
app/Listeners/UserOrderPaidListener.php
Normal file
41
app/Listeners/UserOrderPaidListener.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Jobs\Bonus\BuyIdentityJob;
|
||||
use App\Models\Bouns;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Modules\Task\Facades\TaskFacade;
|
||||
use Modules\User\Events\UserOrderPaid;
|
||||
|
||||
class UserOrderPaidListener implements ShouldQueue
|
||||
{
|
||||
|
||||
public function handle(UserOrderPaid $event)
|
||||
{
|
||||
$order = $event->order;
|
||||
$user = $event->order->user;
|
||||
$identity = $event->order->identity;
|
||||
$source = [
|
||||
'identity_id' => $identity->id,
|
||||
'order_id' => $event->order->id,
|
||||
'type' => $event->order->type,
|
||||
];
|
||||
|
||||
// BuyIdentityJob::dispatch($user, $order, $source);//个人赠送水滴
|
||||
// Bouns::addBouns($order, $order->price);
|
||||
|
||||
#TODO 开通会员赠送水滴
|
||||
// TaskFacade::do('open_vip', $user->id, [
|
||||
// 'identity_id' => $event->order->identity_id
|
||||
// ]);
|
||||
|
||||
#TODO 邀请一名健康体验馆 赠送水滴
|
||||
// if ($user->parent) {
|
||||
// TaskFacade::do('recommend_ty', $user->parent->id, [
|
||||
// 'user_id' => $user->id
|
||||
// ]);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
128
app/Models/Bouns.php
Normal file
128
app/Models/Bouns.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model as BaseModel;
|
||||
|
||||
class Bouns extends Model
|
||||
{
|
||||
protected $dates = ['date'];
|
||||
protected $casts = [
|
||||
'source' => 'array',
|
||||
];
|
||||
const ONE_STAR = 1;
|
||||
const TWO_STAR = 2;
|
||||
const THREE_STAR = 3;
|
||||
const FOUR_STAR = 4;
|
||||
const FIVE_STAR = 5;
|
||||
const TYPES = [
|
||||
self::ONE_STAR => '一星分红',
|
||||
self::TWO_STAR => '二星分红',
|
||||
self::THREE_STAR => '三星分红',
|
||||
self::FOUR_STAR => '四星分红',
|
||||
self::FIVE_STAR => '五星分红',
|
||||
];
|
||||
|
||||
const TYPEARRAY = [self::ONE_STAR, self::TWO_STAR, self::THREE_STAR, self::FOUR_STAR, self::FIVE_STAR];
|
||||
|
||||
const STATUS_INIT = 0;
|
||||
const STATUS_SENDING = 1;
|
||||
const STATUS_SENDED = 2;
|
||||
const STATUS_REJECT = 8;
|
||||
const STATUS_ERROR = 9;
|
||||
const STATUS = [
|
||||
self::STATUS_INIT => '待发放',
|
||||
self::STATUS_SENDING => '发放中',
|
||||
self::STATUS_SENDED => '发放完毕',
|
||||
self::STATUS_REJECT => '停发',
|
||||
self::STATUS_ERROR => '错误',
|
||||
];
|
||||
|
||||
protected function orders()
|
||||
{
|
||||
return $this->hasMany(BounsOrder::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加累计额度,增加对应订单记录
|
||||
* @param BaseModel $order
|
||||
* @param float $total
|
||||
* @param float $rate
|
||||
* @return void
|
||||
*/
|
||||
protected function addAmount(BaseModel $order, float $total, float $rate)
|
||||
{
|
||||
$amount = bcmul($total, bcdiv($rate, 100, 4), 2);
|
||||
if ($this->orders()->create([
|
||||
'order_type' => $order->getMorphClass(),
|
||||
'order_id' => $order->id,
|
||||
'type' => $this->type,
|
||||
'total' => $total,
|
||||
'amount' => $amount,
|
||||
])) {
|
||||
$this->increment('total', $amount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分红模型
|
||||
* @param int $type 类别
|
||||
* @param bool $last 是否上一期
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getBouns(int $type, bool $last = false)
|
||||
{
|
||||
$time = now()->startOfMonth();
|
||||
if ($last) {
|
||||
$time = now()->subMonth()->startOfMonth();
|
||||
}
|
||||
return Bouns::firstOrCreate([
|
||||
'type' => $type,
|
||||
'date' => $time->toDateTimeString(),
|
||||
], [
|
||||
'total' => 0,
|
||||
'status' => self::STATUS_INIT,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加分红
|
||||
* @param BaseModel $order 订单
|
||||
* @param float $total 订单金额(未计算前)
|
||||
* @return void
|
||||
*/
|
||||
public static function addBouns(BaseModel $order, float $total)
|
||||
{
|
||||
$rateArray = [
|
||||
self::ONE_STAR => app('Conf_user')['one_star_balance_rate'] ?? 0,
|
||||
self::TWO_STAR => app('Conf_user')['two_star_balance_rate'] ?? 0,
|
||||
self::THREE_STAR => app('Conf_user')['three_star_balance_rate'] ?? 0,
|
||||
self::FOUR_STAR => app('Conf_user')['four_star_balance_rate'] ?? 0,
|
||||
self::FIVE_STAR => app('Conf_user')['five_star_balance_rate'] ?? 0,
|
||||
];
|
||||
foreach ($rateArray as $key => $rate) {
|
||||
if ($rate > 0) {
|
||||
$model = Bouns::getBouns($key);
|
||||
$model->addAmount($order, $total, $rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function doIng()
|
||||
{
|
||||
$this->status = self::STATUS_SENDING;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function doEnd()
|
||||
{
|
||||
$this->status = self::STATUS_SENDED;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function doError()
|
||||
{
|
||||
$this->status = self::STATUS_ERROR;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
12
app/Models/BounsOrder.php
Normal file
12
app/Models/BounsOrder.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
class BounsOrder extends Model
|
||||
{
|
||||
public function bouns()
|
||||
{
|
||||
return $this->belongsTo(Bouns::class);
|
||||
}
|
||||
}
|
||||
26
app/Models/BounsUserPerf.php
Normal file
26
app/Models/BounsUserPerf.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class BounsUserPerf extends Model
|
||||
{
|
||||
use BelongsToUser;
|
||||
|
||||
const STATUS_INIT = 0;
|
||||
const STATUS_SUCCESS = 1;
|
||||
const STATUS_ERROR = 2;
|
||||
|
||||
const STATUS = [
|
||||
self::STATUS_INIT => '待发放',
|
||||
self::STATUS_SUCCESS => '完成',
|
||||
self::STATUS_ERROR => '失败',
|
||||
];
|
||||
|
||||
public function bouns()
|
||||
{
|
||||
return $this->belongsTo(Bouns::class);
|
||||
}
|
||||
}
|
||||
8
app/Models/Job.php
Normal file
8
app/Models/Job.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class Job extends Model
|
||||
{
|
||||
|
||||
}
|
||||
11
app/Models/Material.php
Normal file
11
app/Models/Material.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
use App\Traits\HasCovers;
|
||||
|
||||
class Material extends Model
|
||||
{
|
||||
use HasCovers;
|
||||
}
|
||||
27
app/Models/Model.php
Normal file
27
app/Models/Model.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Macroable;
|
||||
use Encore\Admin\Traits\DefaultDatetimeFormat;
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
|
||||
class Model extends Eloquent
|
||||
{
|
||||
|
||||
use DefaultDatetimeFormat,
|
||||
Macroable;
|
||||
|
||||
/**
|
||||
* 进制批量写入的字段
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* 修改模型默认分页数量
|
||||
* @var int
|
||||
*/
|
||||
protected $perPage = 10;
|
||||
|
||||
}
|
||||
51
app/Models/Module.php
Normal file
51
app/Models/Module.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Nwidart\Modules\Facades\Module as ModuleManager;
|
||||
|
||||
class Module extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 自定义返回数据
|
||||
* @Date : 2021/3/11 9:59 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator
|
||||
*/
|
||||
public function paginate(): LengthAwarePaginator
|
||||
{
|
||||
$perPage = Request::get('per_page', 20);
|
||||
// $page = Request::get('page', 1);
|
||||
// $start = ($page - 1) * $perPage;
|
||||
|
||||
$data = ModuleManager::toCollection();
|
||||
|
||||
$movies = $data->map(function ($module) {
|
||||
return [
|
||||
'id' => $module->getName(),
|
||||
'name' => $module->getName(),
|
||||
'alias' => $module->getAlias(),
|
||||
'description' => $module->getDescription(),
|
||||
'priority' => $module->getPriority(),
|
||||
'keywords' => $module->get('keywords'),
|
||||
'requires' => $module->getRequires(),
|
||||
'enabled' => $module->isEnabled(),
|
||||
'version' => $module->get('version'),
|
||||
'author' => $module->get('author'),
|
||||
];
|
||||
});
|
||||
|
||||
$movies = static::hydrate($movies->toArray());
|
||||
|
||||
$paginator = new LengthAwarePaginator($movies, ModuleManager::count(), $perPage);
|
||||
|
||||
$paginator->setPath(url()->current());
|
||||
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
}
|
||||
100
app/Notifications/SystemOpenVip.php
Normal file
100
app/Notifications/SystemOpenVip.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Channels\WechatMiniChannel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Channels\DatabaseChannel;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\IdentityMiddle;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class SystemOpenVip extends Notification
|
||||
{
|
||||
|
||||
use Queueable;
|
||||
|
||||
protected $identityMiddle;
|
||||
protected $identity;
|
||||
protected $title;
|
||||
protected $remark;
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(IdentityMiddle $identityMiddle)
|
||||
{
|
||||
$identity = $identityMiddle->identity;
|
||||
$remark = '赠送'.$identity->stock.'箱水';
|
||||
// if ($identity->job == Identity::JOB_HH) {
|
||||
// $remark = '开启奖金模式';
|
||||
// }
|
||||
|
||||
$this->title = "恭喜您!开通{$identityMiddle->identity->name}成功!";
|
||||
$this->identityMiddle = $identityMiddle;
|
||||
$this->identity = $identity;
|
||||
$this->remark = $remark;
|
||||
$this->url = config('user.web.base');
|
||||
}
|
||||
|
||||
public function via(): array
|
||||
{
|
||||
return [DatabaseChannel::class, WechatMiniChannel::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 开通会员
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/9 10:44
|
||||
* @param User $notifiable
|
||||
* @return bool
|
||||
*/
|
||||
public function toWeChat(User $notifiable): bool
|
||||
{
|
||||
if ($notifiable->isOfficialSubscribe()) {
|
||||
$app = app('wechat.official_account');
|
||||
|
||||
$start_at = $this->identityMiddle->started_at ?? '';
|
||||
$end_at = $this->identityMiddle->ended_at ?? '';
|
||||
$time = $start_at.' ~ '.$end_at;
|
||||
if (empty($start_at) || empty($end_at)) {
|
||||
$time = '永久';
|
||||
}
|
||||
|
||||
$app->template_message->send([
|
||||
'touser' => $notifiable->wechat->official_openid,
|
||||
'template_id' => 'gtS1LS9Irw7h2RtQLT5Cxx4p28-k8PrPyH53HBU2oWk',
|
||||
'url' => $this->url,
|
||||
'data' => [
|
||||
'first' => $this->title,
|
||||
'keyword1' => $time,
|
||||
'keyword2' => $this->remark,
|
||||
'remark' => '',
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送到数据库
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toDatabase(User $notifiable): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'content' => $this->remark,
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
}
|
||||
90
app/Notifications/SystemOrderDelivered.php
Normal file
90
app/Notifications/SystemOrderDelivered.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Channels\WechatMiniChannel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Channels\DatabaseChannel;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Modules\Mall\Models\Order;
|
||||
use Modules\Mall\Models\OrderExpress;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class SystemOrderDelivered extends Notification
|
||||
{
|
||||
|
||||
use Queueable;
|
||||
|
||||
protected $order;
|
||||
protected $title;
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($title, Order $order, $url = '')
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->order = $order;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function via(): array
|
||||
{
|
||||
return [DatabaseChannel::class, WechatMiniChannel::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 订单发货
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/4 16:22
|
||||
* @param User $notifiable
|
||||
* @return bool
|
||||
*/
|
||||
public function toWeChat(User $notifiable): bool
|
||||
{
|
||||
if ($notifiable->isOfficialSubscribe()) {
|
||||
$app = app('wechat.official_account');
|
||||
$remark = '您的宝贝已经发货,请耐心等待';
|
||||
if ($this->order->express->type == OrderExpress::TYPE_LOGISTICS) {
|
||||
$remark .= ',经办人:'.$this->order->express->person;
|
||||
}
|
||||
|
||||
$res = $app->template_message->send([
|
||||
'touser' => $notifiable->wechat->official_openid,
|
||||
'template_id' => 'UvUA6wvPSegvT7i8IVrLipktbtCmyjtdnuKD8EvyOO8',
|
||||
'url' => $this->url,
|
||||
'data' => [
|
||||
'first' => $this->title,
|
||||
'keyword1' => $this->order->order_no,
|
||||
'keyword2' => $this->order->express->deliver_at,
|
||||
'keyword3' => $this->order->express->express_id > 0 ? $this->order->express->express->name : '',
|
||||
'keyword4' => $this->order->express->express_no ?? '',
|
||||
'keyword5' => $this->order->express->getFullAddress(),
|
||||
'remark' => $remark,
|
||||
],
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 数据库
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/4 16:38
|
||||
* @param User $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toDatabase(User $notifiable): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'content' => '订单编号:'.$this->order->order_no.' 已发货',
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
}
|
||||
81
app/Notifications/SystemRemindUserSign.php
Normal file
81
app/Notifications/SystemRemindUserSign.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Channels\WechatMiniChannel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Channels\DatabaseChannel;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class SystemRemindUserSign extends Notification
|
||||
{
|
||||
|
||||
use Queueable;
|
||||
|
||||
protected $content;
|
||||
protected $title;
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->title = '喝水打卡提醒';
|
||||
$this->content = '您今天还没有喝水打卡,请前去打卡';
|
||||
$this->url = config('user.web.base');
|
||||
}
|
||||
|
||||
public function via(): array
|
||||
{
|
||||
return [DatabaseChannel::class, WechatMiniChannel::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 喝水打卡提醒
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/8 8:48
|
||||
* @param User $notifiable
|
||||
* @return bool
|
||||
*/
|
||||
public function toWeChat(User $notifiable): bool
|
||||
{
|
||||
if ($notifiable->isOfficialSubscribe()) {
|
||||
$app = app('wechat.official_account');
|
||||
|
||||
$app->template_message->send([
|
||||
'touser' => $notifiable->wechat->official_openid,
|
||||
'template_id' => 'N7-vo1bSYXahw22pplkHtI7WGg96dPf1KdMxbKdx6ao',
|
||||
'url' => $this->url,
|
||||
'data' => [
|
||||
'first' => $this->title,
|
||||
'keyword1' => now(),
|
||||
'keyword2' => $this->content,
|
||||
'remark' => '',
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送到数据库
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toDatabase(User $notifiable): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'content' => $this->content,
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
}
|
||||
81
app/Notifications/SystemUpdateCase.php
Normal file
81
app/Notifications/SystemUpdateCase.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Channels\WechatMiniChannel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Channels\DatabaseChannel;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Modules\User\Models\IdentityMiddle;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
class SystemUpdateCase extends Notification
|
||||
{
|
||||
|
||||
use Queueable;
|
||||
|
||||
protected $content;
|
||||
protected $title;
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->title = '上传报告提醒';
|
||||
$this->url = config('user.web.base');
|
||||
}
|
||||
|
||||
public function via(): array
|
||||
{
|
||||
return [DatabaseChannel::class, WechatMiniChannel::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 喝水打卡提醒
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/8 8:48
|
||||
* @param User $notifiable
|
||||
* @return bool
|
||||
*/
|
||||
public function toWeChat(User $notifiable): bool
|
||||
{
|
||||
if ($notifiable->isOfficialSubscribe()) {
|
||||
$app = app('wechat.official_account');
|
||||
|
||||
$app->template_message->send([
|
||||
'touser' => $notifiable->wechat->official_openid,
|
||||
'template_id' => '3sksrHdMTu3k1yderqyP5hOYXWltNf-CvESRG4r3Fnc',
|
||||
'url' => $this->url,
|
||||
'data' => [
|
||||
'first' => $this->title,
|
||||
'keyword1' => now(),
|
||||
'keyword2' => '您已经连续打卡30天,请上传报告',
|
||||
'remark' => '',
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送到数据库
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toDatabase(User $notifiable): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'content' => '您已经连续打卡30天,请上传报告',
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
}
|
||||
28
app/Providers/AppServiceProvider.php
Normal file
28
app/Providers/AppServiceProvider.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
30
app/Providers/AuthServiceProvider.php
Normal file
30
app/Providers/AuthServiceProvider.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The policy mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $policies = [
|
||||
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
|
||||
];
|
||||
|
||||
/**
|
||||
* Register any authentication / authorization services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->registerPolicies();
|
||||
|
||||
//
|
||||
}
|
||||
}
|
||||
21
app/Providers/BroadcastServiceProvider.php
Normal file
21
app/Providers/BroadcastServiceProvider.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Broadcast;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class BroadcastServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Broadcast::routes();
|
||||
|
||||
require base_path('routes/channels.php');
|
||||
}
|
||||
}
|
||||
32
app/Providers/EventServiceProvider.php
Normal file
32
app/Providers/EventServiceProvider.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Listeners\UserOrderPaidListener;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Modules\User\Events\UserOrderPaid;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The event listener mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listen = [
|
||||
//开通会员
|
||||
UserOrderPaid::class => [
|
||||
UserOrderPaidListener::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Register any events for your application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
63
app/Providers/RouteServiceProvider.php
Normal file
63
app/Providers/RouteServiceProvider.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The path to the "home" route for your application.
|
||||
*
|
||||
* This is used by Laravel authentication to redirect users after login.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const HOME = '/home';
|
||||
|
||||
/**
|
||||
* The controller namespace for the application.
|
||||
*
|
||||
* When present, controller route declarations will automatically be prefixed with this namespace.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
// protected $namespace = 'App\\Http\\Controllers';
|
||||
|
||||
/**
|
||||
* Define your route model bindings, pattern filters, etc.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->configureRateLimiting();
|
||||
|
||||
$this->routes(function () {
|
||||
Route::prefix('api')
|
||||
->middleware('api')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/api.php'));
|
||||
|
||||
Route::middleware('web')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/web.php'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the rate limiters for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureRateLimiting()
|
||||
{
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
|
||||
});
|
||||
}
|
||||
}
|
||||
84
app/Traits/HasClicks.php
Normal file
84
app/Traits/HasClicks.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* 预期给所有拥有浏览计数的模型使用
|
||||
* 使用缓存,计算浏览量,定期更新缓存至数据库中
|
||||
*/
|
||||
trait HasClicks
|
||||
{
|
||||
|
||||
protected int $saveRate = 20;
|
||||
|
||||
/**
|
||||
* Notes : 获取点击量的字段
|
||||
* @Date : 2021/3/17 9:39 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
private function getClicksField(): string
|
||||
{
|
||||
return $this->clicks_filed ?? 'clicks';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取缓存前缀
|
||||
* @Date : 2021/3/16 5:52 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
private function getClickCachePrefix(): string
|
||||
{
|
||||
return $this->cachePrefix ?? class_basename(__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 生成一个缓存KEY
|
||||
* @Date : 2021/3/16 5:52 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param string|null $appends
|
||||
* @return string
|
||||
*/
|
||||
private function getCacheKey(string $appends = null): string
|
||||
{
|
||||
return $this->getClickCachePrefix() . ':' . $this->getKey() . ':' . $appends;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 增加点击量
|
||||
* @Date : 2021/3/17 9:20 上午
|
||||
* @Author : < Jason.C >
|
||||
* @param int $step
|
||||
*/
|
||||
public function incrementClicks(int $step = 1): void
|
||||
{
|
||||
Cache::increment($this->getCacheKey('clicks'), $step);
|
||||
|
||||
if (rand(1, $this->saveRate) === 1) {
|
||||
$this->update([$this->getClicksField() => $this->clicks]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取缓存的浏览次数
|
||||
* @Date : 2021/3/16 5:52 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return int
|
||||
*/
|
||||
public function getClicksAttribute(): int
|
||||
{
|
||||
$clicks = Cache::get($this->getCacheKey('clicks'));
|
||||
|
||||
if (is_null($clicks)) {
|
||||
return Cache::rememberForever($this->getCacheKey('clicks'), function () {
|
||||
return $this->getAttributes()[$this->getClicksField()];
|
||||
});
|
||||
} else {
|
||||
return $clicks;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
83
app/Traits/HasCovers.php
Normal file
83
app/Traits/HasCovers.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait HasCovers
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 获取封面图片字段(单图)
|
||||
* @Date : 2021/3/16 4:34 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
public function getCoverField(): string
|
||||
{
|
||||
return $this->cover_field ?? 'cover';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取图片字段(多图)
|
||||
* @Date : 2021/3/16 4:35 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
public function getPicturesField(): string
|
||||
{
|
||||
return $this->pictures_field ?? 'pictures';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 解析单图地址
|
||||
* @Date : 2021/3/16 4:54 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
public function getCoverUrlAttribute(): string
|
||||
{
|
||||
$cover = $this->getAttribute($this->getCoverField());
|
||||
|
||||
return $this->parseImageUrl($cover);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 解析多图地址
|
||||
* @Date : 2021/3/16 4:54 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return array
|
||||
*/
|
||||
public function getPicturesUrlAttribute(): array
|
||||
{
|
||||
$pictures = $this->getAttribute($this->getPicturesField());
|
||||
|
||||
if (empty($pictures)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return collect($pictures)->map(function ($picture) {
|
||||
return $this->parseImageUrl($picture);
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 解析图片文件的实际展示地址
|
||||
* @Date : 2021/3/16 4:53 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param string|null $image
|
||||
* @return string
|
||||
*/
|
||||
public function parseImageUrl(?string $image): string
|
||||
{
|
||||
if (empty($image)) {
|
||||
return '';
|
||||
} elseif (Str::startsWith($image, 'http')) {
|
||||
return $image;
|
||||
} else {
|
||||
return Storage::url($image);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
87
app/Traits/HasStatus.php
Normal file
87
app/Traits/HasStatus.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
trait HasStatus
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 获取状态字段,主模型可配置 $status_field
|
||||
* @Date : 2021/3/16 4:34 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
protected function getStatusField(): string
|
||||
{
|
||||
return $this->status_field ?? 'status';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取各状态的名称
|
||||
* @Date : 2021/5/27 11:50 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getStatusMap(): array
|
||||
{
|
||||
return isset($this->status_map) && !empty($this->status_map) ? $this->status_map : [
|
||||
0 => '待审核',
|
||||
1 => '正常',
|
||||
2 => '驳回',
|
||||
3 => '关闭',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 正常显示的数据
|
||||
* @Author:<Mr.Wang>
|
||||
* @Date :2021-04-09
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeShown(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->getStatusField(), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不显示的数据
|
||||
* @Author :<Mr.Wang>
|
||||
* @Date :2021-04-09
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeHidden(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->getStatusField(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 状态查询
|
||||
* @Date : 2021/6/28 10:25 上午
|
||||
* @Author : < Jason.C >
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param int $status
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeOfStatus(Builder $query, int $status): Builder
|
||||
{
|
||||
return $query->where($this->getStatusField(), $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取状态的文本信息
|
||||
* @Date : 2021/4/25 2:10 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusTextAttribute(): string
|
||||
{
|
||||
$map = $this->getStatusMap();
|
||||
|
||||
return $map[$this->{$this->getStatusField()}] ?? '未知';
|
||||
}
|
||||
|
||||
}
|
||||
50
app/Traits/Macroable.php
Normal file
50
app/Traits/Macroable.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
trait Macroable
|
||||
{
|
||||
|
||||
use \Illuminate\Support\Traits\Macroable {
|
||||
__call as macroCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRelationValue($key)
|
||||
{
|
||||
$relation = parent::getRelationValue($key);
|
||||
if (!$relation && static::hasMacro($key)) {
|
||||
return $this->getRelationshipFromMethod($key);
|
||||
}
|
||||
|
||||
return $relation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (static::hasMacro($method)) {
|
||||
return $this->macroCall($method, $parameters);
|
||||
}
|
||||
|
||||
return parent::__call($method, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic($method, $parameters)
|
||||
{
|
||||
return parent::__callStatic($method, $parameters);
|
||||
}
|
||||
|
||||
}
|
||||
22
app/Traits/OrderByIdDesc.php
Normal file
22
app/Traits/OrderByIdDesc.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
trait OrderByIdDesc
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes: 初始化trait,自动在模型中,注入作用域
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/19 1:42 下午
|
||||
*/
|
||||
public static function bootOrderByIdDesc(): void
|
||||
{
|
||||
static::addGlobalScope(function (Builder $builder) {
|
||||
$builder->orderByDesc('id');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
22
app/Traits/OrderByOrderAsc.php
Normal file
22
app/Traits/OrderByOrderAsc.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
trait OrderByOrderAsc
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes: 初始化trait,自动在模型中,注入作用域
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/19 1:42 下午
|
||||
*/
|
||||
public static function bootOrderByOrderAsc(): void
|
||||
{
|
||||
static::addGlobalScope(function (Builder $builder) {
|
||||
$builder->orderBy('order')->orderByDesc('id');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
65
app/Traits/WithPosition.php
Normal file
65
app/Traits/WithPosition.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
trait WithPosition
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 获取定位的数组
|
||||
* @Date : 2021/7/2 11:31 上午
|
||||
* @Author : < Jason.C >
|
||||
*/
|
||||
protected function getPositionMap(): array
|
||||
{
|
||||
return $this->position_map ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 定位查询作用域
|
||||
* @Author: Mr.wang
|
||||
* @Date : 2021/5/11 10:48
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param int $pos
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeOfPosition(Builder $query, int $pos): Builder
|
||||
{
|
||||
return $query->whereRaw('position & ' . $pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 设置定位
|
||||
* @Author: Mr.wang
|
||||
* @Date : 2020/5/11 10:48
|
||||
* @param int $value
|
||||
*/
|
||||
protected function setPositionAttribute($value): void
|
||||
{
|
||||
if (is_array($value) && !blank($value)) {
|
||||
$this->attributes['position'] = array_sum($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取定位数据
|
||||
* @Author: Mr.wang
|
||||
* @Date : 2020/5/11 10:48
|
||||
* @param int $value
|
||||
* @return array
|
||||
*/
|
||||
protected function getPositionAttribute(int $value): array
|
||||
{
|
||||
$position = [];
|
||||
foreach ($this->getPositionMap() as $k => $v) {
|
||||
if ($k & $value) {
|
||||
array_push($position, $k);
|
||||
}
|
||||
}
|
||||
|
||||
return $position;
|
||||
}
|
||||
|
||||
}
|
||||
53
artisan
Normal file
53
artisan
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register The Auto Loader
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Composer provides a convenient, automatically generated class loader
|
||||
| for our application. We just need to utilize it! We'll require it
|
||||
| into the script here so that we do not have to worry about the
|
||||
| loading of any our classes "manually". Feels great to relax.
|
||||
|
|
||||
*/
|
||||
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Run The Artisan Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When we run the console application, the current CLI command will be
|
||||
| executed in this console and the response sent back to a terminal
|
||||
| or another output device for the developers. Here goes nothing!
|
||||
|
|
||||
*/
|
||||
|
||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||
|
||||
$status = $kernel->handle(
|
||||
$input = new Symfony\Component\Console\Input\ArgvInput,
|
||||
new Symfony\Component\Console\Output\ConsoleOutput
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Shutdown The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Once Artisan has finished running, we will fire off the shutdown events
|
||||
| so that any final work may be done by the application before we shut
|
||||
| down the process. This is the last thing to happen to the request.
|
||||
|
|
||||
*/
|
||||
|
||||
$kernel->terminate($input, $status);
|
||||
|
||||
exit($status);
|
||||
55
bootstrap/app.php
Normal file
55
bootstrap/app.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The first thing we will do is create a new Laravel application instance
|
||||
| which serves as the "glue" for all the components of Laravel, and is
|
||||
| the IoC container for the system binding all of the various parts.
|
||||
|
|
||||
*/
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bind Important Interfaces
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, we need to bind some important interfaces into the container so
|
||||
| we will be able to resolve them when needed. The kernels serve the
|
||||
| incoming requests to this application from both the web and CLI.
|
||||
|
|
||||
*/
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Http\Kernel::class,
|
||||
App\Http\Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Console\Kernel::class,
|
||||
App\Console\Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Return The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This script returns the application instance. The instance is given to
|
||||
| the calling script so we can separate the building of the instances
|
||||
| from the actual running of the application and sending responses.
|
||||
|
|
||||
*/
|
||||
|
||||
return $app;
|
||||
2
bootstrap/cache/.gitignore
vendored
Normal file
2
bootstrap/cache/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
96
composer.json
Normal file
96
composer.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"name": "uztech/laravel",
|
||||
"type": "project",
|
||||
"description": "The Laravel Framework.",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.4|^8.0",
|
||||
"alibabacloud/sts": "^1.8",
|
||||
"encore/laravel-admin": "^1.8",
|
||||
"fideloper/proxy": "^4.4",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"genealabs/laravel-model-caching": "^0.11.3",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"iidestiny/laravel-filesystem-oss": "^2.1",
|
||||
"intervention/image": "^2.5",
|
||||
"jasonc/api": "^5.0.0",
|
||||
"joshbrw/laravel-module-installer": "^2.0",
|
||||
"laravel-admin-ext/grid-lightbox": "^1.0",
|
||||
"laravel/framework": "^8.5",
|
||||
"liuhelong/laravel-admin-wechat": "^1.3",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"nosun/ueditor": "^3.0",
|
||||
"nwidart/laravel-modules": "^8.2",
|
||||
"overtrue/chinese-calendar": "^1.0",
|
||||
"overtrue/easy-sms": "^1.3",
|
||||
"overtrue/laravel-favorite": "^4.0",
|
||||
"overtrue/laravel-lang": "~5.0",
|
||||
"overtrue/laravel-query-logger": "^2.1",
|
||||
"overtrue/laravel-subscribe": "3.1.0",
|
||||
"overtrue/laravel-versionable": "^2.6",
|
||||
"overtrue/laravel-wechat": "^6.0",
|
||||
"overtrue/socialite": "^3.2",
|
||||
"overtrue/wechat": "^5.0",
|
||||
"propaganistas/laravel-phone": "^4.3",
|
||||
"simplesoftwareio/simple-qrcode": "^4.2",
|
||||
"symfony/workflow": "^5.2",
|
||||
"vinkla/hashids": "^9.1",
|
||||
"wang-tech-commits/kuaidi100-api": "^1.0",
|
||||
"xuanchen/tencent-map-api": "^1.0",
|
||||
"yangjisen/laravel-cache-provider": "^3.0",
|
||||
"yansongda/pay": "^3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"facade/ignition": "^2.5",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"laravel/sail": "^1.0.1",
|
||||
"mockery/mockery": "^1.4.2",
|
||||
"nunomaduro/collision": "^5.0",
|
||||
"phpunit/phpunit": "^9.3.3"
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"easywechat-composer/easywechat-composer": true,
|
||||
"joshbrw/laravel-module-installer": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Modules\\": "modules/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi"
|
||||
]
|
||||
}
|
||||
}
|
||||
13154
composer.lock
generated
Normal file
13154
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user