初始化

main
vine_liutk 2023-12-05 11:58:03 +08:00
commit acc814fa6a
1179 changed files with 343446 additions and 0 deletions

15
.editorconfig 100644
View 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

67
.env.example 100644
View File

@ -0,0 +1,67 @@
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
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
ALIYUN_OSS_PUBLIC_DOMAIN=
ALIYUN_OSS_PRIVATE_DOMAIN=
ALIYUN_OSS_ACCESS_KEY=
ALIYUN_OSS_ACCESS_SECRET=
ALIYUN_OSS_BUCKET=
ALIYUN_OSS_ENDPOINT=
ALIYUN_OSS_IS_CNAME=
ALIYUN_OSS_CDN_DOMAIN=
ALIYUN_OSS_IS_SSL=
ALIYUN_OSS_BUCKET_PRIVATE=
ALIYUN_OSS_DOMAIN=
ALIYUN_STS_RAM=
ALIYUN_STS_ENDPOINT=
ALIYUN_STS_REGION_ID=
OSS_URL=
JWT_SECRET=

5
.gitattributes vendored 100644
View File

@ -0,0 +1,5 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore

14
.gitignore vendored 100644
View File

@ -0,0 +1,14 @@
/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
projects

13
.styleci.yml 100644
View 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

36
README.en.md 100644
View File

@ -0,0 +1,36 @@
# 奶茶后台
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

6
README.md 100644
View File

@ -0,0 +1,6 @@
composer install
php artisan admin:install
php artisan db:seed

View File

