浏览代码

创建golf 1.0.2仓库代码

phperli 3 年之前
当前提交
0077c1808f
共有 100 个文件被更改,包括 9015 次插入0 次删除
  1. 18 0
      .editorconfig
  2. 59 0
      .env.example
  3. 5 0
      .gitattributes
  4. 18 0
      .gitignore
  5. 0 0
      .htaccess
  6. 14 0
      .styleci.yml
  7. 89 0
      README.md
  8. 40 0
      app/Admin/Actions/AdminSetting.php
  9. 71 0
      app/Admin/Actions/Chat/ChatAction.php
  10. 85 0
      app/Admin/Actions/Chat/ChatLog.php
  11. 69 0
      app/Admin/Actions/Chat/TeamChatAction.php
  12. 63 0
      app/Admin/Actions/Chat/TeamChatLog.php
  13. 46 0
      app/Admin/Actions/Chat/TeamUser.php
  14. 34 0
      app/Admin/Actions/Course/CourseField.php
  15. 40 0
      app/Admin/Actions/Course/CourseFieldForm.php
  16. 81 0
      app/Admin/Actions/Feeds/CommentBatchAction.php
  17. 68 0
      app/Admin/Actions/Feeds/CommentList.php
  18. 68 0
      app/Admin/Actions/Feeds/FeedAction.php
  19. 68 0
      app/Admin/Actions/Feeds/ForwardAction.php
  20. 29 0
      app/Admin/Actions/Feeds/ForwardList.php
  21. 68 0
      app/Admin/Actions/Feeds/LikeAction.php
  22. 33 0
      app/Admin/Actions/Feeds/LikeList.php
  23. 38 0
      app/Admin/Actions/Games/GameMembers.php
  24. 80 0
      app/Admin/Actions/Games/GameScores.php
  25. 36 0
      app/Admin/Actions/Games/GameUserScores.php
  26. 75 0
      app/Admin/Actions/Teams/TeamFeeds.php
  27. 75 0
      app/Admin/Actions/Teams/TeamPhotos.php
  28. 25 0
      app/Admin/Actions/Teams/TeamUsers.php
  29. 29 0
      app/Admin/Actions/Users/FansList.php
  30. 28 0
      app/Admin/Actions/Users/FollowList.php
  31. 82 0
      app/Admin/Actions/Users/Report.php
  32. 70 0
      app/Admin/Actions/Users/SetUserInfo.php
  33. 128 0
      app/Admin/Actions/Users/UserAction.php
  34. 81 0
      app/Admin/Actions/Users/UserAuth.php
  35. 56 0
      app/Admin/Actions/Users/UserAuthForm.php
  36. 69 0
      app/Admin/Actions/Users/UserChange.php
  37. 79 0
      app/Admin/Actions/Users/UserCourse.php
  38. 77 0
      app/Admin/Actions/Users/UserCourseForm.php
  39. 65 0
      app/Admin/Actions/Users/UsersInfo.php
  40. 9 0
      app/Admin/Controllers/AuthController.php
  41. 90 0
      app/Admin/Controllers/BaseConfigController.php
  42. 107 0
      app/Admin/Controllers/ChatTeamController.php
  43. 95 0
      app/Admin/Controllers/CourseController.php
  44. 191 0
      app/Admin/Controllers/CourseFieldController.php
  45. 86 0
      app/Admin/Controllers/CourseHoleController.php
  46. 116 0
      app/Admin/Controllers/CourseUserController.php
  47. 82 0
      app/Admin/Controllers/DocumentController.php
  48. 199 0
      app/Admin/Controllers/FeedsController.php
  49. 73 0
      app/Admin/Controllers/GameTypeController.php
  50. 209 0
      app/Admin/Controllers/GameUserController.php
  51. 223 0
      app/Admin/Controllers/GamesController.php
  52. 40 0
      app/Admin/Controllers/HomeController.php
  53. 88 0
      app/Admin/Controllers/SystemAvatarController.php
  54. 163 0
      app/Admin/Controllers/TeamController.php
  55. 121 0
      app/Admin/Controllers/TeamPhotoController.php
  56. 148 0
      app/Admin/Controllers/UserController.php
  57. 113 0
      app/Admin/Controllers/UserFeedbackController.php
  58. 100 0
      app/Admin/Controllers/UserFriendController.php
  59. 119 0
      app/Admin/Controllers/UserIdentifyController.php
  60. 142 0
      app/Admin/Controllers/UserReportController.php
  61. 117 0
      app/Admin/Forms/AdminSetting.php
  62. 58 0
      app/Admin/Metrics/Course/TotalCourse.php
  63. 107 0
      app/Admin/Metrics/Examples/Feedback.php
  64. 112 0
      app/Admin/Metrics/Examples/Games.php
  65. 91 0
      app/Admin/Metrics/Examples/NewDevices.php
  66. 157 0
      app/Admin/Metrics/Examples/NewUsers.php
  67. 114 0
      app/Admin/Metrics/Examples/ProductOrders.php
  68. 106 0
      app/Admin/Metrics/Examples/Report.php
  69. 117 0
      app/Admin/Metrics/Examples/Sessions.php
  70. 116 0
      app/Admin/Metrics/Examples/Tickets.php
  71. 106 0
      app/Admin/Metrics/Examples/TotalCourse.php
  72. 106 0
      app/Admin/Metrics/Examples/TotalGames.php
  73. 105 0
      app/Admin/Metrics/Examples/TotalTeam.php
  74. 107 0
      app/Admin/Metrics/Examples/TotalUsers.php
  75. 72 0
      app/Admin/bootstrap.php
  76. 204 0
      app/Admin/menu.php
  77. 35 0
      app/Admin/routes.php
  78. 44 0
      app/Console/Commands/AnJuKePicker.php
  79. 243 0
      app/Console/Commands/DataSeeder.php
  80. 47 0
      app/Console/Commands/DongFangDiPicker.php
  81. 64 0
      app/Console/Commands/UserRepair.php
  82. 185 0
      app/Console/Commands/importMap.php
  83. 41 0
      app/Console/Kernel.php
  84. 19 0
      app/Enums/ApiEnum.php
  85. 41 0
      app/Exceptions/Handler.php
  86. 10 0
      app/Exceptions/SmsException.php
  87. 9 0
      app/Exceptions/TencentImAccountException.php
  88. 12 0
      app/Exceptions/TencentImException.php
  89. 10 0
      app/Exceptions/TencentImFriendException.php
  90. 10 0
      app/Exceptions/TencentImGroupException.php
  91. 153 0
      app/Helper/AttachmentHelper.php
  92. 335 0
      app/Helper/function.php
  93. 13 0
      app/Http/Controllers/Controller.php
  94. 76 0
      app/Http/Controllers/V1/AttachmentController.php
  95. 433 0
      app/Http/Controllers/V1/AuthController.php
  96. 34 0
      app/Http/Controllers/V1/BaseConfigController.php
  97. 336 0
      app/Http/Controllers/V1/ChatTeamController.php
  98. 80 0
      app/Http/Controllers/V1/Controller.php
  99. 109 0
      app/Http/Controllers/V1/CourseController.php
  100. 208 0
      app/Http/Controllers/V1/FeedsController.php

+ 18 - 0
.editorconfig

xqd
@@ -0,0 +1,18 @@
+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
+
+[docker-compose.yml]
+indent_size = 4

+ 59 - 0
.env.example

xqd
@@ -0,0 +1,59 @@
+APP_NAME=Laravel
+APP_ENV=local
+APP_KEY=base64:R9CHYiFrc5HrENYSOImB1AbOpgJRqHVeY1pGFf3ZS90=
+APP_DEBUG=true
+APP_URL=http://demoapi.cn
+
+LOG_CHANNEL=stack
+LOG_LEVEL=debug
+
+
+DB_CONNECTION=mysql
+DB_HOST=127.0.0.1
+DB_PORT=3306
+DB_DATABASE=demo_api
+DB_USERNAME=root
+DB_PASSWORD=root123
+
+BROADCAST_DRIVER=log
+CACHE_DRIVER=file
+FILESYSTEM_DRIVER=local
+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=
+AWS_USE_PATH_STYLE_ENDPOINT=false
+
+#Dingo API
+API_STANDARDS_TREE=prs
+API_SUBTYPE=api
+API_PREFIX=api
+API_VERSION=v1
+API_DEBUG=false
+
+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}"

+ 5 - 0
.gitattributes

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

+ 18 - 0
.gitignore

xqd
@@ -0,0 +1,18 @@
+/node_modules
+/public/hot
+/public/storage
+/public/upload
+/public/login_log.log
+/storage/*.key
+/vendor
+.env
+.env.backup
+.phpunit.result.cache
+docker-compose.override.yml
+Homestead.json
+Homestead.yaml
+npm-debug.log
+yarn-error.log
+/.idea
+/.vscode
+.DS_Store

+ 0 - 0
.htaccess


+ 14 - 0
.styleci.yml

xqd
@@ -0,0 +1,14 @@
+php:
+  preset: laravel
+  version: 8
+  disabled:
+    - no_unused_imports
+  finder:
+    not-name:
+      - index.php
+      - server.php
+js:
+  finder:
+    not-name:
+      - webpack.mix.js
+css: true

+ 89 - 0
README.md

xqd
@@ -0,0 +1,89 @@
+
+### 项目概要
+该项目为  思维定制基础API标准
+
+## 技术架构
+
+* PHP >7.3.0
+* MySQL >5.7.0
+* Nginx >1.12.0
+* Laravel 8.x (8.0)
+
+##安装
+1. git clone 到本地
+2. 执行 composer install (导入sql创建好数据库)
+3. 配置 .env 中数据库连接信息,没有.env请复制.env.example命名为.env
+4. 执行 php artisan key:generate
+执行 php artisan migrate (可忽略)
+执行 php artisan db:seed (可忽略)
+
+## Dcat-Admin 资源发布
+```
+$ php artisan admin:publish
+$ php artisan admin:install
+```
+
+## 创建 JWT secret
+```
+$ php artisan jwt:secret
+
+```
+
+## 安装第三方组件
+
+>注意:可以自定义 [`composer`](https://mirrors.aliyun.com/composer/) 镜像,加快拉取速度
+
+```
+composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
+
+```
+
+## 短信
+$result = SmsService::send($request->mobile, $request->event, [], $user);
+## 邮箱
+1. Mail::raw($notice, function ($message) use ($email) {
+2. $message->subject(trans('api.MAILBOX_VALIDATION_NOTIFICATION'));
+    $message->to($email);
+3. 邮箱配置
+   MAIL_MAILER=smtp
+   MAIL_HOST=ssl://smtp.163.com
+   MAIL_PORT=465
+   MAIL_USERNAME=youxiang@163.com
+   MAIL_PASSWORD=VIBTDHQAYLKJYIGC
+   MAIL_ENCRYPTION=
+   MAIL_FROM_ADDRESS=youxiang@163.com
+   MAIL_FROM_NAME="${APP_NAME}"
+});
+## 文件
+$result = SmsService::send($request->mobile, $request->event, [], $user);
+
+### 创建目录
+
+> 注意:git clone 从仓库拉取的代码,可能会存在 storage 目录缺失的问题,需要手动创建
+
+```
+$ mkdir -p storage/{app,debugbar,framework,logs}
+$ mkdir -p storage/framework/{cache,sessions,testing,views}
+
+```
+
+```
+$ chmod -R 777 storage bootstrap/cache
+```
+
+## 创建 storage 到 public 的软链接
+
+> 注意:如果是 Docker 环境,此步骤必须在容器内执行
+
+```
+$ php artisan storage:link
+```
+
+### 数据迁移
+
+> 注意:如果是 Docker 环境,此步骤必须在容器内执行
+> 注意:原始SQL 迁移文件不在本项目
+
+```
+$ php artisan migrate
+```

+ 40 - 0
app/Admin/Actions/AdminSetting.php

xqd
@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Admin\Actions;
+
+use App\Admin\Forms\AdminSetting as AdminSettingForm;
+use Dcat\Admin\Actions\Action;
+use Dcat\Admin\Widgets\Modal;
+
+class AdminSetting extends Action
+{
+    /**
+     * @return string
+     */
+	protected $title;
+
+	public function __construct($title = null)
+    {
+        parent::__construct($title);
+        $lang = request()->session()->get('admin.config.lang')??'en';
+        $this->title = '<i class="feather icon-edit" style="font-size: 1.5rem"></i> '.trans('site-setting.Site_settings',[],$lang);
+    }
+
+    public function render()
+    {
+        $modal = Modal::make()
+            ->id('admin-setting-config') // 导航栏显示弹窗,必须固定ID,随机ID会在刷新后失败
+            ->title($this->title())
+            ->body(AdminSettingForm::make())
+            ->lg()
+            ->button(
+                <<<HTML
+<ul class="nav navbar-nav">
+     <li class="nav-item"> &nbsp;{$this->title()} &nbsp;</li>
+</ul>
+HTML
+            );
+
+        return $modal->render();
+    }
+}

+ 71 - 0
app/Admin/Actions/Chat/ChatAction.php

xqd
@@ -0,0 +1,71 @@
+<?php
+
+
+namespace App\Admin\Actions\Chat;
+
+
+use App\admin\Actions\Users\UsersInfo;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+
+class ChatAction extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title =trans('chat-team.fields.Chat_record');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        $form = ChatLog::make()->payload(['id'=>$this->getKey()]);;
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button('<i class="feather icon-list"></i> '.$this->title);
+    }
+}
+{
+
+}

+ 85 - 0
app/Admin/Actions/Chat/ChatLog.php

xqd
@@ -0,0 +1,85 @@
+<?php
+namespace App\Admin\Actions\Chat;
+use App\Models\ChatList;
+use App\Models\User;
+use App\Models\UserFollow;
+use App\Models\UserFriend;
+use App\Repositories\ImMessage;
+use App\Services\TencentImMessage;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class ChatLog extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $chat_data = UserFollow::query()->find($this->payload['id']);
+
+        return Grid::make(new ImMessage($chat_data->user_id,$chat_data->target_id), function (Grid $grid) {
+//            $grid->column('user_id', 'ID')->sortable();
+            $grid->column('From_Account',trans('chat-team.fields.From_Account'))->display(function ($res){
+                $user = User::query()->where('tencent_im_user_id',$res)->first();
+                $str = "";
+                $str.="<div style='margin-right:10px;text-align: center;display: flex'>";
+                $str.='<img data-action="preview-img" src="'.$user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail">';
+                $str.='<p style="margin-top: 5px">'.$user->name.'</p>';
+                $str.="</div>";
+                return $str;
+            });
+            $grid->column('To_Account',trans('chat-team.fields.To_Account'))->display(function ($res){
+                $user = User::query()->where('tencent_im_user_id',$res)->first();
+                $str = "";
+                $str.="<div style='margin-right:10px;text-align: center;display: flex'>";
+                $str.='<img data-action="preview-img" src="'.$user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail">';
+                $str.='<p style="margin-top: 5px">'.$user->name.'</p>';
+                $str.="</div>";
+                return $str;
+            });
+            $grid->column('MsgTimeStamp',trans('chat-team.fields.MsgTimeStamp'))->display(function ($res){
+                return date("m-d H:i",$res);
+            });
+            $grid->column('MsgBody',trans('chat-team.fields.Message_content'))->display(function ($res){
+                //dd($res);
+                //$res = json_decode($res,true);
+                if($res[0]['MsgType']=='TIMTextElem'){
+                    //文本消息
+                    return $res[0]['MsgContent']['Text'];
+                }elseif ($res[0]['MsgType']=="TIMLocationElem"){
+                    //位置消息
+                    return $res[0]['MsgContent']['Desc'];
+                }elseif ($res[0]['MsgType']=="TIMFaceElem"){
+                    //表情消息
+                }elseif ($res[0]['MsgType']=="TIMCustomElem"){
+                    //自定义消息
+                }elseif ($res[0]['MsgType']=="TIMSoundElem"){
+                    //语音消息
+                    $str = "<audio src='".$res[0]['MsgContent']['Url']."' controls='controls'></audio>";
+                    return $str;
+                }elseif ($res[0]['MsgType']=="TIMImageElem"){
+                    //图像消息
+                    $imgs = $res[0]['MsgContent']['ImageInfoArray'];
+                    $str = "";
+                    if(count($imgs)>0){
+                        $str.='<img data-action="preview-img" src="'.$imgs[0]['URL'].'" style="max-width:50px;max-height:200px;cursor:pointer" class="img img-thumbnail">';
+                    }
+                    return $str;
+                }elseif ($res[0]['MsgType']=="TIMFileElem"){
+                    //文件消息
+                }elseif ($res[0]['MsgType']=="TIMVideoFileElem"){
+                    //视频消息
+                    $str = "<video src='".$res[0]['MsgContent']['VideoUrl']."' style='width:200px;height:200px;margin-right:10px' controls='controls'></video>";
+                    return $str;
+                }
+            });
+
+            $grid->quickSearch(['user_id', 'nickname']);
+
+            $grid->paginate(10);
+            $grid->disableActions();
+
+            $grid->filter(function (Grid\Filter $filter) {
+//                $filter->like('nickname','昵称')->width(4);
+            });
+        });
+    }
+}

+ 69 - 0
app/Admin/Actions/Chat/TeamChatAction.php

xqd
@@ -0,0 +1,69 @@
+<?php
+
+
+namespace App\Admin\Actions\Chat;
+
+use App\Models\UserInfoModel;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Dcat\Admin\Widgets\Table;
+
+class TeamChatAction extends RowAction
+{
+    protected $title;
+
+    protected $group_id;
+
+    public function __construct(string $group_id = null)
+    {
+        $this->group_id = $group_id;
+        $this->title = trans('chat-team.fields.Chat_record');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        $form = TeamChatLog::make()->payload(['group_id'=>$this->group_id]);
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button('<i class="feather icon-list"></i> '.$this->title);
+    }
+}

+ 63 - 0
app/Admin/Actions/Chat/TeamChatLog.php

xqd
@@ -0,0 +1,63 @@
+<?php
+namespace App\Admin\Actions\Chat;
+use App\Models\ChatList;
+use App\Models\User;
+use App\Repositories\ChatTeamLog;
+use App\Repositories\ChatTeamUser;
+use App\Repositories\ImMessage;
+use App\Services\TencentImGroupService;
+use App\Services\TencentImMessage;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class TeamChatLog extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $group_id = $this->payload['group_id'];
+
+        return Grid::make(new ChatTeamLog($group_id), function (Grid $grid) {
+            $grid->column('From_Account',trans('feeds.fields.user_id'))->display(function ($res){
+                if($res!='' || $res!='@TIM#SYSTEM'){
+                    $user = User::query()->where('tencent_im_user_id',$res)->first();
+                    $str = "";
+                    if($user){
+                        $str.="<div style='margin-right:10px;text-align: center;display: flex'>";
+                        $str.='<img data-action="preview-img" src="'.$user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail">';
+                        $str.='<p style="margin-top: 5px">'.$user->name.'</p>';
+                        $str.="</div>";
+                    }
+                    return $str;
+                }elseif($res==''){
+                    return '';
+                }elseif($res=='@TIM#SYSTEM'){
+                    return trans('chat-team.fields.System_message');
+                }
+            });
+
+            $grid->column('MsgBody',trans('chat-team.fields.Message_content'))->display(function ($res){
+                $IsSystemMsg = $this->IsSystemMsg??0;
+                if($IsSystemMsg==0 && !empty($res)){
+                    $MsgType = $res[0]['MsgType'];
+                    $MsgContent = $res[0]['MsgContent'];
+                    if($MsgType=='TIMTextElem'){
+                        $str = $MsgContent['Text'];
+                    }elseif($MsgType=='TIMSoundElem'){
+                        $str = '<audio controls="controls" src="'.$MsgContent['Url'].'"></audio>';
+                    }elseif($MsgType=='TIMImageElem'){
+                        $str = '<img data-action="preview-img" src="'.$MsgContent['ImageInfoArray'][0]['URL'].'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail" />';
+                    }
+                }else{
+                    $str = trans('chat-team.fields.System_message');
+                }
+                return $str;
+            });
+
+            $grid->column('MsgTimeStamp',trans('chat-team.fields.MsgTimeStamp'))->display(function ($res){
+                return date('Y-m-d H:i:s',$res);
+            });
+            $grid->paginate(20);
+            $grid->disableActions();
+        });
+    }
+}

+ 46 - 0
app/Admin/Actions/Chat/TeamUser.php

xqd
@@ -0,0 +1,46 @@
+<?php
+namespace App\Admin\Actions\Chat;
+use App\Models\ChatList;
+use App\Models\User;
+use App\Repositories\ChatTeamUser;
+use App\Repositories\ImMessage;
+use App\Services\TencentImGroupService;
+use App\Services\TencentImMessage;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class TeamUser extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $group_id = $this->payload['GroupId'];
+
+        return Grid::make(new ChatTeamUser($group_id), function (Grid $grid) {
+            $grid->column('Member_Account',trans('feeds.fields.user_id'))->display(function ($res){
+                $user = User::query()->where('tencent_im_user_id',$res)->first();
+                $str = "";
+                $str.="<div style='margin-right:10px;text-align: center;display: flex'>";
+                $str.='<img data-action="preview-img" src="'.$user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail">';
+                $str.='<p style="margin-top: 5px">'.$user->name.'</p>';
+                $str.="</div>";
+                return $str;
+            });
+            $grid->column('Role',trans('chat-team.fields.role'))->display(function ($res){
+                if($res=='Owner'){
+                    $str = trans('chat-team.fields.Owner');
+                }elseif($res=='Admin'){
+                    $str = trans('chat-team.fields.Admin');
+                }else{
+                    $str = trans('chat-team.fields.Member');
+                }
+                return $str;
+            });
+            $grid->column('JoinTime', trans('chat-team.fields.JoinTime'))->display(function ($res){
+                return date('Y-m-d H:i',$res);
+            });
+            $grid->disableRowSelector();
+            $grid->paginate(10);
+            $grid->disableActions();
+        });
+    }
+}

+ 34 - 0
app/Admin/Actions/Course/CourseField.php

xqd
@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Admin\Actions\Course;
+
+use Dcat\Admin\Form\AbstractTool;
+use Dcat\Admin\Widgets\Modal;
+
+class CourseField extends AbstractTool
+{
+    /**
+     * @return string
+     */
+    protected $title = '添加场地';
+
+    protected $model;
+
+    public function __construct(string $model = null, $id = 0)
+    {
+        $this->model = $model;
+        $this->title = '<a class="btn btn-sm btn-primary" style="color:#ffffff;margin-right:10px">'.$this->title.'</a>';
+        $this->id = $id;
+    }
+
+    public function render()
+    {
+        $form = CourseFieldForm::make()->payload(['id' => $this->id]);
+        return Modal::make()
+            ->lg()
+            ->title('')
+            ->body($form)
+            ->button($this->title);
+    }
+
+}

+ 40 - 0
app/Admin/Actions/Course/CourseFieldForm.php

xqd
@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Admin\Actions\Course;
+
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+use Illuminate\Support\Facades\App;
+
+class CourseFieldForm extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+    //弹窗表单
+    public function form()
+    {
+        $id = isset($this->payload['id']) ? $this->payload['id'] : 0;
+        $this->hidden('id')->value($id);
+        $this->text('name', '场地名称');
+    }
+
+    //点击表单处理
+    public function handle(array $input)
+    {
+        try {
+            if(\App\Models\CourseField::query()->where('course_id', $input['id'])->where('name', $input['name'])->first()){
+                return $this->response()->error('已存在');
+            };
+            $courseField = App::make('getCourseFieldInstance');
+            $courseField->course_id = $input['id'];
+            $courseField->name = $input['name'];
+            $courseField->save();
+        } catch (\Exception $exception) {
+            return $this->response()->error($exception->getMessage());
+        }
+        return $this->response()->success('success')->refresh();
+    }
+
+
+}

+ 81 - 0
app/Admin/Actions/Feeds/CommentBatchAction.php

xqd
@@ -0,0 +1,81 @@
+<?php
+
+
+namespace App\Admin\Actions\Feeds;
+
+
+use App\Models\FeedComment;
+use App\Models\FeedLike;
+use Dcat\Admin\Grid\BatchAction;
+use Dingo\Blueprint\Annotation\Method\Post;
+use Illuminate\Http\Request;
+
+class CommentBatchAction extends BatchAction
+{
+    protected $action;
+
+    // 注意action的构造方法参数一定要给默认值
+    public function __construct($title = null, $action = 1)
+    {
+        $this->title = $title;
+        $this->action = $action;
+    }
+
+    // 确认弹窗信息
+    public function confirm()
+    {
+        return trans('feeds.action.sure_delete_content').'?';
+    }
+
+    // 处理请求
+    public function handle(Request $request)
+    {
+        // 获取选中的文章ID数组
+        $keys = $this->getKey();
+        //dd($keys);
+        // 获取请求参数
+        $action = $request->get('action');
+        if($action==1){
+            //评论
+            FeedComment::query()->whereIn('id',$keys)->delete();
+        }elseif($action==2){
+            //点赞
+            FeedLike::query()->whereIn('id',$keys)->delete();
+        }
+        return $this->response()->success('success')->refresh();
+    }
+
+    public function script(){
+        if($this->action==1){
+            return <<<JS
+                    $('.app-admin-actions-feeds-commentlist_grid-select-all-btn').bind('click',function (){
+                        if($(this).parent().children().find('.dropdown-menu').hasClass('show')){
+                            $(this).parent().children().find('.dropdown-menu').removeClass('show');
+                        }else{
+                            $(this).parent().children().find('.dropdown-menu').addClass('show');
+                        }
+                    })
+                JS;
+        }else{
+            return <<<JS
+                    $('.app-admin-actions-feeds-likelist_grid-select-all-btn').bind('click',function (){
+                        if($(this).parent().children().find('.dropdown-menu').hasClass('show')){
+                            $(this).parent().children().find('.dropdown-menu').removeClass('show');
+                        }else{
+                            $(this).parent().children().find('.dropdown-menu').addClass('show');
+                        }
+                    })
+                JS;
+        }
+
+
+    }
+
+    // 设置请求参数
+    public function parameters()
+    {
+        return [
+            'action' => $this->action,
+        ];
+    }
+}

+ 68 - 0
app/Admin/Actions/Feeds/CommentList.php

xqd
@@ -0,0 +1,68 @@
+<?php
+namespace App\Admin\Actions\Feeds;
+use App\Models\FeedComment;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class CommentList extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+
+        $grid = new Grid(new FeedComment());
+        $grid->model()->where(['feed_id'=>$this->payload['id']])->with(['user:id,name,avatar','to_user:id,name,avatar']);
+
+        $grid->column('user_id',trans('feeds.action.operator'))->display(function ($res){
+            $str = "";
+            $str.="<div style='margin-right:10px;text-align: center;display: flex'>";
+            $str.='<img data-action="preview-img" src="'.$this->user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail">';
+            $str.='<div>';
+            $str.='<p style="margin-bottom: 2px">ID:'.$this->user->id.'</p>';
+            $str.='<p>'.trans('user.fields.name').':'.$this->user->name.'</p>';
+            $str.="</div>";
+            $str.="</div>";
+            return $str;
+        });
+        $grid->column('pid',trans('feeds.action.type'))->display(function ($res){
+            if($res>0){
+                $str = trans('feeds.action.reply');
+            }else{
+                $str = trans('feeds.action.commented');
+            }
+            return $str;
+        });
+        $grid->column('to_uid',trans('feeds.action.Person_replied'))->display(function ($res){
+            $str = "";
+            $str.="<div style='margin-right:10px;text-align: center;display: flex'>";
+            $str.='<img data-action="preview-img" src="'.$this->to_user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer" class="img img-thumbnail">';
+            $str.='<div>';
+            $str.='<p style="margin-bottom: 2px">ID:'.$this->to_user->id.'</p>';
+            $str.='<p>'.trans('user.fields.name').':'.$this->to_user->name.'</p>';
+            $str.="</div>";
+            $str.="</div>";
+            return $str;
+        });
+        $grid->column('content',trans('feeds.action.content'))->limit(50);
+        $grid->column('created_at');
+        $grid->quickSearch(['content']);
+        $grid->paginate(10);
+        $grid->batchActions(function (Grid\Tools\BatchActions $batch){
+            $batch->disableDelete(false);
+            $batch->add(new CommentBatchAction(trans('feeds.action.Batch_delete'),1));
+        });
+
+        $grid->setActionClass(Grid\Displayers\Actions::class);
+        $grid->disableActions();
+//        $grid->actions(function (Grid\Displayers\Actions $actionss) {
+//
+//            $actionss->disableView();
+//            $actionss->disableEdit();
+//            $actionss->append(new LikeAction());
+//        });
+
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->like('content',trans('feeds.action.content'))->width(4);
+        });
+        return $grid;
+    }
+}

+ 68 - 0
app/Admin/Actions/Feeds/FeedAction.php

xqd
@@ -0,0 +1,68 @@
+<?php
+
+
+namespace App\Admin\Actions\Feeds;
+
+
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+
+class FeedAction extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = trans('feeds.action.Comment_list');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        $form = CommentList::make()->payload(['id'=>$this->getKey()]);;
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button('<i class="feather icon-message-square"></i> '.$this->title);
+    }
+}
+

+ 68 - 0
app/Admin/Actions/Feeds/ForwardAction.php

xqd
@@ -0,0 +1,68 @@
+<?php
+
+
+namespace App\Admin\Actions\Feeds;
+
+
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+
+class ForwardAction extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = trans('feeds.action.Forward_list');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        $form = ForwardList::make()->payload(['id'=>$this->getKey()]);;
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button('<i class="feather icon-thumbs-up"></i> '.$this->title);
+    }
+}
+

+ 29 - 0
app/Admin/Actions/Feeds/ForwardList.php

xqd
@@ -0,0 +1,29 @@
+<?php
+namespace App\Admin\Actions\Feeds;
+use App\Models\FeedForward;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class ForwardList extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new FeedForward());
+        $grid->model()->with('user:id,name,avatar')->where('feed_id',$this->payload['id'])->orderByDesc('id');
+
+        $grid->column('user.id');
+        $grid->column('user.name');
+        $grid->column('user.avatar')->image('',50);
+        $grid->column('created_at');
+        $grid->quickSearch(['user.name']);
+        $grid->paginate(10);
+
+        $grid->disableActions();
+//        $grid->actions(function (Grid\Displayers\Actions $actionss) {
+//            $actionss->disableView();
+//            $actionss->disableEdit();
+//        });
+
+        return $grid;
+    }
+}

+ 68 - 0
app/Admin/Actions/Feeds/LikeAction.php

xqd
@@ -0,0 +1,68 @@
+<?php
+
+
+namespace App\Admin\Actions\Feeds;
+
+
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+
+class LikeAction extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = trans('feeds.action.Like_list');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        $form = LikeList::make()->payload(['id'=>$this->getKey()]);;
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button('<i class="feather icon-thumbs-up"></i> '.$this->title);
+    }
+}
+

+ 33 - 0
app/Admin/Actions/Feeds/LikeList.php

xqd
@@ -0,0 +1,33 @@
+<?php
+namespace App\Admin\Actions\Feeds;
+use App\Models\FeedLike;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class LikeList extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new FeedLike());
+        $grid->model()->with('user:id,name,avatar')->where('feed_id',$this->payload['id'])->orderByDesc('id');
+
+        $grid->column('user.id');
+        $grid->column('user.name');
+        $grid->column('user.avatar')->image('',50);
+        $grid->column('created_at');
+        $grid->quickSearch(['user.name']);
+        $grid->paginate(10);
+
+        $grid->disableActions();
+        $grid->batchActions(function (Grid\Tools\BatchActions $batch){
+            $batch->disableDelete(false);
+            $batch->add(new CommentBatchAction(trans('feeds.action.Batch_delete'),2));
+        });
+//        $grid->actions(function (Grid\Displayers\Actions $actionss) {
+//            $actionss->disableView();
+//            $actionss->disableEdit();
+//        });
+
+        return $grid;
+    }
+}

+ 38 - 0
app/Admin/Actions/Games/GameMembers.php

xqd
@@ -0,0 +1,38 @@
+<?php
+namespace App\Admin\Actions\Games;
+use App\Models\GameUser;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class GameMembers extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new GameUser());
+        $grid->model()->with('user:id,name,avatar')->where('game_id',$this->payload['id'])->orderByDesc('id');
+
+        $grid->column('user.id','ID');
+        $grid->column('user.name',trans('user.fields.name'));
+        $grid->column('user.avatar',trans('user.fields.avatar'))->image('',50);
+
+        $grid->column('level',trans('game-user.fields.level'))->using([
+                1=>trans('game-user.fields.red'),
+                2=>trans('game-user.fields.white'),
+                3=>trans('game-user.fields.blue'),
+                4=>trans('game-user.fields.gold')])
+            ->label(['gray','red','write','blue','gold']);
+
+        $grid->column('type',trans('game-user.fields.type'))->using([
+            1=>trans('game-user.fields.normal'),
+            2=>trans('game-user.fields.fictitious')
+        ])->label(['gray','green','gray']);
+
+        $grid->column('created_at');
+        $grid->quickSearch(['user.name']);
+        $grid->paginate(10);
+        $grid->disableRowSelector();
+        $grid->disableActions();
+
+        return $grid;
+    }
+}

+ 80 - 0
app/Admin/Actions/Games/GameScores.php

xqd
@@ -0,0 +1,80 @@
+<?php
+
+
+namespace App\Admin\Actions\Games;
+
+use App\Models\UserInfoModel;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Dcat\Admin\Widgets\Table;
+
+class GameScores extends RowAction
+{
+    protected $title;
+
+    protected $type;
+
+    public function href(): string
+    {
+//        parent::href(); // TODO: Change the autogenerated stub
+        if($this->type=='game'){
+            return "/admin/game_user_scores?game_id=".$this->getKey();
+        }else{
+            return "/admin/game_user_scores?user_id=".$this->getKey();
+        }
+
+    }
+
+    public function __construct(string $type = 'game')
+    {
+        $this->type = $type;
+        $this->title = '<i class="feather icon-aperture"></i> '.trans('games.fields.game_record');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle()
+    {
+//        return $this->response()
+//            ->success('Processed successfully: '.$this->getKey())
+//            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+//    public function render()
+//    {
+//        $form = UsersInfoForm::make()->payload(['user_id'=>$this->getKey()]);
+//        return Modal::make()
+//            ->lg()
+//            ->title($this->title)
+//            ->body($form)
+//            ->button('<i class="feather icon-settings"></i> '.$this->title);
+//    }
+}

+ 36 - 0
app/Admin/Actions/Games/GameUserScores.php

xqd
@@ -0,0 +1,36 @@
+<?php
+namespace App\Admin\Actions\Games;
+use App\Models\GameUser;
+use App\Models\GameUserScore;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class GameUserScores extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new GameUserScore());
+        $grid->model()
+            ->with(['changeUser:id,name,avatar','gameUser:id,level,type'])
+            ->leftJoin('course_holes','course_holes.id','=','game_user_scores.hole_id')
+            ->where('game_user_scores.game_user_id',$this->payload['id'])
+            ->select(['game_user_scores.*','course_holes.sort'])
+            ->orderBy('sort','asc');
+
+        $grid->column('sort','球洞号');
+        $grid->column('score','分数');
+        $grid->column('gameUser.level','T台')->using([1=>'红',2=>"白",3=>"蓝",4=>"金"])->label(['gray','red','write','blue','gold']);
+        $grid->column('gameUser.type','类型')->using([1=>'正常',2=>"虚拟"])->label(['gray','green','gray']);
+        $grid->column('created_at','时间');
+//        $grid->quickSearch(['user.name']);
+        $grid->paginate(10);
+        $grid->disableRowSelector();
+        $grid->disableActions();
+//        $grid->actions(function (Grid\Displayers\Actions $actionss) {
+//            $actionss->disableView();
+//            $actionss->disableEdit();
+//        });
+
+        return $grid;
+    }
+}

+ 75 - 0
app/Admin/Actions/Teams/TeamFeeds.php

xqd
@@ -0,0 +1,75 @@
+<?php
+
+
+namespace App\Admin\Actions\Teams;
+
+use App\Models\UserInfoModel;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Dcat\Admin\Widgets\Table;
+
+class TeamFeeds extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function href(): string
+    {
+//        parent::href(); // TODO: Change the autogenerated stub
+        return "/admin/feeds?team_id=".$this->getKey();
+    }
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = '<i class="feather icon-aperture"></i> '.trans('team.fields.Team_feeds');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle()
+    {
+//        return $this->response()
+//            ->success('Processed successfully: '.$this->getKey())
+//            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+//    public function render()
+//    {
+//        $form = UsersInfoForm::make()->payload(['user_id'=>$this->getKey()]);
+//        return Modal::make()
+//            ->lg()
+//            ->title($this->title)
+//            ->body($form)
+//            ->button('<i class="feather icon-settings"></i> '.$this->title);
+//    }
+}

+ 75 - 0
app/Admin/Actions/Teams/TeamPhotos.php

xqd
@@ -0,0 +1,75 @@
+<?php
+
+
+namespace App\Admin\Actions\Teams;
+
+use App\Models\UserInfoModel;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Dcat\Admin\Widgets\Table;
+
+class TeamPhotos extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function href(): string
+    {
+//        parent::href(); // TODO: Change the autogenerated stub
+        return "/admin/team_photos?team_id=".$this->getKey();
+    }
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = '<i class="feather icon-instagram"></i> '.trans('team.fields.Team_photos');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle()
+    {
+//        return $this->response()
+//            ->success('Processed successfully: '.$this->getKey())
+//            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+//    public function render()
+//    {
+//        $form = UsersInfoForm::make()->payload(['user_id'=>$this->getKey()]);
+//        return Modal::make()
+//            ->lg()
+//            ->title($this->title)
+//            ->body($form)
+//            ->button('<i class="feather icon-settings"></i> '.$this->title);
+//    }
+}

+ 25 - 0
app/Admin/Actions/Teams/TeamUsers.php

xqd
@@ -0,0 +1,25 @@
+<?php
+namespace App\Admin\Actions\Teams;
+use App\Models\TeamUser;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class TeamUsers extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new TeamUser());
+        $grid->model()->with(['user:id,name,avatar'])->where('team_id',$this->payload['id'])->orderByDesc('id');
+
+        $grid->column('user.id','ID');
+        $grid->column('user.name',trans('user.fields.name'));
+        $grid->column('user.avatar',trans('user.fields.avatar'))->image('',50);
+        $grid->column('created_at');
+        $grid->quickSearch(['user.name']);
+        $grid->paginate(10);
+
+        $grid->disableRowSelector();
+        $grid->disableActions();
+        return $grid;
+    }
+}

+ 29 - 0
app/Admin/Actions/Users/FansList.php

xqd
@@ -0,0 +1,29 @@
+<?php
+namespace App\Admin\Actions\Users;
+use App\Models\UserFollow;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class FansList extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new UserFollow());
+        $grid->model()->with('user:id,name,avatar')->where('target_id',$this->payload['id'])->orderByDesc('id');
+
+        $grid->column('user.name',trans('user.fields.name'));
+        $grid->column('user.avatar',trans('user.fields.avatar'))->image('',50);
+        $grid->column('created_at');
+        $grid->quickSearch(['user.name']);
+        $grid->paginate(10);
+
+        $grid->disableRowSelector();
+        $grid->disableActions();
+//        $grid->actions(function (Grid\Displayers\Actions $actionss) {
+//            $actionss->disableView();
+//            $actionss->disableEdit();
+//        });
+
+        return $grid;
+    }
+}

+ 28 - 0
app/Admin/Actions/Users/FollowList.php

xqd
@@ -0,0 +1,28 @@
+<?php
+namespace App\Admin\Actions\Users;
+use App\Models\UserFollow;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\LazyRenderable;
+
+class FollowList extends LazyRenderable
+{
+    public function grid(): Grid
+    {
+        $grid = new Grid(new UserFollow());
+        $grid->model()->with('target_user:id,name,avatar')->where('user_id',$this->payload['id'])->orderByDesc('id');
+
+        $grid->column('target_user.name',trans('user.fields.name'));
+        $grid->column('target_user.avatar',trans('user.fields.avatar'))->image('',50);
+        $grid->column('created_at');
+        $grid->quickSearch(['target_user.name']);
+        $grid->paginate(10);
+        $grid->disableRowSelector();
+        $grid->disableActions();
+//        $grid->actions(function (Grid\Displayers\Actions $actionss) {
+//            $actionss->disableView();
+//            $actionss->disableEdit();
+//        });
+
+        return $grid;
+    }
+}

+ 82 - 0
app/Admin/Actions/Users/Report.php

xqd
@@ -0,0 +1,82 @@
+<?php
+
+
+namespace App\Admin\Actions\Users;
+
+
+use Dcat\Admin\Grid\RowAction;
+use Illuminate\Http\Request;
+
+class Report extends RowAction
+{
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+    }
+    /**
+     * 返回字段标题
+     *
+     * @return string
+     */
+    public function title()
+    {
+        return trans('user-report.action.mark_processing');
+    }
+
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+        return [
+            // 确认弹窗 title
+            trans('user-report.action.sure_mark')
+        ];
+    }
+
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        // 获取当前行ID
+        $id = $this->getKey();
+
+        // 获取 parameters 方法传递的参数
+        $model = $request->get('model');
+        $apply = $model::find($id);
+        $apply->status=1;
+        $apply->save();
+        // 返回响应结果并刷新页面
+        return $this->response()->success('success')->refresh();
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [
+            // 发送当前行 username 字段数据到接口
+            'status' => $this->row->status,
+            // 把模型类名传递到接口
+            'model' => $this->model,
+        ];
+    }
+
+}

+ 70 - 0
app/Admin/Actions/Users/SetUserInfo.php

xqd
@@ -0,0 +1,70 @@
+<?php
+
+
+namespace App\Admin\Actions\Users;
+
+use Dcat\Admin\Grid\RowAction;
+
+class SetUserInfo extends RowAction
+{
+    protected $title = '<i class="feather icon-settings"></i>设置资料';
+
+    protected $model;
+
+    public function href(): string
+    {
+//        parent::href(); // TODO: Change the autogenerated stub
+        return "/admin/users_info/".$this->getKey().'/edit';
+    }
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle()
+    {
+//        return $this->response()
+//            ->success('Processed successfully: '.$this->getKey())
+//            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+//    public function render()
+//    {
+//        $form = UsersInfoForm::make()->payload(['user_id'=>$this->getKey()]);
+//        return Modal::make()
+//            ->lg()
+//            ->title($this->title)
+//            ->body($form)
+//            ->button('<i class="feather icon-settings"></i> '.$this->title);
+//    }
+}

+ 128 - 0
app/Admin/Actions/Users/UserAction.php

xqd
@@ -0,0 +1,128 @@
+<?php
+
+
+namespace App\Admin\Actions\Users;
+
+use App\Models\UserInfoModel;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Dcat\Admin\Widgets\Table;
+
+class UserAction extends RowAction
+{
+    protected $title = '更多资料';
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($this->table($this->getKey()))
+            ->button('<i class="feather icon-grid"></i> 更多资料');
+    }
+
+    protected function table($user_id)
+    {
+        $userInfo = UserInfoModel::query()->find($user_id);
+        if(!$userInfo){
+            return ;
+        }
+        $photoDiv = "";
+        if(isset($userInfo->photo)&&!empty($userInfo->photo)){
+            $photo = json_decode($userInfo->photo,true);
+            $photoDiv = "<div class='show_img_div'>";
+            if(is_array($photo)&&count($photo)>0){
+                foreach ($photo as $v){
+                    $photoDiv.= "<img  src='".$v['url']."' style='width:80px;height:80px;margin-right:10px'/>";
+                }
+            }
+            $photoDiv .= "</div>";
+        }
+        $videoDiv = "";
+        if(isset($userInfo->video)&&!empty($userInfo->video)){
+            $video = json_decode($userInfo->video,true);
+            $videoDiv = "<div>";
+            if(is_array($video)&&count($video)>0){
+                foreach ($video as $v){
+                    if(isset($v['url'])){
+                        $videoDiv .= "<video src='".$v['url']."' style='width:200px;height:200px;margin-right:10px' controls='controls'></video>";
+                    }
+
+                }
+            }
+            $videoDiv .= "</div>";
+        }
+        Admin::style('.table td{padding: .85rem .55rem}');
+        Admin::script(<<<JS
+                $('.show_img_div>img').click(function(){
+                    Dcat.swal.fire(
+                         {imageUrl:this.src,
+                         imageMaxWidth:1200,
+                         imageMaxHeight:900,
+                         imageAlt:'图片打开失败'}
+                    );
+                });
+            JS);
+        $data = [
+            ['name' => '相册',    'value' => $photoDiv],
+            ['name' => '视频',    'value' => $videoDiv],
+            ['name' => '生日',    'value' => $userInfo->birthday],
+            ['name' => '身高',    'value' => $userInfo->height.'cm'],
+            ['name' => '体重',    'value' => $userInfo->weight.'kg'],
+            ['name' => '职业',    'value' => $userInfo->work],
+            ['name' => '个人简介', 'value' =>$userInfo->info],
+            ['name' => '地区',    'value' => $userInfo->area],
+            ['name' => '身材',    'value' => $userInfo->figure],
+            ['name' => '感情状态', 'value' => $userInfo->feeling],
+            ['name' => '学历',    'value' => $userInfo->education],
+            ['name' => '年收入',   'value' => $userInfo->income],
+            ['name' => '兴趣爱好', 'value' => $userInfo->hobby],
+            ['name' => '抽烟喝酒',  'value' => $userInfo->drink],
+        ];
+        return Table::make(['名称', '值'], $data);
+    }
+}

+ 81 - 0
app/Admin/Actions/Users/UserAuth.php

xqd
@@ -0,0 +1,81 @@
+<?php
+
+
+namespace App\Admin\Actions\Users;
+
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Illuminate\Http\Request;
+
+class UserAuth extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = '<i class="feather icon-user-check"></i> '.trans('user.fields.user_authentication');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+//        return [
+//            "确定认证吗?"
+//        ];
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+//        // 获取当前行ID
+//        $id = $this->getKey();
+//
+//        // 获取 parameters 方法传递的参数
+//        $model = $request->get('model');
+//        $apply = $model::find($id);
+//        $apply->is_auth=1;
+//        $apply->save();
+//        // 返回响应结果并刷新页面
+//        return $this->response()->success("操作成功")->refresh();
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [
+            // 发送当前行 username 字段数据到接口
+            'status' => $this->row->is_auth,
+            // 把模型类名传递到接口
+            'model' => $this->model,
+        ];
+    }
+
+    public function render()
+    {
+        $form = UserAuthForm::make()->payload(['id'=>$this->getKey()]);
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button($this->title);
+    }
+}

+ 56 - 0
app/Admin/Actions/Users/UserAuthForm.php

xqd
@@ -0,0 +1,56 @@
+<?php
+namespace App\Admin\Actions\Users;
+
+use App\Models\User;
+use App\Models\UserIdentify;
+use App\Models\UserVipLogModel;
+use App\Models\VipModel;
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+use Illuminate\Support\Facades\DB;
+use PHPUnit\Util\Exception;
+
+class UserAuthForm extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+
+    public function __construct($data = [], $key = null)
+    {
+        parent::__construct($data, $key);
+    }
+
+    public function handle(array $input)
+    {
+        DB::beginTransaction();
+        try {
+            $user_identify = UserIdentify::query()->find($input['id']);
+            if($input['is_auth']>0){
+                $user_identify->status = 1;
+                $user_identify->save();
+
+                $user = User::query()->find($user_identify->user_id);
+                if(!$user){
+                    throw new Exception(trans('user.help.refresh_error'));
+                }
+                $user->is_auth = $input['is_auth'];
+                $user->save();
+            }
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return $this->response()->error($exception->getMessage());
+        }
+
+        return $this->response()->success('success')->refresh();
+    }
+
+
+    public function form()
+    {
+        $this->hidden('id')->value($this->payload['id']);
+        $this->radio('is_auth', trans('user.fields.is_auth'))->options([0=> trans('user.fields.unauthorized'),1=> trans('user.fields.organization'),2=> trans('user.fields.public_figure')])->default(0);
+    }
+}

+ 69 - 0
app/Admin/Actions/Users/UserChange.php

xqd
@@ -0,0 +1,69 @@
+<?php
+
+
+namespace App\Admin\Actions\Users;
+
+use App\Models\UserInfoModel;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Dcat\Admin\Widgets\Table;
+
+class UserChange extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = trans('user.fields.modify_account');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        return $this->response()
+            ->success('Processed successfully: '.$this->getKey())
+            ->redirect('/');
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [];
+    }
+
+    public function render()
+    {
+        $form = UsersInfo::make()->payload(['id'=>$this->getKey()]);
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button('<i class="feather icon-settings"></i> '.$this->title);
+    }
+}

+ 79 - 0
app/Admin/Actions/Users/UserCourse.php

xqd
@@ -0,0 +1,79 @@
+<?php
+
+
+namespace App\Admin\Actions\Users;
+
+use Dcat\Admin\Grid\RowAction;
+use Dcat\Admin\Widgets\Modal;
+use Illuminate\Http\Request;
+
+class UserCourse extends RowAction
+{
+    protected $title;
+
+    protected $model;
+
+    public function __construct(string $model = null)
+    {
+        $this->model = $model;
+        $this->title = '<i class="feather icon-user-check"></i> '.trans('course-user.fields.Member_court_audit');
+    }
+
+    /**
+     * 设置确认弹窗信息,如果返回空值,则不会弹出弹窗
+     *
+     * 允许返回字符串或数组类型
+     *
+     * @return array|string|void
+     */
+    public function confirm()
+    {
+
+    }
+
+    /**
+     * 处理请求
+     *
+     * @param Request $request
+     *
+     * @return \Dcat\Admin\Actions\Response
+     */
+    public function handle(Request $request)
+    {
+        // 获取当前行ID
+        $id = $this->getKey();
+
+        // 获取 parameters 方法传递的参数
+        $model = $request->get('model');
+        $apply = $model::find($id);
+        $apply->is_auth=1;
+        $apply->save();
+        // 返回响应结果并刷新页面
+        return $this->response()->success('success')->refresh();
+    }
+
+    /**
+     * 设置要POST到接口的数据
+     *
+     * @return array
+     */
+    public function parameters()
+    {
+        return [
+            // 发送当前行 username 字段数据到接口
+            'status' => $this->row->is_auth,
+            // 把模型类名传递到接口
+            'model' => $this->model,
+        ];
+    }
+
+    public function render()
+    {
+        $form = UserCourseForm::make()->payload(['id'=>$this->getKey()]);
+        return Modal::make()
+            ->lg()
+            ->title($this->title)
+            ->body($form)
+            ->button($this->title);
+    }
+}

+ 77 - 0
app/Admin/Actions/Users/UserCourseForm.php

xqd
@@ -0,0 +1,77 @@
+<?php
+
+namespace App\Admin\Actions\Users;
+
+use App\Models\Course;
+use App\Models\CourseUser;
+use App\Models\User;
+use App\Models\UserIdentify;
+use App\Models\UserMessage;
+use App\Models\UserVipLogModel;
+use App\Models\VipModel;
+use App\Services\TencentImMessage;
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+use PHPUnit\Util\Exception;
+
+class UserCourseForm extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+
+    public function __construct($data = [], $key = null)
+    {
+        parent::__construct($data, $key);
+    }
+
+    public function handle(array $input)
+    {
+        DB::beginTransaction();
+        try {
+            $userCourse = CourseUser::query()->find($input['id']);
+            if ($input['status'] > 0) {
+                if ($userCourse['type'] == 1) { //如果当前是主场,就把用户名下其他会员球场变为副场
+                    DB::table('course_users')->where('user_id', $userCourse['user_id'])->where('id', '<>', $input['id'])->update(['type' => 2]);
+                }
+                $userCourse->status = $input['status'];
+                $userCourse->save();
+
+                $course = Course::query()->find($userCourse->course_id);
+                //给用户添加消息记录
+                $user = User::query()->find($userCourse->user_id);
+
+                $lang = $user->lang ?: 'en';
+
+                if ($input['status'] == 1) {
+                    $content = trans('api.YOU_HAVE_PASSED', [], $lang) . ' ' . $course['name'] . ' ' . trans('api.MEMBERSHIP_CERTIFICATION', [], $lang);
+                } elseif ($input['status'] == 2) {
+                    $content = trans('api.YOU_DO_NOT_HAVE_PASSED', [], $lang) . ' ' . $course['name'] . ' ' . trans('api.MEMBERSHIP_CERTIFICATION', [], $lang);
+                }
+                //发送消息通知
+                $im_message = new TencentImMessage();
+                $send_data['from_user'] = 'IM_USER_1';
+                $send_data['to_user'] = $user['tencent_im_user_id'];
+                $send_data['msg'] = $content;
+                $im_message->send_msg($send_data);
+            }
+
+            DB::commit();
+        } catch (\Exception $exception) {
+            DB::rollBack();
+            Log::error('后台同意会员球场申请出错:'.$exception->getMessage());
+            return $this->response()->error(trans('api.NETWORK_ERROR', [], $lang));
+        }
+
+        return $this->response()->success('success')->refresh();
+    }
+
+
+    public function form()
+    {
+        $this->hidden('id')->value($this->payload['id']);
+        $this->radio('status')->options([0 => trans('course-user.fields.check_pending'), 1 => trans('course-user.fields.pass'), 2 => trans('course-user.fields.refuse')])->default(0);
+    }
+}