@ -0,0 +1,37 @@
<?php
namespace App\Admin\Actions\Forms;
use Dcat\Admin\Models\Administrator;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;
use Dcat\Admin\Contracts\LazyRenderable;
class CreateTypeAttr extends Form implements LazyRenderable
{
use LazyWidget; // 使用异步加载功能
// 处理请求
public function handle(array $input)
{
// 获取外部传递参数
$id = $this->payload['id'] ?? null;
// 表单参数
$password = $input['password'] ?? null;
return $this->response()->success('创建成功');
}
public function form()
{
// 获取外部传递参数
//$id = $this->payload['id'] ?? null;
$this->text('attr_name', '属性名称')->required();
// $this->radio('attr_input')->options(['1'=>'输入值', '2'=>'选择值'])->default(2);
// $this->radio('attr_type')->options(['0'=>'只读','1'=>'单选加价'])->default(1);
$this->textarea('ext', '可选值')->help('换行添加可选项')->rows(5);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Admin\Actions\Forms;
use Dcat\Admin\Admin;
use Dcat\Admin\Models\Administrator;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;
use Dcat\Admin\Contracts\LazyRenderable;
use App\Admin\Renderable\QuanTicketTable;
use App\Models\{QuanTicket, User};
class SendQuanTicket extends Form implements LazyRenderable
{
use LazyWidget; // 使用异步加载功能
// 处理请求
public function handle(array $input)
{
// 获取外部传递参数
$id = $this->payload['id'] ?? null;
$user = User::findOrFail($id);
$admin_user = Admin::user()->id;
// 表单参数
$send_tickets = $input['send_ticket'] ?? [];
$user->sendTicket($send_tickets, $admin_user, '系统后台发送');
// dd($send_tickets);
return $this->response()->success('发送成功');
}
public function form()
{
$this->multipleSelectTable('send_ticket', '优惠券')
->from(QuanTicketTable::make())
->model(QuanTicket::class, 'id', 'quan_name');
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Admin\Actions\Grid;
use Dcat\Admin\Grid\RowAction;
use App\Admin\Forms\GuessAnswer as GuessAnswerForm;
use Dcat\Admin\Widgets\Modal;
class GuessAnswer extends RowAction
{
protected $title = '公布答案';
public function render()
{
$form = GuessAnswerForm::make()->payload(['id' => $this->getKey()]);
return Modal::make()
->lg()
->title($this->row->name)
->body($form)
->button($this->title);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Admin\Actions\RowActions;
use App\Admin\Actions\Forms\CreateTypeAttr as CreateTypeAttrForm;
use Dcat\Admin\Widgets\Modal;
use Dcat\Admin\Grid\RowAction;
class CreateTypeAttr extends RowAction
{
protected $title = '新增属性';
protected $model;
public function __construct(string $model = null)
{
$this->model = $model;
}
public function render()
{
// 实例化表单类并传递自定义参数
$form = CreateTypeAttrForm::make()->payload(['id' => $this->getKey()]);
return Modal::make()
->lg()
->title($this->title)
->body($form)
->button($this->title);
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace App\Admin\Actions\RowActions;
use Dcat\Admin\Grid\RowAction;
use App\Models\TypeAttr;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;
class DeleteTypeAttr extends RowAction
{
protected $model;
public function __construct(string $model = null)
{
$this->model = $model;
}
/**
* 标题
*
* @return string
*/
public function title()
{
return '删除属性';
}
/**
* 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
*
* 允许返回字符串或数组类型
*
* @return array|string|void
*/
public function confirm()
{
return [
// 确认弹窗 title
"您确定要删除这行数据吗?",
// 确认弹窗 content
$this->row->attr_name,
];
}
/**
* 处理请求
*
* @param Request $request
*
* @return \Dcat\Admin\Actions\Response
*/
public function handle(Request $request)
{
// 获取当前行ID
$id = $this->getKey();
$attr = TypeAttr::find($id);
$attr->delete();
// 返回响应结果并刷新页面
return $this->response()->success("删除成功")->refresh();
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace App\Admin\Actions\RowActions;
use Dcat\Admin\Grid\RowAction;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;
use App\Jobs\SendPickUpOrderNotice;
class OrderPickUpNotice extends RowAction
{
/**
* 标题
*
* @return string
*/
public function title()
{
return '提醒取餐';
}
/**
* 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
*
* 允许返回字符串或数组类型
*
* @return array|string|void
*/
public function confirm()
{
return [
// 确认弹窗 title
$this->row->order_number,
// 确认弹窗 content
"您确定要该订单餐品已制作完成吗?",
];
}
/**
* 处理请求
*
* @param Request $request
*
* @return \Dcat\Admin\Actions\Response
*/
public function handle(Request $request)
{
// 获取当前行ID
$id = $this->getKey();
$order = Order::findOrFail($id);
$order->pickup_notice = 1;
$order->save();
SendPickUpOrderNotice::dispatch($order);
// 返回响应结果并刷新页面
return $this->response()->success("提醒成功")->refresh();
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Admin\Actions\RowActions;
use Dcat\Admin\Grid\RowAction;
use App\Admin\Actions\Forms\SendQuanTicket as SendQuanTicketForm;
use Dcat\Admin\Widgets\Modal;
class SendUserTicket extends RowAction
{
protected $title = '发放优惠券';
public function render()
{
// 实例化表单类并传递自定义参数
$form = SendQuanTicketForm::make()->payload(['id' => $this->getKey()]);
return Modal::make()
->lg()
->title($this->title)
->body($form)
->button($this->title);
}
}

View File

@ -0,0 +1,106 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\ActivityDayGood;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
class ActivityDayGoodController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
$builder = ActivityDayGood::with('goods');
return Grid::make($builder, function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('title');
$grid->column('goods.goods_name', '商品名称');
$grid->column('start_time');
$grid->column('end_time');
$grid->column('goods_num')->help('库存修改,次日生效');
$grid->column('buy_times');
$grid->column('buy_num');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('id');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
$builder = ActivityDayGood::with('goods');
return Show::make($id, $builder, function (Show $show) {
$show->field('id');
$show->field('title');
$show->field('goods.goods_name', '商品名称');
$show->field('start_time');
$show->field('end_time');
$show->field('goods_num');
$show->field('buy_times');
$show->field('buy_num');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$builder = ActivityDayGood::with('dayNum');
return Form::make($builder, function (Form $form) {
$form->display('id');
$form->text('title')->required();
$form->select('goods_id', '活动商品')->options(admin_route('goods.api', ['is_sell'=>0]))->required();
$form->editor('content', '活动详情')->required();
$form->dateRange('start_time', 'end_time', '活动时间范围')->required();
$form->number('buy_times')->default(1);
$form->number('buy_num')->default(1);
$form->number('goods_num')->default(1)->help('库存修改,次日生效');
$form->hasMany('day_num', function(Form\NestedForm $form) {
$form->column(2, function(Form\NestedForm $form){
});
$form->column(4, function(Form\NestedForm $form){
$form->date('time');
});
$form->column(4, function(Form\NestedForm $form){
$form->number('goods_num', '每日库存')->default(1);
});
});
$form->saving(function (Form $form) {
// 判断是否是新增操作
$form->start_time .= ' 00:00:00';
$form->end_time .= ' 23:59:59';
if ($form->start_time >= $form->end_time) {
// 中断后续逻辑
return $form->response()->error('开始时间不能大于结束时间。');
}
});
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,122 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\ActivityGood;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use App\Models\ActivityOption;
class ActivityGoodController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
$awrad_array = [];
$awrad_array = ActivityOption::where('key_type', 0)
// ->where(['is_hot'=>0,'is_all'=>0])
->pluck('key_name', 'id')->toArray();
$builder = ActivityGood::with('goods');
return Grid::make($builder, function (Grid $grid) use ($awrad_array) {
$grid->column('id')->sortable();
$grid->column('goods.goods_name', '商品名称');
$grid->column('award_ids', '兑换配置')->display(function() use ($awrad_array){
$array = [];
for($i =1; $i<10; $i++){
$key = 'award_'.$i;
if($this->$key){
$array[] = $awrad_array[$i];
}
}
return $array;
})->label();
// $grid->column('award_1');
// $grid->column('award_2');
// $grid->column('award_3');
// $grid->column('award_4');
// $grid->column('award_5');
// $grid->column('award_6');
// $grid->column('award_7');
// $grid->column('award_8');
// $grid->column('award_9');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
// 禁用详情按钮
$grid->disableViewButton();
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->equal('goods_id')->select(admin_route('goods.api'));
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new ActivityGood(), function (Show $show) {
$show->field('id');
$show->field('goods_id');
$show->field('award_1');
$show->field('award_2');
$show->field('award_3');
$show->field('award_4');
$show->field('award_5');
$show->field('award_6');
$show->field('award_7');
$show->field('award_8');
$show->field('award_9');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$awrad_array = [];
$awrad_array = ActivityOption::where('key_type', 0)
// ->where(['is_hot'=>0,'is_all'=>0])
->pluck('key_name','id')->toArray();
return Form::make(new ActivityGood(), function (Form $form) use ($awrad_array) {
$form->display('id');
$form->select('goods_id')->options(admin_route('goods.api'))->required();
$form->radio('award_1', $awrad_array[1])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_2', $awrad_array[2])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_3', $awrad_array[3])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_4', $awrad_array[4])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_5', $awrad_array[5])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_6', $awrad_array[6])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_7', $awrad_array[7])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_8', $awrad_array[8])->options(['0' => '否', '1'=> '是'])->default('0');
$form->radio('award_9', $awrad_array[9])->options(['0' => '否', '1'=> '是'])->default('0');
$form->disableViewButton();
$form->display('created_at');
$form->display('updated_at');
$form->footer(function ($footer) {
// 去掉`查看`checkbox
$footer->disableViewCheck();
});
});
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\ActivityOption;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
class ActivityOptionController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new ActivityOption(), function (Grid $grid) {
// $grid->column('id')->sortable();
$grid->column('key_name')
->if(function($column){
return !$this->key_type;
})
->then(function (Grid\Column $column) {
$column->editable();
});
// $grid->column('key_type');
$grid->column('key_value')
->if(function($column){
return $this->key_type;
})
->then(function (Grid\Column $column) {
$column->editable();
})
->else(function (Grid\Column $column) {
$column->image($column->getValue(), 100, 100);
});
$grid->column('rate')->help('概率总和需要为100%')
->if(function($column){
return $this->key_type;
})
->then(function (Grid\Column $column) {
$column->display('--');
})
->else(function (Grid\Column $column) {
$column->editable();
});
$grid->column('is_all')
->if(function($column){
return $this->key_type || $this->is_niu;
})
->then(function (Grid\Column $column) {
$column->display('--');
})
->else(function (Grid\Column $column) {
$column->switch();
});
// $grid->column('is_niu')
// ->if(function($column){
// return $this->key_type;
// })
// ->then(function (Grid\Column $column) {
// $column->display('--');
// })
// ->else(function (Grid\Column $column) {
// $column->switch();
// });
// $grid->column('created_at');
// $grid->column('updated_at')->sortable();
$grid->model()->orderBy('id', 'desc');
$grid->disableCreateButton();
$grid->disableFilter();
$grid->disableActions();
$grid->disablePagination();
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new ActivityOption(), function (Form $form) {
$form->display('id');
$form->text('key_name');
$form->text('key_type');
$form->text('key_value');
$form->text('rate');
$form->text('is_all');
$form->text('is_niu');
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace App\Admin\Controllers;
use Carbon\Carbon;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use App\Models\{Good,GoodsCategory,GoodsType,TypeAttr,GoodsAttr,Order,Guess,User,QuanTicket};
use App\Http\Resources\OrderInfoResource;
use Dcat\Admin\Http\JsonResponse;
class ApiController extends Controller
{
public function getGoodsCategories(Request $request){
$q = $request->get('q');
$query = GoodsCategory::select('id', 'category_name as text');
if($q){
$query->where('category_name', 'like', "%$q%");
return $query->paginate(null);
}
return response()->json($query->get());
}
public function getGoodsTypes(Request $request){
$q = $request->get('q');
$query = GoodsType::select('id', 'type_name as text')->where('is_use', 1);
if($q){
$query->where('type_name', 'like', "%$q%");
return $query->paginate(null);
}
return response()->json($query->get());
}
public function getTypeAttrs(Request $request){
$q = $request->get('type_id');
$query = TypeAttr::select('id', 'attr_name', 'ext')->where('type_id', $q);
// if($q){
// $query->where('type_name', 'like', "%$q%");
// return $query->paginate(null);
// }
return response()->json($query->get());
}
public function getGoodsAttrs(Request $request){
$q = $request->get('goods_id');
$query = GoodsAttr::select('id', 'attr_value', 'value_price', 'is_use')->where('goods_id', $q);
// if($q){
// $query->where('type_name', 'like', "%$q%");
// return $query->paginate(null);
// }
return response()->json($query->get());
}
public function getGoods(Request $request){
$q = $request->get('q');
$is_sell = intval($request->get('is_sell', 1));
$query = Good::select('id', 'goods_name as text');
if($is_sell){
$query->where('is_sell', 1);
}
if($q){
$query->where('goods_name', 'like', "%$q%");
return $query->paginate(null);
}
return response()->json($query->get());
}
public function getOrder(Request $request){
$order_number = $request->get('order_number');
$start_time = Carbon::now()->startOfDay();
$end_time = Carbon::now()->endOfDay();
// $order = Order::with('goods')->findOrFail(296);
$order = Order::with('goods')
->whereBetween('number_time', [$start_time, $end_time])
->where('order_number', $order_number)->first();
if(!$order){
return JsonResponse::make()->error('未查询到订单');
}
$data = OrderInfoResource::make($order);
$data->offsetSet('is_admin', 1);
// if($q){
// $query->where('goods_name', 'like', "%$q%");
// return $query->paginate(null);
// }
return $data;
}
public function guess(Request $request)
{
$q = $request->get('q');
$data = Guess::where('name', 'like', "%$q%")->paginate(null, ['id', 'name as text']);
return $data ?: [];
}
public function user(Request $request)
{
$q = $request->get('q');
$query = User::select('id', 'nick_name as text');
if($q){
$query->where('phone', 'like', "%$q%");
return $query->paginate(null);
}
return response()->json($query->get());
}
public function ticketValue(Request $request){
$q = $request->get('q');
if($q == 0){//指定所有商品
return [];
}
if($q == 1){//查询上架商品
$query = Good::select('id', 'goods_name as text')->where('is_sell', 1);
}
if($q == 2){
$query = GoodsCategory::select('id', 'category_name as text');
}
return response()->json($query->get());
}
public function quanTicket(Request $request){
$q = $request->get('q');
$query = QuanTicket::select('id', 'quan_name as text')->where('is_use', 1);
if($q){
$query->where('quan_name', 'like', "%$q%");
return $query->paginate(null);
}
return response()->json($query->get());
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\Article;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Carbon\Carbon;
class ArticleController extends AdminController
{
protected $title = '文章管理';
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new Article(), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('title');
$grid->column('cover_res')->image(100, 100);
$grid->column('jump_link', '跳转链接');
// $grid->column('content');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->like('title');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new Article(), function (Show $show) {
$show->field('id');
$show->field('title');
$show->field('cover_res')->image(100, 100);
$show->field('jump_link', '跳转链接');
$show->field('content')->unescape();
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new Article(), function (Form $form) {
$form->display('id');
$form->text('title')->required();
$form->text('jump_link', '跳转链接');
$form->image('cover_res')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/article/'.Carbon::now()->toDateString())
->saveFullUrl()->removable(false)
->required()->help('建议图片尺寸686*388');
$form->editor('content');
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Admin\Controllers;
use Dcat\Admin\Http\Controllers\AuthController as BaseAuthController;
class AuthController extends BaseAuthController
{
}

View File

@ -0,0 +1,121 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\Banner;
use Carbon\Carbon;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
class BannerController extends AdminController
{
protected $title = 'Banner管理';
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new Banner(), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('banner_res')->image(100, 100);
$grid->column('banner_desc');
$grid->column('banner_address')->display(function($banner_address){
$address_options = [
'banner_index'=>"首页广告位",
'banner_goods'=>"商品广告位",
'register_gift'=>"注册活动广告位",
'vote_activity'=>"投票活动广告位",
];
return $address_options[$banner_address];
})->label();
$grid->column('jump_link', '跳转链接');
$grid->column('is_show')->switch();
$grid->column('sort')->editable();
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->equal('banner_address')->select([
'banner_index'=>"首页广告位",
'banner_goods'=>"商品广告位",
'register_gift'=>"注册活动广告位",
'vote_activity'=>"投票活动广告位",
]);
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new Banner(), function (Show $show) {
$show->field('id');
$show->field('banner_res')->image(100, 100);
$show->field('banner_desc');
$show->field('banner_address')->as(function($banner_address){
$address_options = [
'banner_index'=>"首页广告位",
'banner_goods'=>"商品广告位",
'register_gift'=>"注册活动广告位",
'vote_activity'=>"投票活动广告位",
];
return $address_options[$banner_address];
})->label();
$show->field('jump_link', '跳转链接');
$show->field('is_show')->as(function($is_show){
$options = [
'0'=>"",
'1'=>"",
];
return $options[$is_show];
})->label();
$show->field('sort');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new Banner(), function (Form $form) {
$form->display('id');
$form->image('banner_res')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/banners/'.Carbon::now()->toDateString())
->saveFullUrl()->removable(false)
->required()->help('建议图片尺寸:首页[750*580];商品列表[750*400]');
$form->text('banner_desc');
$form->select('banner_address', '广告位')->options([
'banner_index'=>"首页广告位",
'banner_goods'=>"商品广告位",
'register_gift'=>"注册活动广告位",
'vote_activity'=>"投票活动广告位",
])->default('banner_index');
$form->text('jump_link', '跳转链接');
$form->switch('is_show');
$form->number('sort')->default(0);
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,143 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\Good;
use App\Models\{ActivityGood, GoodsCart, Good as GoodModel};
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Carbon\Carbon;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Http\JsonResponse;
class GoodController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
$builder = Good::with(['category', 'type']);
return Grid::make($builder, function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('goods_name');
$grid->column('goods_cover')->image(100, 100);
$grid->column('category.category_name', '商品分类')->label();
// $grid->column('goods_des');
// $grid->column('goods_spu');
$grid->column('type.type_name', '商品类型')->label();
$grid->column('goods_price');
$grid->column('sell_num');
$grid->column('float_sell_null');
// $grid->column('is_too')->bool(['1' => true, '0' => false]);
$grid->column('is_hot')->switch();
$grid->column('is_sell')->switch()->help('已上架商品,下架会导致已加入购物车的商品清空,同时清空对应活动兑换配置');
// $grid->column('created_at');
// $grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->like('goods_name');
$filter->equal('category_id', '商品分类')->select(admin_route('goods_categories.api'));
$filter->equal('type_id', '商品类型')->select(admin_route('goods_types.api'));
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
$builder = Good::with(['category', 'type']);
return Show::make($id, $builder, function (Show $show) {
$show->field('id');
$show->field('goods_name');
$show->field('goods_des');
// $show->field('goods_spu');
$show->field('goods_cover')->image(100, 100);
$show->field('goods_image')->image(100, 100);
$show->field('category.category_name', '商品分类');
$show->field('type.type_name', '商品类型');
$show->field('goods_price');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$builder = Good::with('goods_attrs');
return Form::make($builder, function (Form $form) {
$form->display('id');
$form->text('goods_name');
$form->textarea('goods_des');
// $form->text('goods_spu');
$form->image('goods_cover')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/goods/'.Carbon::now()->toDateString())
->saveFullUrl()->removable(false)->autoUpload()
->required()->help('建议图片尺寸150*150');
$form->image('goods_image')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/goods/'.Carbon::now()->toDateString())
->saveFullUrl()->removable(false)->autoUpload()
->required()->help('建议图片尺寸750*580');
$form->select('category_id')->options(admin_route('goods_categories.api'))->required();
$form->select('type_id')->options(admin_route('goods_types.api'))->required();
$form->currency('goods_price')->symbol('¥')->default(0)->required();
$form->currency('market_price')->symbol('¥')->default(0);
$form->number('float_sell_null')->default(0);
// $form->switch('is_too', '第二杯半价')->default(0);
//上下架
if ($form->isEditing()) {
$form->hidden('is_hot');
$form->hidden('is_sell');
$form->saving(function (Form $form) {
//如果下架
if($form->model()->is_sell == 1 && !$form->is_sell){
// ActivityGood::where('goods_id', $form->model()->id)->delete();//清空对应兑换数据
GoodsCart::where('goods_id', $form->model()->id)->delete();//清空购物车数据
}
});
}
$form->selectAttr('goods_attrs', '属性')->listen('type_id');
// $form->sku('goods_attrs', '属性');
$form->display('created_at');
$form->display('updated_at');
});
}
public function edit($id, Content $content){
$goods = GoodModel::findOrFail($id);
if($goods->is_sell == 1){
admin_toastr('请先下架该商品', 'error');
return redirect(admin_route('goods.index'));
}
return parent::edit($id, $content);
}
public function destroy($id){
$goods = GoodModel::findOrFail($id);
if($goods->is_sell == 1){
return JsonResponse::make()->error('请先下架该商品');
// return Admin::make()->success('请先下架该商品');
}
return parent::destroy($id);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\GoodsCategory;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Carbon\Carbon;
class GoodsCategoryController extends AdminController
{
protected $title = '商品分类';
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new GoodsCategory(), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('category_name');
// $grid->column('category_icon')->image(100,100);
$grid->column('sort');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->equal('category_name');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new GoodsCategory(), function (Show $show) {
$show->field('id');
$show->field('category_name');
// $show->field('category_icon');
$show->field('sort');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new GoodsCategory(), function (Form $form) {
$form->display('id');
$form->text('category_name')->required();
// $form->image('category_icon')
// ->accept('jpg,png,gif,jpeg', 'image/*')
// ->move('milk-tea/goods_category/'.Carbon::now()->toDateString())
// ->saveFullUrl()->removable(false);
$form->number('sort')->default(0);
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\GoodsType;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use App\Admin\Renderable\TypeAttrTable;
use App\Admin\Actions\RowActions\CreateTypeAttr;
class GoodsTypeController extends AdminController
{
protected $title = '商品类型';
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new GoodsType(), function (Grid $grid) {
// $grid->model()->with(['attrs']);
$grid->column('id')->sortable();
$grid->column('type_name');
$grid->column('is_use')->switch();
$grid->column('attrs', '属性列表')->display('属性列表')->modal(TypeAttrTable::make());
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->actions(function (Grid\Displayers\Actions $actions){
// $actions->prepend(new CreateTypeAttr());//弹窗方式添加属性;
// $actions->prepend('<a href="'.admin_route('type_attr.index', ['type_id'=>$actions->getKey()]).'"><i title="属性列表" class="fa fa-bars"></i>&nbsp;&nbsp;</a>');
});
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('type_name');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new GoodsType(), function (Show $show) {
$show->field('id');
$show->field('type_name');
$show->field('is_use');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$builder = GoodsType::with('attrs');
return Form::make($builder, function (Form $form) {
$form->display('id');
$form->text('type_name');
$form->switch('is_use')->default(1);
$form->hasMany('attrs', function(Form\NestedForm $form) {
$form->text('attr_name');
$form->textarea('ext')->help('换行添加可选项')->rows(5);
});
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,169 @@
<?php
namespace App\Admin\Controllers;
use App\Models\{Guess, GuessOption, UserGuess};
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Carbon\Carbon;
use App\Admin\Renderable\GuessOptionsTable;
use App\Admin\Actions\Grid\GuessAnswer;
class GuessController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new Guess(), function (Grid $grid) {
$grid->model()->orderBy('created_at', 'desc');
$grid->disableRefreshButton();
$grid->disableRowSelector();
$grid->column('id');
$grid->column('name');
$grid->column('image', '分享图')->image('', 100);
$grid->column('guess_options', '选项统计')->display('选项列表')->modal(GuessOptionsTable::make());
// $grid->column('description');
$grid->column('start_time');
$grid->column('end_time');
$grid->column('status')->if(function ($column) {
return $this->prize_state === Guess::PRIZE_EXIST && $this->status === Guess::STATUS_DISABLE;
})->display(function () {
return '已结束';
})->else()->switch();
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->like('name')->width(3);
});
$grid->actions(function (Grid\Displayers\Actions $actions) {
// if ($actions->row->status === Guess::PRIZE_UNEXIST) {
$actions->append(new GuessAnswer());
// $actions->append(new GuessAnswer());
// }
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new Guess(), function (Show $show) {
$show->field('id');
$show->field('name');
// $show->field('banner_kv', '活动背景图')->image('', 100);
$show->field('image', '分享图')->image('', 100);
$show->field('description')->unescape();
$show->field('num');
$show->field('start_time');
$show->field('end_time');
$show->field('status')->as(function ($value) {
return $value ? '打开' : '关闭';
});
$show->field('created_at');
$show->options(function ($model) {
$grid = new Grid(new GuessOption());
$grid->disableRefreshButton();
$grid->disableRowSelector();
// $grid->disableCreateButton();
// $grid->disableActions();
$grid->setResource('guess-option');
$grid->model()->where('guess_id', $model->id);
$grid->id();
$grid->column('option_name', __('guess-option.fields.option_name'));
$grid->column('image')->image('', 100);
$grid->column('correct_state', __('guess-option.fields.correct_state'))
->using(GuessOption::$correctStateMap)->dot(GuessOption::$correctIcoMap);
return $grid;
});
// $show->users(function ($model) {
// $grid = new Grid(UserGuess::with(['user', 'options']));
// $grid->disableRefreshButton();
// $grid->disableRowSelector();
// $grid->disableCreateButton();
// $grid->disableActions();
// $grid->model()->where('guess_id', $model->id);
// $grid->column('id');
// $grid->column('user.phone', '用户');
// $grid->column('answers', '答案')->display(function () {
// return $this->options->implode('option_name', ', ');
// });
// $grid->column('correct_state', '是否正确')->using([
// 0 => '不正确',
// 1 => '正确',
// 2 => '未知'
// ])->dot([
// 0 => 'danger',
// 1 => 'success',
// 2 => 'warning',
// ]);
// $grid->column('created_at', '参与时间');
// return $grid;
// });
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(Guess::with(['options']), function (Form $form) {
$form->display('id');
$form->text('name')->required();
$form->datetimeRange('start_time', 'end_time', admin_trans('guess.fields.time'))->required();
// $form->text('description');
// $form->image('banner_kv', '活动背景图')
// ->accept('jpg,png,gif,jpeg', 'image/*')
// ->move('milk-tea/guess-options/'.Carbon::now()->toDateString())
// ->saveFullUrl()
// ->removable()->required();
$form->image('image', '分享图')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/guess-options/'.Carbon::now()->toDateString())
->saveFullUrl()
->removable();
$form->editor('description');
$form->number('num')->default(1)->min(1)->help('用户最多可选择几项');
$form->hidden('status')->default(Guess::STATUS_DISABLE);
// if ($form->isCreating()) {
// $form->hasMany('options', function (Form\NestedForm $form) {
// $form->text('option_name', __('guess-option.fields.option_name'));
// });
// }
// $form->saving(function (Form $form) {
// if (!$form->image) {
// $form->deleteInput('image');
// }
// });
});
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace App\Admin\Controllers;
use App\Models\{Guess, GuessOption};
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Carbon\Carbon;
class GuessOptionController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(GuessOption::with(['guess']), function (Grid $grid) {
$grid->model()->orderBy('id', 'desc');
$grid->disableRefreshButton();
$grid->disableRowSelector();
$grid->column('id');
$grid->column('guess.name', '活动');
$grid->column('option_name');
$grid->column('image')->image('', 100);
$grid->column('correct_state')->using(GuessOption::$correctStateMap)->dot(GuessOption::$correctIcoMap);
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->equal('guess_id')->select(function ($id) {
$guess = Guess::find($id);
if ($guess) {
return [$guess->id => $guess->name];
}
})->ajax('api/guess')->width(3);
$filter->like('option_name')->width(3);
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new GuessOption(), function (Show $show) {
$show->field('id');
$show->field('image')->image('', 100);
$show->field('option_name');
$show->field('description');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new GuessOption(), function (Form $form) {
$form->select('guess_id')->options(function ($id) {
$guess = Guess::find($id);
if ($guess) {
return [$guess->id => $guess->name];
}
})->ajax('api/guess')->required();
$form->image('image')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/guess/'.Carbon::now()->toDateString())
->saveFullUrl()
->removable();
$form->text('option_name');
$form->text('description');
$form->saving(function (Form $form) {
if (!$form->image) {
$form->image = '';
// $form->deleteInput('image');
}
});
});
}
}

View File

@ -0,0 +1,146 @@
<?php
namespace App\Admin\Controllers;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use App\Models\GuessOption;
use App\Models\{UserGuess, Guess, User};
use Dcat\Admin\Http\Controllers\AdminController;
class GuessUserController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(UserGuess::with(['guess', 'user', 'options']), function (Grid $grid) {
$grid->model()->orderBy('id', 'desc');
$grid->disableRefreshButton();
$grid->disableRowSelector();
$grid->disableCreateButton();
$grid->disableViewButton();
$grid->disableDeleteButton();
$grid->column('id');
$grid->column('guess.name', '活动');
$grid->column('user.phone', '用户');
$grid->column('answers', '回答')->display(function () {
return $this->options->implode('option_name', ', ');
});
$grid->column('correct_state')->using(UserGuess::$correctStateMap)->dot(UserGuess::$correctIcoMap);
$grid->column('prize_state')->using(UserGuess::$prizeStateMap)->dot(UserGuess::$correctIcoMap);
$grid->column('convert_time');
$grid->column('convert_prize_time');
$grid->column('created_at');
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->equal('guess_id')->select(function ($id) {
$guess = Guess::find($id);
if ($guess) {
return [$guess->id => $guess->name];
}
})->placeholder('输入活动名称搜索')->ajax('api/guess')->width(3);
$filter->equal('user_id')->select(function ($id) {
$guess = User::find($id);
if ($guess) {
return [$guess->id => $guess->name];
}
})->placeholder('输入手机号搜索')->ajax('api/user')->width(3);
$filter->equal('correct_state')->select(UserGuess::$correctStateMap)->width(3);
$filter->equal('prize_state')->select(UserGuess::$prizeStateMap)->width(3);
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, UserGuess::with(['guess', 'user']), function (Show $show) {
// dd($show);
$show->field('id');
$show->field('guess.name', '活动');
$show->field('user.phone', '用户');
$show->field('correct_state')->using(UserGuess::$correctStateMap)->dot(UserGuess::$correctIcoMap);
$show->field('prize_state')->using(UserGuess::$prizeStateMap)->dot(UserGuess::$correctIcoMap);
$show->field('convert_time');
$show->field('convert_prize_time');
$show->field('created_at');
$show->field('updated_at');
$show->options('用户选择选项', function ($grid) {
// dd($model);
// $grid = new Grid(new GuessOption());
// $grid->disableRefreshButton();
// $grid->disableRowSelector();
// $grid->disableCreateButton();
// $grid->disableActions();
// $grid->setResource('guess-option');
// // $grid->model()->where('guess_id', $model->id);
// $grid->column('id');
// $grid->column('option_name', __('guess-option.fields.option_name'));
// $grid->column('image')->image('', 100);
// $grid->column('correct_state', __('guess-option.fields.correct_state'))
// ->using(GuessOption::$correctStateMap)->dot(GuessOption::$correctIcoMap);
return $grid;
});
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(UserGuess::with(['guess', 'user', 'options']), function (Form $form) {
$form->display('id');
$form->display('guess.name', '活动');
$form->display('user.phone', '用户');
$form->display('answers', '用户选择')->with(function () {
return $this->options->implode('option_name', ', ');
});
$form->display('correct_state')->with(function ($value) {
$map =UserGuess::$correctStateMap;
return data_get($map, $value);
});
$form->display('prize_state')->with(function ($value) {
$map = UserGuess::$prizeStateMap;
return data_get($map, $value);
});
if ($form->model()->correct_state === UserGuess::CORRECT) {
$form->datetime('convert_time');
}
if ($form->model()->prize_state === UserGuess::PRIZE_YES) {
$form->datetime('convert_prize_time');
}
$form->disableViewButton();
$form->display('created_at');
});
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Metrics\Examples;
use App\Http\Controllers\Controller;
use Dcat\Admin\Http\Controllers\Dashboard;
use Dcat\Admin\Layout\Column;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Layout\Row;
use App\Admin\Metrics\{TotalUsers,NewUsers,TotalOrders,NewOrders,ProductOrders,OrderDevices};
class HomeController extends Controller
{
public function index(Content $content)
{
// $a = new OrderDevices();
// $a->fill();
return $content
->header('首页')
->description('数据统计')
// ->body(function (Row $row) {
// $row->column(4, new TotalUsers());//用户总数
// // 新用户数量趋势6
// $row->column(7, new NewUsers());
// })
->body(function (Row $row){
// 订单总数 3
$row->column(4, new TotalOrders());//订单总数
// 每日订单数量趋势,按天,按周,按月 6
$row->column(7, new NewOrders());
})->body(function (Row $row){
// 线上线下订单比例 6
// 小程序订单完成比例 6
$row->column(7, new ProductOrders());
// $row->column(4, new OrderDevices());
});
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace App\Admin\Controllers;
use Carbon\Carbon;
use App\Admin\Repositories\LuckDrawActivity;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use App\Admin\Renderable\LuckDrawTable;
use Dcat\Admin\Http\Controllers\AdminController;
class LuckDrawActivityController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new LuckDrawActivity(), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('activity_name');
// $grid->column('activity_kv');
// $grid->column('activity_desc');
$grid->column('options', '奖品列表')->display('奖品列表')->modal(LuckDrawTable::make());
$grid->column('one_draw')->append('分');
$grid->column('five_draw')->append('分');
$grid->column('start_time');
$grid->column('end_time');
$grid->column('created_at');
// $grid->column('updated_at')->sortable();
$grid->model()->orderBy('created_at', 'desc');
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('id');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new LuckDrawActivity(), function (Show $show) {
$show->field('id');
$show->field('activity_name');
$show->field('activity_kv');
$show->field('activity_desc');
$show->field('one_draw');
$show->field('five_draw');
$show->field('start_time');
$show->field('end_time');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(LuckDrawActivity::with('options'), function (Form $form) {
$form->display('id');
$form->text('activity_name')->required();
// $form->text('activity_kv');
$form->textarea('activity_desc');
$form->number('one_draw')->attribute('min', 0);
$form->number('five_draw')->attribute('min', 0);
$form->dateRange('start_time', 'end_time', '活动时间范围')->required()->help('开始日期0点~结束日期0点');
$form->hasMany('options', function($form) {
// $form->row(function (Form\Row $form){
// $form->horizontal();
// $form->width(6)->text('username')->width(8,4)->required();
// $form->text('title')->width(8);
// });
$form->column(2, function(Form\NestedForm $form){
});
$form->column(4, function(Form\NestedForm $form){
$form->select('draw_info','奖品')->options(admin_route('quan_ticket.api'))->required();
$form->text('draw_name','奖品名称')->required();
$form->image('draw_logo', '奖品图片')
->accept('jpg,png,gif,jpeg', 'image/*')
->move('milk-tea/activities/'.Carbon::now()->toDateString())
->saveFullUrl()->removable(false)
->required()->help('建议图片尺寸750*580');
});
$form->column(4, function(Form\NestedForm $form){
$form->currency('draw_rate', '中奖概率')->symbol('%')->default(0)->required();
$form->switch('is_five', '是否5连必中')->options(['0'=>'否','1'=>'是'])->default(0);
$form->radio('is_num', '是否限量')->when(0, function (Form\NestedForm $form) {
// $form->
})->when(1, function (Form\NestedForm $form) {
$form->number('draw_num', '限制数量');
})->options(['0'=>'不限量','1'=>'限量'])->default(0)->required();
});
});
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,287 @@
<?php
namespace App\Admin\Controllers;
use Carbon\Carbon;
use App\Admin\Repositories\{Order, OrderGoods};
use Illuminate\Http\Request;
use Dcat\Admin\Admin;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Dcat\Admin\Layout\Content;
use App\Admin\Pages\{CreateOrder,PickupOrder};
use App\Models\{Order as OrderModel};
use App\Services\OrderService;
use App\Admin\Actions\RowActions\OrderPickUpNotice;
use Dcat\Admin\Http\JsonResponse;
class OrderController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
$builder = Order::with(['user']);
return Grid::make($builder, function (Grid $grid) {
// $grid->column('id')->sortable();
$grid->column('order_sn');
$grid->column('order_number');
$grid->column('order_phone', '手机号');
$grid->column('order_price');
$grid->column('pay_type')->using(['1'=>'微信支付', '2' => '兑换支付', '3'=>'线下点单'])->label([
1 => 'success',
2 => 'warning',
3 => Admin::color()->info(),
]);
$grid->column('order_status')->bool(['1' => true, '-1' => false]);
$grid->column('pay_status')->bool(['1' => true, '0' => false]);
// $grid->column('shipping_status')->bool(['1' => true, '0' => false]);
// $grid->column('pay_time');
// $grid->column('shipping_time');
// $grid->column('closed_time');
// $grid->column('is_reserve','是否预约')->using(['1'=>'预约订单', '0' => '普通订单'])->label([
// 0 => 'success',
// 1 => 'danger',
// ]);
// $grid->column('is_niu')->using(['1'=>'吹牛订单', '0' => '普通订单'])->label([
// 0 => 'success',
// 1 => 'danger',
// ]);
$grid->column('created_at', '下单时间');
// $grid->column('updated_at')->sortable();
$grid->model()->orderBy('created_at', 'desc');
$grid->filter(function (Grid\Filter $filter) {
$filter->expand(false);
// $filter->equal('id');
$filter->equal('order_sn');
$filter->equal('pay_status')->select([0 => '未支付', 1 => '已支付'])->default(1);
$filter->equal('order_phone', '手机号');
$filter->between('created_at', '下单时间')->date();
});
$grid->actions(function (Grid\Displayers\Actions $actions) {
if($actions->row->order_status == 1){
$actions->disableDelete();
}
if( $actions->row->pay_type == 1 &&
$actions->row->order_status == 1 &&
$actions->row->pay_status != 3 &&
$actions->row->pickup_notice == 0 &&
!empty($actions->row->order_number)
){
$actions->append(new OrderPickUpNotice());
}
$actions->disableEdit();
});
$grid->header(function ($collection) use ($grid) {
$query = OrderModel::query();
// 拿到表格筛选 where 条件数组进行遍历
$grid->model()->getQueries()->unique()->each(function ($value) use (&$query) {
if (in_array($value['method'], ['paginate', 'get', 'orderBy', 'orderByDesc'], true)) {
return;
}
$query = call_user_func_array([$query, $value['method']], $value['arguments'] ?? []);
});
// 查出统计数据
$data = $query->get();
$total_fee = $data->sum('pay_price');
$total_num = $data->count();
return "<div style='padding: 10px;'>订单数:$total_num 单 | 统计收益 $total_fee 元</div>";
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, Order::with(['ticket','ticket.quanTicket']), function (Show $show) {
$show->row(function(Show\Row $show){
$show->width(4)->field('order_sn');
$show->width(4)->field('is_reserve', '是否预约')->using(['0' => '普通订单', '1'=>'预约订单'])->label()->append(function($info){
return $this->is_reserve? Carbon::parse($this->reserve_time)->toDateString():'';
});
// $show->width(4)->field('is_niu','是否吹牛')->using(['0' => '普通订单', '1'=>'吹牛订单'])->label();
});
$show->row(function(Show\Row $show){
$show->width(4)->field('order_number');
$show->width(4)->field('order_phone', '手机号');
$show->width(4)->field('order_price')->prepend('¥');
});
//优惠券信息
$show->row(function(Show\Row $show){
$show->width(4)->field('ticket_id', '优惠券')->as(function(){
return $this->ticket->quanTicket->quan_name??'';
})->label();
$show->width(4)->field('ticket_value', '优惠金额')->prepend('¥');
$show->width(4)->field('pay_price', '支付价格')->prepend('¥');
});
$show->row(function(Show\Row $show){
$show->width(4)->field('order_status', '订单状态')->using(['0'=>'未确认', '1' => '已确认', '-1'=>'已取消']);
$show->width(4)->field('pay_status', '支付状态')->using(['0'=>'未支付', '1' => '已支付']);
$show->width(4)->field('shipping_status', '取餐状态')->using(['0'=>'未取餐', '1' => '已取餐']);
});
$show->row(function(Show\Row $show){
$show->width(4)->field('created_at', '下单时间');
$show->width(4)->field('pay_time', '支付时间');
$show->width(4)->field('shipping_time', '取餐时间');
});
// $show->row(function(Show\Row $show){
$show->goods(function ($model) {
$grid = new Grid(new OrderGoods);
$grid->disablePagination();
$grid->disableToolbar();
$grid->disableRefreshButton();
$grid->disableActions();
$grid->model()->where('order_id', $model->id);
$grid->disableRowSelector();
$grid->goods_name('商品名称');
// $grid->column('is_too', '第二杯半价')->bool(['1' => true, '0' => false]);
$grid->goods_attrs('规格属性')->display(function($goods_attrs){
$goods_attrs = json_decode($goods_attrs, true);
return isset($goods_attrs['info_name']) ? $goods_attrs['info_name']:'';
})->label();
$grid->goods_num('商品数量')->prepend('X ');
$grid->goods_price('商品价格')->prepend('¥');
// $grid->goods_cover()->image(100, 100);
return $grid;
});
// });
$show->panel()
->tools(function ($tools) {
$tools->disableEdit();
$tools->disableDelete();
});
});
}
/**
* 线下下单
*/
public function create(Content $content){
return $content->header('线下下单')
->description('表单')
->body(new CreateOrder());
}
public function toStore(Request $request){
$goods_infos = $request->input('goods_info');
$goods_infos = json_decode($goods_infos, true);
$is_ajax = $request->ajax();
if(count($goods_infos) > 0){
$order_service = new OrderService();
$order = $order_service->createOrderToAdmin($goods_infos);
if(isset($order['status']) && $order['status'] == false){
if($is_ajax){
return JsonResponse::make()->error('下单失败:'.$order['message']);
}else{
admin_toastr('下单失败:'.$order['message'], 'error');
}
}else{
if($is_ajax){
$order = $order_service->payOrder($order);
return JsonResponse::make()->success('下单成功, 取餐码: '.($order->order_number??''));
}else{
admin_toastr('下单成功', 'success');
}
}
}else{
if($is_ajax){
return JsonResponse::make()->error('下单失败');
}else{
admin_toastr('下单失败', 'error');
}
}
return redirect(admin_route('orders.index'));
}
/**
* 取餐核销
*/
public function pickup(Content $content){
return $content->header('取餐核销')
->description('表单')
->body(new PickupOrder());
}
/**
* 确认取餐
*/
public function toPickup(Request $request){
$order_sn = $request->input('order_number');
$order = OrderModel::where('order_sn', $order_sn)
// $start_time = Carbon::now()->startOfDay();
// $end_time = Carbon::now()->endOfDay();
// $order_number = $request->input('order_number');
// OrderModel::where('order_number', $order_number)
// ->whereBetween('created_at', [$start_time, $end_time])
->where([
'order_status' =>1,
'pay_status' =>1
])
->first();
if($order){
if($order->shipping_status == 0){
$order_service = new OrderService();
$res = $order_service->shippingOrder($order);
if(isset($res['status']) && $res['status']==false){
return JsonResponse::make()->error($res['message']);
}else{
return JsonResponse::make()->success('取餐成功');
}
}else{
return JsonResponse::make()->error('该订单已取餐');
}
}else{
return JsonResponse::make()->error('未找到符合订单');
}
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new Order(), function (Form $form) {
$form->display('id');
$form->text('user_id');
$form->text('order_sn');
$form->text('order_number');
$form->text('order_price');
$form->text('pay_type');
$form->text('shipping_status');
$form->text('is_niu');
$form->display('created_at');
$form->display('updated_at');
});
}
public function destroy($id){
$goods = OrderModel::findOrFail($id);
if($goods->pay_status == 1){
return JsonResponse::make()->error('该订单已支付,无法删除');
}
return parent::destroy($id);
}
}

View File

@ -0,0 +1,133 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\QuanTicket;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
class QuanTicketController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(QuanTicket::with(['cateValue', 'goodsValue']), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('quan_name');
// $grid->column('ticket_type');
$grid->column('ticket_value');
$grid->column('the_type')->using([0=>'全场通用',1=>'指定商品',2=>'指定分类'])->label([
0 => 'primary',
1 => 'danger',
2 => 'success',
]);
$grid->column('the_value')->display(function(){
if($this->the_type == 1){
return array_column($this->goodsValue->toArray(), 'goods_name');
}
if($this->the_type == 2){
return array_column($this->cateValue->toArray(), 'category_name');
}
return ['全场通用'];
})->label();
$grid->column('use_limit');
$grid->column('use_day')->append('天');
$grid->column('is_use')->switch();
$grid->column('created_at');
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->append('<a href="'.admin_route('user_ticket.index', ['quan_id'=>$actions->getKey()]).'" title="领取列表"><i class="feather icon-align-right"></i></a> ');
});
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->like('quan_name');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new QuanTicket(), function (Show $show) {
$show->field('id');
$show->field('quan_name');
// $show->field('ticket_type');
$show->field('ticket_value');
$show->field('the_type');
$show->field('use_limit');
$show->field('use_day');
$show->field('is_use');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(QuanTicket::with(['cateValue', 'goodsValue']), function (Form $form) {
$form->display('id');
$form->text('quan_name')->required();
// $form->radio('ticket_type')->options(['0'=>'现金券','1'=>'折扣券']);
$form->currency('ticket_value')->symbol('¥')->default(0)->required();
$form->currency('use_limit')->symbol('¥')->default(0)->required();
$form->radio('the_type')->when(0, function (Form $form) {
// $form->
})->when(1, function (Form $form) {
$form->multipleSelect('goodsValue', '指定商品')->options(admin_route('goods.api'))->customFormat(function ($v) {
if (! $v) {
return [];
}
// 从数据库中查出的二维数组中转化成ID
return array_column($v, 'id');
});
})->when(2, function (Form $form) {
$form->multipleSelect('cateValue', '指定分类')->options(admin_route('goods_categories.api'))->customFormat(function ($v) {
if (! $v) {
return [];
}
// 从数据库中查出的二维数组中转化成ID
return array_column($v, 'id');
});;
})->options(['0'=>'全场通用','1'=>'指定商品','2'=>'指定分类'])->default(0);
$form->number('use_day')->default(1)->required();
$form->switch('is_use')->default(1);
$form->text('use_rule');
$form->saving(function(Form $form){
//清除
if($form->the_type == 1){
$form->cateValue = [];
}
else if($form->the_type == 2){
$form->goodsValue = [];
}else{
$form->cateValue = [];
$form->goodsValue = [];
}
});
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace App\Admin\Controllers;
use DB;
use App\Http\Controllers\Controller;
use Dcat\Admin\Layout\Column;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Layout\Row;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Illuminate\Http\Request;
use App\Models\Good;
class TotalController extends Controller
{
public function goodsTotal(Request $request)
{
$content = New Content();
$grid = new Grid(null, function ($grid) use ($request){
$grid->column('id', '商品ID');
$grid->column('goods_name', '商品名称');
$grid->column('total_goods_num', '销售数量')->display(function(){
return $this->total_goods_num??0;
});
$grid->disableCreateButton();
$grid->disableActions();
$grid->disableBatchDelete();
$grid->disablePagination();
$grid->model()->setData($this->goodsTotalData($request));
$grid->filter(function (Grid\Filter $filter) {
$filter->between('created_at', '统计时间')->date();
});
});
return $content->header('统计')
->description('商品统计')
->body($grid);
}
public function goodsTotalData(Request $request){
$time = $request->input('created_at');
// $order_task = DB::table('orders')->where('order_status', 1)->where('pay_status', 1);
$order_task = DB::table('order_goods')
->select('order_goods.goods_id', DB::raw('SUM(order_goods.goods_num) AS total_goods_num'))
->leftJoin('orders', 'orders.id', '=', 'order_goods.order_id')
->where('orders.order_status', 1)
->where('orders.pay_status', 1);
if($time){
if($time['start']){
$order_task->where('orders.created_at', '>=', $time['start'].' 00:00:00');
}
if($time['end']){
$order_task->where('orders.created_at', '<=', $time['end'].' 23:59:59');
}
}
$order_task->groupBy('order_goods.goods_id');
$data = Good::select('goods.id', 'goods_name', 'order_task.total_goods_num')
->leftJoinSub($order_task, 'order_task', function ($join) {
$join->on('order_task.goods_id', '=', 'goods.id');
})->orderBy('order_task.total_goods_num', 'desc')->get()->toArray();
// dd($data);
return $data;
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace App\Admin\Controllers;
use App\Models\TypeAttr;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Illuminate\Support\Facades\Request;
class TypeAttrController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new TypeAttr(), function (Grid $grid) {
$type_id = Request::get('type_id', 0);
$grid->model()->where('type_id', );
$grid->column('id')->sortable();
$grid->column('attr_name');
// $grid->column('type.type_name', '类型名称');
// $grid->column('attr_input');
// $grid->column('attr_type');
$grid->column('ext');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('id');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new TypeAttr(), function (Show $show) {
$show->field('id');
$show->field('type_id');
$show->field('attr_input');
$show->field('attr_type');
$show->field('ext');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new TypeAttr(), function (Form $form) {
$form->display('id');
$form->text('attr_name');
// $form->text('attr_type');
$form->textarea('ext')->help('换行添加可选项')->rows(5);
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Admin\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Cache;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Storage;
use Auth;
class UploadsController extends Controller
{
//
public function uploadImage(Request $request){
$data = [
'errno'=>'501',
'message'=>'上传失败',
// 'success'=>false,
'data'=>[],
];
if($request->upload_file){
// foreach ($request->file() as $file) {
$res = Storage::url($request->upload_file->store('editor/body'));
// }
if($res){
$data['errno'] = 0;
$data['message'] = '上传成功';
// $data['success'] = true;
$data['data'][] = ['url'=>$res];
}
}
return $data;
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\User;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Layout\Row;
use Dcat\Admin\Widgets\Tab;
use Dcat\Admin\Layout\Content;
use App\Admin\Forms\UserSetting;
use Dcat\Admin\Http\Controllers\AdminController;
use App\Admin\Actions\RowActions\SendUserTicket;
class UserController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new User(), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('mini_openid');
$grid->column('avatar')->image(50,50);
$grid->column('nick_name');
$grid->column('phone');
$grid->column('points');
$grid->column('draw_num');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
// $filter->equal('id');
$filter->like('phone');
});
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableView();
$actions->disableEdit();
$actions->disableDelete();
$actions->append(new SendUserTicket());
});
$grid->disableCreateButton();
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new User(), function (Show $show) {
$show->field('id');
$show->field('mini_openid');
$show->field('phone');
$show->field('avatar');
$show->field('nick_name');
$show->field('points');
$show->field('draw_num');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new User(), function (Form $form) {
$form->display('id');
$form->text('mini_openid');
$form->text('phone');
$form->text('avatar');
$form->text('nick_name');
$form->text('points');
$form->text('draw_num');
$form->display('created_at');
$form->display('updated_at');
});
}
public function settings(Content $content){
return $content->header('会员配置')
->description('会员相关配置')
->body(function (Row $row) {
$tab = new Tab();
$tab->add('会员配置', new UserSetting(), true);
$row->column(12, $tab->withCard());
});
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace App\Admin\Controllers;
use App\Admin\Repositories\UserTalk;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Widgets\Card;
use Dcat\Admin\Http\Controllers\AdminController;
class UserTalkController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(UserTalk::with('user'), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('user.nick_name', '昵称');
$grid->column('talk_content')
->if(function($column){
return mb_strlen($this->talk_content)>=30 ? 1:0;
})->then(function (Grid\Column $column) {
$column->display(function(){
return mb_substr($this->talk_content, 0, 30);
})->expand(function () {
// 返回显示的详情
// 这里返回 content 字段内容,并用 Card 包裹起来
$card = new Card(null, $this->talk_content);
return "<div style='padding:5px 5px 0'>$card</div>";
});
})->else(function (Grid\Column $column) {
$column->display(function(){
return $this->talk_content;
});
});
$grid->column('praise_num')->sortable();
$grid->column('is_show')->switch();
$grid->column('created_at');
$grid->model()->orderBy('created_at', 'desc');
$grid->disableActions();
$grid->disableCreateButton();
$grid->filter(function (Grid\Filter $filter) {
$filter->like('talk_content');
$filter->equal('user_id', '留言人')->select(admin_route('user.api'));
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new UserTalk(), function (Show $show) {
$show->field('id');
$show->field('user_id');
$show->field('talk_content');
$show->field('praise_num');
$show->field('is_show');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new UserTalk(), function (Form $form) {
$form->display('id');
$form->text('user_id');
$form->text('talk_content');
$form->text('praise_num');
$form->text('is_show');
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace App\Admin\Controllers;
use Carbon\Carbon;
use App\Admin\Repositories\UserTicket;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Illuminate\Support\Facades\Request;
class UserTicketController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(UserTicket::with(['quanTicket', 'user', 'adminUser']), function (Grid $grid) {
$quan_id = Request::get('quan_id', 0);
if($quan_id > 0){
$grid->model()->where('quan_id', $quan_id);
}
// $grid->column('id')->sortable();
$grid->column('quanTicket.quan_name', '优惠券名称');
$grid->column('user.phone', '领取人');
$grid->column('adminUser.name', '发放人');
$grid->column('ticket_status')->display(function(){
return ($this->ticket_status == 1 || $this->end_time <= Carbon::now()) ? '1':'0';
})->bool(['0' => true, '1' => false]);
$grid->column('start_time');
$grid->column('end_time');
$grid->column('ticket_desc');
$grid->column('created_at');
$grid->model()->orderBy('created_at', 'desc');
$grid->disableActions();
$grid->disableCreateButton();
$grid->filter(function (Grid\Filter $filter) use($quan_id) {
$filter->expand(false);
$filter->equal('quan_id', '优惠券')->select(admin_route('quan_ticket.api'));
// $filter->like('quan_name');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new UserTicket(), function (Show $show) {
$show->field('id');
$show->field('user_id');
$show->field('quan_id');
$show->field('admin_user_id');
$show->field('ticket_status');
$show->field('start_time');
$show->field('end_time');
$show->field('ticket_desc');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new UserTicket(), function (Form $form) {
$form->display('id');
$form->text('user_id');
$form->text('quan_id');
$form->text('admin_user_id');
$form->text('ticket_status');
$form->text('start_time');
$form->text('end_time');
$form->text('ticket_desc');
$form->display('created_at');
$form->display('updated_at');
});
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Admin\Extensions\Form;
use App\Models\{TypeAttr};
use Dcat\Admin\Form\Field;
class SelectAttr extends Field
{
protected $view = 'admin.extensions.select_attr';
protected $listen = "";
protected $goods_id = 0;
protected static $js = [
'/vendor/vue/vue.js'
// 'https://cdn.jsdelivr.net/npm/vue/dist/vue.js' // 这里可以将vue.js下载下来引入
];
public function listen($listen = '', $goods_id = 0)
{
$this->listen = $listen;
$this->goods_id = $goods_id;
return $this;
}
/**
* {@inheritdoc}
*/
public function render()
{
$this->addVariables(['listen' => $this->listen, 'goods_id' => $this->goods_id]);
return parent::render();
}
protected function prepareInputValue($value){
$goods_attrs = json_decode($value, true);
// dd($goods_attrs);
if(count($goods_attrs) > 1){
foreach($goods_attrs as $key => $goods_attr){
if(!isset($goods_attr['_remove_'])){
$goods_attr['_remove_'] = 0;
}
$goods_attrs[$key] = $goods_attr;
}
}
return $goods_attrs;
}
protected function formatFieldData($data)
{
// 获取到当前字段值
$value = parent::formatFieldData($data);
$select_attr_value = [
'arr'=>[],
'arr2'=>[],
'goodsAttr'=>$value
];
$goods_attrs = [];
foreach($value as $goods_attr){
$goods_attrs[$goods_attr['attr_id']][] = $goods_attr['attr_value'];
}
$type_attr = TypeAttr::where('type_id', $data['type_id'])->get()->toArray();
foreach($type_attr as $type_attr){
if(isset($goods_attrs[$type_attr['id']])){
$select_attr_value['arr'][] = [
'attr_name'=>$type_attr['attr_name'],
'attr_id'=>$type_attr['id']
];
$select_attr_value['arr2'][] = implode('<br>', $goods_attrs[$type_attr['id']]);
}
}
// dd($select_attr_value);
return json_encode($select_attr_value);
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Admin\Extensions\Form;
use Dcat\Admin\Form\Field;
class Sku extends Field {
protected $view = 'admin.extensions.sku';
protected static $js = [
'/vendor/vue/vue.js'
// 'https://cdn.jsdelivr.net/npm/vue/dist/vue.js' // 这里可以将vue.js下载下来引入
];
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Admin\Extensions\Form;
use Dcat\Admin\Form\Field;
class WangEditor extends Field
{
protected $view = 'admin.extensions.wang-editor';
}

View File

@ -0,0 +1,125 @@
<?php
namespace App\Admin\Forms;
use Dcat\Admin\Widgets\Form;
use App\Models\{Guess, GuessOption, UserGuess};
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Contracts\LazyRenderable;
/**
* 弹窗设置竞猜答案
*/
class GuessAnswer extends Form implements LazyRenderable
{
use LazyWidget;
/**
* Handle the form request.
*
* @param array $input
*
* @return mixed
*/
public function handle(array $input)
{
$id = $this->payload['id'] ?? null;
$info = Guess::findOrFail($id);
if ($info->prize_state === Guess::PRIZE_EXIST) {
return $this->response()->error('已经公布答案');
}
// 正确答案id
$answers = $input['option'];
sort($answers);
if (count($answers) != $info->num) {
return $this->response()->error('答案应该有'.$info->num.'个');
}
// 关闭答题活动
$info->update([
'prize_state' => Guess::PRIZE_EXIST
]);
// 修改选项结果
$info->options()->update([
'correct_state' => GuessOption::UN_CORRECT
]);
$info->options()->whereIn('id', $answers)->update([
'correct_state' => GuessOption::CORRECT
]);
// 回答正确的记录
$right_ids = [];
// 遍历所有答题记录
foreach($info->users()->with(['options'])->get() as $item) {
$options_id = $item->options->pluck('id')->all();
sort($options_id);
if ($options_id == $answers) {
array_push($right_ids, $item->id);
}
}
// 开奖
$prize_id = [];
$prize_num = data_get($input, 'prize_num', 1);
if ($prize_num > 0) {
# code...
if ($prize_num > count($right_ids)) {
$prize_num = count($right_ids);
$prize_id = $right_ids;
} else if($prize_num == 1 && count($right_ids) >= 1) {
$prize_id_key = array_rand($right_ids, $prize_num);
$prize_id[] = $right_ids[$prize_id_key];
} else if ($prize_num > 1 && count($right_ids) >= 2) {
$prize_id_key = array_rand($right_ids, $prize_num);
foreach ($prize_id_key as $key => $value) {
$prize_id[] = $right_ids[$value];
}
}
}
$info->users()->update([
'correct_state' => UserGuess::UN_CORRECT,
'prize_state' => UserGuess::PRIZE_NO
]);
if (count($right_ids) > 0) {
$info->users()->whereIn('id', $right_ids)->update([
'correct_state' => UserGuess::CORRECT
]);
}
if (count($prize_id) > 0) {
$info->users()->whereIn('id', $prize_id)->update([
'prize_state' => UserGuess::PRIZE_YES
]);
}
if ($input['tel'] && $input['tel'] != '') {
# code...
$tel_array = explode(',', $input['tel']);
if (count($tel_array) > 0) {
$info->users()->whereHas('user', function ($query) use($tel_array) {
$query->whereIn('phone', $tel_array);
})->update([
'prize_state' => UserGuess::PRIZE_YES
]);
}
}
return $this->response()->success('操作成功')->refresh();
}
/**
* Build a form here.
*/
public function form()
{
$id = $this->payload['id'] ?? null;
$info = Guess::findOrFail($id);
$options = $info->options()->pluck('option_name', 'id');
$this->disableResetButton();
$this->checkbox('option', '选项')->help('请勾选正确的选项')->options($options)->canCheckAll();
$this->number('prize_num', '多少个奖励')->default(0)->min(0)->help('多少个奖励');
$this->text('tel', '电话号码')->help('用户电话号码');
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Admin\Forms;
use Carbon\Carbon;
use Dcat\Admin\Widgets\Form;
class UserSetting extends Form
{
/**
* Handle the form request.
*
* @param array $input
*
* @return mixed
*/
public function handle(array $input)
{
admin_setting($input);
return $this
->response()
->success('配置更新成功!')
->refresh();
}
/**
* Build a form here.
*/
public function form()
{
$this->multipleSelect('register_ticket', '绑定手机号领券')
->options(admin_route('quan_ticket.api'))
->saving(function ($value) {
// 转化成json字符串保存到数据库
return json_encode($value);
})->default(admin_setting('register_ticket'));
$this->table('user_rank', '会员等级', function ($table) {
$table->text('rank_name','等级名称')->required();
// $table->image('rank_icon', '等级图片')
// ->accept('jpg,png,gif,jpeg', 'image/*')
// ->move('milk-tea/user_setting/'.Carbon::now()->toDateString())
// ->saveFullUrl()->removable(false)
// ->required()->help('建议图片尺寸16*16');
$table->number('rank_limit', '等级门槛')->attribute('min', 0);;
})->saving(function ($value) {
$value = collect($value)->sortBy('rank_limit')->toArray();
// dd($value);
return json_encode($value);
})->default(admin_setting('user_rank'));
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace App\Admin\Metrics\Examples;
use Dcat\Admin\Admin;
use Dcat\Admin\Widgets\Metrics\Donut;
class NewDevices extends Donut
{
protected $labels = ['Desktop', 'Mobile'];
/**
* 初始化卡片内容
*/
protected function init()
{
parent::init();
$color = Admin::color();
$colors = [$color->primary(), $color->alpha('blue2', 0.5)];
$this->title('New Devices');
$this->subTitle('Last 30 days');
$this->chartLabels($this->labels);
// 设置图表颜色
$this->chartColors($colors);
}
/**
* 渲染模板
*
* @return string
*/
public function render()
{
$this->fill();
return parent::render();
}
/**
* 写入数据.
*
* @return void
*/
public function fill()
{
$this->withContent(44.9, 28.6);
// 图表数据
$this->withChart([44.9, 28.6]);
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => $data
]);
}
/**
* 设置卡片头部内容.
*
* @param mixed $desktop
* @param mixed $mobile
*
* @return $this
*/
protected function withContent($desktop, $mobile)
{
$blue = Admin::color()->alpha('blue2', 0.5);
$style = 'margin-bottom: 8px';
$labelWidth = 120;
return $this->content(
<<<HTML
<div class="d-flex pl-1 pr-1 pt-1" style="{$style}">
<div style="width: {$labelWidth}px">
<i class="fa fa-circle text-primary"></i> {$this->labels[0]}
</div>
<div>{$desktop}</div>
</div>
<div class="d-flex pl-1 pr-1" style="{$style}">
<div style="width: {$labelWidth}px">
<i class="fa fa-circle" style="color: $blue"></i> {$this->labels[1]}
</div>
<div>{$mobile}</div>
</div>
HTML
);
}
}

View File

@ -0,0 +1,108 @@
<?php
namespace App\Admin\Metrics\Examples;
use Dcat\Admin\Widgets\Metrics\Line;
use Illuminate\Http\Request;
class NewUsers extends Line
{
/**
* 初始化卡片内容
*
* @return void
*/
protected function init()
{
parent::init();
$this->title('New Users');
$this->dropdown([
'7' => 'Last 7 Days',
'28' => 'Last 28 Days',
'30' => 'Last Month',
'365' => 'Last Year',
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
$generator = function ($len, $min = 10, $max = 300) {
for ($i = 0; $i <= $len; $i++) {
yield mt_rand($min, $max);
}
};
switch ($request->get('option')) {
case '365':
// 卡片内容
$this->withContent(mt_rand(1000, 5000).'k');
// 图表数据
$this->withChart(collect($generator(30))->toArray());
break;
case '30':
// 卡片内容
$this->withContent(mt_rand(400, 1000).'k');
// 图表数据
$this->withChart(collect($generator(30))->toArray());
break;
case '28':
// 卡片内容
$this->withContent(mt_rand(400, 1000).'k');
// 图表数据
$this->withChart(collect($generator(28))->toArray());
break;
case '7':
default:
// 卡片内容
$this->withContent('89.2k');
// 图表数据
$this->withChart([28, 40, 36, 52, 38, 60, 55,]);
}
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => [
[
'name' => $this->title,
'data' => $data,
],
],
]);
}
/**
* 设置卡片内容.
*
* @param string $content
*
* @return $this
*/
public function withContent($content)
{
return $this->content(
<<<HTML
<div class="d-flex justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
<h2 class="ml-1 font-lg-1">{$content}</h2>
<span class="mb-0 mr-1 text-80">{$this->title}</span>
</div>
HTML
);
}
}

View File

@ -0,0 +1,114 @@
<?php
namespace App\Admin\Metrics\Examples;
use Dcat\Admin\Widgets\Metrics\Round;
use Illuminate\Http\Request;
class ProductOrders extends Round
{
/**
* 初始化卡片内容
*/
protected function init()
{
parent::init();
$this->title('Product Orders');
$this->chartLabels(['Finished', 'Pending', 'Rejected']);
$this->dropdown([
'7' => 'Last 7 Days',
'28' => 'Last 28 Days',
'30' => 'Last Month',
'365' => 'Last Year',
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
switch ($request->get('option')) {
case '365':
case '30':
case '28':
case '7':
default:
// 卡片内容
$this->withContent(23043, 14658, 4758);
// 图表数据
$this->withChart([70, 52, 26]);
// 总数
$this->chartTotal('Total', 344);
}
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => $data,
]);
}
/**
* 卡片内容.
*
* @param int $finished
* @param int $pending
* @param int $rejected
*
* @return $this
*/
public function withContent($finished, $pending, $rejected)
{
return $this->content(
<<<HTML
<div class="col-12 d-flex flex-column flex-wrap text-center" style="max-width: 220px">
<div class="chart-info d-flex justify-content-between mb-1 mt-2" >
<div class="series-info d-flex align-items-center">
<i class="fa fa-circle-o text-bold-700 text-primary"></i>
<span class="text-bold-600 ml-50">Finished</span>
</div>
<div class="product-result">
<span>{$finished}</span>
</div>
</div>
<div class="chart-info d-flex justify-content-between mb-1">
<div class="series-info d-flex align-items-center">
<i class="fa fa-circle-o text-bold-700 text-warning"></i>
<span class="text-bold-600 ml-50">Pending</span>
</div>
<div class="product-result">
<span>{$pending}</span>
</div>
</div>
<div class="chart-info d-flex justify-content-between mb-1">
<div class="series-info d-flex align-items-center">
<i class="fa fa-circle-o text-bold-700 text-danger"></i>
<span class="text-bold-600 ml-50">Rejected</span>
</div>
<div class="product-result">
<span>{$rejected}</span>
</div>
</div>
</div>
HTML
);
}
}

View File

@ -0,0 +1,117 @@
<?php
namespace App\Admin\Metrics\Examples;
use Dcat\Admin\Admin;
use Dcat\Admin\Widgets\Metrics\Bar;
use Illuminate\Http\Request;
class Sessions extends Bar
{
/**
* 初始化卡片内容
*/
protected function init()
{
parent::init();
$color = Admin::color();
$dark35 = $color->dark35();
// 卡片内容宽度
$this->contentWidth(5, 7);
// 标题
$this->title('Avg Sessions');
// 设置下拉选项
$this->dropdown([
'7' => 'Last 7 Days',
'28' => 'Last 28 Days',
'30' => 'Last Month',
'365' => 'Last Year',
]);
// 设置图表颜色
$this->chartColors([
$dark35,
$dark35,
$color->primary(),
$dark35,
$dark35,
$dark35
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
switch ($request->get('option')) {
case '7':
default:
// 卡片内容
$this->withContent('2.7k', '+5.2%');
// 图表数据
$this->withChart([
[
'name' => 'Sessions',
'data' => [75, 125, 225, 175, 125, 75, 25],
],
]);
}
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => $data,
]);
}
/**
* 设置卡片内容.
*
* @param string $title
* @param string $value
* @param string $style
*
* @return $this
*/
public function withContent($title, $value, $style = 'success')
{
// 根据选项显示
$label = strtolower(
$this->dropdown[request()->option] ?? 'last 7 days'
);
$minHeight = '183px';
return $this->content(
<<<HTML
<div class="d-flex p-1 flex-column justify-content-between" style="padding-top: 0;width: 100%;height: 100%;min-height: {$minHeight}">
<div class="text-left">
<h1 class="font-lg-2 mt-2 mb-0">{$title}</h1>
<h5 class="font-medium-2" style="margin-top: 10px;">
<span class="text-{$style}">{$value} </span>
<span>vs {$label}</span>
</h5>
</div>
<a href="#" class="btn btn-primary shadow waves-effect waves-light">View Details <i class="feather icon-chevrons-right"></i></a>
</div>
HTML
);
}
}

View File

@ -0,0 +1,116 @@
<?php
namespace App\Admin\Metrics\Examples;
use Dcat\Admin\Widgets\Metrics\RadialBar;
use Illuminate\Http\Request;
class Tickets extends RadialBar
{
/**
* 初始化卡片内容
*/
protected function init()
{
parent::init();
$this->title('Tickets');
$this->height(400);
$this->chartHeight(300);
$this->chartLabels('Completed Tickets');
$this->dropdown([
'7' => 'Last 7 Days',
'28' => 'Last 28 Days',
'30' => 'Last Month',
'365' => 'Last Year',
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
switch ($request->get('option')) {
case '365':
case '30':
case '28':
case '7':
default:
// 卡片内容
$this->withContent(162);
// 卡片底部
$this->withFooter(29, 63, '1d');
// 图表数据
$this->withChart(83);
}
}
/**
* 设置图表数据.
*
* @param int $data
*
* @return $this
*/
public function withChart(int $data)
{
return $this->chart([
'series' => [$data],
]);
}
/**
* 卡片内容
*
* @param string $content
*
* @return $this
*/
public function withContent($content)
{
return $this->content(
<<<HTML
<div class="d-flex flex-column flex-wrap text-center">
<h1 class="font-lg-2 mt-2 mb-0">{$content}</h1>
<small>Tickets</small>
</div>
HTML
);
}
/**
* 卡片底部内容.
*
* @param string $new
* @param string $open
* @param string $response
*
* @return $this
*/
public function withFooter($new, $open, $response)
{
return $this->footer(
<<<HTML
<div class="d-flex justify-content-between p-1" style="padding-top: 0!important;">
<div class="text-center">
<p>New Tickets</p>
<span class="font-lg-1">{$new}</span>
</div>
<div class="text-center">
<p>Open Tickets</p>
<span class="font-lg-1">{$open}</span>
</div>
<div class="text-center">
<p>Response Time</p>
<span class="font-lg-1">{$response}</span>
</div>
</div>
HTML
);
}
}

View File

@ -0,0 +1,129 @@
<?php
namespace App\Admin\Metrics\Examples;
use Dcat\Admin\Widgets\Metrics\Card;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
class TotalUsers extends Card
{
/**
* 卡片底部内容.
*
* @var string|Renderable|\Closure
*/
protected $footer;
/**
* 初始化卡片.
*/
protected function init()
{
parent::init();
$this->title('Total Users');
$this->dropdown([
'7' => 'Last 7 Days',
'28' => 'Last 28 Days',
'30' => 'Last Month',
'365' => 'Last Year',
]);
}
/**
* 处理请求.
*
* @param Request $request
*
* @return void
*/
public function handle(Request $request)
{
switch ($request->get('option')) {
case '365':
$this->content(mt_rand(600, 1500));
$this->down(mt_rand(1, 30));
break;
case '30':
$this->content(mt_rand(170, 250));
$this->up(mt_rand(12, 50));
break;
case '28':
$this->content(mt_rand(155, 200));
$this->up(mt_rand(5, 50));
break;
case '7':
default:
$this->content(143);
$this->up(15);
}
}
/**
* @param int $percent
*
* @return $this
*/
public function up($percent)
{
return $this->footer(
"<i class=\"feather icon-trending-up text-success\"></i> {$percent}% Increase"
);
}
/**
* @param int $percent
*
* @return $this
*/
public function down($percent)
{
return $this->footer(
"<i class=\"feather icon-trending-down text-danger\"></i> {$percent}% Decrease"
);
}
/**
* 设置卡片底部内容.
*
* @param string|Renderable|\Closure $footer
*
* @return $this
*/
public function footer($footer)
{
$this->footer = $footer;
return $this;
}
/**
* 渲染卡片内容.
*
* @return string
*/
public function renderContent()
{
$content = parent::renderContent();
return <<<HTML
<div class="d-flex justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
<h2 class="ml-1 font-lg-1">{$content}</h2>
</div>
<div class="ml-1 mt-1 font-weight-bold text-80">
{$this->renderFooter()}
</div>
HTML;
}
/**
* 渲染卡片底部内容.
*
* @return string
*/
public function renderFooter()
{
return $this->toString($this->footer);
}
}

View File

@ -0,0 +1,143 @@
<?php
namespace App\Admin\Metrics;
use Dcat\Admin\Widgets\Metrics\Line;
use Illuminate\Http\Request;
use App\Models\Order;
use Carbon\Carbon;
class NewOrders extends Line
{
/**
* 初始化卡片内容
*
* @return void
*/
protected function init()
{
parent::init();
$this->title('支付订单统计');
$this->dropdown([
'1' => '今日',
'7' => '7天内',
'30' => '30天内',
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
switch ($request->get('option')) {
case '1':
// 卡片内容
$start_time = Carbon::now()->startOfDay();
$end_time = Carbon::now()->endOfDay();
$this->withContent($this->getOrderCount($start_time, $end_time).'单');
$start_time = Carbon::now()->subDays(7)->startOfDay();
// 图表数据
$this->withChart($this->getOrderGenerator($start_time, $end_time, 6));
break;
case '7':
// 卡片内容
$start_time = Carbon::now()->subDays(6)->startOfDay();
$end_time = Carbon::now()->endOfDay();
$this->withContent($this->getOrderCount($start_time, $end_time).'单');
// 图表数据
$this->withChart($this->getOrderGenerator($start_time, $end_time, 6));
break;
case '30':
// 卡片内容
$start_time = Carbon::now()->subDays(29)->startOfDay();
$end_time = Carbon::now()->endOfDay();
$this->withContent($this->getOrderCount($start_time, $end_time).'单');
// 图表数据
$this->withChart($this->getOrderGenerator($start_time, $end_time, 29));
break;
default:
// 卡片内容
$start_time = Carbon::now()->startOfDay();
$end_time = Carbon::now()->endOfDay();
$this->withContent($this->getOrderCount($start_time, $end_time).'单');
$start_time = Carbon::now()->subDays(6)->startOfDay();
// 图表数据
$this->withChart($this->getOrderGenerator($start_time, $end_time, 6));
}
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => [
[
'name' => $this->title,
'data' => $data,
],
],
]);
}
/**
* 设置卡片内容.
*
* @param string $content
*
* @return $this
*/
public function withContent($content)
{
return $this->content(
<<<HTML
<div class="d-flex justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
<h2 class="ml-1 font-lg-1">{$content}</h2>
<span class="mb-0 mr-1 text-80">{$this->title}</span>
</div>
HTML
);
}
/**
* 获取指定时间段用户数量
*/
public function getOrderCount($start_time, $end_time){
return Order::where([
'order_status'=>1,
'pay_status'=>1
])->whereBetween('created_at', [$start_time, $end_time])->count();
}
public function getOrderGenerator($start_time, $end_time, $days, $groupBy='d'){
$list = Order::selectRaw("COUNT(DISTINCT id) AS orderNum, DATE_FORMAT(created_at,'%Y-%m-%d') dDay")
->where([
'order_status'=>1,
'pay_status'=>1
])
->whereBetween('created_at', [$start_time, $end_time])
->groupBy('dDay')->pluck('orderNum','dDay')->toArray();
for($i = 0; $i< $days; $i++){
$time = Carbon::now()->subDay($i)->toDateString();
if(!isset($list[Carbon::now()->subDay($i)->toDateString()])){
$list[$time] = 0;
}
}
ksort($list);
// dd($list);
return array_values($list);
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace App\Admin\Metrics;
use Dcat\Admin\Widgets\Metrics\Line;
use Illuminate\Http\Request;
use App\Models\User;
use Carbon\Carbon;
class NewUsers extends Line
{
/**
* 初始化卡片内容
*
* @return void
*/
protected function init()
{
parent::init();
$this->title('新用户统计');
$this->dropdown([
'1' => '今日',
'7' => '7天内',
'30' => '30天内',
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
// $start_time = Carbon::now()->subDays(7)->startOfDay();
// $end_time = Carbon::now()->subDays(1)->endOfDay();
// $this->withContent($this->getUserCount($start_time, $end_time).'人');
// // 图表数据
// $this->withChart($this->getUserGenerator($start_time, $end_time, 7));
switch ($request->get('option')) {
case '1':
// 卡片内容
$start_time = Carbon::now()->startOfDay();
$end_time = Carbon::now()->endOfDay();
$this->withContent($this->getUserCount($start_time, $end_time).'人');
$start_time = Carbon::now()->subDays(7)->startOfDay();
// 图表数据
$this->withChart($this->getUserGenerator($start_time, $end_time, 7));
break;
case '7':
// 卡片内容
$start_time = Carbon::now()->subDays(7)->startOfDay();
$end_time = Carbon::now()->subDays(1)->endOfDay();
$this->withContent($this->getUserCount($start_time, $end_time).'人');
// 图表数据
$this->withChart($this->getUserGenerator($start_time, $end_time, 7));
break;
case '30':
// 卡片内容
$start_time = Carbon::now()->subDays(30)->startOfDay();
$end_time = Carbon::now()->subDays(1)->endOfDay();
$this->withContent($this->getUserCount($start_time, $end_time).'人');
// 图表数据
$this->withChart($this->getUserGenerator($start_time, $end_time, 30));
break;
default:
// 卡片内容
$start_time = Carbon::now()->startOfDay();
$end_time = Carbon::now()->endOfDay();
$this->withContent($this->getUserCount($start_time, $end_time).'人');
$start_time = Carbon::now()->subDays(7)->startOfDay();
// 图表数据
$this->withChart($this->getUserGenerator($start_time, $end_time, 7));
}
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => [
[
'name' => $this->title,
'data' => $data,
],
],
]);
}
/**
* 设置卡片内容.
*
* @param string $content
*
* @return $this
*/
public function withContent($content)
{
return $this->content(
<<<HTML
<div class="d-flex justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
<h2 class="ml-1 font-lg-1">{$content}</h2>
<span class="mb-0 mr-1 text-80">{$this->title}</span>
</div>
HTML
);
}
/**
* 获取指定时间段用户数量
*/
public function getUserCount($start_time, $end_time){
return User::whereBetween('created_at', [$start_time, $end_time])->count();
}
public function getUserGenerator($start_time, $end_time, $days, $groupBy='d'){
$list = User::selectRaw("COUNT(DISTINCT id) AS userNum, DATE_FORMAT(created_at,'%Y-%m-%d') dDay")
->whereBetween('created_at', [$start_time, $end_time])
->groupBy('dDay')->pluck('userNum','dDay')->toArray();
for($i = 1; $i<=$days; $i++){
$time = Carbon::now()->subDay($i)->toDateString();
if(!isset($list[Carbon::now()->subDay($i)->toDateString()])){
$list[$time] = 0;
}
}
ksort($list);
// dd($list);
return array_values($list);
}
}

View File

@ -0,0 +1,123 @@
<?php
namespace App\Admin\Metrics;
use Dcat\Admin\Admin;
use Dcat\Admin\Widgets\Metrics\Donut;
use App\Models\Order;
use Carbon\Carbon;
class OrderDevices extends Donut
{
protected $labels = ['线下订单', '小程序订单'];
/**
* 初始化卡片内容
*/
protected function init()
{
parent::init();
$color = Admin::color();
$colors = [$color->primary(), $color->alpha('blue2', 0.5)];
$this->title('订单比例');
$this->subTitle('近30天内');
$this->chartLabels($this->labels);
// 设置图表颜色
$this->chartColors($colors);
}
/**
* 渲染模板
*
* @return string
*/
public function render()
{
$this->fill();
return parent::render();
}
/**
* 写入数据.
*
* @return void
*/
public function fill()
{
$start_time = Carbon::now()->subDays(29)->startOfDay();
$end_time = Carbon::now()->endOfDay();
$mini_count = $this->miniprogramOrderCount($start_time, $end_time);
$admin_count = $this->adminOrderCount($start_time, $end_time);
$all_count = $mini_count+$admin_count;
$mini_rate = number_format(($all_count==0 ? 0:($mini_count/$all_count*100)), 2);
$admin_rate = number_format(($all_count==0 ? 0:($admin_count/$all_count*100)), 2);
$this->withContent($admin_rate, $mini_rate);
// 图表数据
$this->withChart([floatval($admin_rate), floatval($mini_rate)]);
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => $data
]);
}
/**
* 设置卡片头部内容.
*
* @param mixed $desktop
* @param mixed $mobile
*
* @return $this
*/
protected function withContent($desktop, $mobile)
{
$blue = Admin::color()->alpha('blue2', 0.5);
$style = 'margin-bottom: 8px';
$labelWidth = 120;
return $this->content(
<<<HTML
<div class="d-flex pl-1 pr-1 pt-1" style="{$style}">
<div style="width: {$labelWidth}px">
<i class="fa fa-circle text-primary"></i> {$this->labels[0]}
</div>
<div>{$desktop}%</div>
</div>
<div class="d-flex pl-1 pr-1" style="{$style}">
<div style="width: {$labelWidth}px">
<i class="fa fa-circle" style="color: $blue"></i> {$this->labels[1]}
</div>
<div>{$mobile}%</div>
</div>
HTML
);
}
public function miniprogramOrderCount($start_time, $end_time){
return Order::where([
'order_status'=>1,
'pay_status'=>1,
])->where('pay_type', '<', 3)->whereBetween('created_at', [$start_time, $end_time])->count();
}
public function adminOrderCount($start_time, $end_time){
return Order::where([
'order_status'=>1,
'pay_status'=>1,
])->where('pay_type', 3)->whereBetween('created_at', [$start_time, $end_time])->count();
}
}

View File

@ -0,0 +1,156 @@
<?php
namespace App\Admin\Metrics;
use Dcat\Admin\Widgets\Metrics\Round;
use Illuminate\Http\Request;
use App\Models\Order;
use Carbon\Carbon;
class ProductOrders extends Round
{
protected $labels = ['完成订单', '支付订单', '取消订单'];
/**
* 初始化卡片内容
*/
protected function init()
{
parent::init();
$this->title('订单情况');
$this->chartLabels($this->labels);
$this->dropdown([
'7' => '7天内',
'30' => '30天内',
'365' => '今年',
// '365' => 'Last Year',
]);
}
/**
* 处理请求
*
* @param Request $request
*
* @return mixed|void
*/
public function handle(Request $request)
{
switch ($request->get('option')) {
case '365':
$start_time = Carbon::now()->startOfYear();
$end_time = Carbon::now()->endOfDay();
case '30':
$start_time = Carbon::now()->subDays(29)->startOfDay();
$end_time = Carbon::now()->endOfDay();
case '7':
$start_time = Carbon::now()->subDays(6)->startOfDay();
$end_time = Carbon::now()->endOfDay();
default:
$start_time = Carbon::now()->subDays(6)->startOfDay();
$end_time = Carbon::now()->endOfDay();
}
$finished_count = $this->finishedOrderCount($start_time, $end_time);
$payed_count = $this->payedOrderCount($start_time, $end_time);
$canceled_count = $this->canceledOrderCount($start_time, $end_time);
// 卡片内容
$this->withContent($finished_count, $payed_count, $canceled_count);
$all_count = $this->orderCount($start_time, $end_time);
$finished_rate = number_format(($all_count==0 ? 0:($finished_count/$all_count*100)), 2);
$payed_rate = number_format(($all_count==0 ? 0:($payed_count/$all_count*100)), 2);
$canceled_rate = number_format(($all_count==0 ? 0:($canceled_count/$all_count*100)), 2);
// 图表数据
$this->withChart([$finished_rate, $payed_rate, $canceled_rate]);
// 总数
$this->chartTotal('总数', $all_count);
}
/**
* 设置图表数据.
*
* @param array $data
*
* @return $this
*/
public function withChart(array $data)
{
return $this->chart([
'series' => $data,
]);
}
public function orderCount($start_time, $end_time){
return Order::whereBetween('created_at', [$start_time, $end_time])->count();
}
public function finishedOrderCount($start_time, $end_time){
return Order::where([
'order_status'=>1,
'pay_status'=>1,
'shipping_status'=>1
])->whereBetween('created_at', [$start_time, $end_time])->count();
}
public function payedOrderCount($start_time, $end_time){
return Order::where([
'order_status'=>1,
'pay_status'=>1,
])->whereBetween('created_at', [$start_time, $end_time])->count();
}
public function canceledOrderCount($start_time, $end_time){
return Order::where([
'order_status'=>-1,
])->whereBetween('created_at', [$start_time, $end_time])->count();
}
/**
* 卡片内容.
*
* @param int $finished
* @param int $pending
* @param int $rejected
*
* @return $this
*/
public function withContent($finished, $pending, $rejected)
{
return $this->content(
<<<HTML
<div class="col-12 d-flex flex-column flex-wrap text-center" style="max-width: 220px">
<div class="chart-info d-flex justify-content-between mb-1 mt-2" >
<div class="series-info d-flex align-items-center">
<i class="fa fa-circle-o text-bold-700 text-primary"></i>
<span class="text-bold-600 ml-50">{$this->labels[0]}</span>
</div>
<div class="product-result">
<span>{$finished}</span>
</div>
</div>
<div class="chart-info d-flex justify-content-between mb-1">
<div class="series-info d-flex align-items-center">
<i class="fa fa-circle-o text-bold-700 text-warning"></i>
<span class="text-bold-600 ml-50">{$this->labels[1]}</span>
</div>
<div class="product-result">
<span>{$pending}</span>
</div>
</div>
<div class="chart-info d-flex justify-content-between mb-1">
<div class="series-info d-flex align-items-center">
<i class="fa fa-circle-o text-bold-700 text-danger"></i>
<span class="text-bold-600 ml-50">{$this->labels[2]}</span>
</div>
<div class="product-result">
<span>{$rejected}</span>
</div>
</div>
</div>
HTML
);
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Admin\Metrics;
use Dcat\Admin\Widgets\Metrics\Card;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use App\Models\Order;
class TotalOrders extends Card
{
/**
* 卡片底部内容.
*
* @var string|Renderable|\Closure
*/
protected $footer;
/**
* 初始化卡片.
*/
protected function init()
{
parent::init();
$this->title('订单统计');
$this->subTitle('当前支付订单总数');
$this->content($this->getOrdersCount().'单');
}
/**
* 渲染卡片内容.
*
* @return string
*/
public function renderContent()
{
$content = parent::renderContent();
return <<<HTML
<div class="d-flex justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
<h2 class="ml-1 font-lg-1">{$content}</h2>
</div>
HTML;
}
/**
* 获取指定时间段用户数量
*/
public function getOrdersCount(){
return Order::where([
'order_status'=>1,
'pay_status'=>1
])->count();
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Admin\Metrics;
use Dcat\Admin\Widgets\Metrics\Card;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use App\Models\User;
class TotalUsers extends Card
{
/**
* 卡片底部内容.
*
* @var string|Renderable|\Closure
*/
protected $footer;
/**
* 初始化卡片.
*/
protected function init()
{
parent::init();
$this->title('用户统计');
$this->subTitle('当前注册用户');
$this->content($this->getUserCount().'人');
}
/**
* 渲染卡片内容.
*
* @return string
*/
public function renderContent()
{
$content = parent::renderContent();
return <<<HTML
<div class="d-flex justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
<h2 class="ml-1 font-lg-1">{$content}</h2>
</div>
HTML;
}
/**
* 获取指定时间段用户数量
*/
public function getUserCount(){
return User::count();
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Admin\Pages;
use Illuminate\Contracts\Support\Renderable;
use App\Models\Good;
use App\Http\Resources\GoodsInfoResource;
class CreateOrder implements Renderable
{
public function render()
{
$goods_list = Good::with(['useGoodsAttrs'])->where('is_sell', 1)->orderBy('created_at', 'asc')->get();
// dd(GoodsResource::collection($goods_list)->toJson());
return admin_view('admin.orders.create', ['goods'=>GoodsInfoResource::collection($goods_list)->toJson()]);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Admin\Pages;
use Illuminate\Contracts\Support\Renderable;
use App\Http\Resources\GoodsInfoResource;
class PickupOrder implements Renderable
{
public function render()
{
return admin_view('admin.orders.pickup');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Admin\Renderable;
use App\Models\GuessOption;
use Dcat\Admin\Grid;
use Dcat\Admin\Grid\LazyRenderable;
class GuessOptionsTable extends LazyRenderable
{
public function grid(): Grid
{
return Grid::make(GuessOption::withCount('users'), function (Grid $grid) {
$grid->model()->where('guess_id', $this->key);
$grid->model()->orderBy('users_count', 'desc');
$grid->column('id');
$grid->column('option_name', '选项名称');
$grid->column('users_count', '选择数量');
// $grid->disablePagination();
$grid->paginate(10);
$grid->disableRowSelector();
$grid->disableActions();
});
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Admin\Renderable;
use App\Models\LuckDrawOption;
use Dcat\Admin\Grid;
use Dcat\Admin\Grid\LazyRenderable;
class LuckDrawTable extends LazyRenderable
{
public function grid(): Grid
{
return Grid::make(new LuckDrawOption(), function (Grid $grid) {
$grid->model()->where('activity_id', $this->key);
$grid->column('id');
$grid->column('draw_name', '奖品名称');
$grid->column('draw_rate', '中奖概率');
$grid->column('draw_num', '奖品数量')->display(function(){
return $this->is_num ? $this->draw_num:'不限量';
});
$grid->paginate(10);
$grid->disableRowSelector();
$grid->disableActions();
});
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Admin\Renderable;
use Dcat\Admin\Grid;
use Dcat\Admin\Grid\LazyRenderable;
use App\Models\QuanTicket;
class QuanTicketTable extends LazyRenderable
{
public function grid(): Grid
{
// // 获取外部传递的参数
// $id = $this->id;
return Grid::make(new QuanTicket(), function (Grid $grid) {
$grid->column('id');
$grid->column('quan_name', '券名称');
$grid->column('ticket_value', '券面值')->append('元');
$grid->column('created_at');
$grid->column('updated_at');
$grid->quickSearch(['id', 'quan_name']);
$grid->paginate(10);
$grid->disableActions();
$grid->filter(function (Grid\Filter $filter) {
$filter->like('quan_name', '券名称')->width(4);
});
});
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Admin\Renderable;
use App\Models\TypeAttr;
use Dcat\Admin\Grid;
use Dcat\Admin\Grid\LazyRenderable;
class TypeAttrTable extends LazyRenderable
{
public function grid(): Grid
{
return Grid::make(new TypeAttr(), function (Grid $grid) {
$grid->model()->where('type_id', $this->key);
$grid->column('id');
$grid->column('attr_name', '属性名称');
$grid->column('ext', '可选内容')->display(function ($ext){
$ext = str_replace("\n", '&', str_replace("\r\n", "\n", $ext));
return explode('&', $ext);
})->label('primary');
$grid->paginate(10);
$grid->disableActions();
// $grid->actions(function (Grid\Displayers\Actions $actions) {
// $actions->disableDelete();
// $actions->disableEdit();
// $actions->disableView();
// // append一个操作
// $actions->append(new DeleteTypeAttr(TypeAttr::class));
// });
});
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\ActivityDayGood as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class ActivityDayGood extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\ActivityGood as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class ActivityGood extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\ActivityOption as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class ActivityOption extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\Article as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class Article extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\Banner as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class Banner extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Admin\Repositories;
use App\Models\Good as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class Good extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\GoodsCategory as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class GoodsCategory extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\GoodsType as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class GoodsType extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\LuckDrawActivity as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class LuckDrawActivity extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\Order as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class Order extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\OrderGoods as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class OrderGoods extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\QuanTicket as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class QuanTicket extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\TypeAttr as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class TypeAttr extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\User as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class User extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\UserTalk as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class UserTalk extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Admin\Repositories;
use App\Models\UserTicket as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class UserTicket extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -0,0 +1,40 @@
<?php
use Dcat\Admin\Admin;
use Dcat\Admin\Grid;
use Dcat\Admin\Form;
use Dcat\Admin\Grid\Filter;
use Dcat\Admin\Show;
/**
* Dcat-admin - admin builder based on Laravel.
* @author jqh <https://github.com/jqhph>
*
* Bootstraper for Admin.
*
* Here you can remove builtin form field:
*
* extend custom field:
* Dcat\Admin\Form::extend('php', PHPEditor::class);
* Dcat\Admin\Grid\Column::extend('php', PHPEditor::class);
* Dcat\Admin\Grid\Filter::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\Form\WangEditor;
use App\Admin\Extensions\Form\Sku;
use App\Admin\Extensions\Form\SelectAttr;
// 注册前端组件别名
Admin::asset()->alias('@wang-editor', [
'js' => ['/vendor/wangEditor-4.7.1/wangEditor.min.js'],
// 'js' => ['/vendor/wangEditor-3.0.9/wangEditor.min.js'],
// 'css' => ['/vendor/wangEditor-3.0.9/wangEditor.min.css'],
]);
Form::extend('editor', WangEditor::class);
Form::extend('selectAttr', SelectAttr::class);
Form::extend('sku', Sku::class);

View File

@ -0,0 +1,63 @@
<?php
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
use Dcat\Admin\Admin;
Admin::routes();
Route::group([
'prefix' => config('admin.route.prefix'),
'namespace' => config('admin.route.namespace'),
'middleware' => config('admin.route.middleware'),
], function (Router $router) {
$router->get('/', 'HomeController@index');
$router->resource('/banners', 'BannerController');
$router->resource('/articles', 'ArticleController');
$router->resource('/goods', 'GoodController');
$router->resource('/goods_categories', 'GoodsCategoryController');
$router->resource('/goods_types', 'GoodsTypeController');
$router->resource('/type_attr', 'TypeAttrController');
$router->resource('/quan_tickets', 'QuanTicketController');
$router->resource('/activity_options', 'ActivityOptionController')->only(['index', 'update']);
$router->resource('/activity_goods', 'ActivityGoodController');
$router->resource('/activity_day', 'ActivityDayGoodController');
$router->resource('/luck_activities', 'LuckDrawActivityController');
$router->resource('/users', 'UserController')->only(['index', 'update', 'show']);
$router->get('/user_setting', 'UserController@settings')->name('users.setting');
$router->resource('/user_ticket', 'UserTicketController')->only(['index', 'delete']);
$router->resource('/orders', 'OrderController')->only(['index', 'create', 'show', 'destroy']);
$router->post('/orders/store', 'OrderController@toStore')->name('order.sotre');
$router->get('/order_pickup', 'OrderController@pickup')->name('order.pickup');
$router->get('/pickup_order', 'OrderController@toPickup')->name('order.topickup');
$router->resource('/user_talks', 'UserTalkController')->only(['index','update']);
$router->get('/total/goods', 'TotalController@goodsTotal')->name('total.goods');
/*API*/
$router->prefix('api')->group(function(){
Route::get('goods_categories', 'ApiController@getGoodsCategories')->name('goods_categories.api');
Route::get('goods_types', 'ApiController@getGoodsTypes')->name('goods_types.api');
Route::get('type_attrs', 'ApiController@getTypeAttrs')->name('type_attrs.api');
Route::get('goods_attrs', 'ApiController@getGoodsAttrs')->name('goods_attrs.api');
Route::get('goods', 'ApiController@getGoods')->name('goods.api');
Route::get('orders', 'ApiController@getOrder')->name('get_order.api');
Route::get('guess', 'ApiController@guess')->name('guess.api');
Route::get('user', 'ApiController@user')->name('user.api');
Route::get('quan_ticket', 'ApiController@quanTicket')->name('quan_ticket.api');
// Route::get('ticket_the_value', 'ApiController@ticketValue')->name('tickets.values');
});
$router->post('upload_image', 'UploadsController@uploadImage')->name('upload_image');
$router->resource('guess', 'GuessController')->names('guess');
$router->resource('guess-option', 'GuessOptionController')->names('guess_option');
$router->resource('guess-user', 'GuessUserController')->names('guess_user');
});

View File

@ -0,0 +1,52 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Models\Order;
class FinishReserveOrder extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'milk-tea:finish_reserve_order';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动过期两个星期的预约订单';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$list = Order::where([
'is_reserve'=>1,
'order_status'=>1,
'pay_status'=>1,
])->where('reserve_time', Carbon::now()->subDays(14)->startOfDay())
->whereNull('order_number')->update(['shipping_status'=>1]);
$this->info('执行成功');
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Models\Order;
class FinishWaitShippingOrder extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'milk-tea:finish_wait_shipping_order';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动完成有取餐码待取货的订单';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$list = Order::where([
'order_status'=>1,
'pay_status'=>1,
])->whereNotNull('order_number')->where('number_time', '<', now())->update(['shipping_status'=>1]);
$this->info('执行成功');
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Schema;
class ModelFillable extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'model:fillable {table}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'get model fillable ';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
*/
public function handle()
{
$table = $this->argument('table');
if (Schema::hasTable($table)) {
$list = Schema::getColumnListing($table);
$this->info("protected \$fillable = ['".implode('\', \'', $list)."'];");
}
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Models\{Order, ReserveEditLog};
use App\Jobs\SendReserveNotice;
class SendNoticeMessage extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'milk-tea:send_notice_message';
/**
* The console command description.
*
* @var string
*/
protected $description = '发送过时的取餐超时提醒';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$list = Order::with(['user', 'goods'])->where([
'is_reserve'=>1,
'order_status'=>1,
'pay_status'=>1,
])->where('reserve_time', Carbon::now()->subDays(1)->startOfDay())
->whereNull('order_number')->get();
foreach($list as $order){
//如果已经有修改记录则不用发送通知;
if(!ReserveEditLog::where('order_sn', $order->order_sn)->exists()){
SendReserveNotice::dispatch($order);
}
}
$this->info('发送成功!');
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Models\User;
class SendTicketForAllUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'milk-tea:send_ticket_for_all_user {ticket_id}';
/**
* The console command description.
*
* @var string
*/
protected $description = '给领取过券的人发券';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$ticket_id = $this->argument('ticket_id');
foreach(User::where('register_gift', 1)->orderBy('id', 'asc')->get() as $user) {
$user->sendTicket($ticket_id, 0, '系统后台发送');
$this->info($user->id.':执行成功');
}
$this->info('执行成功');
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
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('milk-tea:send_notice_message')->dailyAt('10:00');
$schedule->command('milk-tea:finish_reserve_order')->dailyAt('23:00');
$schedule->command('milk-tea:finish_wait_shipping_order')->dailyAt('23:00');
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Auth\AuthenticationException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Tymon\JWTAuth\Exceptions\JWTException;
class Handler extends ExceptionHandler
{
/**
* 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) {
//
});
}
public function render($request, Throwable $e){
// FirstOrFail 和 FindOrFail 异常处理
if ($e instanceof ModelNotFoundException) {
if ($request->ajax() || $request->wantsJson()) {
return response()->json(['code'=>404 , 'message' => '数据未找到,或已被删除' ], 404);
}
}elseif($e instanceof AuthenticationException){
if ($request->ajax() || $request->wantsJson()) {
return response()->json(['code'=>401 , 'message' => '未认证' ], 401);
}
}elseif($e instanceof TokenBlacklistedException){
if ($request->ajax() || $request->wantsJson()) {
return response()->json(['code'=>401 , 'message' => '凭证过期' ], 401);
}
}elseif($e instanceof TokenExpiredException){
if ($request->ajax() || $request->wantsJson()) {
return response()->json(['code'=>401 , 'message' => '登录过期,请重新登录' ], 401);
}
}elseif($e instanceof TokenInvalidException){
if ($request->ajax() || $request->wantsJson()) {
return response()->json(['code'=>401 , 'message' => '未认证' ], 401);
}
}elseif($e instanceof JWTException){
if ($request->ajax() || $request->wantsJson()) {
return response()->json(['code'=>401 , 'message' => '未认证' ], 401);
}
}
return parent::render($request, $e);
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\Handlers;
use Image;
use Illuminate\Support\Str;
class ImageUploadHandler{
protected $allowed_ext=['png', 'jpg', 'jpeg', 'gif'];
public function save($file, $folder, $file_prefix, $max_width = false, $need_cut = false, $cut_data=""){
// 构建存储的文件夹规则值如uploads/images/avatars/201709/21/
// 文件夹切割能让查找效率更高。
$folder_name = "uploads/images/$folder/" . date("Ym/d", time());
// 文件具体存储的物理路径,`public_path()` 获取的是 `public` 文件夹的物理路径。
// 值如:/home/vagrant/Code/larabbs/public/uploads/images/avatars/201709/21/
$upload_path = public_path() . '/' . $folder_name;
//获取文件后缀默认png
$extension = strtolower($file->getClientOriginalExtension()) ?: 'png';
// 拼接文件名,加前缀是为了增加辨析度,前缀可以是相关数据模型的 ID
// 值如1_1493521050_7BVc9v9ujP.png
$filename = $file_prefix . '_' . time() . '_' . Str::random(10) . '.' . $extension;
if(! in_array($extension, $this->allowed_ext)){
return false;
}
$file->move($upload_path, $filename);
//对图片进行裁剪
if($need_cut && $extension!='gif' && $cut_data){
$this->cutPhoto($upload_path."/$filename", $cut_data);
}
if($max_width && $extension!='gif'){
$this->reduceSize($upload_path."/$filename", $max_width);
}
return [
'path'=> config('app.url')."/$folder_name/$filename"
];
}
public function reduceSize($file_path, $max_width)
{
// 先实例化,传参是文件的磁盘物理路径
$image = Image::make($file_path);
// 进行大小调整的操作
$image->resize($max_width, null, function ($constraint) {
// 设定宽度是 $max_width高度等比例缩放
$constraint->aspectRatio();
// 防止裁图时图片尺寸变大
$constraint->upsize();
});
// 对图片修改后进行保存
$image->save();
}
/**
* 裁剪图片
*/
public function cutPhoto($file_path, $cut_data){
$image = Image::make($file_path);
// 获取用户对文件进行处理的数据
$avatarInfo = json_decode($cut_data);
$cropX = floor($avatarInfo->x);
$cropY = floor($avatarInfo->y);
$cropW = floor($avatarInfo->width);
$cropH = floor($avatarInfo->height);
$rotate = $avatarInfo->rotate;
$image->rotate(-$rotate)
->crop($cropW, $cropH, $cropX, $cropY)
->save();
}
}

View File

@ -0,0 +1,356 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use DB;
use Carbon\Carbon;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\{ActivityLog, ActivityOption, PointsLog,LuckDrawActivity,LuckDrawOption,UserLuckTime,UserLuckLog};
use App\Services\ActivityService;
use App\Jobs\{SendActivityDrawJob, SendLuckActivityDrawJob};
use App\Http\Resources\{LuckActivityResource};
class ActivityController extends Controller
{
protected $activity_service;
public function __construct(ActivityService $activity_service){
$this->activity_service = $activity_service;
}
public function awardsOptions(Request $request){
return $this->success([
'exchange_points'=>ActivityOption::findOrFail(13)->key_value,
'f_draw_points'=>ActivityOption::findOrFail(14)->key_value,
'activity_dec'=>ActivityOption::findOrFail(15)->key_value
]);
}
public function awardsName(Request $request){
$awrad_array = ActivityOption::where('key_type', 0)
->where(['is_niu'=>0])
->pluck('key_name', 'id')->toArray();
return $this->success($awrad_array);
}
/**
* 一发入魂兑换次数;
*/
public function pointToTimes(Request $request){
$user = auth('api')->user();
$times = 1;
$points = $times*(ActivityOption::findOrFail(13)->key_value);
if($user->points >= $points){
$res_data = [];
try {
DB::beginTransaction();
$user->decrement('points', $points);
$user->increment('draw_num', $times);
//记录积分消耗记录
PointsLog::create([
'user_id'=>$user->id,
'type'=>2,
'points'=> 0-$points,
'now_points'=>$user->points,
'desc'=>'扭蛋:一发入魂',
]);
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
return $this->success('兑换成功');
}else{
return $this->error('剩余积分不足');
}
}
/**
* 翻牌抽奖
*/
public function toDraw(Request $request){
//消耗抽奖机会
$user = auth('api')->user();
if($user->draw_num > 0){
$res_data = [];
try {
DB::beginTransaction();
$user->decrement('draw_num');
//抽奖
$res_data = $this->activity_service->activityDarw();
//记录并发放结果
foreach($res_data as $draw_id){
$activity_log = new ActivityLog();
$activity_log->user_id = $user->id;
$activity_log->draw_id = $draw_id;
$activity_log->save();
SendActivityDrawJob::dispatch($activity_log);
}
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
return $this->success($res_data);
}else{
return $this->error('剩余抽奖次数不足');
}
}
/**
* 五连必中
*/
public function toDrawFive(Request $request){
//消耗积分抽5次
$user = auth('api')->user();
$times = 5;
$points = ActivityOption::findOrFail(14)->key_value;
if($user->points >= $points){
$res_data = [];
try {
DB::beginTransaction();
$user->decrement('points', $points);
//记录积分消耗记录
PointsLog::create([
'user_id'=>$user->id,
'type'=>3,
'points'=> 0-$points,
'now_points'=>$user->points,
'desc'=>'扭蛋:五连必中',
]);
//抽奖
$res_data = $this->activity_service->activityDarw($times);
//检查中奖结果中有没有is_niu没有则随机替换一个现有奖品
$niu_list = ActivityOption::where('is_niu', 1)->pluck('id')->toArray();
if(count(array_intersect($res_data, $niu_list)) < 1){
$key = rand(0, count($res_data)-1);
$draw_id = array_rand($niu_list);
$res_data[$key] = $niu_list[$draw_id];
}
//记录并发放结果
foreach($res_data as $draw_id){
$activity_log = new ActivityLog();
$activity_log->user_id = $user->id;
$activity_log->draw_id = $draw_id;
$activity_log->save();
SendActivityDrawJob::dispatch($activity_log);
}
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
return $this->success($res_data);
}else{
return $this->error('剩余积分不足');
}
}
/**
* 抽奖活动
*/
public function luckIndex($activity_id){
return LuckActivityResource::make(LuckDrawActivity::findOrFail($activity_id));
// $this->activity_service->luckActivityDarw(1,5);
}
/**
* 抽奖活动-兑换次数
*/
public function luckPointsToTimes($activity_id){
$user = auth('api')->user();
$times = 1;
$time = Carbon::now();
$activity = LuckDrawActivity::findOrFail($activity_id);
if($activity->start_time > $time){
return $this->error('活动暂未开启');
}
if($activity->end_time < $time){
return $this->error('活动已经结束');
}
$points = $times*($activity->one_draw);
if($user->points >= $points){
try {
DB::beginTransaction();
$user->decrement('points', $points);
//新增活动抽奖次数
$user_luck_times = UserLuckTime::where(['user_id'=>$user->id,'activity_id'=>$activity->id])->first();
if($user_luck_times){
$user_luck_times->increment('times');
}else{
UserLuckTime::create([
'user_id'=>$user->id,
'activity_id'=>$activity->id,
'times'=>1
]);
}
//记录积分消耗记录
PointsLog::create([
'user_id'=>$user->id,
'type'=>2,
'points'=> 0-$points,
'now_points'=>$user->points,
'desc'=>'抽奖活动:一发入魂',
]);
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
return $this->success('兑换成功');
}else{
return $this->error('剩余积分不足');
}
}
/**
* 抽奖活动-单次抽奖
*/
public function luckToDraw($activity_id){
//消耗抽奖机会
$user = auth('api')->user();
$time = Carbon::now();
$activity = LuckDrawActivity::findOrFail($activity_id);
if($activity->start_time > $time){
return $this->error('活动暂未开启');
}
if($activity->end_time < $time){
return $this->error('活动已经结束');
}
$user_luck_times = UserLuckTime::where(['user_id'=>$user->id,'activity_id'=>$activity->id])->first();
if($user_luck_times && $user_luck_times->times > 0){
$res_data = [];
try {
DB::beginTransaction();
$user_luck_times->decrement('times');
//抽奖
$res_data = $this->activity_service->luckActivityDarw($activity->id);
//记录并发放结果
$draw_id = $res_data[0];
// foreach($res_data as $draw_id){
$luck_log = new UserLuckLog();
$luck_log->user_id = $user->id;
$luck_log->activity_id = $activity->id;
$luck_log->draw_id = $draw_id;
// $luck_log->ext = '恭喜抽中';
$luck_log->save();
if($draw_id){
LuckDrawOption::findOrFail($draw_id)->increment('luck_num');
SendLuckActivityDrawJob::dispatch($luck_log);
}
// }
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
$res_data = $this->drawIdToDrawName($res_data, $activity_id);
return $this->success($res_data);
}else{
return $this->error('剩余抽奖次数不足');
}
}
/**
* 抽奖活动-五连抽
*/
public function luckToDrawFive($activity_id){
//消耗积分抽5次
$user = auth('api')->user();
$times = 5;
$time = Carbon::now();
$activity = LuckDrawActivity::findOrFail($activity_id);
if($activity->start_time > $time){
return $this->error('活动暂未开启');
}
if($activity->end_time < $time){
return $this->error('活动已经结束');
}
$points = $activity->five_draw;
if($user->points >= $points){
$res_data = [];
try {
DB::beginTransaction();
$user->decrement('points', $points);
//记录积分消耗记录
PointsLog::create([
'user_id'=>$user->id,
'type'=>3,
'points'=> 0-$points,
'now_points'=>$user->points,
'desc'=>'抽奖活动:五连必中',
]);
//抽奖
$res_data = $this->activity_service->luckActivityDarw($activity->id, $times);
//检查中奖结果中有没有五连必中,没有则随机替换一个现有奖品
$niu_list = LuckDrawOption::where('is_five', 1)->pluck('id')->toArray();
if(count($niu_list) > 0 && count(array_intersect($res_data, $niu_list)) < 1){
$key = rand(0, count($res_data)-1);
$draw_id = array_rand($niu_list);
$res_data[$key] = $niu_list[$draw_id];
}
// dd($res_data);
//记录并发放结果
foreach($res_data as $draw_id){
$luck_log = new UserLuckLog();
$luck_log->user_id = $user->id;
$luck_log->activity_id = $activity->id;
$luck_log->draw_id = $draw_id;
// $luck_log->ext = '恭喜抽中';
$luck_log->save();
if($draw_id){
SendLuckActivityDrawJob::dispatch($luck_log);
}
}
$up_res_data = array_filter($res_data);
if($up_res_data){
LuckDrawOption::whereIn('id', $up_res_data)->increment('luck_num');
}
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
$res_data = $this->drawIdToDrawName($res_data, $activity_id);
return $this->success($res_data);
}else{
return $this->error('剩余积分不足');
}
}
/**
* 奖品ID替换为奖品名称
*/
private function drawIdToDrawName($draw_ids, $activity_id=0){
if(!is_array($draw_ids)){
$draw_ids = [$draw_ids];
}
$luck_draw_options = LuckDrawOption::where('activity_id', $activity_id)->get()->keyBy('id');
$draw_name = [];
foreach($draw_ids as $draw_id){
if(isset($luck_draw_options[$draw_id])){
$draw_name[] = [
'draw_id' => $draw_id,
'draw_name' => $luck_draw_options[$draw_id]->draw_name,
'draw_image'=> $luck_draw_options[$draw_id]->draw_logo,
];
}else{
$draw_name[] = [
'draw_id' => $draw_id,
'draw_name' => '谢谢参与',
'draw_image'=> ''
];
}
}
return $draw_name;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\Article;
use App\Http\Resources\{ArticlesResource,ArticleInfoResource};
class ArticleController extends Controller
{
public function list(Request $request){
$per_page = $request->input('per_page', 10);
$list = Article::orderBy('created_at', 'desc')->paginate($per_page);
return ArticlesResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
public function detail($id){
$info = Article::findOrFail($id);
return ArticleInfoResource::make($info);
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Str;
use EasyWeChat\Factory;
use App\Models\{User, ActivityUser};
use Carbon\Carbon;
use Cache;
use App\Http\Resources\UserResource;
class AuthController extends Controller
{
public function authMiniprogram(Request $request){
$request->validate([
'code' => 'required',
], [
'code.required' => '授权码必填',
]);
//绑定OPenid
$code = $request->input('code');
$app = \EasyWeChat::miniProgram();
$result = $app->auth->session($code);
if (data_get($result, 'errcode')) {
return $this->error(data_get($result, 'errmsg'));
}
if ($openid = data_get($result, 'openid')) {
$session_key = data_get($result, 'session_key');
//判断是否已绑定对应用户
$user = User::where(['mini_openid'=>$openid])->first();
//写入缓存
Cache::put($openid, $session_key, 48*60*60);
if(!$user){
//写入新用户
$user = new User();
$user->mini_openid = $openid;
$user->save();
//写入用户抽奖记录
$activity_user = new ActivityUser();
$activity_user->user_id = $user->id;
$activity_user->save();
}
return $this->attemptUser($user, $request);
}
return $this->error('授权失败');
}
public function refreshToken(Request $request){
try {
$token = auth('api')->refresh();
}catch (\Throwable $th) {
// $this->message = $th->getMessage();
return $this->error('刷新错误,请稍后再试');
}
return $this->success([
'api_token'=> $token,
'expire_in'=> Carbon::parse()->addSeconds(auth('api')->factory()->getTTL() * 60)->toDateTimeString()
]);
}
protected function attemptUser(User $user, Request $request)
{
$token = auth('api')->login($user);
// if (!$user->api_token) {
// $user->api_token = Str::random(32);
// }
// $user->api_token = $token;
$data = UserResource::make($user);
$data->offsetSet('api_token', $token);
return $data;
}
}

View File

@ -0,0 +1,178 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\{Good, GoodsCategory, GoodsAttr, GoodsCart};
use App\Http\Resources\{GoodsCategoryResource, GoodsResource, GoodsInfoResource, GoodsCartResource};
use App\Services\GoodsService;
class GoodsController extends Controller
{
public function cateList(Request $request){
$list = GoodsCategory::orderBy('sort', 'asc')->get();
return GoodsCategoryResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
/**
* 获取菜单以及商品
*/
public function goodsList(Request $request){
//热销商品
$data['hot_data'] = [
'cate_name'=>'热销',
'cate_goods'=> GoodsInfoResource::collection(
Good::with(['activityExchange', 'useGoodsAttrs'])
->where('is_hot', 1)
->where('is_sell', 1)
->orderBy('goods_price', 'desc')
->orderBy('created_at', 'desc')
->get()),
];
$list = GoodsCategory::with(['goods', 'goods.activityExchange', 'goods.useGoodsAttrs'])->orderBy('sort', 'asc')->get();
$data['goods_List'] = GoodsCategoryResource::collection($list);
// [
// 'cate_name'=>"",
// "cate_goods"=>[
// [
// 'goods_id'=>1,
// 'goods_name'=>'ddd',
// 'goods_cover'=>'',
// 'goods_price'=>'10.00',
// 'sell_num'=>0,
// 'exchange_array'=>[
// 1,2,3,4
// ],
// 'goods_attr'=>[
// [
// 'attr_name'=>'规格名称',
// 'attr_values'=>[
// [
// 'value_name'=>'属性名称',
// 'value_peice'=>'属性价格',
// ]
// ]
// ]
// ]
// ]
// ]
// ]
return $this->success($data);
}
public function toCart(Request $request){
//返回最新购物车
return GoodsCartResource::collection(auth('api')->user()->getUserCart())->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
public function toCartPrice(Request $request){
$goodsService = new GoodsService();
return $this->success(['cart_price'=>$goodsService->goodsCartPrice()], '请求成功');
}
/**修改购物车 */
public function editCart(Request $request){
$user = auth('api')->user();
$user_id = $user->id;
//检测是否绑定昵称头像
if(!$user->avatar || !$user->nick_name){
return $this->error('未绑定昵称头像', 501);
}
//检测是否绑定手机号
if(!$user->phone){
return $this->error('未绑定手机号', 502);
}
//
$init_num = $request->input('edit_num', 0);
$goods_info = $request->input('goods_info', '{}');//{"goods_id":1,"goods_attr":[1,2,3]}
//按给到的goods_info改变购物车内容
$goods_info = json_decode($goods_info, true);
$goods = Good::findOrFail($goods_info['goods_id']);
// 判断是否下架
if(!$goods->is_sell){
return $this->error('该商品已下架');
}
$attr_data['goods_info'] = $goods_info;
$info_name = [];
$attr_price = 0;
// 处理有属性情况
if(isset($goods_info['goods_attr'])){
$goods_attrs = GoodsAttr::select('id')->where('is_use', 1)->where('goods_id', $goods->id)->groupBy('attr_id')->get();
//判断属性
if($goods_attrs->count() != count($goods_info['goods_attr'])){
return $this->error('请选择属性');
}
$goods_attrs = GoodsAttr::with('attr')->where('is_use', 1)->whereIn('id', $goods_info['goods_attr'])->get();
//判断属性是否均可用
if($goods_attrs->count() != count($goods_info['goods_attr'])){
return $this->error('属性错误');
}
foreach($goods_attrs as $goods_attr){
//判断属性是否有重复选择
if($goods_attr->attr->attr_type == 1 && isset($info_name[$goods_attr->attr_id])){
return $this->error('属性错误');
}
if(isset($info_name[$goods_attr->attr_id])){
$info_name[$goods_attr->attr_id] .= '|'.$goods_attr->attr_value;
}else{
$info_name[$goods_attr->attr_id] = $goods_attr->attr_name.":".$goods_attr->attr_value;
}
$attr_price += $goods_attr->value_price;
}
$attr_data['info_name'] = $info_name;
}
$attr_json = json_encode($attr_data, JSON_UNESCAPED_UNICODE);
//改变购物车
$code = md5($attr_json);
$cart_has = GoodsCart::where(['user_id'=>$user_id, 'goods_encode'=>$code])->exists();
$goods_num = abs($init_num);
if($cart_has){
$cart_goods = GoodsCart::where(['user_id'=>$user_id, 'goods_encode'=>$code])->first();
if($init_num > 0){
$cart_goods->increment('goods_num', $goods_num);
}elseif($init_num < 0){
$cart_goods->decrement('goods_num');
//如果数量为0 则删除
if($cart_goods->goods_num == 0){
$cart_goods->delete();
}
}
}else{
if($init_num > 0){
GoodsCart::create([
'user_id' => $user_id,
'goods_id' => $goods->id,
'goods_name' => $goods->goods_name,
'goods_encode' => $code,
'goods_attrs' => $attr_json,
'goods_price' => $goods->goods_price+$attr_price,
'goods_num' => $goods_num,
'is_too' => $goods->is_too,
]);
}else{
return $this->error('加入购物车失败:参数错误');
}
}
//返回最新购物车
return GoodsCartResource::collection(auth('api')->user()->getUserCart())->additional(['code' => Response::HTTP_OK, 'message' => '修改购物车成功']);
}
/**
* 清空购物车
*/
public function cleanCart(){
auth('api')->user()->cleanUserCart();
return $this->success('清空成功');
}
}

View File

@ -0,0 +1,159 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use App\Models\User;
use App\Models\Guess;
use App\Models\UserGuess;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Http\Resources\GuessResource;
use Illuminate\Support\Facades\Storage;
use App\Http\Resources\UserGuessResource;
class GuessController extends Controller
{
//
public function index() {
}
public function guessContent(Request $request) {
$date_time = date('Y-m-d H:i:s');
$info = Guess::query()
->where('start_time', '<' ,$date_time)
->where('end_time', '>=', $date_time)
->where([
'status' => Guess::STATUS_ABLE,
'prize_state' => Guess::PRIZE_UNEXIST
])->with(['options'])->first();
if ($info == null) {
return $this->error('暂时没有开始的竞猜活动');
}
return GuessResource::make($info);
}
public function guessNewContent(Request $request) {
$date_time = date('Y-m-d H:i:s');
$info = Guess::query()
->where([
'status' => Guess::STATUS_ABLE,
])->with(['options'])->first();
if ($info == null) {
return $this->error('暂时没有开始的竞猜活动');
}
return GuessResource::make($info);
}
/**
* 用户竞猜结果
*
* @param Request $request
* @return void
*/
public function guessResult(Request $request) {
$user = auth('api')->user();
$list = UserGuess::query()->where('user_id', $user->id)
->with(['guess.options', 'options'])->orderByDesc('id')->get();
return UserGuessResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
/**
* 竞猜
*
*/
public function userGuess(Request $request) {
$request->validate([
'guess_id' => 'required',
'options_id' => 'required|array'
]);
$user = auth('api')->user();
if (!$user->phone || $user->phone == "") {
return $this->error("未绑定用户手机号码");
}
$date_time = date('Y-m-d H:i:s');
$info = Guess::query()
->where('start_time', '<' ,$date_time)
->where('end_time', '>=', $date_time)
->where([
'status' => Guess::STATUS_ABLE,
'prize_state' => Guess::PRIZE_UNEXIST
])->with(['options'])->first();
if (!$info) {
return $this->error('暂时没有开始的竞猜活动');
}
if ($info->id != $request->guess_id) {
return $this->error("该活动已经结束或者关闭");
}
if ($info->prize_state == Guess::PRIZE_EXIST) {
return $this->error("竞猜结果已经公布");
}
if (sizeof($request->options_id) != $info->num) {
return $this->error("此次竞猜只能选择{$info->num}个选项");
}
if (UserGuess::query()->where(['guess_id' => $info->id , 'user_id'=> $user->id])->exists()) {
return $this->error('每轮竞猜,只能进行一次');
}
$data = [];
$user_guess_id = 0;
foreach ($request->options_id as $key => $value) {
# code...
if (!$info->options->firstWhere('id', $value)) {
return $this->error('请选择竞猜内的选项');
}
$data[] = ['user_guess_id'=> &$user_guess_id, 'guess_option_id' => $value];
}
try {
DB::beginTransaction();
//code...
$user_guess_info = UserGuess::query()->create([
'guess_id' => $info->id,
'user_id' => $user->id,
'correct_state' => UserGuess::UN_SET,
'prize_state' => UserGuess::PRIZE_UN_SET,
'prize' => null
]);
$user_guess_id = $user_guess_info->id;
DB::table('user_guess_option')->insert($data);
DB::commit();
} catch (\Throwable $th) {
//throw $th;
DB::rollBack();
logger('+++抽奖失败+++', [$th]);
return $this->error("抽奖失败");
}
return $this->success("抽奖成功");
}
public function shareCode (Request $request) {
$request->validate([
'path' => 'required',
// 'width' => ''
]);
$path = 'miniProgram/app_code/guess';
if (Storage::disk()->exists($path.'/'. md5($request->path).'.png')) {
return $this->success(['path' => Storage::url($path.'/'. md5($request->path).'.png')]);
}
$miniProgram = \EasyWeChat::miniProgram();
$response = $miniProgram->app_code->get($request->path, [
'width' => $request->input('width',430)
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
// $filename = $response->saveAs('../storage/app/public/miniProgram/app_code/guess', 'appcode.png');
Storage::put($path.'/'. md5($request->path).'.png', $response->getBody()->getContents());
}
return $this->success(['path' => Storage::url($path.'/'. md5($request->path).'.png')]);
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use App\Models\{Good, Banner};
use App\Http\Resources\{GoodsResource,BannersResource};
use EasyWeChat\Factory;
class IndexController extends Controller
{
public function index(Request $request){
//热销商品
$list = Good::where('is_hot', 1)->where('is_sell', 1)->orderBy('goods_price', 'desc')->orderBy('created_at', 'desc')->get();
return GoodsResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
public function bannerList(Request $request){
$type = $request->input('address', 'banner_index');
$list = Banner::where('is_show', 1)->where('banner_address', $type)->get();
return BannersResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
/**
* 执行资源上传
*/
public function uploadResource(Request $request){
$path = $request->input('path', 'uploads') . '/avatar/' . date('Y-m-d');
$result = [];
// file 文件
$files = $request->file();
if($files){
foreach ($files as $key => $fileData) {
$item = null;
if (is_array($fileData)) {
foreach ($fileData as $file) {
$item[] = str_replace(env('ALIYUN_OSS_DOMAIN').'/', env('OSS_URL'), Storage::url($this->saveFile($path, $file)));
}
} else {
$item = str_replace(env('ALIYUN_OSS_DOMAIN').'/', env('OSS_URL'), Storage::url($this->saveFile($path, $fileData)));
}
$result[$key] = $item;
}
}else{
$data = $request->except(['path']);
foreach ($data as $key => $files) {
$item = null;
if (is_array($files)) {
// $_stop = 0;
foreach ($files as $file) {
$item[] = str_replace(env('ALIYUN_OSS_DOMAIN').'/', env('OSS_URL'), Storage::url($this->saveFile($path, $file)));
}
} else {
$item = str_replace(env('ALIYUN_OSS_DOMAIN').'/', env('OSS_URL'), Storage::url($this->saveFile($path, $files)));
}
$result[$key] = $item;
}
}
return $this->json($result);
}
protected function saveFile($path, $file = null)
{
if (gettype($file) == 'object') {
$file = Storage::putFile($path, $file);
} else if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)) {
$type = $result[2];
if (in_array($type, array('jpeg', 'jpg', 'gif', 'bmp', 'png'))) {
$savePath = $path . '/' . uniqid() . '.' . $type;
Storage::put($savePath, base64_decode(str_replace($result[1], '', $file)));
$file = $savePath;
}
}
return $file;
}
public function createCode(){
// dd(public_path().'/');
$app = \EasyWeChat::miniProgram();
$response = $app->app_code->get('/pages/welcome/welcome?type_lk=3&path=%2Fpages%2Flucky-draw%2Flucky-draw', [
'width' => 600,
//...
]);
// dd($response);
$filename = '';
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->saveAs(public_path().'/', 'appcode.png');
}
dd($filename);
}
}

View File

@ -0,0 +1,476 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use DB;
use Carbon\Carbon;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\{Order,PayLog,ActivityUser,ReserveEditLog,ActivityOption,UserTicket,TicketGoodsValue,TicketCateValue};
use App\Http\Resources\{OrderResource, OrderInfoResource,UserTicketResource};
use App\Services\OrderService;
use App\Traits\WechatPay;
use App\Jobs\{PayOrderJob,PrintOrderJob};
class OrderController extends Controller
{
protected $order_service;
public function __construct(OrderService $order_service){
$this->order_service = $order_service;
}
/**
* 确认创建订单
* 购物车下单to_cart/直接兑换to_exchange
* 返回订单信息
*/
public function createOrder(Request $request){
$type = $request->input('type', 'to_cart');
$goods_info = $request->input('goods_info', '{}');//{"goods_id":1,"goods_attr":[1,2,3]}
$goods_info = json_decode($goods_info, true);
$user = auth('api')->user();
//检测是否绑定昵称头像
if(!$user->avatar || !$user->nick_name){
return $this->error('未绑定昵称头像', 501);
}
//检测是否绑定手机号
if(!$user->phone){
return $this->error('未绑定手机号', 502);
}
$order = false;
switch($type){
case 'to_cart':
$order = $this->order_service->createOrderToCart($user);
break;
case 'to_exchange':
$order = $this->order_service->createOrderToExchange($user, $goods_info);
break;
case 'to_reserve':
$reserve_data = [
'activity_id' => $request->input('activity_id', 0),
'reserve_time' => $request->input('reserve_time', ''),
'goods_num' => $request->input('goods_num', 0),
];
//判断时间是否有效当前时间后的7天内
$reserve_time = Carbon::parse($reserve_data['reserve_time'])->endOfDay();
if( empty($reserve_data['reserve_time']) ||
( $reserve_time < Carbon::now()->startOfDay() ||
$reserve_time > Carbon::now()->addDays(7)->endOfDay())
){
return $this->error('请选择有效的预约时间');
}
$order = $this->order_service->createOrderToReserve($user, $goods_info, $reserve_data);
break;
}
if(isset($order['status']) && $order['status'] == false){
return $this->error($order['message']);
}
return OrderInfoResource::make($order);
}
/**
* 支付订单
*/
public function payOrder(Request $request){
$user = auth('api')->user();
$order_sn = $request->input('order_sn', '');
$ticket_id = $request->input('ticket_id', 0);
//查看当前支付类型;
$order = Order::where([
'user_id'=>$user->id,
'order_sn'=>$order_sn,
'order_status'=>1,
'pay_status'=>0,
])->first();
if($order){
$pay_data = [];
switch($order->pay_type){
case 1://微信支付
/** 使用优惠券,更新订单结算信息 start **/
$update_order = false;
//如果是已经优惠的订单则不能使用优惠券
if($ticket_id > 0 && $order->ticket_value > 0 && $order->ticket_id ==0){
return $this->error('已享受其他满减优惠,无法再使用优惠券');
}
if($ticket_id > 0 && $ticket_id!=$order->ticket_id){
$now_time = Carbon::now();
$user_ticket = UserTicket::with('quanTicket')->where([
'user_id'=>$user->id,
'id'=>$ticket_id,
'ticket_status'=>0,
])->where('start_time', '<', $now_time)->where('end_time', '>', $now_time)->first();
if($user_ticket){
try {
DB::beginTransaction();
$old_ticket = $order->ticket_id;
$old_pay_price = $order->pay_price;
$order->ticket_id = $user_ticket->id;
$order->ticket_value = $user_ticket->quanTicket->ticket_value;
$order->pay_price = number_format((intval($order->order_price*100) - intval($order->ticket_value*100))/100, 2);
if($order->pay_price <= 0 || env('APP_ENV', 'local') == 'local'){
$order->pay_price = 0.01;
}
//处理商品优惠
$goods_list = $order->goods;
$goods_ids = $cate_ids = [];
foreach($goods_list as $goods){
//整理商品数量
$goods_ids[] = $goods->goods_id;
$cate_ids[] = $goods->goods->category_id;
}
$num = $times = 0;
$order_goods_ids = [];
if($user_ticket->quanTicket->the_type == 1){//指定商品
$a_goods_ids = TicketGoodsValue::where('quan_id', $user_ticket->quanTicket->id)->whereIn('goods_id', $goods_ids)->pluck('goods_id')->toArray();
foreach($goods_list as $goods){
if(in_array($goods->goods_id, $a_goods_ids)){
$num+= $goods->goods_num;
$times++;
$order_goods_ids[] = $goods->id;
}
}
}elseif($user_ticket->quanTicket->the_type == 2){//指定分类
$a_cate_ids = TicketCateValue::where('quan_id', $user_ticket->quanTicket->id)->whereIn('category_id', $cate_ids)->pluck('category_id')->toArray();
foreach($goods_list as $goods){
if(in_array($goods->goods->category_id, $a_cate_ids)){
$num+= $goods->goods_num;
$times++;
$order_goods_ids[] = $goods->id;
}
}
}else{
foreach($goods_list as $goods){
$num+= $goods->goods_num;
$times++;
$order_goods_ids[] = $goods->id;
}
}
$one_price = number_format((intval($user_ticket->quanTicket->ticket_value*100)/$num)/100, 2);
$i = 1;
foreach ($order->goods as $key =>$goods){
if(in_array($goods->id, $order_goods_ids)){
if($times == $i){
$order->goods[$key]->special_value = number_format((intval($user_ticket->quanTicket->ticket_value*100)-intval($one_price*100)*($num-$goods->goods_num))/100, 2);
}else{
$order->goods[$key]->special_value = number_format(intval($one_price*100)*$goods->goods_num/100, 2);
}
$order->goods[$key]->ticket_id = $user_ticket->id;
$i++;
}else{
$order->goods[$key]->special_value = 0;
$order->goods[$key]->ticket_id = 0;
}
}
$user_ticket->ticket_status = 1;
$user_ticket->save();
//检查历史支付的金额和本次支付金额是否一致不一致生成新的订单号以及paylog
if($old_pay_price!=$order->pay_price ){
$order->order_sn = $this->order_service->createOrderSn($user->id);
//插入支付记录
PayLog::create([
'type' => $order->pay_type,
'order_sn' => $order->order_sn,
'status' => 0,
]);
$update_order = true;
}
$order->push();
if($old_ticket){
UserTicket::where('id', $old_ticket)->update(['ticket_status'=>0]);
}
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
}else{
return $this->error('优惠券不能使用');
}
}
/** 使用优惠券,更新订单结算信息 end **/
$wechat_pay = new WechatPay();
if($update_order){//若更新订单号,则需要重新创建预付单
$res = $wechat_pay->createOrder($order);
if($res['return_code'] == 'SUCCESS'){
//记录perpay_id;
PayLog::where(['order_sn'=>$order->order_sn, 'status'=>0])->update(['pay_ext'=>$res['prepay_id']]);
$prepay_id = $res['prepay_id'];
}else{
return $this->error($res['return_msg']);
}
}else{
$pay_log = PayLog::where(['order_sn'=>$order->order_sn,'status'=>0])->first();
$prepay_id = $pay_log->pay_ext;
}
$pay_data = $wechat_pay->createPayConfig($prepay_id);
$pay_data['order_sn'] = $order->order_sn;
break;
case 2://兑换
//扣除对应奖品;
$pay_log = PayLog::where([
'order_sn'=>$order->order_sn,
'status'=>0
])->first();
foreach(json_decode($pay_log->pay_ext) as $award_id){
$key = 'award_'.$award_id;
$user->activity->decrement($key);
}
//支付订单;
PayOrderJob::dispatch($order);
break;
}
return $this->success($pay_data, '支付成功');
}else{
return $this->error('订单不存在');
}
}
/**
* 订单列表
*/
public function orderList(Request $request){
$user = auth('api')->user();
$per_page = $request->input('per_page', 10);
$query = Order::with('goods')->where([
'user_id'=>$user->id,
'order_status'=>1
]);
$order_type = $request->input('order_type', 'all');
switch($order_type){
case 'wait_pay':
//获取待支付
$query->where([
'pay_status'=>0,
'shipping_status'=>0,
]);
break;
case 'wait_pickup':
//获取待取餐
$query->where([
'pay_status'=>1,
'shipping_status'=>0,
]);
break;
case 'finish':
//获取已完成
$query->where([
'pay_status'=>1,
'shipping_status'=>1,
]);
break;
}
$list = $query->orderBy('created_at', 'desc')->paginate($per_page);
return OrderResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
/**
* 订单详情
*/
public function orderInfo($order_sn){
$user = auth('api')->user();
$order = Order::where([
'user_id' => $user->id,
'order_sn' => $order_sn,
'order_status'=> 1
])->first();
if($order){
return OrderInfoResource::make($order);
}else{
return $this->error('订单不存在', 404);
}
}
/**
* 预约订单修改时间
*/
public function editReserveTime($order_sn, Request $request){
$user = auth('api')->user();
$order = Order::where([
'user_id' => $user->id,
'order_sn' => $order_sn,
'order_status'=> 1,
'pay_status'=> 1,
'is_reserve'=> 1
])->first();
if(!$order){
return $this->error('订单不存在', 404);
}
//检查是否已经生成取餐码
if($order->order_number){
return $this->error('已生成取餐码,无法修改预约时间');
}
//修改时间是否已经改过一次
if(ReserveEditLog::where('order_sn', $order_sn)->exists()){
return $this->error('您已修改过预约时间,无法再次修改');
}
//当前时间是否在有效时间范围内上次预约时间的14天内
if(Carbon::now() > Carbon::parse($order->reserve_time)->addDays(14)->endOfDay()){
return $this->error('订单已过期,无法修改');
}
//修改的时间是否在有效的时间范围内
$reserve_time = $request->input('reserve_time', '');
if(empty($reserve_time) ||
( Carbon::parse($reserve_time)->endOfDay() < Carbon::now()->startOfDay() ||
Carbon::parse($reserve_time)->endOfDay() > Carbon::now()->addDays(7)->endOfDay())){
return $this->error('请选择有效的预约时间');
}
if(Carbon::parse($reserve_time)->startOfDay() == $order->reserve_time){
return $this->error('与当前预约时间一致,无需修改');
}
$old_reserve_time = $order->reserve_time;
try {
DB::beginTransaction();
$order->reserve_time = $reserve_time;
$order->save();
ReserveEditLog::create([
'order_sn' => $order->order_sn,
'old_reserve_time' => $old_reserve_time,
'to_reserve_time' => $order->reserve_time,
]);
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
return $this->error($th->getMessage());
}
return $this->success('修改成功');
}
/**
* 生成预约单取餐码
*/
public function reserveCreateOrderNumber($order_sn){
$user = auth('api')->user();
$order = Order::where([
'user_id' => $user->id,
'order_sn' => $order_sn,
'order_status'=> 1,
'pay_status'=> 1,
'is_reserve'=> 1
])->first();
if(!$order){
return $this->error('订单不存在', 404);
}
//检查是否已经生成取餐码
if($order->order_number){
return $this->error('已生成取餐码,无法再次生成');
}
//检测是否当天
if($order->reserve_time > Carbon::now()->startOfDay()){
return $this->error('未到预约时间');
}
//
if($order->shipping_status == 1){
return $this->error('已过期');
}
if($order->reserve_time < Carbon::now()->startOfDay()){
return $this->error('已超过预约时间,请修改预约时间');
}
$order->order_number = $this->order_service->createOrderNumber();
//处理订单吹牛逻辑,是否幸运号
$luck_number = ActivityOption::findOrFail(11)->key_value;
$luck_number = explode(',', $luck_number);
if(in_array($order->order_number, $luck_number)){
$order->is_niu = 1;
}
$order->number_time = now();
$order->save();
$this->order_service->insertBigScreenNumber($order->order_number);
if(env('APP_ENV', 'local') == 'production'){
//打印订单
PrintOrderJob::dispatch($order);
}
return OrderInfoResource::make($order);
}
public function cancelOrder($order_sn){
$user = auth('api')->user();
$order = Order::where([
'user_id' => $user->id,
'order_sn' => $order_sn,
'order_status'=> 1,
'pay_status'=> 0,
])->first();
if(!$order){
return $this->error('订单不存在', 404);
}
if($this->order_service->cancleOrder($order)){
return $this->success('取消成功');
}else{
return $this->error('取消失败');
}
}
/**
* 获取可用优惠券
*/
public function getUserTicket($order_sn){
$user = auth('api')->user();
$order = Order::with(['goods'])->where([
'user_id' => $user->id,
'order_sn' => $order_sn,
'order_status'=> 1,
'pay_status'=> 0,
])->first();
if(!$order){
return $this->error('订单不存在', 404);
}
//获取用户的有效优惠券
$user_tickets = UserTicket::with('quanTicket')->where([
'user_id'=>$user->id,
])->where('ticket_status', 0)->where('start_time', '<', Carbon::now())->where('end_time', '>', Carbon::now())->get();
$quan_ids = $user_tickets->pluck('quan_id');
//获取订单商品;
$goods_list = $order->goods;
//遍历商品获取商品和分类ID
$goods_ids = $cate_ids = [];
foreach ($goods_list as $goods){
$goods_ids[] = $goods->goods_id;
$cate_ids[] = $goods->goods->category_id;
}
$goods_quan_ids = TicketGoodsValue::whereIn('quan_id', $quan_ids)->whereIn('goods_id', array_unique($goods_ids))->pluck('quan_id')->toArray();
$cate_quan_ids = TicketCateValue::whereIn('quan_id', $quan_ids)->whereIn('category_id', array_unique($cate_ids))->pluck('quan_id')->toArray();
//合并数组,并去重
$can_quan_ids = array_unique(array_merge($goods_quan_ids, $cate_quan_ids));
//比较价格,筛选可用优惠券
// dd($can_quan_ids);
foreach ($user_tickets as $key => $ticket){
if($ticket->quanTicket->the_type!=0 && !in_array($ticket->quan_id, $can_quan_ids)){
unset($user_tickets[$key]);
}else{
if($ticket->quanTicket->use_limit > $order->order_price){
unset($user_tickets[$key]);
}
}
}
return UserTicketResource::collection($user_tickets)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use Carbon\Carbon;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\{ActivityDayGood, ActivityDayNum};
use App\Http\Resources\{ActivityDayGoodInfoResource};
use Illuminate\Support\Facades\Redis;
class ReserveController extends Controller
{
public function detail($id){
$info = ActivityDayGood::with(['goods', 'goods.useGoodsAttrs'])->findOrFail($id);
$today = Carbon::now()->toDateString();
$hash_key = 'reserve_goods_' . $info->id. '_' . $today;
if(Redis::command('exists', [$hash_key]) == 0){//今日库存是否存入redis
//获取今日指定库存
$num = $info->goods_num;
$day_num = ActivityDayNum::where(['activity_day_id'=>$info->id, 'time'=>$today])->first();
if($day_num){
$num = $day_num->goods_num;
}
Redis::command('set', [$hash_key, $num]);
}
$data = ActivityDayGoodInfoResource::make($info);
$num = Redis::command('get', [$hash_key]);
$data->offsetSet('day_num', $num);
return $data;
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use DB;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\{UserTalk,UserPraiseTalk};
use App\Http\Resources\{UserTalksResource};
class TalkController extends Controller
{
public function list(Request $request){
$sort_type = $request->input('sort_type', '1');
$per_page = $request->input('per_page', 10);
$user = auth('api')->user();
$query = UserTalk::with(['praise', 'user']);
if($sort_type == 2){
$query->orderBy('praise_num', 'desc');
}
$list = $query->where('is_show', 1)->orderBy('created_at', 'desc')->paginate($per_page);
// dd($list);
return UserTalksResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
/**
* 发表言论
*/
public function post(Request $request){
$content = $request->input('content');
//检查是否有头像昵称
$user = auth('api')->user();
//检测是否绑定昵称头像
if(!$user->avatar || !$user->nick_name){
return $this->error('未绑定昵称头像', 501);
}
$len = mb_strlen($content);
if($len <= 0 || $len > 200){
return $this->error('留言长度应不长于200');
}
UserTalk::create([
'user_id' => $user->id,
'talk_content' => $content,
'is_show' => 1
]);
return $this->success('发布成功!');
}
/**
* 点赞, 取消点赞
*/
public function clickPraise($talk_id){
$user = auth('api')->user();
$talk = UserTalk::findOrFail($talk_id);
if(!$talk){
return $this->error('数据不存在', 404);
}
try {
DB::beginTransaction();
if(UserPraiseTalk::where(['user_id'=>$user->id, 'talk_id'=>$talk_id])->exists()){//已点赞,则取消
UserPraiseTalk::where(['user_id'=>$user->id, 'talk_id'=>$talk_id])->delete();
$talk->decrement('praise_num');
$talk_praise = false;
}else{
UserPraiseTalk::create([
'user_id'=>$user->id,
'talk_id'=>$talk_id,
]);
$talk->increment('praise_num');
$talk_praise = true;
}
DB::commit();
} catch(\Throwable $th){
return $this->error('操作失败:'.$th->getMessage());
}
return $this->success(['praise_status'=>$talk_praise],'操作成功');
}
}

View File

@ -0,0 +1,158 @@
<?php
namespace App\Http\Controllers\Api\Miniprogram;
use Cache;
use Carbon\Carbon;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\{User, PointsLog, UserTicket};
use App\Http\Resources\{UserResource, PointsLogsResource, UserTicketResource};
class UsersController extends Controller
{
/**
* 绑定用户信息,头像
*/
public function bindInfo(Request $request)
{
$request->validate([
'data' => 'required',
'iv' => 'required'
]);
$app = \EasyWeChat::miniProgram();
$user = auth('api')->user();
// 解密
$session = Cache::has($user->mini_openid) ? Cache::get($user->mini_openid):'';
if(!$session){
return $this->error('解析失败, 请重新调用auth');
}
$iv = $request->input('iv');
$data = $request->input('data');
try {
$decryptedData = $app->encryptor->decryptData($session, $iv, $data);
$user->nick_name = data_get($decryptedData, 'nickName');
$user->avatar = data_get($decryptedData, 'avatarUrl');
$user->save();
return UserResource::make($user);
} catch (\EasyWeChat\Kernel\Exceptions\DecryptException $e) {
return $this->error('解析失败, '.$e->getMessage());
}
}
public function bindPhone(Request $request){
$request->validate([
'data' => 'required',
'iv' => 'required',
]);
$app = \EasyWeChat::miniProgram();
$user = auth('api')->user();
// 解密
$session = Cache::has($user->mini_openid) ? Cache::get($user->mini_openid):'';
if(!$session){
return $this->error('解析失败, 请重新调用auth');
}
$iv = $request->input('iv');
$data = $request->input('data');
try {
$decryptedData = $app->encryptor->decryptData($session, $iv, $data);
$phone = data_get($decryptedData, 'phoneNumber');
$message = '绑定成功';
if($user->register_gift == 0){
//查询注册赠送的优惠券
$tickets = json_decode(admin_setting('register_ticket'));
if(count($tickets) > 0){
$user->sendTicket($tickets, 0, '注册绑定手机号赠送');
$message = '恭喜获得优惠券,请在【我的优惠券】中查看';
$user->register_gift = 1;
}
}
$user->phone = $phone;
$user->save();
return $this->success(UserResource::make($user)->resolve(), $message);
} catch (\EasyWeChat\Kernel\Exceptions\DecryptException $e) {
return $this->error('解析失败, 重新进入小程序再绑定');
}
}
/**
* 更新用户信息
*/
public function updateInfo(Request $request){
$user = auth('api')->user();
$need_update = 0;
//更新头像
if($request->filled('avatar')){
$user->avatar = str_replace(env('OSS_URL'), '', $request->input('avatar'));
// dd(env('OSS_URL'),$request->input('avatar'), str_replace(env('OSS_URL'), '', $request->input('avatar')), $user->avatar);
$need_update = 1;
}
$need_update && $user->save();
return UserResource::make($user);
}
/**
* 积分记录
*/
public function pointsLog(Request $request){
$user = auth('api')->user();
$per_page = $request->input('per_page', 10);
$list = PointsLog::where([
'user_id'=>$user->id,
])->orderBy('created_at', 'desc')->paginate($per_page);
return PointsLogsResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
/**
* 获取用户奖品数量情况
*/
public function getUserAward(Request $request){
$user = auth('api')->user();
$award_array = [];
for($i =1; $i<10; $i++){
$key = 'award_'.$i;
$award_array[$i] = $user->activity->$key;
}
return $this->success($award_array);
}
public function userInfo(Request $request){
$user = auth('api')->user();
return UserResource::make($user);
}
/**
* 获取用户优惠券
*/
public function userTicket(Request $request){
$type = $request->input('type', 1);//1可用2失效
$user = auth('api')->user();
$per_page = $request->input('per_page', 10);
$query = UserTicket::with('quanTicket')->where([
'user_id'=>$user->id,
]);
if($type == 1){
$query->where('ticket_status', 0)->where('end_time', '>', Carbon::now());
}else{
$query->where(function($q){
$q->where('ticket_status', 1)->orWhere('end_time', '<=', Carbon::now());
});
}
$list = $query->orderBy('created_at', 'desc')->paginate($per_page);
return UserTicketResource::collection($list)->additional(['code' => Response::HTTP_OK, 'message' => '']);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Redis;
class BigScreenController extends Controller
{
public function number(Request $request){
$hash_prefix = "milk_tea_order_number_at_";
$date = Carbon::now()->toDateString();
// Redis 哈希表的命名larabbs_last_actived_at_2017-10-21
$hash = $hash_prefix . $date;
$number_list = Redis::lrange($hash, 0, -1);
return $this->success(array_reverse($number_list));
}
public function notice(Request $request){
$hash_prefix = "milk_tea_number_notice_at_";
$date = Carbon::now()->toDateString();
// Redis 哈希表的命名larabbs_last_actived_at_2017-10-21
$hash = $hash_prefix . $date;
$number_notice = Redis::lpop($hash);
return $this->success(['notice'=> $number_notice !== false ?$number_notice:'']);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Response;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function json($data, $code = Response::HTTP_OK, $message = '')
{
$result = ['data' => $data, 'code' => $code, 'message' => $message];
return response()->json($result);
}
public function success($data = [], $message = '')
{
return $this->json($data, Response::HTTP_OK, $message);
}
public function error($message = '', $code = Response::HTTP_BAD_REQUEST)
{
return $this->json([], $code, $message);
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\{Order, PayLog};
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Jobs\{PayOrderJob};
class NotifyController extends Controller
{
/**
* 集中处理支付回调
*
* @param $out_trade_no
* @param array $params
*/
protected function notify($out_trade_no, $params = [])
{
try {
$order = Order::where([
'order_sn'=> $out_trade_no,
'order_status'=>1,
'pay_status'=>0,
])->first();
//修改paylog的ext字段;
if($order){
PayLog::where([
'order_sn'=>$order->order_sn,
'status'=>0
])->update(['pay_ext'=>$params['pay_trade_no']]);
//支付订单;
PayOrderJob::dispatch($order);
}
} catch (\Throwable $th) {
logger()->error($th);
}
}
/**
* 微信支付异步通知
*/
public function wechatPay(Request $request){
// if (config('app.env') !== 'production') {
// $message = XML::parse(file_get_contents('php://input'));
// if (data_get($message, 'return_code') == 'SUCCESS' && data_get($message, 'result_code') == 'SUCCESS') {
// $this->notify(data_get($message, 'out_trade_no'), [
// 'pay_at' => now(),
// 'pay_trade_no' => data_get($message, 'transaction_id')
// ]);
// }
// return XML::build(['return_code' => 'SUCCESS', 'return_msg' => 'OK']);
// }
$payment = \EasyWeChat::payment();
$response = $payment->handlePaidNotify(function ($message, $fail) {
if (data_get($message, 'return_code') == 'SUCCESS' && data_get($message, 'result_code') == 'SUCCESS') {
//处理公众号支付
switch(data_get($message, 'trade_type')){
case 'JSAPI':
$this->notify(data_get($message, 'out_trade_no'), [
'pay_at' => now(),
'pay_trade_no' => data_get($message, 'transaction_id')
]);
break;
default:
break;
}
}
return true;
});
return $response;
}
// public function testToPay(){
// $this->notify('2107071121001608', [
// 'pay_at' => now(),
// 'pay_trade_no' => '123456',
// ]);
// dd(123456);
// }
}

View File

@ -0,0 +1,67 @@
<?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' => [
\App\Http\Middleware\AcceptHeader::class,
// '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,
];
}

Some files were not shown because too many files have changed in this diff Show More