+ 65 - 0
app/Admin/Actions/Users/UsersInfo.php

xqd
@@ -0,0 +1,65 @@
+<?php
+namespace App\Admin\Actions\Users;
+
+use App\Models\User;
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+use Illuminate\Support\Facades\Auth;
+use PHPUnit\Util\Exception;
+
+class UsersInfo extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+
+    public function __construct($data = [], $key = null)
+    {
+        parent::__construct($data, $key);
+    }
+
+    public function handle(array $input)
+    {
+        $user = User::query()->where(['id'=>$input['id']])->first();
+        if(!$user){
+            return $this->response()->error(trans('user.help.refresh_error'));
+        }
+        if($input['mobile']!=$user->mobile && User::query()->where('mobile',$input['mobile'])->first()){
+            return $this->response()->error(trans('user.help.mobile_used'));
+        }else{
+            $user->mobile = $input['mobile'];
+        }
+        if($input['email']!=$user->email && User::query()->where('email',$input['email'])->first()){
+            return $this->response()->error(trans('user.help.email_used'));
+        }else{
+            $user->mobile = $input['mobile'];
+        }
+
+        if($input['password']!=''){
+            $user->password = $input['password'];
+        }
+        $user->sex = $input['sex'];
+        $user->save();
+        return $this->response()->success('success')->refresh();
+    }
+
+
+    public function form()
+    {
+        $user = User::query()->find($this->payload['id']);
+        $this->hidden('id')->value($this->payload['id']);
+        $this->text('mobile')->default($user->mobile??'')->help(trans('user.help.mobile_help'));
+        $this->text('email')->default($user->email??'')->help(trans('user.help.eamil_help'));
+        $this->text('password')
+            ->minLength(6)
+            ->maxLength(20)
+            ->customFormat(function ($v) {
+                if ($v == $this->password) {
+                    return;
+                }
+                return $v;
+            })
+            ->help(trans('user.help.password_help'));
+        $this->radio('sex',trans('user.fields.sex'))->options([1=>trans('user.fields.man'),2=>trans('user.fields.woman')])->value($user->sex);
+    }
+}

+ 9 - 0
app/Admin/Controllers/AuthController.php

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

+ 90 - 0
app/Admin/Controllers/BaseConfigController.php

xqd
@@ -0,0 +1,90 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Models\SystemConfig;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class BaseConfigController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new SystemConfig);
+
+        $grid->column('id')->sortable();
+        $grid->column('group')->editable();
+        $grid->column('key')->editable();
+        $grid->column('value')->copyable()->width(150);
+        $grid->column('chinese')->editable();
+        $grid->column('fieldType')->select(SystemConfig::getType());
+        $grid->column('comment')->editable()->width(150);
+        $grid->column('updated_at')->sortable();
+        $grid->quickSearch(function ($model, $query) {
+            $model->where('group', 'like', "%{$query}%")
+                ->orWhere('key', 'like', "%{$query}%")
+                ->orWhere('value', 'like', "%{$query}%");
+        });
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed   $id
+     * @return \Encore\Admin\Show
+     */
+    protected function detail($id)
+    {
+        $show = new Show(SystemConfig::findOrFail($id));
+
+        $show->field('id');
+        $show->field('group');
+        $show->field('key');
+        $show->field('value');
+        $show->field('fieldType')->using(SystemConfig::getType());
+        $show->field('chinese');
+        $show->field('comment');
+        $show->field('created_at');
+        $show->field('updated_at');
+
+        return $show;
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return \Encore\Admin\Form
+     */
+    protected function form()
+    {
+        $form = new Form(new SystemConfig);
+        $form->display('id');
+        $form->text('group');
+        $form->text('key');
+        $form->text('chinese');
+        $form->select('fieldType')->options(SystemConfig::getType());
+        $form->text('comment');
+        $form->textarea('value');
+        $form->display('created_at');
+        $form->display('updated_at');
+
+        $form->footer(function ($footer) {
+            // 去掉`查看`checkbox
+            $footer->disableViewCheck();
+            // 去掉`继续编辑`checkbox
+            $footer->disableEditingCheck();
+            // 去掉`继续创建`checkbox
+            $footer->disableCreatingCheck();
+        });
+
+        return $form;
+    }
+}

+ 107 - 0
app/Admin/Controllers/ChatTeamController.php

xqd
@@ -0,0 +1,107 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Chat\TeamChatAction;
+use App\Admin\Actions\Chat\TeamUser;
+use App\Admin\Actions\Users\FollowList;
+use App\Admin\Actions\Users\UserAuth;
+use App\Admin\Actions\Users\UserChange;
+use App\Models\ChatTeam;
+use App\Models\User;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Widgets\Modal;
+
+class ChatTeamController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new ChatTeam());
+        $grid->model()->with('user.id,name,avatar')->orderByDesc('id');
+
+        $grid->column('id')->sortable();
+        $grid->column('user.name');
+        $grid->column('user.avatar')->image('', 50);
+        $grid->column('group_name');
+        $grid->column('GroupId');
+        $grid->column('FaceUrl')->image('', 50);
+        $grid->column('MemberCount')->display(function ($res) {
+            $form = TeamUser::make()->payload(['GroupId' => $this->GroupId]);
+            return Modal::make()
+                ->lg()
+                ->title(trans('chat-team.fields.group_members'))
+                ->body($form)
+                ->button('<i class="feather icon-align-right"></i> ' . $res);
+        });
+        $grid->column('updated_at')->sortable();
+        $grid->disableRowSelector();
+        $grid->disableCreateButton();
+        //操作管理
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->disableEdit();
+            $actions->append(new TeamChatAction($this->GroupId));
+        });
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new ChatTeam(), function (Show $show) {
+            $show->field('id');
+            $show->field('user_id');
+            $show->field('Owner_Account');
+            $show->field('group_name');
+            $show->field('GroupId');
+            $show->field('FaceUrl');
+            $show->field('MaxMemberCount');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new ChatTeam(), function (Form $form) {
+            $form->display('id');
+            $form->text('user_id');
+            $form->text('Owner_Account');
+            $form->text('group_name');
+            $form->text('GroupId');
+            $form->text('FaceUrl');
+            $form->text('MaxMemberCount');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 95 - 0
app/Admin/Controllers/CourseController.php

xqd
@@ -0,0 +1,95 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Course\CourseField;
+use App\Admin\Actions\Course\CourseHoles;
+use App\Admin\Metrics\Course\TotalCourse;
+use App\Models\Course;
+use App\Models\CourseField as CourseFieldModel;
+use Dcat\Admin\Form;
+use Dcat\Admin\Form\NestedForm;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Layout\Row;
+
+class CourseController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new Course());
+        $grid->model()->orderByDesc('id');
+        $grid->column('id')->sortable();
+        $grid->column('img')->image('', 50);
+        $grid->column('name');
+        $grid->column('course_field', '场地数')->display(function (){
+            $fieldCount = CourseFieldModel::where('course_id', $this->id)->count();
+            $url  = admin_url('/course_field?course_id='.$this->id.'');
+            $html = $fieldCount.'<a href="'.$url.'"> 查看</a>';
+            return $html;
+        });
+        $grid->column('photos')->display(function ($photos) {
+            return json_decode($photos, true);
+        })->image('', 60, 60);
+        $grid->column('address');
+        $grid->column('contacts_phone');
+        $grid->column('style');
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->panel();
+            $filter->equal('id')->width(4);
+            $filter->equal('course_id')->width(4);
+        });
+        $grid->disableViewButton();
+        return $grid;
+    }
+
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(Course::with('course_fileds'), function (Form $form) {
+
+//            $form->tab('球场', function (Form $form) {
+                $form->column(5, function (Form $form) {
+                    $form->width(10, 2);
+                    $form->display('id');
+                    $form->text('name')->required();
+                    $form->image('img')->removable(true)->uniqueName()->saveFullUrl()->autoUpload()->required();
+                    $form->map('lat', 'lng', trans('course.fields.address'))->required();
+                });
+                $form->column(7, function (Form $form) {
+                    $form->width(10, 2);
+                    $form->text('contacts_phone');
+                    $form->time('open_time')->format('HH:mm')->default('09:00', true);
+                    $form->time('close_time')->format('HH:mm')->default('18:00', true);
+                    $form->text('style');
+                    $form->textarea('service');
+                    $form->number('square');
+                    $form->number('length');
+                    $form->multipleImage('photos')->saveFullUrl()->autoUpload()->uniqueName()->saveAsJson();
+                });
+
+            $form->disableViewButton();
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+
+    }
+
+}

+ 191 - 0
app/Admin/Controllers/CourseFieldController.php

xqd
@@ -0,0 +1,191 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Models\Course;
+use App\Models\CourseField;
+use App\Models\CourseHole;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Illuminate\Support\Facades\Cache;
+
+class CourseFieldController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(CourseField::with('course'), function (Grid $grid) {
+            $course_id = request()->input('course_id');
+            Cache::put('course_id', $course_id); //设置缓存,添加场地是可用
+            $grid->model()->where('course_id', '=', $course_id);
+            $grid->model()->orderByDesc('id');
+            $grid->column('id')->sortable();
+            $grid->column('course_id')->display(function () {
+                $str = "";
+                $str .= "<div style='margin-right:10px;display: flex;align-items: center'>";
+                $str .= '<img data-action="preview-img" src="' . $this->course->img . '" style="height:50px;width:50px;cursor:pointer;margin-right:10px;" class="img img-thumbnail">';
+                $str .= '<p style="margin-bottom: 5px">' . $this->course->name . '</p>';
+                $str .= "</div>";
+                return $str;
+            });
+            $grid->column('name');
+            $grid->column('hole_list')->display(function ($res) {
+                $res = json_decode($res, true);
+                //总标杆
+                $par_total = 0;
+                foreach ($res as $key => $val) {
+                    $par_total += $val['par'];
+                }
+                //前九标杆
+                $bf9_par_total = 0;
+                foreach ($res as $key => $val) {
+                    if ($val['sort'] <= 9) {
+                        $bf9_par_total += $val['par'];
+                    }
+                }
+                //球洞
+                $hole_con = '';
+                foreach ($res as $key => $val) {
+                    $hole_con .= "<td>" . ($key + 1) . "</td>";
+                    if ($val['sort'] == 9) {
+                        $hole_con .= "<td>" . trans('game-user.fields.before9') . "</td>";
+                    }
+                }
+                //难度
+                $diff_con = '';
+                foreach ($res as $key => $val) {
+                    $diff_con .= "<td>" . $val['difficulty'] . "</td>";
+                    if ($val['sort'] == 9) {
+                        $diff_con .= "<td>" . '#' . "</td>";
+                    }
+                }
+                //标杆
+                $par_con = '';
+                foreach ($res as $key => $val) {
+                    $par_con .= "<td>" . $val['par'] . "</td>";
+                    if ($val['sort'] == 9) {
+                        $par_con .= "<td>" . $bf9_par_total . "</td>";
+                    }
+                }
+                $str = "<style>
+                        .scores_table td{
+                            border: 1px solid #ccc!important;
+                            width: 40px;
+                        }
+                    </style>
+                    <table class='scores_table' style='text-align: center'>
+                        <tr>
+                            <td>" . trans('game-user.fields.hole') . "</td>
+                            " . $hole_con . "
+                        </tr>
+                        <tr>
+                            <td>" . trans('game-user.fields.difficulty') . "</td>
+                            " . $diff_con . "
+                        </tr>
+                        <tr>
+                            <td>" . trans('game-user.fields.par') . "</td>
+                            " . $par_con . "
+                        </tr>
+                       
+                    </table>";
+
+                return $str;
+            });
+
+            $grid->disableViewButton();
+
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new CourseField(), function (Form $form) {
+
+            $courseId = Cache::get('course_id');
+            $course = Course::find($courseId);
+
+            $form->column(9, function (Form $form)use ($course) {
+                $form->html(function () use ($course) {
+                    $str = "";
+                    $str .= "<div style='display: flex;align-items: center'>";
+                    $str .= '<img data-action="preview-img" src="' . $course->img . '" style="height:50px;width:50px;cursor:pointer;margin-right:10px;" class="img img-thumbnail">';
+                    $str .= '<div>';
+                    $str .= '<p style="margin-bottom: 5px">球场名:' . $course->name . '</p>';
+                    $str .= "</div>";
+                    $str .= "</div>";
+                    return $str;
+                });
+                $form->text('name')->width(4);
+                $form->table('hole_list', function (Form\NestedForm $table) {
+                    $table->text('sort', trans('course.labels.sort'))->width(12, 0);
+                    $table->text('par', trans('course.labels.par'));
+                    $table->text('difficulty', trans('course.labels.difficulty'));
+                    $table->text('gold_dis', trans('course.labels.gold_dis'));
+                    $table->text('blue_dis', trans('course.labels.blue_dis'));
+                    $table->text('white_dis', trans('course.labels.white_dis'));
+                    $table->text('red_dis', trans('course.labels.red_dis'));
+                })->label(trans('course.labels.hole_list'))->width(12, 0);
+            });
+
+            $form->saving(function (Form $form) {
+                if (is_array($form->hole_list)) {
+                    $this->hole_list = array_values($form->hole_list);
+                    $form->deleteInput('hole_list');
+                }
+            });
+
+            $form->saved(function (Form $form) {
+                $id = $form->getKey();
+                if (!empty($this->hole_list) && is_array($this->hole_list)) {
+                    foreach ($this->hole_list as $val) {
+                        unset($val['id']);
+                        unset($val['_remove_']);
+                        $val['course_field_id'] = $id;
+                        $map = ['course_field_id' => $id, 'sort' => $val['sort']];
+                        if ($info = CourseHole::query()->where($map)->first()) {
+                            CourseHole::query()->where($map)->update($val);
+                        } else {
+                            CourseHole::query()->create($val);
+                        }
+                    }
+                    $list = CourseHole::query()
+                        ->where('course_field_id', $id)
+                        ->select('sort', 'par', 'difficulty', 'gold_dis', 'blue_dis', 'white_dis', 'red_dis')
+                        ->orderBy('sort', 'asc')
+                        ->get()
+                        ->toArray();
+                    $courseField = CourseField::find($id);
+                    $courseField->hole_list = json_encode($list);
+                    $courseField->save();
+                }
+                return $form->response()->success('保存成功')->redirect('course_field/'.$form->model()->id.'/edit');
+            });
+
+            $form->disableViewButton();
+            $form->disableListButton();
+            $form->tools(function (Form\Tools $tools) {
+                $tools->append('<a class="btn btn-sm btn-primary" onClick="javascript :history.back(-1);"  style="color:#ffffff;margin-right:10px">返回</a>');
+            });
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 86 - 0
app/Admin/Controllers/CourseHoleController.php

xqd
@@ -0,0 +1,86 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Models\CourseHole;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class CourseHoleController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new CourseHole(), function (Grid $grid) {
+            $grid->column('id')->sortable();
+            $grid->column('sort');
+            $grid->column('course_id');
+            $grid->column('par');
+            $grid->column('difficulty');
+            $grid->column('gold_dis');
+            $grid->column('blue_dis');
+            $grid->column('white_dis');
+            $grid->column('red_dis');
+            $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 CourseHole(), function (Show $show) {
+            $show->field('id');
+            $show->field('sort');
+            $show->field('course_id');
+            $show->field('par');
+            $show->field('difficulty');
+            $show->field('gold_dis');
+            $show->field('blue_dis');
+            $show->field('white_dis');
+            $show->field('red_dis');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new CourseHole(), function (Form $form) {
+            $form->display('id');
+            $form->text('sort');
+            $form->text('course_id');
+            $form->text('par');
+            $form->text('difficulty');
+            $form->text('gold_dis');
+            $form->text('blue_dis');
+            $form->text('white_dis');
+            $form->text('red_dis');
+        
+            $form->display('created_at');
+            $form->display('updated_at');
+        });
+    }
+}

+ 116 - 0
app/Admin/Controllers/CourseUserController.php

xqd
@@ -0,0 +1,116 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Users\UserCourse;
+use App\Models\CourseUser;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Show;
+
+class CourseUserController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new CourseUser());
+        $grid->model()->with(['user:id,name,avatar','course:id,name'])->orderByDesc('id');
+
+        $grid->column('id')->sortable();
+        $grid->column('course.name',trans('course-user.fields.course_id'));
+        $grid->column('user_id')->display(function (){
+            if($this->user){
+                $str = "";
+                $str.="<div style='margin-right:10px;display: flex;align-items: center'>";
+                $str.='<img data-action="preview-img" src="'.$this->user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer;margin-right:5px;" class="img img-thumbnail">';
+                $str.='<div>';
+                $str.='<p style="margin-bottom: 2px">ID:'.$this->user->id.'</p>';
+                $str.='<p>'.trans('user.fields.name').':'.$this->user->name.'</p>';
+                $str.="</div>";
+                $str.="</div>";
+                return $str;
+            }else{
+                return '';
+            }
+
+        });
+        $grid->column('type')->using([1=>trans('course-user.fields.home'),2=>trans('course-user.fields.vice')])->label(['','green','blue']);
+        $grid->column('member_name');
+        $grid->column('member_no');
+        $grid->column('whs');
+        $grid->column('status')->using([0=>trans('course-user.fields.check_pending'),1=>trans('course-user.fields.pass'),2=>trans('course-user.fields.refuse')])->label(['yellow','green','danger']);
+        $grid->column('created_at');
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+
+        });
+
+        //操作管理
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->disableEdit();
+            if ($actions->row->status == 0) {
+                $actions->append(new UserCourse());
+            }
+        });
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new CourseUser(), function (Show $show) {
+            $show->field('id');
+            $show->field('course_id');
+            $show->field('user_id');
+            $show->field('type');
+            $show->field('member_name');
+            $show->field('member_no');
+            $show->field('whs');
+            $show->field('status');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new CourseUser(), function (Form $form) {
+            $form->display('id');
+            $form->text('course_id');
+            $form->text('user_id');
+            $form->text('type');
+            $form->text('member_name');
+            $form->text('member_no');
+            $form->text('whs');
+            $form->text('status');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 82 - 0
app/Admin/Controllers/DocumentController.php

xqd
@@ -0,0 +1,82 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Models\Document;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class DocumentController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new Document(), function (Grid $grid) {
+            $grid->column('id')->sortable();
+            $grid->column('title');
+            $grid->column('en_title');
+            $grid->column('content')->limit(50);
+            $grid->column('en_content')->limit(50);
+//            $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 Document(), function (Show $show) {
+            $show->field('id');
+            $show->field('title');
+            $show->field('en_title');
+            $show->field('content')->unescape();
+            $show->field('en_content')->unescape();
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new Document(), function (Form $form) {
+            $form->display('id');
+            $form->text('title');
+            $form->text('en_title');
+            $form->editor('content');
+            $form->editor('en_content');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 199 - 0
app/Admin/Controllers/FeedsController.php

xqd
@@ -0,0 +1,199 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Feeds\FeedAction;
+use App\Admin\Actions\Feeds\ForwardAction;
+use App\Admin\Actions\Feeds\LikeAction;
+use App\Admin\Actions\Games\GameMembers;
+use App\Admin\Actions\Games\GameUserScores;
+use App\Models\Feed;
+use App\Models\Team;
+use App\Models\User;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Show;
+use Dcat\Admin\Widgets\Modal;
+
+class FeedsController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new Feed());
+        $grid->model()->with(['user:id,name,avatar'])->orderByDesc('id');
+        $grid->column('id')->sortable();
+//        $grid->column('user.avatar','头像')->image("",50);;
+        $grid->column('user_id')->display(function (){
+            if($this->user){
+                $str = "";
+                $str.="<div style='margin-right:10px;display: flex;align-items: center'>";
+                $str.='<img data-action="preview-img" src="'.$this->user->avatar.'" style="max-width:50px;max-height:50px;cursor:pointer;margin-right:5px;" class="img img-thumbnail">';
+                $str.='<div>';
+                $str.='<p style="margin-bottom: 2px">ID:'.$this->user->id.'</p>';
+                $str.='<p>'.trans('feeds.fields.nickname').':'.$this->user->name.'</p>';
+                $str.="</div>";
+                $str.="</div>";
+                return $str;
+            }else{
+                return '';
+            }
+
+        });
+        $grid->column('team_id')->display(function ($res){
+            if($res>0){
+                $team = Team::query()->find($res);
+                if($team){
+                    return '<span class="label" style="background:#586cb1">'.trans('feeds.fields.team').'</span>
+                        <br>
+                        <br>
+                        <span class="label" style="background:#586cb1">'.$team->name.'</span>';
+                }else{
+                    return "";
+                }
+
+            }else{
+                return '<span class="label" style="background:#21b978">'.trans('feeds.fields.personal').'</span>';
+            }
+        });
+        $grid->column('forward_id')->display(function ($res){
+            if($res>0){
+                return '<span class="label" style="background:#586cb1">'.trans('feeds.fields.forward').' ID:'.$res.'</span>';
+            }else{
+                return '<span class="label" style="background:#21b978">'.trans('feeds.fields.original').'</span>';
+            }
+        });
+        $grid->column('content')->limit(30);
+        $grid->column('file_url')->display(function ($v){
+            if(isset($v)&&!empty($v)){
+                $v = json_decode($v,true);
+                $str = '';
+                if(!empty($v)&&count($v)>0){
+                    foreach ($v as $item){
+                        $str.='<img data-action="preview-img" src="'.$item.'" style="max-width:50px;max-height:200px;cursor:pointer" class="img img-thumbnail">';
+                    }
+                }
+                return $str;
+            }else{
+                return "";
+            }
+        });
+        $grid->column('status')->switch();
+        $grid->column('like_num');
+        $grid->column('forward_num');
+        $grid->column('address_info');
+
+        $grid->column('match_title')->display(function ($res){
+            //dd($this->game_per_id);
+            $game_per_id = isset($this->game_per_id)&&!empty($this->game_per_id)?$this->game_per_id:'###';
+            if(!empty($res)) {
+                return '<a href="/admin/game_user_scores?id='.$game_per_id.'" target="_self"><span class="label" style="background:#21b978;line-height: 40px;">' . $res . '</span>
+                        <br><i class="feather icon-bar-chart-2"></i> '.trans('feeds.fields.scorecard').'</a>';
+            }else{
+                return '';
+            }
+        });
+
+        $grid->column('created_at');
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('user.name');
+            $team = Team::query()->select(['id','name'])->get()->toArray();
+            $team_arr[0] = trans('feeds.fields.personal');
+            foreach ($team as $v){
+                $team_arr[$v['id']] = $v['name'];
+            }
+            $filter->equal('team_id')->select($team_arr);
+
+            $filter->like('content');
+
+        });
+
+        //批量操作
+//        $grid->batchActions(function (Grid\Tools\BatchActions $batch) {
+//            $batch->disableDelete();
+//        });
+        //操作管理
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->disableEdit();
+
+            $actions->append(new FeedAction());
+            $actions->append(new LikeAction());
+            $actions->append(new ForwardAction());
+        });
+
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new Feed(), function (Show $show) {
+            $show->field('id');
+            $show->field('user_id');
+            $show->field('content');
+            $show->field('file_url');
+            $show->field('status');
+            $show->field('like_num');
+            $show->field('address_info');
+            $show->field('match_title');
+            $show->field('game_per_id');
+            $show->field('is_delete');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new Feed(), function (Form $form) {
+            $form->display('id');
+
+            $user = User::query()->select(['id','name'])->get()->toArray();
+            $user_arr = array();
+            foreach ($user as $v){
+                $user_arr[$v['id']] = $v['name'];
+            }
+            $form->select('user_id')->options($user_arr);
+            $form->textarea('content');
+            $form->text('file_url');
+            $form->switch('status')->default(1);
+            $form->number('like_num')->default(0);
+            $form->text('address_info');
+            $form->text('match_title');
+            $form->text('game_per_id');
+            $form->text('is_delete');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+
+        });
+    }
+}

+ 73 - 0
app/Admin/Controllers/GameTypeController.php

xqd
@@ -0,0 +1,73 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Models\GameType;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class GameTypeController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new GameType(), function (Grid $grid) {
+            $grid->column('id')->sortable();
+            $grid->column('name');
+            $grid->column('rule');
+            $grid->column('scale');
+        
+            $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 GameType(), function (Show $show) {
+            $show->field('id');
+            $show->field('name');
+            $show->field('rule');
+            $show->field('scale');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new GameType(), function (Form $form) {
+            $form->display('id');
+            $form->text('name');
+            $form->text('rule');
+            $form->text('scale');
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 209 - 0
app/Admin/Controllers/GameUserController.php

xqd
@@ -0,0 +1,209 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Course\CourseHoles;
+use App\Models\Game;
+use App\Models\GameType;
+use App\Models\GameUser;
+use App\Models\GameUserScore;
+use App\Models\User;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Illuminate\Support\Facades\Log;
+
+class GameUserController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new GameUser());
+        $grid->model()->orderByDesc('id');
+
+        $grid->disableCreateButton();
+        $grid->disableRowSelector();
+        $grid->disableActions();
+
+        $grid->column('id')->sortable();
+        $grid->column('game_id')->display(function ($game_id) {
+            $game = Game::query()->find($game_id);
+            if ($game) {
+                return '<span class="label" style="background:#21b978;line-height: 40px;">' . $game->name . '</span>';
+            } else {
+                return "";
+            }
+        });
+        $grid->column('user_id')->display(function ($user_id) {
+            $user = User::query()->find($user_id);
+            $str = "";
+            if ($user) {
+                $str .= "<div style='margin-right:10px;display: flex;align-items: center'>";
+                $str .= '<img data-action="preview-img" src="' . $user->avatar . '" style="max-width:50px;max-height:50px;cursor:pointer;margin-right:5px;" class="img img-thumbnail">';
+                $str .= '<div>';
+                $str .= '<p style="margin-bottom: 2px">ID:' . $user->id . '</p>';
+                $str .= '<p>' . trans('user.fields.name') . ':' . $user->name . '</p>';
+                $str .= "</div>";
+                $str .= "</div>";
+            }
+            return $str;
+        });
+
+        $grid->column('level')->using([
+                1 => trans('game-user.fields.red'),
+                2 => trans('game-user.fields.white'),
+                3 => trans('game-user.fields.blue'),
+                4 => trans('game-user.fields.gold')])
+            ->label(['gray', 'red', 'white', 'blue', 'gold']);
+
+        $grid->column('type')->using([
+                1 => trans('game-user.fields.normal'),
+                2 => trans('game-user.fields.fictitious')])
+            ->label(['gray', 'green']);
+
+        $grid->column('scores')->display(function ($res) {
+
+            $game_user_score = (new GameUserScore())->setTable('gu')->from('game_user_scores as gu')
+                ->where('gu.game_user_id', $this->id)
+                ->leftJoin('course_holes as ch', 'ch.id', '=', 'gu.hole_id')
+                ->select('gu.score', 'ch.sort', 'ch.par', 'ch.course_id')
+                ->orderBy('sort', 'asc')
+                ->get()
+                ->toArray();
+
+            //总标杆
+            $par_total = 0;
+            foreach ($game_user_score as $key => $val) {
+                $par_total += $val['par'];
+            }
+            //总成绩
+            $game_user_score_total = GameUserScore::where('game_user_id', $this->id)->sum('score');
+            //前九标杆
+            $bf9_par_total = 0;
+            foreach ($game_user_score as $key => $val) {
+                if($val['sort'] <= 9){
+                    $bf9_par_total += $val['par'];
+                }
+            }
+            //前九成绩
+            $bf9_score = 0;
+            foreach ($game_user_score as $key => $val) {
+                if($val['sort'] <= 9){
+                    $bf9_score += $val['score'];
+                }
+            }
+            //球洞
+            $hole_con = '';
+            foreach ($game_user_score as $key => $val) {
+                $hole_con .= "<td>" . ($key + 1) . "</td>";
+                if($val['sort'] == 9){
+                    $hole_con .= "<td>" . trans('game-user.fields.before9') . "</td>";
+                }
+            }
+            //标杆
+            $par_con = '';
+            foreach ($game_user_score as $key => $val) {
+                $par_con .= "<td>" . $val['par'] . "</td>";
+                if($val['sort'] == 9){
+                    $par_con .= "<td>" . $bf9_par_total . "</td>";
+                }
+            }
+            //成绩
+            $score_con = '';
+            foreach ($game_user_score as $key => $val) {
+                $score_con .= "<td>" . $val['score'] . "</td>";
+                if($val['sort'] == 9){
+                    $score_con .= "<td>" . $bf9_score . "</td>";
+                }
+            }
+            $str = "<style>
+                        .scores_table td{
+                            border: 1px solid #ccc!important;
+                            width: 40px;
+                        }
+                    </style>
+                    <table class='scores_table' style='text-align: center'>
+                        <tr>
+                            <td>" . trans('game-user.fields.hole') . "</td>
+                            " . $hole_con . "
+                            <td>" . trans('game-user.fields.Total_rod') . "</td>
+                        </tr>
+                        <tr>
+                            <td>" . trans('game-user.fields.par') . "</td>
+                            " . $par_con . "
+                            <td>" . $par_total . "</td>
+                        </tr>
+                        <tr>
+                            <td>" . trans('game-user.fields.rod') . "</td>
+                            " . $score_con . "
+                            <td>" . $game_user_score_total . "</td>
+                        </tr>
+                    </table>";
+
+            return $str;
+        });
+
+
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $game_type = Game::query()->get();
+            $game_type_arr = array();
+            foreach ($game_type as $v) {
+                $game_type_arr[$v['id']] = $v['name'];
+            }
+            $filter->equal('game_id')->select($game_type_arr);
+            $user = User::query()->where('status', 1)->get()->toArray();
+            $user_arr = array();
+            foreach ($user as $v) {
+                $user_arr[$v['id']] = $v['name'];
+            }
+            $filter->equal('user_id')->select($user_arr);
+            $filter->equal('type')->select([1 => trans('game-user.fields.normal'), 2 => trans('game-user.fields.fictitious')]);
+        });
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new GameUser(), function (Show $show) {
+            $show->field('id');
+            $show->field('game_id');
+            $show->field('user_id');
+            $show->field('level');
+            $show->field('type');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new GameUser(), function (Form $form) {
+            $form->display('id');
+            $form->text('game_id');
+            $form->text('user_id');
+            $form->text('level');
+            $form->text('type');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+        });
+    }
+}

+ 223 - 0
app/Admin/Controllers/GamesController.php

xqd
@@ -0,0 +1,223 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Games\GameLookers;
+use App\Admin\Actions\Games\GameMembers;
+use App\Admin\Actions\Games\GameScores;
+use App\Admin\Actions\Teams\TeamFeeds;
+use App\Admin\Actions\Teams\TeamPhotos;
+use App\Models\ChatTeam;
+use App\Models\Course;
+use App\Models\Game;
+use App\Models\GameType;
+use App\Models\GameUser;
+use App\Models\User;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Show;
+use Dcat\Admin\Widgets\Modal;
+use App\Services\TencentImGroupService;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class GamesController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new Game());
+        $grid->model()->with(['game_types', 'creator_s:id,name,avatar', 'course:id,name'])->orderByDesc('id');
+
+        $grid->column('id')->sortable();
+        $grid->column('img')->image('', 50);
+        $grid->column('name');
+        $grid->column('creator')->display(function ($res) {
+            if($this->creator_s){
+                $str = "";
+                $str .= "<div style='margin-right:10px;display: flex;align-items: center'>";
+                $str .= '<img data-action="preview-img" src="' . $this->creator_s->avatar . '" style="max-height:50px;cursor:pointer;margin-right:5px;" class="img img-thumbnail">';
+                $str .= '<div>';
+                $str .= '<p style="margin-bottom: 2px">ID:' . $this->creator_s->id . '</p>';
+                $str .= '<p>' . trans('user.fields.name') . ':' . $this->creator_s->name . '</p>';
+                $str .= "</div>";
+                $str .= "</div>";
+                return $str;
+            }
+        });
+        $grid->column('game_types.name', trans('games.fields.game_type_id'));
+        $grid->column('scale');
+        $grid->column('members')->display(function ($res) {
+            $form = GameMembers::make()->payload(['id' => $this->id]);
+            return Modal::make()
+                ->lg()
+                ->title(trans('games.fields.Players'))
+                ->body($form)
+                ->button('<i class="feather icon-align-right"></i> ' . $res);
+        });
+        $grid->column('course.name', trans('games.fields.course_id'));
+        $grid->column('forbid_look')->switch();
+        $grid->column('forbid_join')->switch();
+        $grid->column('lookers');
+        $grid->column('begin_time')->display(function ($res) {
+            return date('m-d H:i', strtotime($res));
+        });
+        $grid->column('end_time')->display(function ($res) {
+            if(!empty($res)){
+                return date('m-d H:i', strtotime($res));
+            }else{
+                return '';
+            }
+
+        });
+        $grid->column('created_at')->display(function ($res) {
+            return date('Y-m-d H:i', strtotime($res));
+        });
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('name');
+            $game_type = GameType::query()->get();
+            $game_type_arr = array();
+            foreach ($game_type as $v) {
+                $game_type_arr[$v['id']] = $v['name'];
+            }
+            $filter->equal('game_type_id')->select($game_type_arr);
+            $course = Course::query()->get();
+            $course_arr = array();
+            foreach ($course as $v) {
+                $course_arr[$v['id']] = $v['name'];
+            }
+            $filter->equal('course_id')->select($course_arr);
+        });
+
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->append(new GameScores('game'));
+        });
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new Game(), function (Show $show) {
+            $show->field('id');
+            $show->field('name');
+            $show->field('begin_time');
+            $show->field('end_time');
+            $show->field('scale');
+            $show->field('game_type_id');
+            $show->field('creator');
+            $show->field('forbid_look');
+            $show->field('forbid_join');
+            $show->field('img')->image('', 200);
+            $show->field('lookers');
+            $show->field('members');
+            $show->field('course_id');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new Game(), function (Form $form) {
+            $form->display('id');
+            $form->text('name')->required();
+            $form->datetime('begin_time')->required();
+            $form->number('scale')
+                ->attribute('min', 2)
+                ->attribute('max', 50)
+                ->required();
+            $game_types = GameType::query()->get()->toArray();
+            $types = array();
+            foreach ($game_types as $key => $val) {
+                $types[$val['id']] = $val['name'] . '(' . $val['scale'] . ')';
+            }
+            $form->select('game_type_id')->options($types);
+
+            $form->switch('forbid_look')->default(0);
+            $form->switch('forbid_join')->default(0);
+            $form->image('img')->saveFullUrl()->autoUpload();
+            $form->number('lookers')
+                ->attribute('min', 0);
+            $form->number('members')
+                ->attribute('min', 0)->default(10);
+            $course = Course::query()->get();
+            $course_arr = array();
+            foreach ($course as $v) {
+                $course_arr[$v['id']] = $v['name'];
+            }
+            $form->select('course_id')->options($course_arr)->required();
+
+            if($form->isCreating()){
+                $users = User::query()->where('status', 1)->get();
+                $users_arr = array();
+                foreach ($users as $v) {
+                    $users_arr[$v['id']] = $v['name'];
+                }
+                $form->select('creator')->options($users_arr);
+
+                $form->saved(function (Form $form) {
+                    $gameId = $form->getKey();
+                    $gameUser = new GameUser();
+                    $gameUser->game_id = $gameId;
+                    $gameUser->user_id = $form->creator;
+                    $gameUser->level = 4;
+                    $gameUser->type = 1;
+                    $gameUser->status = 1;
+                    $gameUser->save();
+
+                    //创建群聊
+                    $user = User::query()->where('id', $form->creator)->first();
+                    $groupService = new TencentImGroupService();
+                    $data = array();
+                    $data['member_list'] [] = $user;
+                    $data['Owner_Account'] = $user->tencent_im_user_id;
+                    $data['group_name'] = $form->name;
+                    $data['avatar'] = $form->img;
+                    $groupResult = $groupService->createGroup($data);
+                    Log::info($user);
+                    Log::info($groupResult);
+                    if ($groupResult['ActionStatus'] == 'OK' && $groupResult['ErrorCode'] == 0) {
+                        DB::table('games')->where('id', $gameId)->update(['GroupId'=>$groupResult['GroupId']]);
+                    }
+                    $chatTeam = new ChatTeam();
+                    $chatTeam->user_id = $user->id;
+                    $chatTeam->Owner_Account = $user->tencent_im_user_id;
+                    $chatTeam->group_name = $form->name;
+                    $chatTeam->GroupId = $groupResult['GroupId'];
+                    $chatTeam->FaceUrl = $form->img;
+                    $chatTeam->MaxMemberCount = 20;
+                    $chatTeam->ApplyJoinOption = 'FreeAccess';
+                    $chatTeam->save();
+                });
+            }
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 40 - 0
app/Admin/Controllers/HomeController.php

xqd
@@ -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;
+
+class HomeController extends Controller
+{
+    public function index(Content $content)
+    {
+        return $content
+            ->header(trans('admin-home.Data_panel'))
+            ->description('')
+            ->body(function (Row $row) {
+                $row->column(6, function (Column $column) {
+                    $column->row(new Examples\NewUsers());
+                    $column->row(new Examples\Games());
+                });
+                $row->column(6, function (Column $column) {
+                    $column->row(function (Row $row) {
+                        $row->column(6, new Examples\TotalGames());
+                        $row->column(6, new Examples\TotalUsers());
+                    });
+                    $column->row(function (Row $row) {
+                        $row->column(6, new Examples\TotalTeam());
+                        $row->column(6, new Examples\TotalCourse());
+                    });
+                    $column->row(function (Row $row) {
+                        $row->column(6, new Examples\Report());
+                        $row->column(6, new Examples\Feedback());
+                    });
+                });
+            });
+    }
+}

+ 88 - 0
app/Admin/Controllers/SystemAvatarController.php

xqd
@@ -0,0 +1,88 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Models\SystemAvatar;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Illuminate\Support\Facades\Redis;
+
+class SystemAvatarController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new SystemAvatar(), function (Grid $grid) {
+            $grid->model()->orderByDesc('id');
+            $grid->column('id')->sortable();
+            $grid->column('img')->image('',80);
+            $grid->column('sex')->using([
+                0 => trans('user.fields.unknown'),
+                1 => trans('user.fields.man'),
+                2 => trans('user.fields.woman')
+            ])->label([
+                'gray',
+                'primary',
+                'danger'
+            ]);
+            $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 SystemAvatar(), function (Show $show) {
+            $show->field('id');
+            $show->field('img')->image('',100);
+            $show->select('sex')->options([
+                1 => trans('user.fields.man'),
+                2 => trans('user.fields.woman')
+            ]);
+            $show->field('updated_at');
+            $show->field('created_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new SystemAvatar(), function (Form $form) {
+            $form->display('id');
+            $form->image('img')->autoUpload()->uniqueName()->saveFullUrl();
+            $form->select('sex')->options([
+                1 => trans('user.fields.man'),
+                2 => trans('user.fields.woman')
+            ]);
+            $form->saved(function(Form $form){
+                Redis::del('system_avatar');
+            });
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 163 - 0
app/Admin/Controllers/TeamController.php

xqd
@@ -0,0 +1,163 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Teams\TeamFeeds;
+use App\Admin\Actions\Teams\TeamPhotos;
+use App\Admin\Actions\Teams\TeamUsers;
+use App\Models\ChatTeam;
+use App\Models\Team;
+use App\Models\TeamUser;
+use App\Models\User;
+use App\Services\TencentImGroupService;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Widgets\Modal;
+use Illuminate\Support\Facades\DB;
+
+class TeamController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new Team());
+        $grid->model()->with(['creator_s:id,name,avatar'])->orderByDesc('id');
+        $grid->column('id')->sortable();
+        $grid->column('img')->image('', 50);
+        $grid->column('name');
+//        $grid->column('creator');
+        $grid->column('creator_s.name', trans('team.fields.creator'));
+        $grid->column('address');
+        $grid->column('member_counts')->display(function ($res) {
+            $form = TeamUsers::make()->payload(['id' => $this->id]);
+            return Modal::make()
+                ->lg()
+                ->title(trans('team.fields.Member_list'))
+                ->body($form)
+                ->button('<i class="feather icon-align-right"></i> ' . $res);
+
+        });
+        $grid->column('slogan');
+        $grid->column('desc');
+
+        $grid->column('allow_join')->switch('success', true);
+        $grid->column('set_date');
+//        $grid->column('created_at');
+//        $grid->column('updated_at')->sortable();
+
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('name');
+        });
+
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->append(new TeamFeeds(User::class));
+            $actions->append(new TeamPhotos(User::class));
+            $actions->disableView();
+        });
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new Team(), function (Show $show) {
+            $show->field('id');
+            $show->field('name');
+            $show->field('img');
+            $show->field('address');
+            $show->field('member_counts');
+            $show->field('slogan');
+            $show->field('desc');
+            $show->field('creator');
+            $show->field('allow_join');
+            $show->field('set_date');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new Team(), function (Form $form) {
+            $form->display('id');
+            $form->text('name')->required();
+            $form->image('img')->saveFullUrl()->autoUpload();
+            $form->text('address')->default('');
+            $form->text('member_counts')->default(10);
+            $form->text('slogan')->default('');
+            $form->text('desc')->default('');
+
+            $users = User::query()->where('status', 1)->whereNull('deleted_at')->get();
+            $users_arr = array();
+            foreach ($users as $v) {
+                $users_arr[$v['id']] = $v['name'];
+            }
+            $form->select('creator')->options($users_arr);
+            $form->switch('allow_join');
+            $form->date('set_date');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+
+            $form->saved(function (Form $form) {
+                if ($form->isCreating()) {
+                    $teamId = $form->getKey();
+                    $teamUser = new TeamUser();
+                    $teamUser->team_id = $teamId;
+                    $teamUser->user_id = $form->creator;
+                    $teamUser->save();
+
+                    //创建群聊
+                    $user = User::query()->where('id', $form->creator)->first();
+                    $groupService = new TencentImGroupService();
+                    $data = array();
+                    $data['member_list'] [] = $user;
+                    $data['Owner_Account'] = $user->tencent_im_user_id;
+                    $data['group_name'] = $form->name;
+                    $data['avatar'] = $form->img;
+                    $groupResult = $groupService->createGroup($data);
+                    if ($groupResult['ActionStatus'] == 'OK' && $groupResult['ErrorCode'] == 0) {
+                        DB::table('teams')->where('id', $teamId)->update(['GroupId' => $groupResult['GroupId']]);
+                    }
+                    $chatTeam = new ChatTeam();
+                    $chatTeam->user_id = $user->id;
+                    $chatTeam->Owner_Account = $user->tencent_im_user_id;
+                    $chatTeam->group_name = $form->name;
+                    $chatTeam->GroupId = $groupResult['GroupId'];
+                    $chatTeam->FaceUrl = $form->img;
+                    $chatTeam->MaxMemberCount = 20;
+                    $chatTeam->ApplyJoinOption = 'FreeAccess';
+                    $chatTeam->save();
+                }
+            });
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 121 - 0
app/Admin/Controllers/TeamPhotoController.php

xqd
@@ -0,0 +1,121 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Feeds\FeedAction;
+use App\Admin\Actions\Feeds\LikeAction;
+use App\Models\Team;
+use App\Models\TeamPhoto;
+use App\Models\User;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class TeamPhotoController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new TeamPhoto());
+        $grid->model()->with(['user:id,name','team:id,name'])->orderByDesc('id');
+        $grid->column('id')->sortable();
+        $grid->column('team.name',trans('team-photo.fields.team_id'));
+        $grid->column('user.name',trans('team-photo.fields.user_id'));
+        $grid->column('photo_urls')->display(function ($res){
+            if(isset($res)&&!empty($res)){
+                $res = json_decode($res,true);
+                $str = '';
+                if(!empty($res)&&is_array($res)&&count($res)>0){
+                    foreach ($res as $item){
+                        $str.='<img data-action="preview-img" src="'.$item['url'].'" style="max-width:50px;max-height:200px;cursor:pointer" class="img img-thumbnail">';
+                    }
+                }
+                return $str;
+            }else{
+                return "";
+            }
+        });
+        $grid->column('sort')->sortable();
+        $grid->column('created_at');
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('user.name',trans('user.fields.name'));
+            $team = Team::query()->select(['id','name'])->get()->toArray();
+            foreach ($team as $v){
+                $team_arr[$v['id']] = $v['name'];
+            }
+            $filter->equal('team_id',trans('team.labels.team'))->select($team_arr);
+        });
+
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+        });
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new TeamPhoto(), function (Show $show) {
+            $show->field('id');
+            $show->field('team_id');
+            $show->field('user_id');
+            $show->field('url')->image('',100);
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new TeamPhoto(), function (Form $form) {
+            $form->width(11, 1);
+            $form->width(7, 1)->display('id');
+            $team = Team::query()->select(['id','name'])->get()->toArray();
+            $team_arr = array();
+            foreach ($team as $v){
+                $team_arr[$v['id']] = $v['name'];
+            }
+            $form->select('team_id')->options($team_arr);
+            $user = User::query()->select(['id','name'])->get()->toArray();
+            $user_arr = array();
+            foreach ($user as $v){
+                $user_arr[$v['id']] = $v['name'];
+            }
+            $form->select('user_id')->options($user_arr);
+            $form->array('photo_urls', function ($form) {
+                $form->image('url', '图片')->disk("oss")->saveFullUrl()->uniqueName()->removable(false)->autoUpload();
+            })->label("图片");
+
+            $form->text('sort');
+            $form->display('created_at');
+            $form->display('updated_at');
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 148 - 0
app/Admin/Controllers/UserController.php

xqd
@@ -0,0 +1,148 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Games\GameScores;
+use App\Admin\Actions\Users\FansList;
+use App\Admin\Actions\Users\FollowList;
+use App\Admin\Actions\Users\SetUserInfo;
+use App\Admin\Actions\Users\UserAction;
+use App\Admin\Actions\Users\UserAuth;
+use App\Admin\Actions\Users\UserChange;
+use App\Admin\Actions\Users\UsersInfo;
+use App\Admin\Actions\Users\UserVip;
+use App\Models\User;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Dcat\Admin\Widgets\Modal;
+use Illuminate\Database\Eloquent\Model;
+
+class UserController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new User());
+        $grid->model()->with('user_extra')->orderBy('id', 'desc');
+
+        $grid->column('id')->sortable();
+        $grid->column('name');
+        $grid->column('avatar')->image("", 50);
+        $grid->column('email');
+        $grid->column('mobile');
+        $grid->column('sex')->using([0 => trans('user.fields.unknown'), 1 => trans('user.fields.man'), 2 => trans('user.fields.woman')])->label(['gray', 'primary', 'danger']);
+        $grid->column('is_auth')->using([0 => trans('user.fields.unauthorized'), 1 => trans('user.fields.organization'), 2 => trans('user.fields.public_figure')])->label(['gray', 'success', 'red']);;
+        $grid->column('online', trans('user.fields.online_status'))->using([0 => trans('user.fields.offline'), 1 => trans('user.fields.online')])->label(['gray', 'success']);
+        $grid->column('user_extra.fans_count', trans('user.fields.fansNum'))->display(function ($res) {
+            $form = FansList::make()->payload(['id' => $this->id]);
+            return Modal::make()
+                ->lg()
+                ->title(trans('user.fields.fansList'))
+                ->body($form)
+                ->button('<i class="feather icon-align-right"></i> ' . $res);
+        });
+        $grid->column('user_extra.follow_count', trans('user.fields.followNum'))->display(function ($res) {
+            $form = FollowList::make()->payload(['id' => $this->id]);
+            return Modal::make()
+                ->lg()
+                ->title(trans('user.fields.followList'))
+                ->body($form)
+                ->button('<i class="feather icon-align-right"></i> ' . $res);
+        });
+        $grid->column('status')->switch('success', true);
+        $grid->column('created_at');
+
+        // 禁用
+        $grid->disableRowSelector();
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('mobile');
+            $filter->like('email');
+            $filter->like('name');
+            $filter->equal('sex')->select(['1' => trans('user.fields.man'), '2' => trans('user.fields.woman')]);
+            $filter->equal('is_auth')->select(['0' => trans('user.fields.unauthorized'), '1' => trans('user.fields.organization'), '2' => trans('user.fields.public_figure')]);
+            $filter->equal('status')->select(['1' => trans('user.fields.normal'), '0' => trans('user.fields.frozen')]);
+        });
+
+        //操作管理
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->append(new UserChange(User::class));
+            $actions->append(new UserAuth(User::class));
+            $actions->append(new GameScores('user'));
+        });
+
+        //批量操作
+        $grid->batchActions(function (Grid\Tools\BatchActions $batch) {
+            $batch->disableDelete();
+        });
+
+
+        return $grid;
+    }
+
+    /**
+     * 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('name');
+            $show->field('avatar');
+            $show->field('email');
+            $show->field('mobile');
+            $show->field('bio');
+            $show->field('sex');
+            $show->field('location');
+            $show->field('bg');
+            $show->field('tencent_im_user_id');
+            $show->field('register_ip');
+            $show->field('last_login_ip');
+            $show->field('is_auth');
+            $show->field('online');
+            $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('name');
+            $form->image('avatar');
+            $form->text('email');
+            $form->text('mobile');
+            $form->text('bio');
+            $form->image('bg');
+            $form->text('tencent_im_user_id')->readOnly();
+            $form->switch('status')->default(1);
+            $form->display('created_at');
+            $form->display('updated_at');
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 113 - 0
app/Admin/Controllers/UserFeedbackController.php

xqd
@@ -0,0 +1,113 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Users\Report;
+use App\Models\UserFeedback;
+use App\Models\UserReportModel;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+use Illuminate\Database\Eloquent\Model;
+
+class UserFeedbackController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new UserFeedback());
+        $grid->model()->with(['user:id,name'])->orderByDesc('id');
+
+        $grid->column('id')->sortable();
+        $grid->column('user.name',trans('user-feedback.fields.user_id'));
+        $grid->column('content');
+        $grid->column('file')->display(function ($v){
+            if(isset($v)&&!empty($v)){
+                $v = json_decode($v,true);
+                $str = '';
+                if(is_array($v)&&count($v)>0){
+                    foreach ($v as $item){
+                        $str.='<img data-action="preview-img" src="'.$item.'" style="max-width:50px;max-height:200px;cursor:pointer" class="img img-thumbnail">';
+                    }
+                }
+                return $str;
+            }else{
+                return "";
+            }
+        });
+        $grid->column('status')->using([0=>trans('user-report.fields.untreated'),1=>trans('user-report.fields.processed')])->label(['red','green']);
+        $grid->column('created_at');
+//        $grid->column('updated_at')->sortable();
+
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('user.name');
+            $filter->like('content');
+            $filter->equal('status')->select(['0'=>trans('user-report.fields.untreated'),'1'=>trans('user-report.fields.processed')]);
+        });
+
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->disableEdit();
+            $actions->disableDelete();
+            if($actions->row->status==0){
+                $actions->append(new Report(UserFeedback::class));
+            }
+        });
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new UserFeedback(), function (Show $show) {
+            $show->field('id');
+            $show->field('user_id');
+            $show->field('content');
+            $show->field('file');
+            $show->field('status');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new UserFeedback(), function (Form $form) {
+            $form->display('id');
+            $form->text('user_id');
+            $form->text('content');
+            $form->text('file');
+            $form->text('status');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 100 - 0
app/Admin/Controllers/UserFriendController.php

xqd
@@ -0,0 +1,100 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Chat\ChatAction;
+use App\Models\UserFollow;
+use App\Models\UserFriend;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class UserFriendController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     * @throws \Dcat\Admin\Exception\InvalidArgumentException
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new UserFollow());
+        $grid->model()->with(['user:id,avatar,name','target_user:id,avatar,name'])->orderBy('id','desc');
+
+        $grid->column('id')->sortable();
+
+        $grid->combine('user', ['user.id','user.avatar', 'user.name'],trans('user-friend.fields.messaging_user'));
+        $grid->combine('target_user', ['target_user.id','target_user.avatar', 'target_user.name'],trans('user-friend.fields.receiving_message_user'));
+
+        $grid->column('user.id');
+        $grid->column('user.avatar')->image('',50);
+        $grid->column('user.name');
+
+        $grid->column('target_user.id');
+        $grid->column('target_user.avatar')->image('',50);
+        $grid->column('target_user.name');
+//        $grid->column('status');
+//        $grid->column('created_at');
+        $grid->column('updated_at')->sortable();
+
+        $grid->disableCreateButton();
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('user.name');
+
+        });
+        $grid->disableRowSelector();
+        //批量操作
+        $grid->batchActions(function (Grid\Tools\BatchActions $batch) {
+            $batch->disableDelete();
+        });
+        //操作管理
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->disableEdit();
+
+            $actions->append(new ChatAction());
+        });
+
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new UserFriend(), function (Show $show) {
+            $show->field('id');
+            $show->field('user_id');
+            $show->field('to_uid');
+            $show->field('status');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new UserFriend(), function (Form $form) {
+            $form->display('id');
+            $form->text('user_id');
+            $form->text('to_uid');
+            $form->text('status');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+        });
+    }
+}

+ 119 - 0
app/Admin/Controllers/UserIdentifyController.php

xqd
@@ -0,0 +1,119 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Users\UserAuth;
+use App\Admin\Actions\Users\UserChange;
+use App\Models\User;
+use App\Models\UserIdentify;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class UserIdentifyController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        return Grid::make(new UserIdentify(), function (Grid $grid) {
+            $grid->column('id')->sortable();
+            $grid->column('user_id');
+            $grid->column('avatar')->image('',50);
+            $grid->column('name');
+            $grid->column('email');
+            $grid->column('mobile');
+            $grid->column('sex')->using([0=>trans('user.fields.unknown'),1=>trans('user.fields.man'),2=>trans('user.fields.woman')])->label(['gray','primary','danger']);
+            $grid->column('bio');
+            $grid->column('birthday');
+            $grid->column('action_type')->using([0=>trans('user.fields.unknown'),1=>trans('user-identify.fields.background_add'),2=>trans('user-identify.fields.user_apply')])->label(['gray','primary','blue']);
+            $grid->column('type')->using([0=>trans('user.fields.unknown'),1=>trans('user.fields.organization'),2=>trans('user.fields.public_figure')])->label(['gray','primary','blue']);
+            $grid->column('status')->using([0=>trans('user.fields.unauthorized'),1=>trans('user.fields.authorized')])->label(['gray','success']);
+            $grid->column('created_at');
+//            $grid->column('updated_at')->sortable();
+
+            $grid->filter(function (Grid\Filter $filter) {
+                $filter->equal('id');
+                $filter->equal('user_id');
+                $filter->like('mobile');
+                $filter->like('email');
+                $filter->like('name');
+                $filter->equal('status')->select(['0'=>trans('user.fields.unauthorized'),'1'=>trans('user.fields.authorized')]);
+
+            });
+            //操作管理
+            $grid->actions(function (Grid\Displayers\Actions $actions) {
+                $actions->disableView();
+                $actions->disableEdit();
+                if ($actions->row->status == 0) {
+                    $actions->append(new UserAuth(User::class));
+                }
+            });
+        });
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new UserIdentify(), function (Show $show) {
+            $show->field('id');
+            $show->field('user_id');
+            $show->field('name');
+            $show->field('email');
+            $show->field('mobile');
+            $show->field('bio');
+            $show->field('sex');
+            $show->field('birthday');
+            $show->field('avatar');
+            $show->field('action_type');
+            $show->field('type');
+            $show->field('status');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new UserIdentify(), function (Form $form) {
+            $form->display('id');
+            $form->text('user_id');
+            $form->text('name');
+            $form->text('email');
+            $form->text('mobile');
+            $form->text('bio');
+            $form->text('sex');
+            $form->text('birthday');
+            $form->text('avatar');
+            $form->text('action_type');
+            $form->text('type');
+            $form->text('status');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+            $form->footer(function ($footer) {
+                // 去掉`查看`checkbox
+                $footer->disableViewCheck();
+                // 去掉`继续编辑`checkbox
+                $footer->disableEditingCheck();
+                // 去掉`继续创建`checkbox
+                $footer->disableCreatingCheck();
+            });
+        });
+    }
+}

+ 142 - 0
app/Admin/Controllers/UserReportController.php

xqd
@@ -0,0 +1,142 @@
+<?php
+
+namespace App\Admin\Controllers;
+
+use App\Admin\Actions\Users\Report;
+use App\Models\UserReport;
+use App\Models\UserReportModel;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Show;
+use Dcat\Admin\Http\Controllers\AdminController;
+
+class UserReportController extends AdminController
+{
+    /**
+     * Make a grid builder.
+     *
+     * @return Grid
+     */
+    protected function grid()
+    {
+        $grid = new Grid(new UserReport());
+        $grid->model()->with(['user:id,name,avatar'])->orderByDesc('id');
+        $grid->column('id')->sortable();
+//        $grid->column('user_id');
+        $grid->column('user.avatar')->image("",50);
+        $grid->column('user.name');
+        $grid->column('to_id');
+        $grid->column('type')->using([1=>trans('user-report.fields.feeds'),2=>trans('user-report.fields.users')])->label(['blue','green']);
+        $grid->column('content');
+        $grid->column('files')->display(function ($v){
+            if(isset($v)&&!empty($v)){
+                $v = json_decode($v,true);
+                $str = '';
+                if(!empty($v)&&count($v)>0){
+                    foreach ($v as $item){
+                        $str.='<img data-action="preview-img" src="'.$item.'" style="max-width:50px;max-height:200px;cursor:pointer" class="img img-thumbnail">';
+                    }
+                }
+                return $str;
+            }else{
+                return "";
+            }
+        });;
+        $grid->column('status')->using([0=>trans('user-report.fields.untreated'),1=>trans('user-report.fields.processed')])->label(['red','green']);
+        $grid->column('result');
+        $grid->column('created_at');
+        $grid->column('updated_at')->sortable();
+
+        $grid->filter(function (Grid\Filter $filter) {
+            $filter->equal('id');
+            $filter->like('user.name');
+            $filter->equal('type')->select(['1'=>trans('user-report.fields.feeds'),'2'=>trans('user-report.fields.users')]);
+            $filter->equal('status')->select(['0'=>trans('user-report.fields.untreated'),'1'=>trans('user-report.fields.processed')]);
+        });
+
+        $grid->disableCreateButton();
+
+        $grid->actions(function (Grid\Displayers\Actions $actions) {
+            $actions->disableView();
+            $actions->disableEdit();
+            $actions->disableDelete();
+            if($actions->row->status==0){
+                $actions->append(new Report(UserReport::class));
+            }
+        });
+        return $grid;
+    }
+
+    /**
+     * Make a show builder.
+     *
+     * @param mixed $id
+     *
+     * @return Show
+     */
+    protected function detail($id)
+    {
+        return Show::make($id, new UserReport(), function (Show $show) {
+            $show->field('id');
+            $show->field('user_id');
+            $show->field('to_id');
+            $show->field('type');
+            $show->field('content')->unescape();
+            $show->html(function ($res){
+                $str = "";
+                if($res['files']){
+                    $res = json_decode($res['files'],true);
+                    if(count($res)>0){
+                        foreach ($res as $k=>$v){
+                            $str.='<img data-action="preview-img" src="'.$v.'" style="max-width:100px;max-height:100px;cursor:pointer" class="img img-thumbnail">';
+                        }
+                    }else{
+                        $str = "无";
+                    }
+                }else{
+                    $str = "无";
+                }
+                $html = '<div class="show-field form-group row">
+                    <div class="col-sm-2 control-label">
+                        <span>图片</span>
+                    </div>
+
+                    <div class="col-sm-8">
+                        <div class="box box-solid box-default no-margin box-show">
+                            <div class="box-body">
+                                      '.$str.'
+                            </div>
+                        </div>
+                    </div>
+                </div>';
+                return $html;
+            });
+            $show->field('status');
+            $show->field('result');
+            $show->field('created_at');
+            $show->field('updated_at');
+        });
+    }
+
+    /**
+     * Make a form builder.
+     *
+     * @return Form
+     */
+    protected function form()
+    {
+        return Form::make(new UserReport(), function (Form $form) {
+            $form->display('id');
+            $form->text('user_id');
+            $form->text('to_id');
+            $form->text('type');
+            $form->text('content');
+            $form->text('files');
+            $form->text('status');
+            $form->text('result');
+
+            $form->display('created_at');
+            $form->display('updated_at');
+        });
+    }
+}

+ 117 - 0
app/Admin/Forms/AdminSetting.php

xqd
@@ -0,0 +1,117 @@
+<?php
+
+namespace App\Admin\Forms;
+
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+use Illuminate\Support\Arr;
+
+class AdminSetting extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+    /**
+     * 主题颜色.
+     *
+     * @var array
+     */
+    protected $colors;
+
+    public function __construct($data = [], $key = null)
+    {
+        parent::__construct($data, $key);
+        $this->colors = [
+            'default'    => trans('site-setting.Dark_blue'),
+            'blue'       => trans('site-setting.blue'),
+//        'blue-light' => '浅蓝',
+//        'blue-dark'  => '深蓝',
+            'green'      => trans('site-setting.green'),
+        ];
+    }
+
+    /**
+     * 处理表单请求.
+     *
+     * @param array $input
+     *
+     * @return mixed
+     */
+    public function handle(array $input)
+    {
+        $input['layout']['horizontal_menu'] = in_array('horizontal_menu', $input['layout']['body_class'], true);
+
+        foreach (Arr::dot($input) as $k => $v) {
+            $this->update($k, $v);
+        }
+
+        return $this->response()->success(trans('site-setting.Set_successfully'));
+    }
+
+    /**
+     * 构建表单.
+     */
+    public function form()
+    {
+        $this->text('name')->required()->help(trans('site-setting.Website_name'));
+        $this->text('logo')->required()->help(trans('site-setting.logo'));
+        $this->text('logo-mini', 'Logo mini')->required();
+        $this->radio('lang', trans('site-setting.language'))->required()->options(['en' => 'English', 'zh' => '简体中文']);
+        $this->radio('layout.color', trans('site-setting.theme'))
+            ->required()
+            ->help(trans('site-setting.theme_color'))
+            ->options($this->colors);
+
+        $this->radio('layout.sidebar_style', trans('site-setting.menu_style'))
+            ->options(['light' => 'Light', 'primary' => 'Primary'])
+            ->help(trans('site-setting.t_menu_style'));
+
+        $this->checkbox('layout.body_class', trans('site-setting.Menu_layout'))
+            ->options([
+                'horizontal_menu' => 'Horizontal',
+                'sidebar-separate' => 'sidebar-separate',
+            ])
+            ->help(trans('site-setting.Switch_menu_layout'));
+//        $this->switch('https', '启用HTTPS');
+        $this->switch('helpers.enable', trans('site-setting.development_tool'));
+    }
+
+    /**
+     * 设置接口保存成功后的回调JS代码.
+     *
+     * 1.2秒后刷新整个页面.
+     *
+     * @return string|void
+     */
+    public function savedScript()
+    {
+        return <<<'JS'
+    if (data.status) {
+        setTimeout(function () {
+          location.reload()
+        }, 1200);
+    }
+JS;
+    }
+
+    /**
+     * 返回表单数据.
+     *
+     * @return array
+     */
+    public function default()
+    {
+        return user_admin_config();
+    }
+
+    /**
+     * 更新配置.
+     *
+     * @param string $key
+     * @param string $value
+     */
+    protected function update($key, $value)
+    {
+        user_admin_config([$key => $value]);
+    }
+}

+ 58 - 0
app/Admin/Metrics/Course/TotalCourse.php

xqd
@@ -0,0 +1,58 @@
+<?php
+
+namespace App\Admin\Metrics\Course;
+
+use App\Models\Course;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Http\Request;
+
+class TotalCourse extends Card
+{
+    /**
+     * 卡片底部内容.
+     *
+     * @var string|Renderable|\Closure
+     */
+    protected $footer;
+
+    /**
+     * 初始化卡片.
+     */
+    protected function init()
+    {
+        parent::init();
+        $this->title(trans('course.fields.Total_Courses'));
+        $this->height='120';
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total = Course::query()->whereNull('deleted_at')->count();
+        $this->content($total);
+    }
+
+    /**
+     * 渲染卡片内容.
+     *
+     * @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;
+    }
+
+}

+ 107 - 0
app/Admin/Metrics/Examples/Feedback.php

xqd
@@ -0,0 +1,107 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Team;
+use App\Models\UserFeedback;
+use App\Models\UserReport;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Http\Request;
+
+class Feedback extends Card
+{
+    /**
+     * 卡片底部内容.
+     *
+     * @var string|Renderable|\Closure
+     */
+    protected $footer;
+
+    /**
+     * 初始化卡片.
+     */
+    protected function init()
+    {
+        parent::init();
+        $this->title(trans('admin-home.Pending_feedback'));
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total_team = UserFeedback::query()->where(['status'=>0])->count();
+        $this->content($total_team);
+    }
+
+    /**
+     * @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;cursor: pointer" onclick="location.href='/admin/feedback'">
+    <h2 class="ml-1 font-lg-1" style="font-size: 48px!important;">{$content}</h2>
+</div>
+
+HTML;
+    }
+
+    /**
+     * 渲染卡片底部内容.
+     *
+     * @return string
+     */
+    public function renderFooter()
+    {
+        return $this->toString($this->footer);
+    }
+}

+ 112 - 0
app/Admin/Metrics/Examples/Games.php

xqd
@@ -0,0 +1,112 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Game;
+use Dcat\Admin\Widgets\Metrics\Line;
+use Illuminate\Http\Request;
+
+class Games extends Line
+{
+    /**
+     * 初始化卡片内容
+     */
+    protected function init()
+    {
+        parent::init();
+
+        $this->title(trans('admin-home.Recent_events'));
+        $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)
+    {
+        $games = Game::query()->orderByDesc('id')->limit(5)->select(['id','name','begin_time'])->get()->toArray();
+
+        $this->withContent($games);
+    }
+
+    /**
+     * 设置图表数据.
+     *
+     * @param int $data
+     *
+     * @return $this
+     */
+    public function withChart(int $data)
+    {
+        return $this->chart([
+            'series' => [$data],
+        ]);
+    }
+
+    /**
+     * 卡片内容
+     *
+     * @param string $content
+     *
+     * @return $this
+     */
+    public function withContent($content)
+    {
+        $str = '';
+        foreach ($content as $k=>$v){
+            $str.= '<h4 class="font-lg-12 mt-2 mb-3">'.$v['name'].' &nbsp;&nbsp;&nbsp;&nbsp;'.'<span style="float: right;font-size: 16px">'.trans('admin-home.Start_time').':'.$v['begin_time'].'</span></h4>';
+        }
+
+
+        return $this->content(
+            <<<HTML
+<div class="justify-content-between align-items-center p-1">
+   {$str}
+</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
+        );
+    }
+}

+ 91 - 0
app/Admin/Metrics/Examples/NewDevices.php

xqd
@@ -0,0 +1,91 @@
+<?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 justify-content-between align-items-center mt-1" style="margin-bottom: 2px">
+    <h2 class="ml-1 font-lg-1">1000</h2>
+</div>
+HTML
+        );
+    }
+}

+ 157 - 0
app/Admin/Metrics/Examples/NewUsers.php

xqd
@@ -0,0 +1,157 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\User;
+use Dcat\Admin\Widgets\Metrics\Line;
+use Illuminate\Http\Request;
+
+class NewUsers extends Line
+{
+    /**
+     * 初始化卡片内容
+     *
+     * @return void
+     */
+    protected function init()
+    {
+        parent::init();
+
+        $this->title(trans('admin-home.New_Users'));
+        $this->dropdown([
+            '7' => trans('admin-home.Last_7_days'),
+            '30' => trans('admin-home.Last_month'),
+            '180' => trans('admin-home.Last_half_year'),
+            '365' => trans('admin-home.Last_year'),
+        ]);
+       // dd($this->new_user("365"));
+    }
+
+    /**
+     * 处理请求
+     *
+     * @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':
+                $user = $this->new_user("365");
+                // 卡片内容
+                $this->withContent($user['num']);
+                // 图表数据
+                $this->withChart($user['num_arr']);
+                break;
+            case '180':
+                $user = $this->new_user("180");
+                // 卡片内容
+                $this->withContent($user['num']);
+                // 图表数据
+                $this->withChart($user['num_arr']);
+                break;
+            case '30':
+                $user = $this->new_user("30");
+                // 卡片内容
+                $this->withContent($user['num']);
+                // 图表数据
+                $this->withChart($user['num_arr']);
+                break;
+            case '7':
+            default:
+                $user = $this->new_user("7");
+                // 卡片内容
+                $this->withContent($user['num']);
+                // 图表数据
+                $this->withChart($user['num_arr']);
+        }
+    }
+
+    /**
+     * 设置图表数据.
+     *
+     * @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
+        );
+    }
+
+
+
+    /**
+     *  新用户 一年
+     *   write by wanglas
+     */
+    public function new_user($kind){
+
+        if ($kind=='365'){
+            $t_last = date('Y-m-d H:i:s',strtotime('-1 year'));
+            $t_time = 86400*12;
+            $count = 31;
+        }elseif ($kind=='180'){
+            $t_last = date('Y-m-d H:i:s',strtotime('-180 day'));
+            $t_time = 86400*6;
+            $count = 31;
+        }elseif ($kind=='30'){
+            $t_last = date('Y-m-d H:i:s',strtotime('-30 day'));
+            $t_time = 86400;
+            $count = 31;
+        }elseif ($kind=='7'){
+            $t_last = date('Y-m-d H:i:s',strtotime('-7 day'));
+            $t_time = 86400;
+            $count = 8;
+        }
+        //统计会员总数
+        $t_now = date('Y-m-d H:i:s');
+        $num=User::query()->whereBetween('created_at',array($t_last,$t_now))->whereNull('deleted_at')->count();
+        //计算会员增长数量
+        for ($i=1 ; $i < $count; $i++) {
+            $today=strtotime(date('Ymd'));
+            $now  = date('Y-m-d H:i:s',$today-$t_time*($i-1));
+            $time = date('Y-m-d H:i:s',$today-$t_time*$i);
+            $inc_num=User::query()->whereBetween('created_at',array($time,$now))->count();
+            //$arr_t[]=$now;
+            $arr_n[]=$inc_num;
+        }
+        //逆序输出数组
+        //$arr_t=array_reverse($arr_t);  //时间
+        $arr_n=array_reverse($arr_n);  //数量
+        return array('num'=>$num,'num_arr'=>$arr_n);
+    }
+}

+ 114 - 0
app/Admin/Metrics/Examples/ProductOrders.php

xqd
@@ -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
+        );
+    }
+}

+ 106 - 0
app/Admin/Metrics/Examples/Report.php

xqd
@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Team;
+use App\Models\UserReport;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Http\Request;
+
+class Report extends Card
+{
+    /**
+     * 卡片底部内容.
+     *
+     * @var string|Renderable|\Closure
+     */
+    protected $footer;
+
+    /**
+     * 初始化卡片.
+     */
+    protected function init()
+    {
+        parent::init();
+        $this->title(trans('admin-home.Pending_report'));
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total_team = UserReport::query()->where(['status'=>0])->count();
+        $this->content($total_team);
+    }
+
+    /**
+     * @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;cursor: pointer" onclick="location.href='/admin/report'">
+    <h2 class="ml-1 font-lg-1" style="font-size: 48px!important;">{$content}</h2>
+</div>
+
+HTML;
+    }
+
+    /**
+     * 渲染卡片底部内容.
+     *
+     * @return string
+     */
+    public function renderFooter()
+    {
+        return $this->toString($this->footer);
+    }
+}

+ 117 - 0
app/Admin/Metrics/Examples/Sessions.php

xqd
@@ -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
+        );
+    }
+}

+ 116 - 0
app/Admin/Metrics/Examples/Tickets.php

xqd
@@ -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
+        );
+    }
+}

+ 106 - 0
app/Admin/Metrics/Examples/TotalCourse.php

xqd
@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Course;
+use App\Models\Team;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Http\Request;
+
+class TotalCourse extends Card
+{
+    /**
+     * 卡片底部内容.
+     *
+     * @var string|Renderable|\Closure
+     */
+    protected $footer;
+
+    /**
+     * 初始化卡片.
+     */
+    protected function init()
+    {
+        parent::init();
+        $this->title(trans('admin-home.Total_course'));
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total_team = Course::query()->count();
+        $this->content($total_team);
+    }
+
+    /**
+     * @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;cursor: pointer" onclick="location.href='/admin/courses'">
+    <h2 class="ml-1 font-lg-1" style="font-size: 48px!important;">{$content}</h2>
+</div>
+
+HTML;
+    }
+
+    /**
+     * 渲染卡片底部内容.
+     *
+     * @return string
+     */
+    public function renderFooter()
+    {
+        return $this->toString($this->footer);
+    }
+}

+ 106 - 0
app/Admin/Metrics/Examples/TotalGames.php

xqd
@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Game;
+use App\Models\Team;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Http\Request;
+
+class TotalGames extends Card
+{
+    /**
+     * 卡片底部内容.
+     *
+     * @var string|Renderable|\Closure
+     */
+    protected $footer;
+
+    /**
+     * 初始化卡片.
+     */
+    protected function init()
+    {
+        parent::init();
+        $this->title(trans('admin-home.Total_games'));
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total_team = Game::query()->count();
+        $this->content($total_team);
+    }
+
+    /**
+     * @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;cursor: pointer" onclick="location.href='/admin/games'">
+    <h2 class="ml-1 font-lg-1" style="font-size: 48px!important;">{$content}</h2>
+</div>
+
+HTML;
+    }
+
+    /**
+     * 渲染卡片底部内容.
+     *
+     * @return string
+     */
+    public function renderFooter()
+    {
+        return $this->toString($this->footer);
+    }
+}

+ 105 - 0
app/Admin/Metrics/Examples/TotalTeam.php

xqd
@@ -0,0 +1,105 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Team;
+use Dcat\Admin\Widgets\Metrics\Card;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Http\Request;
+
+class TotalTeam extends Card
+{
+    /**
+     * 卡片底部内容.
+     *
+     * @var string|Renderable|\Closure
+     */
+    protected $footer;
+
+    /**
+     * 初始化卡片.
+     */
+    protected function init()
+    {
+        parent::init();
+        $this->title(trans('admin-home.Total_team'));
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total_team = Team::query()->count();
+        $this->content($total_team);
+    }
+
+    /**
+     * @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;cursor: pointer" onclick="location.href='/admin/teams'">
+    <h2 class="ml-1 font-lg-1" style="font-size: 48px!important;">{$content}</h2>
+</div>
+
+HTML;
+    }
+
+    /**
+     * 渲染卡片底部内容.
+     *
+     * @return string
+     */
+    public function renderFooter()
+    {
+        return $this->toString($this->footer);
+    }
+}

+ 107 - 0
app/Admin/Metrics/Examples/TotalUsers.php

xqd
@@ -0,0 +1,107 @@
+<?php
+
+namespace App\Admin\Metrics\Examples;
+
+use App\Models\Game;
+use App\Models\Team;
+use App\Models\User;
+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(trans('admin-home.Total_users'));
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param Request $request
+     *
+     * @return void
+     */
+    public function handle(Request $request)
+    {
+        $total_team = User::query()->whereNull('deleted_at')->count();
+        $this->content($total_team);
+    }
+
+    /**
+     * @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;cursor: pointer" onclick="location.href='/admin/users'">
+    <h2 class="ml-1 font-lg-1" style="font-size: 48px!important;">{$content}</h2>
+</div>
+
+HTML;
+    }
+
+    /**
+     * 渲染卡片底部内容.
+     *
+     * @return string
+     */
+    public function renderFooter()
+    {
+        return $this->toString($this->footer);
+    }
+}

+ 72 - 0
app/Admin/bootstrap.php

xqd
@@ -0,0 +1,72 @@
+<?php
+
+use App\Admin\Grid\Tools\SwitchGridMode;
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Form;
+use Dcat\Admin\Grid\Filter;
+use Dcat\Admin\Layout\Navbar;
+use Dcat\Admin\Show;
+use Dcat\Admin\Repositories\Repository;
+//use Illuminate\Support\Facades\App;
+
+/**
+ * Dcat-admin - admin builder based on Laravel.
+ * @author jqhph <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');
+ *
+ */
+
+// 覆盖默认配置
+config(['admin' => user_admin_config()]);
+config(['app.locale' => config('admin.lang') ?: config('app.locale')]);
+//App::setLocale('en');  //配置默认语言
+Admin::style('.main-sidebar .nav-sidebar .nav-item>.nav-link {
+    border-radius: .1rem;
+}');
+
+Admin::style('.main-sidebar .nav-treeview.nav .nav-item .nav-link {
+    padding: 5px 10px 7px 50px!important;
+}');
+
+// 扩展Column
+Grid\Column::extend('code', function ($v) {
+    return "<code>$v</code>";
+});
+
+Grid::resolving(function (Grid $grid) {
+    if (! request('_row_')) {
+        $grid->tableCollapse();
+    }
+});
+
+// 追加菜单
+Admin::menu()->add(include __DIR__.'/menu.php', 0);
+
+Admin::navbar(function (Navbar $navbar) {
+    $method = config('admin.layout.horizontal_menu') ? 'left' : 'right';
+    // ajax请求不执行
+    if (! Dcat\Admin\Support\Helper::isAjaxRequest()) {
+        $navbar->$method(App\Admin\Actions\AdminSetting::make()->render());
+    }
+    // 搜索框
+    $navbar->right(
+        <<<HTML
+HTML
+    );
+});
+
+//地图组件使用
+Form\Field\Map::requireAssets();

+ 204 - 0
app/Admin/menu.php

xqd
@@ -0,0 +1,204 @@
+<?php
+$lang = request()->session()->get('admin.config.lang')??'en';
+return [
+    /**
+     * 用户中心
+     * ------------------------------------------
+     */
+    [
+        'id'        => 8,
+        'title'     => trans('menu.User',[],$lang),
+        'icon'      => 'fa-user-circle-o',
+        'uri'       => 'users',
+        'parent_id' => 0,
+    ],
+    [
+        'id'        => 27,
+        'title'     => trans('menu.User_list',[],$lang),
+        'icon'      => '',
+        'uri'       => 'users',
+        'parent_id' => 8,
+    ],
+    [
+        'id'        => 28,
+        'title'     => trans('menu.User_auth',[],$lang),
+        'icon'      => '',
+        'uri'       => 'user_identify',
+        'parent_id' => 8,
+    ],
+    [
+        'id'        => 29,
+        'title'     => trans('menu.Course_user',[],$lang),
+        'icon'      => '',
+        'uri'       => 'course_user',
+        'parent_id' => 8,
+    ],
+
+    /**
+     * 球场管理
+     * ------------------------------------------
+     */
+    [
+        'id'        => 13,
+        'title'     => trans('menu.Course',[],$lang),
+        'icon'      => 'fa-university',
+        'uri'       => 'courses',
+        'parent_id' => 0
+    ],
+//    [
+//        'id'        => 30,
+//        'title'     => trans('menu.Course_list',[],$lang),
+//        'icon'      => '',
+//        'uri'       => 'courses',
+//        'parent_id' => 13
+//    ],
+//    [
+//        'id'        => 31,
+//        'title'     => trans('menu.Course_field',[],$lang),
+//        'icon'      => '',
+//        'uri'       => 'course_field',
+//        'parent_id' => 13
+//    ],
+
+    /**
+     * 球队管理
+     * ------------------------------------------
+     */
+    [
+        'id'        => 22,
+        'title'     => trans('menu.Team',[],$lang),
+        'icon'      => 'fa-group',
+        'uri'       => '',
+        'parent_id' => 0
+    ],
+    [
+        'id'        => 31,
+        'title'     => trans('menu.Team_list',[],$lang),
+        'icon'      => '',
+        'uri'       => 'teams',
+        'parent_id' => 22,
+    ],
+    [
+        'id'        => 23,
+        'title'     => trans('menu.Team_photo',[],$lang),
+        'icon'      => '',
+        'uri'       => 'team_photos',
+        'parent_id' => 22,
+    ],
+
+    /**
+     * 赛事管理
+     * ------------------------------------------
+     */
+    [
+        'id'        => 10,
+        'title'     => trans('menu.Games',[],$lang),
+        'icon'      => 'fa-soccer-ball-o',
+        'uri'       => 'games',
+        'parent_id' => 0,
+    ],
+    [
+        'id'        => 20,
+        'title'     => trans('menu.Game_list',[],$lang),
+        'icon'      => '',
+        'uri'       => 'games',
+        'parent_id' => 10,
+    ],
+    [
+        'id'        => 21,
+        'title'     => trans('menu.Game_type',[],$lang),
+        'icon'      => '',
+        'uri'       => 'game_types',
+        'parent_id' => 10,
+    ],
+    [
+        'id'        => 26,
+        'title'     => trans('menu.Game_record',[],$lang),
+        'icon'      => '',
+        'uri'       => 'game_user_scores',
+        'parent_id' => 10,
+    ],
+
+    /**
+     * 动态管理
+     * ------------------------------------------
+     */
+    [
+        'id'        => 9,
+        'title'     => trans('menu.Feeds',[],$lang),
+        'icon'      => 'fa-commenting-o',
+        'uri'       => 'feeds',
+        'parent_id' => 0,
+    ],
+
+    /**
+     * 运营管理
+     * ------------------------------------------
+     */
+    [
+        'id'        => 11,
+        'title'     => trans('menu.Operation',[],$lang),
+        'icon'      => 'fa-list-alt',
+        'uri'       => 'operate',
+        'parent_id' => 0,
+    ],
+    [
+        'id'        => 19,
+        'title'     =>trans('menu.Avatar',[],$lang),
+        'icon'      => '',
+        'uri'       => 'avatar',
+        'parent_id' => 11,
+    ],
+    [
+        'id'        => 24,
+        'title'     => trans('menu.Feedback',[],$lang),
+        'icon'      => '',
+        'uri'       => 'feedback',
+        'parent_id' => 11,
+    ],
+    [
+        'id'        => 25,
+        'title'     => trans('menu.Document',[],$lang),
+        'icon'      => '',
+        'uri'       => 'document',
+        'parent_id' => 11,
+    ],
+
+    /**
+     * 聊天管理
+     * ------------------------------------------
+     */
+    [
+        'id'        => 18,
+        'title'     => trans('menu.Chat',[],$lang),
+        'icon'      => 'fa-comments',
+        'uri'       => '',
+        'parent_id' => 0,
+    ],[
+        'id'        => 16,
+        'title'     => trans('menu.chats',[],$lang),
+        'icon'      => '',
+        'uri'       => 'chat',
+        'parent_id' => 18,
+    ],[
+        'id'        => 17,
+        'title'     => trans('menu.chat_team',[],$lang),
+        'icon'      => '',
+        'uri'       => 'chat_team',
+        'parent_id' => 18,
+    ],
+
+    /**
+     * 系统配置
+     * ------------------------------------------
+     */
+    [
+        'id'        => 12,
+        'title'     => trans('menu.Setting',[],$lang),
+        'icon'      => 'fa-gears',
+        'uri'       => 'setting',
+        'parent_id' => 0
+    ],
+
+
+];

+ 35 - 0
app/Admin/routes.php

xqd
@@ -0,0 +1,35 @@
+<?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('/users', 'UserController');
+    $router->resource('/feeds', 'FeedsController');
+    $router->resource('/games', 'GamesController');
+    $router->resource('/setting', 'BaseConfigController');
+    $router->resource('/courses', 'CourseController');
+    $router->resource('/course_field', 'CourseFieldController');
+    $router->resource('/report', 'UserReportController');
+    $router->resource('/chat_team', 'ChatTeamController');
+    $router->resource('/avatar', 'SystemAvatarController');
+    $router->resource('/chat', 'UserFriendController');
+    $router->resource('/game_types', 'GameTypeController');
+    $router->resource('/teams', 'TeamController');
+    $router->resource('/team_photos', 'TeamPhotoController');
+    $router->resource('/feedback', 'UserFeedbackController');
+    $router->resource('/document', 'DocumentController');
+    $router->resource('/game_user_scores', 'GameUserController');
+    $router->resource('/user_identify', 'UserIdentifyController');
+    $router->resource('/course_user', 'CourseUserController');
+
+});

+ 44 - 0
app/Console/Commands/AnJuKePicker.php

xqd
@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+
+class AnJuKePicker extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'picker:anjuke';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        //
+        $picker = new \App\Http\Controllers\Service\AnJuKePicker();
+        $picker->startPick();
+    }
+}

+ 243 - 0
app/Console/Commands/DataSeeder.php

xqd
@@ -0,0 +1,243 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Model\AccountInfo;
+use App\Model\Appeals;
+use App\Model\BaseArea;
+use App\Model\WithdrawInfo;
+use App\Model\DeliverInfo;
+use App\Model\DeviceInfo;
+use App\Model\DeviceToUser;
+use App\Model\RechargeInfo;
+use App\Model\TransportInfo;
+use App\Model\UserInfo;
+use Faker\Generator;
+use Illuminate\Console\Command;
+
+/**
+ * 数据填充器
+ * Class DataSeeder
+ * @package App\Console\Commands
+ */
+
+class DataSeeder extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'data:seeder';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        //用户表数据填充300条
+
+
+
+        $faker_zh = \Faker\Factory::create('zh_CN');
+        $faker_en = \Faker\Factory::create();
+
+
+
+
+
+
+
+        $cities = BaseArea::where('pid','510117')->with(['communities'=>function($query){
+            $query->select(['area_id','id']);
+        }])->get(['id'])->toArray();
+        $area_ids = [];
+        $communities_ids =[];
+        $city_max = 0;
+        $com_max = 0;
+         foreach ($cities as $city){
+             $area_ids[]= $city['id'];
+             $city_max ++;
+             foreach ($city['communities'] as $community){
+                 $communities_ids[] = $community['id'];
+                 $com_max++;
+             }
+
+        }
+
+
+
+
+
+
+
+
+            $us = UserInfo::all(['id','role'])->toArray();
+            $user_common = [];
+            $user_agent = [];
+            $user_agent_user = [];
+            foreach ($us as $u){
+                if ($u['role'] == UserInfo::Role_Common)
+                    $user_common[] = $u['id'];
+                if ($u['role'] == UserInfo::Role_Agent)
+                    $user_agent[] = $u['id'];
+                if ($u['role'] == UserInfo::Role_Agent_User)
+                    $user_agent_user[] = $u['id'];
+            }
+
+            $us = DeviceInfo::all(['id'])->toArray();
+
+            $device_ids =[];
+            $device_max = 0;
+            foreach ($us as $u){
+                $device_max ++;
+                $device_ids[] = $u['id'];
+            }
+
+
+        for ($i = 0;$i<2000;$i++){
+            echo "第{$i}个投放记录开始创建\r\n";
+            $tempRow = [];
+            $tempRow['device_id'] = $device_ids[rand(0,$device_max-1)];
+            $tempRow['user_id'] = $user_common[rand(0,count($user_common)-1)];
+            $tempRow['no'] = strtoupper(uniqid());
+            $tempRow['weight'] = rand(1,99999);
+            $tempRow['money'] = rand(0,1000);
+            $tempRow['finished_at'] = date('Y-m-d H:i:s');
+            $tempRow['status'] = rand(1,3);
+            $tempRow['created_at'] = date('Y-m-d H:i:s',strtotime("-".rand(1,365)." days"));
+            DeliverInfo::create($tempRow);
+        }
+
+
+
+
+
+        for ($i = 0;$i<2000;$i++){
+            echo "第{$i}个收运记录开始创建\r\n";
+            $tempRow = [];
+            $tempRow['device_id'] = $device_ids[rand(0,$device_max-1)];
+            $tempRow['user_id'] = $user_agent_user[rand(0,count($user_agent_user)-1)];
+            $tempRow['no'] = strtoupper(uniqid());
+            $tempRow['weight'] = rand(1,999999);
+            $tempRow['money'] = rand(0,1000);
+            $tempRow['created_at'] = date('Y-m-d H:i:s',strtotime("-".rand(1,365)." days"));
+            $tempRow['status'] = rand(1,2);
+            TransportInfo::create($tempRow);
+        }
+
+        $banks = array(
+            '渤海银行',
+            '广发银行',
+            '国家开发银行',
+            '恒丰银行',
+            '华夏银行',
+            '交通银行',
+            '平安银行',
+            '上海浦东发展银行',
+            '兴业银行',
+            '招商银行',
+            '浙商银行',
+            '中国工商银行',
+            '中国光大银行',
+            '中国建设银行',
+            '中国民生银行',
+            '中国农业银行',
+            '中国银行',
+            '中国邮政储蓄银行',
+            '中信银行',
+        );
+
+
+        for ($i = 0;$i<2000;$i++){
+            echo "第{$i}个提现记录开始创建\r\n";
+            $tempRow = [];
+            $tempRow['user_id'] = $user_common[rand(0,count($user_common)-1)];
+            $tempRow['order_no'] = strtoupper(uniqid());
+            $tempRow['money'] = rand(0,3000);
+            $tempRow['poundage'] = rand(0,200);
+            $tempRow['pay_money'] = $tempRow['money']-$tempRow['poundage'];
+            $tempRow['paid_at'] = date('Y-m-d H:i:s');
+            $tempRow['bank_card'] = $faker_zh->phoneNumber;
+            $tempRow['bank_name'] = $banks[rand(0,count($banks)-1)];
+            $tempRow['name'] = $faker_zh->name;
+            $tempRow['mobile'] = $faker_zh->phoneNumber;
+            $tempRow['ali_account'] = $faker_zh->phoneNumber;
+            $tempRow['ali_name'] = $faker_zh->name;
+            $tempRow['status'] = rand(0,1);
+            $tempRow['type'] = rand(0,2);
+            $tempRow['created_at'] = date('Y-m-d H:i:s',strtotime("-".rand(1,365)." days"));
+            $tempRow['reason'] = $faker_en->company;
+            WithdrawInfo::create($tempRow);
+        }
+
+        for ($i = 0;$i<2000;$i++){
+            echo "第{$i}个充值记录开始创建\r\n";
+            $tempRow = [];
+            $tempRow['user_id'] =  $user_common[rand(0,count($user_common)-1)];
+            $tempRow['order_no'] = strtoupper(uniqid());
+            $tempRow['money'] = rand(0,1000);
+            $tempRow['type'] =rand(0,1);
+            $tempRow['created_at'] = date('Y-m-d H:i:s',strtotime("-".rand(1,365)." days"));
+
+            $tempRow['finished_at'] = date('Y-m-d H:i:s',strtotime("-".rand(1,365)." days"));
+            $tempRow['status'] = rand(0,1);
+            RechargeInfo::create($tempRow);
+        }
+
+
+
+        for ($i = 0;$i<2000;$i++){
+            echo "第{$i}个余额记录开始创建\r\n";
+            $tempRow = [];
+            $tempRow['user_id'] =  $user_common[rand(0,count($user_common)-1)];
+            $tempRow['method'] = rand(1,6);
+            $s = [-1,1];
+            $tempRow['admin_id'] = $s[rand(0,1)];
+            $tempRow['balance'] = rand(10,1000);
+            $tempRow['money'] =rand(10,1000);
+            $tempRow['detail'] = $faker_en->text;
+
+            AccountInfo::create($tempRow);
+        }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    }
+}

+ 47 - 0
app/Console/Commands/DongFangDiPicker.php

xqd
@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+
+class DongFangDiPicker extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'picker:dfd';
+
+    /**
+     * 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 mixed
+     */
+    public function handle()
+    {
+        //
+        $dfd = new \App\Http\Controllers\Service\DongFangDiPicker();
+        $dfd->startPick();
+
+
+
+    }
+}

+ 64 - 0
app/Console/Commands/UserRepair.php

xqd
@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Model\AccountInfo;
+use App\Model\DeliverInfo;
+use App\Model\RechargeInfo;
+use App\Model\UserInfo;
+use Illuminate\Console\Command;
+
+class UserRepair extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'user:reset';
+
+    /**
+     * 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 mixed
+     */
+    public function handle()
+    {
+        //TODO 10465 宣传员展示不删除
+        $ids = [9997,10025,10318,10340,10024,10572,10517,10690,10538,10533,10044,10679,10347,10142,10190,10329,11036,11460,10004,10045,10446,12000,12031];
+        foreach ($ids as $id){
+            $user = UserInfo::where(['id'=>$id])->first();
+            if(empty($user)){continue;}
+            $user_arr = [];
+            //echo '用户id:'.$id.'  角色'.$user->role.PHP_EOL;
+            if(!in_array($user->role,$user_arr)){
+                $user_arr[] = $user->role;
+            }
+            DeliverInfo::where(['user_id'=>$id])->delete();
+            AccountInfo::where(['user_id'=>$id])->delete();
+            RechargeInfo::where(['user_id'=>$id])->delete();
+            $data['account']=0;
+            if($user->role == 2){
+                $data['agent_account'] = 0;
+            }
+            UserInfo::where(['id'=>$id])->update($data);
+        }
+    }
+}

+ 185 - 0
app/Console/Commands/importMap.php

xqd
@@ -0,0 +1,185 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Model\BaseArea;
+use App\Model\BaseAreaNew;
+use Faker\Provider\Base;
+use Illuminate\Console\Command;
+use Overtrue\Pinyin\Pinyin;
+
+class importMap extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'import:map';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+    //    $data = json_decode(file_get_contents(public_path('docs/maps.txt')),true);
+
+        $total = [];
+
+//        foreach ($data['plist']['dict']['key'] as $value){
+//            $prefix = substr($value,0,6);
+//            $name = str_replace($prefix,'',$value);
+//            $total[substr($prefix,0,2)] = ['pid'=>$prefix,'name'=>$name];
+//        }
+//
+//
+//
+//
+//
+//
+//     foreach ($data['plist']['dict']['dict'] as $datum){
+//             foreach ($datum['key'] as $vv){
+//                     $g2_prefix = substr($vv,0,6);
+//                     $g2_prefix_half = substr($vv,0,2);
+//                     $name = str_replace($g2_prefix,'',$vv);
+//                     $total[substr($g2_prefix,0,4)] = ['pid'=>$g2_prefix,'name'=>$name];
+//         }
+//     }
+//
+//
+//        foreach ($data['plist']['dict']['dict'] as $datum){
+//            foreach ($datum['array'] as $vv){
+//                foreach ($vv['string'] as $vvv){
+//
+//                    $g2_prefix = substr($vvv,0,6);
+//                    $g2_prefix_half = substr($vvv,0,2);
+//                    $g2_prefix_3 = substr($vvv,0,4);
+//                    $name = str_replace($g2_prefix,'',$vvv);
+//                    $total[substr($g2_prefix,0,5)] = ['pid'=>$g2_prefix,'name'=>$name];
+//
+//                }
+//            }
+//        }
+//
+//
+//
+//
+//
+//
+//
+//        $res = BaseAreaNew::find($g2_prefix);
+//        if ($res)
+//            continue;
+//        $id = BaseAreaNew::insert([
+//            'name'=>$name,
+//            'pid'=>$total[$g2_prefix_3]['pid'],
+//            'id'=>$g2_prefix,
+//            'short_name'=>$name,
+//            'grade'=>3,
+//            'city_code'=>0,
+//            'zip_code'=>0,
+//            'merger_name'=>$total[$g2_prefix_half]['name'].','.$total[$g2_prefix_3]['name'].','.$name,
+//            'lng'=>0,
+//            'lat'=>0,
+//            'pinyin'=>'',
+//        ]);
+//
+//
+//     $dd = scandir(public_path('docs/town'));
+//
+//     $arr = array_map(function ($v){
+//         return str_replace('.json','',$v);
+//     },$dd);
+//     unset($dd);
+//     $ds = BaseAreaNew::whereIn('id',$arr)->get(['id','name','merger_name']);
+//
+//
+//     foreach ($ds as $d){
+//         $dds = json_decode(file_get_contents(public_path('docs/town/'.$d->id.'.json')),true);
+//         foreach ($dds as $k =>$v){
+//
+//             $res = BaseAreaNew::find($k);
+//        if ($res)
+//            continue;
+//        $id = BaseAreaNew::insert([
+//            'name'=>$v,
+//            'pid'=>$d->id,
+//            'id'=>$k,
+//            'short_name'=>$v,
+//            'grade'=>4,
+//            'city_code'=>0,
+//            'zip_code'=>0,
+//            'merger_name'=>$d->merger_name.','.$v,
+//            'lng'=>0,
+//            'lat'=>0,
+//            'pinyin'=>'',
+//        ]);
+//
+//        echo "{$v}:{$k} ³É¹¦µ¼ÈëÁË£¡\r\n";
+//
+//         }
+
+
+        $i = 0;
+        $maps =  BaseArea::where('relation','')->get(['pid','id']);
+
+        foreach ($maps as $map) {
+            $i++;
+            echo "Deal:{$i}\r\n";
+            $relation = ["1"];
+            $pid = $map->pid;
+            if ($pid == 1)
+                $map->update(['relation' => implode(',',$relation)]);
+
+            $relation[] = $map->id;
+            while ($pid!=1){
+                $area = BaseArea::find($pid);
+                if ($area){
+                    $relation[] = $pid;
+                    $pid = $area->pid;
+                }
+            }
+            $str = implode(',',$relation);
+
+            $map->update(['relation' => $str]);
+            echo "{$str}\r\n";
+
+
+
+
+        }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    }
+}

+ 41 - 0
app/Console/Kernel.php

xqd
@@ -0,0 +1,41 @@
+<?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();
+    }
+
+    /**
+     * Register the commands for the application.
+     *
+     * @return void
+     */
+    protected function commands()
+    {
+        $this->load(__DIR__.'/Commands');
+
+        require base_path('routes/console.php');
+    }
+}

+ 19 - 0
app/Enums/ApiEnum.php

xqd
@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Enums;
+
+use BenSampo\Enum\Enum;
+
+/**
+ * @method static static OptionOne()
+ * @method static static OptionTwo()
+ * @method static static OptionThree()
+ */
+final class ApiEnum extends Enum
+{
+
+    const FEED_RELEASE =  "feed_release_";  //发布动态
+    const FEED_ZAN =  "feed_zan_";  //动态点赞
+    const FRIEND_ACTION =  "friend_action_";  //好友操作
+
+}

+ 41 - 0
app/Exceptions/Handler.php

xqd
@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Exceptions;
+
+use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use Throwable;
+
+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) {
+            //
+        });
+    }
+}

+ 10 - 0
app/Exceptions/SmsException.php

xqd
@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Exceptions;
+
+use Exception;
+
+class SmsException extends Exception
+{
+    //
+}

+ 9 - 0
app/Exceptions/TencentImAccountException.php

xqd
@@ -0,0 +1,9 @@
+<?php
+
+
+namespace App\Exceptions;
+use Exception;
+class TencentImAccountException extends Exception
+{
+
+}

+ 12 - 0
app/Exceptions/TencentImException.php

xqd
@@ -0,0 +1,12 @@
+<?php
+
+
+namespace App\Exceptions;
+
+
+use Exception;
+
+class TencentImException extends Exception
+{
+
+}

+ 10 - 0
app/Exceptions/TencentImFriendException.php

xqd
@@ -0,0 +1,10 @@
+<?php
+
+
+namespace App\Exceptions;
+
+use Exception;
+class TencentImFriendException extends Exception
+{
+
+}

+ 10 - 0
app/Exceptions/TencentImGroupException.php

xqd
@@ -0,0 +1,10 @@
+<?php
+
+
+namespace App\Exceptions;
+
+use Exception;
+class TencentImGroupException extends Exception
+{
+
+}

+ 153 - 0
app/Helper/AttachmentHelper.php

xqd
@@ -0,0 +1,153 @@
+<?php
+namespace App\Helper;
+
+use FFMpeg;
+use Illuminate\Http\Request;
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Log;
+use OSS\OssClient;
+use Symfony\Component\HttpFoundation\File\Exception\FileException;
+use App\Services\Base\ErrorCode;
+use App\Models\BaseAttachment;
+
+trait AttachmentHelper
+{
+    /**
+     * @param Request $request
+     * @param $key
+     * @param string $tag
+     * @param float|int $size
+     * @param array $mimeType
+     * @return array|mixed
+     * @throws \OSS\Core\OssException
+     */
+    public function uploadAttachment(Request $request, $key, $tag = 'files', $size = 200 * 1024 * 1024, array $mimeType = []) {
+        if ($request->hasFile($key)) {
+            $files = $request->file($key);
+            if ($files === null) {
+                throw new \Exception(trans('api.ATTACHMENT_FILE_NULL'));
+            }
+            if ($files instanceof UploadedFile) {
+                $files = [$files];
+            }
+
+            $result = [];
+            foreach ($files as $idx => $file) {
+                if (!$file->isValid()) {
+                    throw new \Exception(trans('api.ATTACHMENT_TYPE_ERROR'));
+                    continue;
+                }
+                $fileSize = $file->getSize();
+                if ($fileSize > $size) {
+                    throw new \Exception(trans('api.ATTACHMENT_SIZE_EXCEEDED'));
+                    continue;
+                }
+                $fileMimeType = $file->getMimeType();
+                if (!empty($mimeType) && !in_array($fileMimeType, $mimeType)) {
+                    throw new \Exception(trans('api.ATTACHMENT_TYPE_ERROR'));
+                    continue;
+                }
+                $clientName = $file->getClientOriginalName();
+                $md5 = md5($clientName . time());
+                //因为 $md5 32 位字符太长,创建群聊头像失败
+                $md5_filename = substr($md5, 0, 20) . '.' . $file->getClientOriginalExtension();
+                try {
+                    //本地上传
+                    if(env('FILESYSTEM_DRIVER')=='local'){
+                        $rel_path = '/upload/' . $tag . '/' . date('Ymd');
+                        $path = public_path() . $rel_path;
+                        if (!file_exists($path)) {
+                            if (!@mkdir($path, 0755, true)) {
+                                throw new \Exception(trans('api.ATTACHMENT_MAKE_FOLDER_ERROR'));
+                            }
+                        }
+
+                        $file->move($path, $md5_filename);
+
+                        $real_path = $path . '/' . $md5_filename;
+                        $url_path = $rel_path . '/' . $md5_filename;
+
+                        if ($fileMimeType == "video/mp4" || $fileMimeType == "video/quicktime") {
+                            $ffmpeg = FFMpeg\FFMpeg::create(array(
+                                'ffmpeg.binaries'  => '/usr/bin/ffmpeg',
+                                'ffprobe.binaries' => '/usr/bin/ffprobe'
+                            ));
+                            $video = $ffmpeg->open($real_path);
+                            $vpath = public_path() . '/upload/vpic/';
+                            if (!file_exists($vpath)) {
+                                if (!@mkdir($vpath, 0755, true)) {
+                                    return trans('api.ATTACHMENT_MAKE_FOLDER_ERROR');
+                                }
+                            }
+                            $pic = $vpath.$md5.'.jpg';
+                            $video
+                                ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(1))
+                                ->save( $pic );
+                        }
+
+                        $result[$idx] = 'https://'.$_SERVER['HTTP_HOST'].$url_path;
+                    }elseif (env('FILESYSTEM_DRIVER')=='oss'){
+                        //获取上传图片的临时地址
+                        $tmppath = $file->getRealPath();
+                        //生成文件名
+                        $fileName = rand(100, 999) . time() . date('ymd') . '.' . $file->getClientOriginalExtension();
+                        $pathName = 'golf/' . date('Y-m/d') . '/' . $fileName;
+                        //上传图片到阿里云OSS
+                        $oss = new OssClient(env('ALI_OSS_ACCESS_ID'), env('ALI_OSS_ACCESS_KEY'), env('ALI_OSS_ENDPOINT'));
+                        $res = $oss->uploadFile(env('ALI_OSS_BUCKET'), $pathName, $tmppath, ['ContentType' => $file->getClientMimeType()]);
+                        $url = $res['info']['url'];
+                        $result[$idx] = $url;
+                    }
+                    $attachment = new BaseAttachment();
+                    $attachment->name = $clientName;
+                    $attachment->md5  = $md5;
+                    $attachment->path = $url;
+                    $attachment->url  = $url;
+                    $attachment->size = $fileSize;
+                    $attachment->file_type = $fileMimeType;
+                    if (!$attachment->save()) {
+                        @unlink($url);
+                        throw new \Exception(trans('api.ATTACHMENT_SAVE_ERROR'));
+                    }
+                } catch (FileException $e) {
+                    throw new \Exception(trans('api.ATTACHMENT_UPLOAD_INVALID'));
+                }
+            }
+            if (count($result) == 1) {
+                return array_shift($result);
+            }
+            return $result;
+        } else {
+            throw new \Exception(trans('api.ATTACHMENT_UPLOAD_INVALID'));
+        }
+
+    }
+
+    /**
+     * 删除附件
+     *
+     * @param $md5 string 删除文件的md5码
+     * @return int 错误码or 0(成功)
+     */
+    public function deleteAttachment($md5) {
+        $attachment = BaseAttachment::where(['md5' => $md5])->first();
+        if (!$attachment) {
+            return ErrorCode::ATTACHMENT_NOT_EXIST;
+        }
+        if (file_exists($attachment->path)) {
+            if (@unlink($attachment->path)) {
+                if ($attachment->delete()) {
+                    return 0;
+                } else {
+                    return ErrorCode::ATTACHMENT_RECORD_DELETE_FAILED;
+                }
+            } else {
+                return ErrorCode::ATTACHMENT_DELETE_FAILED;
+            }
+        } else {
+            return ErrorCode::ATTACHMENT_NOT_EXIST;
+        }
+
+    }
+
+}

+ 335 - 0
app/Helper/function.php

xqd
@@ -0,0 +1,335 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: pijh
+ * Date: 2017/8/20
+ * Time: 00:33
+ */
+
+
+use Illuminate\Support\Arr;
+use \Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Storage;
+
+if (! function_exists('user_admin_config')) {
+    function user_admin_config($key = null, $value = null)
+    {
+        $session = session();
+
+        if (! $config = $session->get('admin.config')) {
+            $config = config('admin');
+
+            $config['lang'] = config('app.locale');
+        }
+
+        if (is_array($key)) {
+            // 保存
+            foreach ($key as $k => $v) {
+                Arr::set($config, $k, $v);
+            }
+
+            $session->put('admin.config', $config);
+
+            return;
+        }
+
+        if ($key === null) {
+            return $config;
+        }
+
+        return Arr::get($config, $key, $value);
+    }
+}
+
+//生成随机码
+function create_invite_code() {
+    $code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+    $rand = $code[rand(0,25)]
+        .strtoupper(dechex(date('m')))
+        .date('d')
+        .substr(time(),-5)
+        .substr(microtime(),2,5)
+        .sprintf('%02d',rand(0,99));
+    for(
+        $a = md5( $rand, true ),
+        $s = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+        $d = '',
+        $f = 0;
+        $f < 6;
+        $g = ord( $a[ $f ] ),
+        $d .= $s[ ( $g ^ ord( $a[ $f + 8 ] ) ) - $g & 0x1F ],
+        $f++
+    );
+    return $d;
+}
+
+/**
+ * 时间格式化(时间戳)
+ * @param $ptime
+ * @return false|string
+ */
+function uc_time_ago($ptime)
+{
+    $lang = request()->header('lang','zh');
+
+    date_default_timezone_set('PRC');
+    $etime = time() - $ptime;
+
+    switch ($etime) {
+        case $etime <= 60:
+            $msg = trans('api.JUST_NOW');
+            break;
+        case $etime > 60 && $etime <= 60 * 60:
+            $msg = floor($etime / 60) . trans('api.MINUTES_AGO');
+            break;
+        case $etime > 60 * 60 && $etime <= 24 * 60 * 60:
+            $msg = date('Ymd', $ptime) == date('Ymd', time()) ? trans('api.TODAY').' ' . date('H:i', $ptime) : trans('api.YESTERDAY').' ' . date('H:i', $ptime);
+            break;
+//        case $etime > 24 * 60 * 60 && $etime <= 2 * 24 * 60 * 60:
+//            $msg = date('Ymd', $ptime) + 1 == date('Ymd', time()) ? trans('api.YESTERDAY').' ' . date('H:i', $ptime) : '前天 ' . date('H:i', $ptime);
+//            break;
+//        case $etime > 2 * 24 * 60 * 60 && $etime <= 12 * 30 * 24 * 60 * 60:
+//            $msg = date('Y', $ptime) == date('Y', time()) ? date('m-d H:i', $ptime) : date('Y-m-d H:i', $ptime);
+//            break;
+        default:
+            $msg = date('Y-m-d H:i', $ptime);
+    }
+    return $msg;
+}
+
+
+
+/**
+ * 获取IP地址归属地
+ * @param $ip
+ * @return string
+ */
+function get_ip_address($ip)
+{
+    if ('127.0.0.1' == $ip) return 'Localhost';
+    $url = 'http://ip.taobao.com/service/getIpInfo.php?ip=' . $ip;
+    $ch = curl_init($url);
+    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取数据返回
+    $location = curl_exec($ch);
+    $location = json_decode($location, true);
+    curl_close($ch);
+
+    if (false != $location && 0 === $location['code']) {
+        return $location['data']['region'] . $location['data']['city'] . $location['data']['county'] . '・' . $location['data']['isp'];
+    } else {
+        return 'unknown';
+    }
+
+}
+
+/**
+ * 递归查询获取分类树结构
+ * @param $data
+ * @param int $pid
+ * @param int $level
+ * @param array $tree
+ * @param string $pidField
+ * @param string $showField
+ * @return array
+ */
+function get_tree_list(&$data, $pid = 0, $level = 0, &$tree = [], $pidField = 'pid', $showField = 'name')
+{
+    foreach ($data as $key => &$value) {
+        if ($value[$pidField] == $pid) {
+            $value['level'] = $level;
+            $value['level'] && $value[$showField] = '&nbsp;' . $value[$showField];
+            $value[$showField] = str_repeat('ㅡ', $value['level']) . $value[$showField];
+            $tree[] = $value;
+            unset($data[$key]);
+            get_tree_list($data, $value['id'], $level + 1, $tree);
+        }
+    }
+    unset($value);
+
+    return $tree;
+}
+
+/**
+ * 递归查询获取分类树结构带child
+ * @param $data
+ * @param int $pid
+ * @param int $level
+ * @param string $pidField
+ * @return array
+ */
+function get_tree_list_with_child(&$data, $pid = 0, $level = 0, $pidField = 'pid')
+{
+    $tree = [];
+    foreach ($data as $key => &$value) {
+        if ($value[$pidField] == $pid) {
+            $value['level'] = $level;
+            $value['child'] = get_tree_list_with_child($data, $value['id'], $level + 1);
+            $tree[] = $value;
+            unset($data[$key]);
+        }
+    }
+    unset($value);
+
+    return $tree;
+}
+
+/**
+ * 打印sql语句,在sql语句之前调用
+ */
+function dump_sql()
+{
+    \DB::listen(function ($query) {
+        $bindings = $query->bindings;
+        $i = 0;
+        $rawSql = preg_replace_callback('/\?/', function ($matches) use ($bindings, &$i) {
+            $item = isset($bindings[$i]) ? $bindings[$i] : $matches[0];
+            $i++;
+            return gettype($item) == 'string' ? "'$item'" : $item;
+        }, $query->sql);
+        echo $rawSql . "\n<br /><br />\n";
+    });
+}
+
+function create_guid($namespace = null)
+{
+    static $guid = '';
+    $uid = uniqid("", true);
+
+    $data = $namespace;
+    $data .= $_SERVER ['REQUEST_TIME'];     // 请求那一刻的时间戳
+    $data .= $_SERVER ['HTTP_USER_AGENT'];  // 获取访问者在用什么操作系统
+    $data .= $_SERVER ['SERVER_ADDR'];      // 服务器IP
+    $data .= $_SERVER ['SERVER_PORT'];      // 端口号
+    $data .= $_SERVER ['REMOTE_ADDR'];      // 远程IP
+    $data .= $_SERVER ['REMOTE_PORT'];      // 端口信息
+
+    $hash = strtoupper(hash('ripemd128', $uid . $guid . md5($data)));
+    $guid = substr($hash, 0, 8);
+
+    return $guid;
+}
+
+function create_order_number()
+{
+    return date('Ymd') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
+}
+
+/**
+ * curl 请求
+ * @param $url
+ * @param null $header
+ * @param null $data
+ * @return mixed
+ */
+function curlRequest($url, $header = null, $data = null)
+{
+    $ch = curl_init();
+    curl_setopt($ch, CURLOPT_URL, $url);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
+    curl_setopt($ch, CURLOPT_HEADER, 1);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+    if ($data) {
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+    }
+    if ($header) {
+        curl_setopt($ch, CURLOPT_HEADER, $header);
+    }
+    $ret = curl_exec($ch);
+    curl_close($ch);
+
+    return $ret;
+}
+
+/**
+ * 数字金额转换成中文大写金额的函数
+ * @param $num
+ * @return string
+ */
+function cny($num)
+{
+
+    $c1 = "零壹贰叁肆伍陆柒捌玖";
+    $c2 = "分角元拾佰仟万拾佰仟亿";
+    $num = round($num, 2);
+    $num = $num * 100;
+    if (strlen($num) > 10) {
+        return "数据太长,没有这么大的钱吧,检查下";
+    }
+    $i = 0;
+    $c = "";
+    while (1) {
+        if ($i == 0) {
+            $n = substr($num, strlen($num) - 1, 1);
+        } else {
+            $n = $num % 10;
+        }
+        $p1 = substr($c1, 3 * $n, 3);
+        $p2 = substr($c2, 3 * $i, 3);
+        if ($n != '0' || ($n == '0' && ($p2 == '亿' || $p2 == '万' || $p2 == '元'))) {
+            $c = $p1 . $p2 . $c;
+        } else {
+            $c = $p1 . $c;
+        }
+        $i = $i + 1;
+        $num = $num / 10;
+        $num = (int)$num;
+        if ($num == 0) {
+            break;
+        }
+    }
+    $j = 0;
+    $slen = strlen($c);
+    while ($j < $slen) {
+        $m = substr($c, $j, 6);
+        if ($m == '零元' || $m == '零万' || $m == '零亿' || $m == '零零') {
+            $left = substr($c, 0, $j);
+            $right = substr($c, $j + 3);
+            $c = $left . $right;
+            $j = $j - 3;
+            $slen = $slen - 3;
+        }
+        $j = $j + 3;
+    }
+
+    if (substr($c, strlen($c) - 3, 3) == '零') {
+        $c = substr($c, 0, strlen($c) - 3);
+    }
+    if (empty($c)) {
+        return "零元整";
+    } else {
+        return $c . "整";
+    }
+}
+
+if (!function_exists('valid_url')) {
+    /**
+     * 路径助手函数
+     * @param $url
+     * @param null $disk_name
+     * @param false $temp
+     * @param null|DateTimeInterface  $expiration
+     * @return string|null
+     */
+    function valid_url($url, $disk_name = null, $temp = false, $expiration = null)
+    {
+        if (is_null($url)) {
+            return null;
+        }
+
+        if (filter_var($url, FILTER_VALIDATE_URL)) {
+            return $url;
+        }
+
+        if ($temp) {
+            $expiration = $expiration ?: now()->addMinutes(30);
+            return Storage::disk($disk_name)->temporaryUrl($url, $expiration);
+        }
+
+        return Storage::disk($disk_name)->url($url);
+    }
+}
+

+ 13 - 0
app/Http/Controllers/Controller.php

xqd
@@ -0,0 +1,13 @@
+<?php
+
+namespace App\Http\Controllers;
+
+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;
+}

+ 76 - 0
app/Http/Controllers/V1/AttachmentController.php

xqd
@@ -0,0 +1,76 @@
+<?php
+
+namespace App\Http\Controllers\V1;
+
+use Illuminate\Http\Request;
+use App\Services\Base\Attachment;
+use App\Services\Base\ErrorCode;
+use App\Helper\AttachmentHelper;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Facades\Validator;
+
+
+class AttachmentController extends Controller
+{
+    use AttachmentHelper;
+
+    /**
+     *    可能出现的错误代码:
+     *    200     SAVE_USER_FAILED                保存用户数据失败
+     *    201     ATTACHMENT_MKDIR_FAILED         创建附件目录失败
+     *    202     ATTACHMENT_UPLOAD_INVALID       上传附件文件无效
+     *    203     ATTACHMENT_SAVE_FAILED          保存附件失败
+     *    204     ATTACHMENT_MOVE_FAILED          移动附件失败
+     *    205     ATTACHMENT_DELETE_FAILED        删除附件文件失败
+     *    206     ATTACHMENT_RECORD_DELETE_FAILED 删除附件记录失败
+     *    1000    CLIENT_WRONG_PARAMS             传入参数不正确
+     *    1101    INCORRECT_VERIFY_CODE           输入验证码错误
+     *    1105    USER_DOES_NOT_EXIST             用户不存在
+     *    1200    ATTACHMENT_UPLOAD_FAILED        附件上传失败
+     *    1201    ATTACHMENT_SIZE_EXCEEDED        附件大小超过限制
+     *    1202    ATTACHMENT_MIME_NOT_ALLOWED     附件类型不允许
+     *    1203    ATTACHMENT_NOT_EXIST            附件不存在
+     */
+    public function upload(Request $request) {
+        try {
+            $validator = Validator::make($request->all(),
+                [
+                    'tag'  => 'required|alpha_dash',
+                ], [
+                    'tag.required'      => 'tag必填',
+                    'tag.alpha_dash'    => 'tag只能为字母数字中/下划线',
+                ]
+            );
+            if ($validator->fails()) {
+                throw new \Exception($validator->messages()->first());
+            }
+            $result = $this->uploadAttachment($request, $request->input('file'), $request->input('tag'), 10 * 1024 * 1024, [
+                'image/jpeg',
+                'image/png',
+                'image/gif',
+                'video/mp4',
+            ]);
+        }catch (\Exception $exception){
+            return $this->error($exception->getMessage());
+        }
+        return $this->success(['file' => $result],0,trans("api.UPLOAD_SUCCESS"));
+    }
+
+    /**
+     * @api {post} /api/attachment/delete/ 删除文件(图片)
+     * 可能出现的错误代码:
+     *    205     ATTACHMENT_DELETE_FAILED        删除附件文件失败
+     *    206     ATTACHMENT_RECORD_DELETE_FAILED 删除附件记录失败
+     *    1203    ATTACHMENT_NOT_EXIST            附件不存在
+     */
+    public function delete($url, Request $request) {
+        $lang = request('lang','cn');
+        $result = $this->deleteAttachment($url);
+        if ($result === 0) {
+            return json(200,trans("api.Successfully",[],$lang),['result' => true]);
+        } else {
+            return json(501, trans("api.Fail",[],$lang));
+        }
+    }
+
+}

+ 433 - 0
app/Http/Controllers/V1/AuthController.php

xqd
@@ -0,0 +1,433 @@
+<?php
+
+namespace App\Http\Controllers\V1;
+
+use App\Models\Job;
+use App\Models\User;
+use App\Models\UserBlacklistModel;
+use App\Models\UserExtra;
+use App\Models\UserInfoModel;
+use App\Models\UserInviteLog;
+use App\Models\UserLookModel;
+use App\Models\UserVipLimit;
+use App\Models\EmailCode;
+use App\Services\Api\UserService;
+use App\Services\JPushService;
+use App\Services\SmsServer;
+use App\Services\TencentImAccountService;
+use App\Traits\TencentIm;
+use Cache;
+use GuzzleHttp\Client;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\App;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Redis;
+use Illuminate\Support\Facades\Validator;
+use Laravel\Socialite\Facades\Socialite;
+use PHPUnit\Util\Exception;
+
+
+class AuthController extends Controller
+{
+    use TencentIm;
+    protected $tencentImAccountService;
+
+    public function __construct(TencentImAccountService $tencentImAccountService)
+    {
+        $this->tencentImAccountService = $tencentImAccountService;
+    }
+
+    //手机(注册/登录)
+    public function interByMobile(Request $request)
+    {
+        try {
+            $validator = Validator::make($request->all(), [
+                'mobile' => 'required',
+                'smsCode' => 'required',
+                //'verifyKey' => 'required',
+            ], [
+                'mobile.required' => trans('api.PLEASE_ENTER_MOBILE_PHONE_NUMBER'),
+                'mobile.regex' => trans('api.MOBILE_PHONE_NUMBER_FORMAT_ERROR'),
+                'smsCode.required' => trans('api.VERIFICATION_CODE_NOT_NULL'),
+                //'verifyKey.required'=> trans('api.KEY_NOT_NULL'),
+            ]);
+            if ($validator->fails()) {
+                throw new Exception($validator->messages()->first());
+            }
+            //手机验证码验证
+            //SmsServer::checkSmsCodeByVerifyKey($request->verifyKey, $request->smsCode);
+
+            //如果登录类型和 openid 不为空
+            $type = $request->type;
+            if (isset($type) && !empty($type)) {
+                if (!$user = User::where(['mobile' => $request->mobile])->whereNull('deleted_at')->first()) {
+                    throw new Exception(trans('api.NOT_EXIST'));
+                }
+                if ($type == 'weixin') {
+                    if ($user->wx_openid != '') {
+                        throw new Exception(trans('api.HAD_BIND'));
+                    }
+                    $user->wx_openid = $request->openid;
+                    $user->save();
+                } elseif ($type == 'facebook') {
+                    if ($user->fb_openid != '') {
+                        throw new Exception(trans('api.HAD_BIND'));
+                    }
+                    $user->fb_openid = $request->openid;
+                    $user->save();
+                } elseif ($type == 'apple') {
+                    if ($user->apple_openid != '') {
+                        throw new Exception(trans('api.HAD_BIND'));
+                    }
+                    $user->apple_openid = $request->openid;
+                    $user->save();
+                }
+            }
+
+            $data = self::doLogin($request->mobile, 'mobile', $request->post('jpush_reg_id', null));
+
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+
+        return $this->success($data);
+    }
+
+    //登录操作
+    public function doLogin($account, $type = null, $jpush_reg_id = null)
+    {
+        if (!$user = self::isUserExist($account, $type)) { //新用户注册
+            $user = self::addNewUser($account, $type);
+            $is_have_pwd = 0;
+            $is_have_email = 0;
+        } else {
+            //老用户登录
+            $is_have_pwd = $user->password ? 1 : 0;
+            $is_have_email = $user->password ? 1 : 0;
+        }
+        if (!$user->tencent_im_user_id) {
+            $user->tencent_im_user_id = $this->tencentImAccountService->accountImport($user);
+        }
+        if (!empty($jpush_reg_id)) {
+            //清除登陆过本设备的账号设备id
+            User::query()->where('jpush_reg_id', $jpush_reg_id)->update(['jpush_reg_id' => '']);
+            //当前登录用户绑定设备
+            $user->jpush_reg_id = $jpush_reg_id;
+            //清除别名
+            JPushService::deleteAlias('user_id_' . $user->id);
+            //设置极光推送别名
+            JPushService::updateAlias($user->jpush_reg_id, 'user_id_' . $user->id);
+        }
+        if ($name = Redis::get($account)) {
+            $user->name = $name;
+        }
+        $user->online = 1;
+        $user->jpush_voice = $user->jpush_voice ?: 'chat_auto.caf';
+        $user->last_login_time = date("Y-m-d H:i:s");
+        $user->last_login_ip = request()->ip();
+        if (!$user->save()) {
+            return $this->error(trans('api.DATA_SAVE_FALSE'));
+        }
+        $token = Auth::guard('api')->fromUser($user);
+        $user_info = UserService::getUserInfo($user->id);
+        $userSig = $this->getUserSig($user->tencent_im_user_id);
+
+        return [
+            'is_have_pwd' => $is_have_pwd, //0没密码,1有密码
+            'is_have_email' => $is_have_email, //0没密码,1有密码
+            'user_info' => $user_info,
+            'token' => "Bearer " . $token,
+            'userSig' => $userSig,
+        ];
+    }
+
+    //用户是否存在
+    public function isUserExist($account, $type)
+    {
+        $user = User::where([$type => $account])->whereNull('deleted_at')->first();
+        if (!$user) {
+            return false;
+        }
+        return $user;
+    }
+
+    //新增用户
+    public function addNewUser($account, $type)
+    {
+        $user = App::make('getUserInstance');
+
+        switch ($type) {
+            case 'mobile';
+                $user->mobile = $account;
+                break;
+            case 'email';
+                $user->email = $account;
+                break;
+            case 'wx_openid';
+                $user->wx_openid = $account;
+                break;
+            case 'fb_openid';
+                $user->fb_openid = $account;
+                break;
+            case 'apple_openid';
+                $user->apple_openid = $account;
+                break;
+        }
+        //给新用户进行基本信息初始化
+        $user->name = 'Euser' . mb_substr($account, 0, 6);
+        $user->avatar = 'https://easygolf.oss-ap-southeast-6.aliyuncs.com/golf/2022-03/18/b92858ba88d3cee76590.png';
+        $user->password = $account;
+        $user->jpush_voice = 'chat_auto.caf';
+        $user->register_ip = request()->ip();
+        DB::beginTransaction();
+        try {
+            if (!$user->save() || !self::addUserExtrasRecord($user->id)) {
+                return false;
+            }
+            DB::commit();
+        } catch (Exception $exception) {
+            DB::rollBack();
+            return $this->error($exception->getMessage());
+        }
+        return User::where([$type => $account])->first();
+    }
+
+    //邮箱 (注册/登录)
+    public function interByEmail(Request $request)
+    {
+        try {
+            $params = $request->all();
+            $validator = Validator::make($params, [
+                'email' => 'bail|required|email',
+                'code' => 'required',
+            ], [
+                'email.required' => trans('api.PLEASE_ENTER_EMAIL'),
+                'email.email' => trans('api.MAILBOX_FORMAT_ERROR'),
+                'code.required' => trans('api.VERIFICATION_CODE_NOT_NULL'),
+            ]);
+            if ($validator->fails()) {
+                throw new Exception($validator->messages()->first());
+            }
+            if (!self::isEmailCodeRight($request->email, $request->code)) {
+                return $this->error(trans('api.VERIFICATION_CODE_ERROR'));
+            }
+
+            //如果登录类型和 openid 不为空
+            $type = $request->type;
+            if (isset($type) && !empty($type)) {
+                if (!$user = User::where(['email' => $request->email])->whereNull('deleted_at')->first()) {
+                    throw new Exception(trans('api.NOT_EXIST'));
+                }
+                if ($type == 'weixin') {
+                    if ($user->wx_openid != '') {
+                        throw new Exception(trans('api.HAS_BIND_WEIXIN'));
+                    }
+                    $user->wx_openid = $request->openid;
+                    $user->save();
+                } elseif ($type == 'facebook') {
+                    if ($user->fb_openid != '') {
+                        throw new Exception(trans('api.HAS_BIND_FACEBOOK'));
+                    }
+                    $user->fb_openid = $request->openid;
+                    $user->save();
+                }
+            }
+            $data = $this->doLogin($request->email, 'email', $request->post('jpush_reg_id', null));
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+
+        return $this->success($data);
+    }
+
+    //判断邮箱验证码
+    protected function isEmailCodeRight($email, $code)
+    {
+        $result = EmailCode::where('channel', 'email')
+            ->where('account', $email)
+            ->where('code', $code)
+            ->where('state', 0)
+            ->orderBy('id', 'desc')
+            ->first();
+        if (!$result) {
+            return false;
+        }
+        $verify = EmailCode::find($result->id);
+        $verify->state = 1; //验证通过就失效
+        $verify->save();
+
+        return true;
+    }
+
+    //账号密码登录
+    public function login(Request $request)
+    {
+        try {
+            $account = $request->account;
+            $password = $request->password;
+
+            if (!$user = User::where(['mobile' => $account])->orWhere(['email' => $account])->whereNull('deleted_at')->first()) {
+                throw new Exception(trans('api.NOT_EXIST'));
+            }
+            if (!$user->password) {
+                throw new Exception(trans('api.PASSWORD_NOT_SET'));
+            }
+            $credentials1 = ['mobile' => $account, 'password' => $password];
+            $credentials2 = ['email' => $account, 'password' => $password];
+
+            if (!auth('api')->attempt($credentials1) && !auth('api')->attempt($credentials2)) {
+                throw new Exception(trans('api.ACCOUNT_OR_PASSWORD_ERROR'));
+            }
+            $type = strpos($account, '@') ? 'email' : 'mobile';
+            $data = $this->doLogin($account, $type, $request->post('jpush_reg_id', null));
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+        return $this->success($data);
+    }
+
+    //短信验证码登录
+    public function loginByCode(Request $request)
+    {
+        try {
+            if (!$user = User::query()->where(['mobile' => $request->mobile])->whereNull('deleted_at')->first()) {
+                throw new Exception(trans('api.NOT_EXIST'));
+            }
+            //手机验证码验证
+            SmsServer::checkSmsCodeByVerifyKey($request->verifyKey, $request->smsCode);
+            //如果登录类型和 openid 不为空
+            $type = $request->type;
+            if (isset($type) && !empty($type)) {
+                if ($type == 'weixin') {
+                    if ($user->wx_openid != '') {
+                        throw new Exception(trans('api.HAS_BIND_WEIXIN'));
+                    }
+                    $user->wx_openid = $request->openid;
+                    $user->save();
+                } elseif ($type == 'facebook') {
+                    if ($user->fb_openid != '') {
+                        throw new Exception(trans('api.HAS_BIND_FACEBOOK'));
+                    }
+                    $user->fb_openid = $request->openid;
+                    $user->save();
+                }
+            }
+            $data = $this->doLogin($request->mobile, 'mobile', $request->post('jpush_reg_id', null));
+        } catch (\Exception $exception) {
+            return $this->error($exception);
+        }
+        return $this->success($data);
+    }
+
+    //第三方授权跳转
+    public function authRedirect(Request $request)
+    {
+        $type = $request->get('type', 'weixin');
+        return Socialite::driver($type)->redirect();
+    }
+
+    //微信授权登录
+    public function authLogin(Request $request)
+    {
+        try {
+            $github_user = Socialite::driver('weixin')->stateless()->user();
+            $account = $github_user->getId();
+            $data = $this->doLogin($account, 'wx_openid', $request->post('jpush_reg_id', null));
+            $data['need_binding'] = 0;
+        } catch (\Exception $exception) {
+            Log::error('微信 登录出错~' . $exception->getMessage() . '---' . $exception->getFile() . '---' . $exception->getLine());
+            //return $this->error(trans('api.NETWORK_ERROR'));
+        }
+        return $this->success($data);
+    }
+
+    //facebook授权登录
+    public function facebookLogin(Request $request)
+    {
+        try {
+            $token = $request->input('token');
+            $result = Http::get('https://graph.facebook.com/me', ['access_token' => $token])->throw()->json();
+            $data = $this->doLogin($result['id'], 'fb_openid', $request->post('jpush_reg_id', null));
+            $data['need_binding'] = 0;
+            Redis::setex($result['id'], 15, $result['name']); //把名字缓存
+        } catch (\Exception $exception) {
+            Log::error('facebook 登录出错~' . $exception->getMessage() . '---' . $exception->getFile() . '---' . $exception->getLine());
+            //return $this->error(trans('api.NETWORK_ERROR'));
+        }
+
+        return $this->success($data);
+    }
+
+    //苹果授权登录
+    public function appleLogin(Request $request)
+    {
+        try {
+            $appleOpenId = $request->apple_openid;
+            $data = $this->doLogin($appleOpenId, 'apple_openid', $request->post('jpush_reg_id', null));
+            $data['need_binding'] = 0;
+        } catch (\Exception $exception) {
+            Log::error('苹果登录出错~' . $exception->getMessage() . '---' . $exception->getFile() . '---' . $exception->getLine());
+            //return $this->error(trans('api.NETWORK_ERROR'));
+        }
+        return $this->success($data);
+    }
+
+    //忘记密码
+    public function forgetPassword(Request $request)
+    {
+        try {
+            $account = $request->account;
+            if ($request->password != $request->confirm_password) {
+                throw new Exception(trans('api.TWO_PASSWORD_IS_NOT_SAME'));
+            }
+            if (strpos($account, '@')) { //邮箱
+                if (!self::isEmailCodeRight($account, $request->code)) {
+                    throw new Exception(trans('api.VERIFY_CODE_FALSE'));
+                }
+                $type = 'email';
+            } else { //短信
+                SmsServer::checkSmsCodeByVerifyKey($request->verifyKey, $request->code);
+                $type = 'mobile';
+            }
+            $user = User::query()->where('mobile', $account)->orWhere('email', $account)->whereNull('deleted_at')->first();
+            $user->password = $request->password;
+            if (!$user->save()) {
+                throw new Exception(trans('api.DATA_SAVE_FALSE'));
+            }
+
+            $data = $this->doLogin($account, $type, $request->post('jpush_reg_id', null));
+
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+        return $this->success($data);
+    }
+
+    //退出
+    public function logout()
+    {
+        $user = auth('api')->user();
+
+        //清空极光别名
+        JPushService::updateAlias($user->jpush_reg_id, '');
+        $user->online = 0;
+        $user->save();
+
+        auth('api')->logout();
+        return $this->success();
+    }
+
+    //在user_extras 新增一条用户记录
+    public static function addUserExtrasRecord($user_id)
+    {
+        $userExtras = App::make('getUserExtraInstance');
+        $userExtras->user_id = $user_id;
+        if (!$userExtras->save()) {
+            return false;
+        }
+        return true;
+    }
+}

+ 34 - 0
app/Http/Controllers/V1/BaseConfigController.php

xqd
@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Controllers\V1;
+
+use App\Models\BaseConfig;
+use App\Models\SystemConfig;
+
+class BaseConfigController extends Controller
+{
+    /**
+     * UserController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->middleware('check', ['except' => ['index']]);
+    }
+
+    /**
+     * 获取配置
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function index()
+    {
+        $group = request('group');
+        if (!$group) {
+            return $this->error(trans("api.PARAMS_ERROR"));
+        }
+        $key = request('key', '');
+        $arr = SystemConfig::get($group, $key, "");
+
+        return $this->success($arr);
+    }
+}

+ 336 - 0
app/Http/Controllers/V1/ChatTeamController.php

xqd
@@ -0,0 +1,336 @@
+<?php
+
+
+namespace App\Http\Controllers\V1;
+
+use App\Exceptions\TencentImException;
+use App\Models\ChatTeam;
+use App\Models\User;
+use App\Services\Api\UserService;
+use App\Services\TencentImGroupService;
+use GuzzleHttp\Exception\GuzzleException;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+use PHPUnit\Util\Exception;
+use Illuminate\Support\Facades\Log;
+
+class ChatTeamController extends Controller
+{
+    private $groupService;
+
+    public function __construct()
+    {
+        parent::__construct();
+        $this->groupService = TencentImGroupService::getInstance();;
+        $this->user = auth('api')->user();
+    }
+
+    //创建群聊
+    public function createGroup(Request $request)
+    {
+        try {
+            DB::beginTransaction();
+            $user = $this->user;
+            $ids = $request->ids;
+            if (empty($ids) || !is_array($ids)) {
+                throw new Exception(trans('api.PARAMS_ERROR'));
+            }
+            $group_name = 'Group';  //组装群名
+            $data = $this->groupService->getUsersAndAvatar($ids); //获取群头像和 users
+
+            $group_info['group_name'] = $group_name;
+            $group_info['Owner_Account'] = $user->tencent_im_user_id;
+            $group_info['member_list'] = $data['users'];
+            $group_info['avatar'] = $data['file_avatar'];
+            $res = $this->groupService->createGroup($group_info);
+
+            $chatTeam = new ChatTeam();
+            $chatTeam->user_id = $user->id;
+            $chatTeam->Owner_Account = $user->tencent_im_user_id;
+            $chatTeam->group_name = $group_name;
+            $chatTeam->GroupId = $res['GroupId'];
+            $chatTeam->FaceUrl = $data['file_avatar'];
+            $chatTeam->MaxMemberCount = 20;
+            $chatTeam->ApplyJoinOption = 'FreeAccess';
+            $chatTeam->save();
+
+            //发一条群公告,目的是为了让群自动发一条消息
+            $initData['GroupId'] = $res['GroupId'];
+            $initData['Introduction'] = 'Hello everyone!, Welcome to join us!';
+            $this->groupService->modifyGroupBaseInfo($initData);
+
+            DB::commit();
+        } catch (GuzzleException $e) {
+            DB::rollBack();
+            Log::error('创建群聊:GuzzleException:' . $e->getMessage());
+
+            return $this->error(trans('api.NETWORK_ERROR'));
+        }
+
+        return $this->success($res);
+    }
+
+    //获取用户群聊列表
+    public function getUserGroup()
+    {
+        try {
+            $user = $this->user;
+            $data['tencent_im_user_id'] = $user->tencent_im_user_id;
+            $res = $this->groupService->getJoinedGroupList($data);
+        } catch (GuzzleException $e) {
+            Log::error('获取用户群聊列表:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+        }
+
+        return $this->success($res);
+    }
+
+    //获取群聊详细信息
+    public function getGroupInfo(Request $request)
+    {
+        try {
+            $groupId = $request->group_id;
+            if (!$chatTeam = ChatTeam::query()->where(['GroupId' => $groupId])->first()) {
+                throw new \Exception(trans('api.GROUP_CHAT_DOES_NOT_EXIST'));
+            }
+            $res = $this->groupService->getGroupInfo($groupId);
+            if ($res['ErrorCode'] == 0 && !empty($res['GroupInfo'])) {
+                if (!empty($res['GroupInfo'][0]['MemberList'])) {
+                    foreach ($res['GroupInfo'][0]['MemberList'] as &$v) {
+                        $user = User::query()->where('tencent_im_user_id', $v['Member_Account'])->select('id', 'name', 'avatar', 'is_auth')->first();
+                        $v['user_id'] = $user->id;
+                        $v['name']    = $user->name;
+                        $v['avatar']  = $user->avatar;
+                        $v['is_auth'] = $user->is_auth;
+                        $v['have_user_course'] = UserService::haveUserCourse($user->id);
+                    }
+                }
+            }
+        } catch (GuzzleException $e) {
+            return $this->error(trans('api.NETWORK_ERROR'));
+        }
+        return $this->success($res);
+    }
+
+    //修改群名称
+    public function updateGroupName(Request $request)
+    {
+        try {
+            $user = $this->user;
+            $groupId = $request->group_id;
+            $group_name = $request->group_name;
+            if (empty($group_name)) {
+                throw new Exception(trans('api.GROUP_NAME_NOT_NULL'));
+            }
+            if (!$chatTeam = $this->isGroupExist($groupId)) {
+                throw new Exception(trans('api.GROUP_CHAT_DOES_NOT_EXIST'));
+            }
+            if (!$this->isHasActionAuth($user, $chatTeam)) {
+                throw new Exception(trans('api.UNAUTHORIZED_OPERATION'));
+            }
+
+            $data['GroupId'] = $groupId;
+            $data['name'] = $group_name;
+            $res = $this->groupService->modifyGroupBaseInfo($data);
+            //修改本地数据
+            $chatTeam->group_name = $group_name;
+            $chatTeam->save();
+
+        } catch (GuzzleException $e) {
+            Log::error('修改群名称:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+        } catch (Exception $e) {
+            return $this->error($e->getMessage());
+        }
+
+        return $this->success($res);
+    }
+
+    //退出群聊 (成员)
+    public function quitGroup(Request $request)
+    {
+        try {
+            $user = $this->user;
+            $groupId = $request->group_id;
+            $this->isGroupExist($groupId);
+
+            $data['GroupId'] = $groupId;
+            $data['member_list'] [] = $user;
+            $this->groupService->deleteGroupMember($data);
+
+        } catch (GuzzleException $e) {
+            Log::error('退出群聊:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+        } catch (Exception $e) {
+            return $this->error($e->getMessage());
+        }
+
+        return $this->success();
+    }
+
+    //添加群成员
+    public function addGroupUsers(Request $request)
+    {
+        try {
+            $user = $this->user;
+            $ids = $request->ids;
+            if (empty($ids) || !is_array($ids)) {
+                return $this->error(trans('api.PARAMS_ERROR'));
+            }
+
+            $groupId = $request->group_id;
+            if (!$chatTeam = $this->isGroupExist($groupId)) {
+                throw new Exception(trans('api.GROUP_CHAT_DOES_NOT_EXIST'));
+            }
+            if (!$this->isHasActionAuth($user, $chatTeam)) {
+                throw new Exception(trans('api.UNAUTHORIZED_OPERATION'));
+            }
+
+            $users = User::query()->whereIn('id', $ids)
+                ->select(['id', 'name', 'avatar', 'tencent_im_user_id'])
+                ->get()->toArray();
+
+            $data['GroupId'] = $groupId;
+            $data['member_list'] = $users;
+            $this->groupService->addGroupMember($data);
+
+        } catch (GuzzleException $e) {
+            Log::error('添加群成员:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+        } catch (Exception $e) {
+            return $this->error($e->getMessage());
+        }
+
+        return $this->success();
+    }
+
+    //删除群成员
+    public function delGroupUsers(Request $request)
+    {
+        try {
+            $user = $this->user;
+            $ids = $request->ids;
+            if (empty($ids) || !is_array($ids)) {
+                return $this->error(trans('api.PARAMS_ERROR'));
+            }
+            $groupId = $request->group_id;
+
+            if (!$chatTeam = $this->isGroupExist($groupId)) {
+                throw new Exception(trans('api.GROUP_CHAT_DOES_NOT_EXIST'));
+            }
+            if (!$this->isHasActionAuth($user, $chatTeam)) {
+                throw new Exception(trans('api.UNAUTHORIZED_OPERATION'));
+            }
+
+            $users = User::query()
+                ->whereIn('id', $ids)
+                ->select(['id', 'name', 'avatar', 'tencent_im_user_id'])
+                ->get()
+                ->toArray();
+
+            $data['GroupId'] = $groupId;
+            $data['member_list'] = $users;
+            $this->groupService->deleteGroupMember($data);
+
+        } catch (GuzzleException $e) {
+            Log::error('删除群成员:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+        } catch (Exception $e) {
+            return $this->error($e->getMessage());
+        }
+
+        return $this->success();
+    }
+
+    //群主转让
+    public function changeGroupOwner(Request $request)
+    {
+        try {
+            DB::beginTransaction();
+            $user = $this->user;
+            $groupId = $request->group_id;
+
+            if (!$chatTeam = $this->isGroupExist($groupId)) {
+                throw new Exception(trans('api.GROUP_CHAT_DOES_NOT_EXIST'));
+            }
+            if (!$this->isHasActionAuth($user, $chatTeam)) {
+                throw new Exception(trans('api.UNAUTHORIZED_OPERATION'));
+            }
+
+            $new_user_id = $request->user_id;
+            $new_user = User::query()->find($new_user_id);
+            $data['GroupId'] = $groupId;
+            $data['tencent_im_user_id'] = $new_user->tencent_im_user_id;
+            $this->groupService->changeGroupOwner($data);
+
+            $chatTeam->Owner_Account = $new_user->tencent_im_user_id;
+            $chatTeam->save();
+            DB::commit();
+
+        } catch (GuzzleException $e) {
+            DB::rollBack();
+            Log::error('删除群成员:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+
+        } catch (Exception $e) {
+            DB::rollBack();
+            return $this->error($e->getMessage());
+        }
+
+        return $this->success();
+    }
+
+    //解散群
+    public function destroyGroup(Request $request)
+    {
+        try {
+            $user = $this->user;
+            $groupId = $request->group_id;
+
+            if (!$chatTeam = $this->isGroupExist($groupId)) {
+                throw new Exception(trans('api.GROUP_CHAT_DOES_NOT_EXIST'));
+            }
+            if (!$this->isHasActionAuth($user, $chatTeam)) {
+                throw new Exception(trans('api.UNAUTHORIZED_OPERATION'));
+            }
+
+            $chatTeam->deleted_at = date('Y-m-d H:i:s');
+            $chatTeam->save();
+            $data['GroupId'] = $groupId;
+            $this->groupService->destroyGroup($data);
+
+        } catch (GuzzleException $e) {
+            Log::error('解散群:' . $e->getMessage());
+            return $this->error(trans('api.NETWORK_ERROR'));
+        } catch (Exception $e) {
+            return $this->error($e->getMessage());
+        }
+
+        return $this->success();
+    }
+
+    //判断群聊是否已删除
+    public function isGroupExist($groupId)
+    {
+        $chatTeam = ChatTeam::query()
+            ->where('GroupId', $groupId)
+            ->whereNull('deleted_at')
+            ->first();
+
+        if (!$chatTeam) {
+            return false;
+        }
+        return $chatTeam;
+    }
+
+    //判断群聊是有操作权限
+    public function isHasActionAuth($user, $chatTeam)
+    {
+        if ($user->tencent_im_user_id != $chatTeam->Owner_Account) {
+            return false;
+        }
+        return true;
+    }
+
+
+}

+ 80 - 0
app/Http/Controllers/V1/Controller.php

xqd
@@ -0,0 +1,80 @@
+<?php
+
+namespace App\Http\Controllers\V1;
+
+use Dingo\Api\Routing\Helpers;
+use Illuminate\Foundation\Bus\DispatchesJobs;
+use Illuminate\Http\Client\Response;
+use Illuminate\Routing\Controller as BaseController;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
+use App\Services\Base\ErrorCode;
+use Request, Auth,Log;
+
+class Controller extends BaseController
+{
+    use AuthorizesRequests, DispatchesJobs, ValidatesRequests,Helpers;
+
+    protected $_user = null;
+
+    public function __construct()
+    {
+        //将用户选择的语言存进用户表
+        $user = auth('api')->user();
+        if($user){
+            $lang = request()->header('lang','en');
+            $user->lang = $lang;
+            $user->save();
+        }
+    }
+
+
+
+    private function genApiData($data, $code = 0, $msg = '') {
+        if ($code !== 0 && ErrorCode::CLIENT_WRONG_PARAMS && empty($msg)) {
+            $msg = ErrorCode::message($code);
+        }
+        $ret = [
+            'code'   => $code,
+            'msg'    => $msg,
+            'data'   => $data
+        ];
+        return $ret;
+    }
+
+    public function success($data=null,$code=0,$msg = null)
+    {
+        if(!$msg) $msg = trans('api.SUCCESS');
+        return $this->api($data, $code, $msg);
+    }
+
+    public function error($msg = null,$code=1, $data = null) {
+        return $this->api($data, $code, $msg);
+    }
+
+    public function api($data, $code = 0, $message = '') {
+        //$ret = $this->genApiData($data, $code, $message);
+        $ret = [
+            'code'   => $code,
+            'msg'    => $message,
+            'data'   => $data
+        ];
+        return response()->json($ret);
+    }
+
+    public function validatorError($arr, $code = 1, $message = '')
+    {
+        foreach ($arr as $val){
+            if($val&&$message==''){
+                $message = $val;
+            }
+        }
+        $ret = $this->genApiData(null, $code, $message);
+        return response()->json($ret);
+    }
+
+
+
+
+
+}

+ 109 - 0
app/Http/Controllers/V1/CourseController.php

xqd
@@ -0,0 +1,109 @@
+<?php
+
+namespace App\Http\Controllers\V1;
+
+use App\Http\Requests\StoreCourse;
+use App\Models\CourseUser;
+use App\Services\Api\CourseService;
+use Illuminate\Http\Request;
+use PHPUnit\Util\Exception;
+
+class CourseController extends Controller
+{
+    public function __construct()
+    {
+        parent::__construct();
+        $this->user = auth('api')->user();
+        $this->CourseService = new CourseService();
+    }
+
+    //新增球场会员
+    public function addCourseUser(StoreCourse $request)
+    {
+        try {
+            $courseUser = CourseUser::query()
+                ->where([
+                    'course_id' => $request->course_id,
+                    'user_id' => $this->user->id,
+                ])
+                ->whereNull('deleted_at')
+                ->first();
+            if ($courseUser) {
+                throw new Exception(trans('api.CANNOT_BE_ADDED_REPEATED'));
+            } else {
+                $courseUser = new CourseUser();
+                $courseUser->course_id = $request->course_id;
+                $courseUser->user_id = $this->user->id;
+                $courseUser->type = $request->type;
+                $courseUser->member_name = $request->member_name;
+                $courseUser->member_no = $request->member_no;
+                $courseUser->whs = $request->whs;
+                $courseUser->status = 0; //待审核
+                if (!$courseUser->save()) {
+                    throw new Exception(trans('api.DATA_SAVE_FALSE'));
+                }
+            }
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+
+        return $this->success();
+    }
+
+    //球场会员
+    public function userCourses(Request $request)
+    {
+        $status = $request->input('status', 1);
+
+        $list = $this->CourseService->getUserCourseList($status, $this->user->id);
+
+        return $this->success($list);
+    }
+
+    //球场列表
+    public function courseList()
+    {
+        $list = $this->CourseService->getCourseList();
+
+        return $this->success($list);
+    }
+
+    //附近的球场
+    public function nearby(Request $request)
+    {
+        try {
+            $lng = $request->input('lng');
+            $lat = $request->input('lat');
+
+            if (empty($lng) || empty($lat)) {
+                throw new Exception(trans('api.PARAMS_ERROR'));
+            }
+            $list = $this->CourseService->getNearByCourses($lng, $lat);
+
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+
+        return $this->success($list);
+    }
+
+    //修改会员主场
+    public function setMainCourse(Request $request)
+    {
+        try {
+            $user_id = $this->user->id;
+            $course_id = $request->input('course_id');
+
+            CourseUser::where('user_id', $user_id)->update(['type' => 2]);
+            $courseUser = CourseUser::query()->where(['user_id' => $user_id, 'course_id' => $course_id])->first();
+            $courseUser->type = 1;
+            $courseUser->save();
+
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+        return $this->success();
+    }
+
+
+}

+ 208 - 0
app/Http/Controllers/V1/FeedsController.php

xqd
@@ -0,0 +1,208 @@
+<?php
+
+
+namespace App\Http\Controllers\V1;
+
+
+use App\Enums\ApiEnum;
+use App\Http\Params\DynamicParam;
+use App\Http\Params\DynamicZanParam;
+use App\Http\Params\FeedsParam;
+use App\Http\Requests\FeedsRequest;
+use App\Models\Feed;
+use App\Models\FeedForward;
+use App\Services\Api\ErrorMsgServive;
+use App\Services\Api\FeedsService;
+use App\Services\Api\FriendService;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
+use PHPUnit\Util\Exception;
+
+class FeedsController extends Controller
+{
+    private $feedsService;
+
+    public function __construct()
+    {
+        parent::__construct();
+        $this->feedsService = new FeedsService();
+    }
+
+    //动态列表
+    public function feedList(Request $request)
+    {
+        $data = $this->feedsService->getList($request);
+        return $this->success($data);
+    }
+
+    //动态详情
+    public function detail(Request $request)
+    {
+        $data = $this->feedsService->getDetail($request->feed_id);
+        return $this->success($data);
+    }
+
+    //发布动态
+    public function release(FeedsRequest $request)
+    {
+        try {
+            $user = auth('api')->user();
+            $lock = Cache::lock(ApiEnum::FEED_RELEASE . $user->id, 1);
+            if ($lock->get()) {
+                $this->feedsService->release($request);
+                $lock->release();
+            } else {
+                throw new Exception(trans('api.REQUESTS_TOO_FREQUENTLY'));
+            }
+        } catch (\Exception $exception) {
+            ErrorMsgServive::write($exception, request()->url());
+            return $this->error($exception->getLine() . $exception->getMessage());
+        }
+        return $this->success();
+    }
+
+    //动态点赞
+    public function like(Request $request)
+    {
+        try {
+            $user = auth('api')->user();
+            $lock = Cache::lock(ApiEnum::FEED_ZAN . $user->id, 1);
+            if ($lock->get()) {
+                DB::beginTransaction();
+                $like = $this->feedsService->like($request);
+                DB::commit();
+                $lock->release();
+            } else {
+                throw new Exception(trans('api.REQUESTS_TOO_FREQUENTLY'));
+            }
+        } catch (\Exception $exception) {
+            DB::rollBack();
+            return $this->error($exception->getMessage());
+        }
+
+        $res['like'] = $like;
+        return $this->success($res);
+    }
+
+    //删除动态
+    public function del(Request $request)
+    {
+        try {
+            $this->feedsService->del($request);
+        } catch (\Exception $exception) {
+            return $this->error($exception->getMessage());
+        }
+        return $this->success();
+    }
+
+    //动态评论
+    public function comment(Request $request)
+    {
+        try {
+            $this->feedsService->comment($request);
+        } catch (\Exception $exception) {
+            ErrorMsgServive::write($exception, request()->url());
+            return $this->error($exception->getMessage());
+        }
+        return $this->success();
+    }
+
+    //动态评论回复
+    public function commentReply(Request $request)
+    {
+        try {
+            $this->feedsService->commentReply($request);
+        } catch (\Exception $exception) {
+            ErrorMsgServive::write($exception, request()->url());
+            return $this->error($exception->getMessage());
+        }
+        return $this->success();
+    }
+
+    //动态举报
+    public function report(Request $request)
+    {
+        try {
+            $this->feedsService->report($request);
+        } catch (\Exception $exception) {
+            ErrorMsgServive::write($exception, request()->url());
+            return $this->error($exception->getMessage());
+        }
+        return $this->success();
+    }
+
+
+    //我的动态
+    public function myFeeds(Request $request)
+    {
+        $user = auth('api')->user();
+        $team_id = $request->post('team_id', 0);
+        $data = $this->feedsService->userFeeds($user->id, $team_id);
+
+        return $this->success($data);
+    }
+
+    //转发 好友列表
+    public function getFriends(Request $request)
+    {
+        $user = auth('api')->user();
+        $FriendService = new FriendService();
+        $data = $FriendService->getFriendsList($user->id, $request->post('keyword', ''));
+
+        return $this->success($data);
+    }
+
+    //动态转发
+    public function feedsForward(Request $request)
+    {
+        try {
+            DB::beginTransaction();
+
+            $feed_id = $request->post('feed_id');
+            if (empty($feed_id)) {
+                throw new Exception(trans('api.PARAMS_ERROR'));
+            }
+            $feed = Feed::query()->where(['id' => $feed_id])->whereNull('deleted_at')->first();
+            if (!$feed) {
+                throw new Exception(trans('api.FEED_NOT_EXIST'));
+            }
+
+            $user = auth('api')->user();
+            $type = $request->post('type', 1); //转发类型  1转发至动态 2转发给用户 3转发给weixin或者Facebook;
+            if ($type == 1) {
+                $content = $request->post('content', ''); //转发内容
+                //保存动态
+                $feed_arr = array();
+                $feed_arr['user_id'] = $user->id;
+                $feed_arr['content'] = $content;
+                $feed_arr['file_url'] = json_encode([]);
+                $feed_arr['address_info'] = '';
+                $feed_arr['match_title'] = '';
+                $feed_arr['game_per_id'] = 0;
+                //$feed_arr['team_id'] = $feed->team_id;
+                $feed_arr['forward_id'] = $feed_id;
+                if (!Feed::query()->create($feed_arr)) {
+                    throw new Exception(trans('api.SAVE_ERROR'));
+                }
+            }
+            //增加转发数量
+            $feed->forward_num = $feed->forward_num + 1;
+            $feed->save();
+            //保存转发记录
+            FeedForward::query()->create([
+                'user_id' => $user->id,
+                'feed_id' => $feed_id,
+                'status' => 0,
+                'created_at' => date('Y-m-d H:i:s'),
+                'updated_at' => date('Y-m-d H:i:s'),
+            ]);
+            DB::commit();
+        } catch (\Exception $exception) {
+            DB::rollBack();
+            ErrorMsgServive::write($exception, request()->url());
+            return $this->error($exception->getFile());
+        }
+        return $this->success();
+    }
+}

部分文件因为文件数量过多而无法显示