Przeglądaj źródła

Merge branch 'master' of 47.76.126.2:seven/bot-28

seven 11 godzin temu
rodzic
commit
07c1c34d60
38 zmienionych plików z 732 dodań i 301 usunięć
  1. 33 29
      app/Http/Controllers/admin/ActivityUser.php
  2. 36 37
      app/Http/Controllers/admin/Admin.php
  3. 0 2
      app/Http/Controllers/admin/Balance.php
  4. 48 123
      app/Http/Controllers/admin/Config.php
  5. 16 2
      app/Http/Controllers/admin/Home.php
  6. 21 36
      app/Http/Controllers/admin/Keyboard.php
  7. 1 0
      app/Http/Controllers/admin/PaymentOrder.php
  8. 24 8
      app/Http/Controllers/api/ActivityReward.php
  9. 22 2
      app/Models/ActivityUser.php
  10. 1 1
      app/Models/Bet.php
  11. 12 1
      app/Models/Keyboard.php
  12. 5 0
      app/Models/Recharge.php
  13. 9 0
      app/Models/User.php
  14. 18 0
      app/Services/ActivityRewardService.php
  15. 55 0
      app/Services/ActivityUserService.php
  16. 0 19
      app/Services/BaseService.php
  17. 2 0
      app/Services/BetService.php
  18. 12 0
      app/Services/ConfigService.php
  19. 19 4
      app/Services/KeyboardService.php
  20. 14 12
      app/Services/PaymentOrderService.php
  21. 7 0
      app/Services/PhoneCodeService.php
  22. 3 8
      app/Services/QianBaoWithdrawService.php
  23. 12 10
      app/Services/RechargeService.php
  24. 1 3
      app/Services/TopUpService.php
  25. 2 4
      app/Services/WithdrawService.php
  26. 30 0
      database/migrations/2026_01_29_102017_update_keyboard.php
  27. 30 0
      database/migrations/2026_01_29_102018_update_keyboard.php
  28. 30 0
      database/migrations/2026_01_29_102019_update_keyboard.php
  29. 30 0
      database/migrations/2026_01_30_094751_update_rebates.php
  30. 30 0
      database/migrations/2026_01_30_095109_update_backflow.php
  31. 46 0
      database/migrations/2026_01_30_111118_insert_config.php
  32. 30 0
      database/migrations/2026_01_30_112935_update_config.php
  33. 30 0
      database/migrations/2026_02_02_134352_update_activity_user.php
  34. 30 0
      database/migrations/2026_02_02_134741_update_activity_user.php
  35. 32 0
      database/migrations/2026_02_02_143549_update_activity_user.php
  36. 37 0
      database/migrations/2026_02_05_160839_insert_config.php
  37. 1 0
      routes/admin.php
  38. 3 0
      routes/api.php

+ 33 - 29
app/Http/Controllers/admin/ActivityUser.php

@@ -5,7 +5,6 @@ namespace App\Http\Controllers\admin;
 use App\Constants\HttpStatus;
 use App\Http\Controllers\Controller;
 use App\Models\Wallet as WalletModel;
-use App\Services\ActivityRewardService;
 use App\Services\ActivityUserService;
 use App\Services\BalanceLogService;
 use App\Services\TopUpService;
@@ -23,31 +22,32 @@ class ActivityUser extends Controller
         DB::beginTransaction();
         try {
             $params = request()->validate([
-                'amount' => ['required', 'numeric', 'min:0.01'],
-                'remark' => ['required', 'string', 'min:1'],
-                'change_type' => ['required', 'string', 'in:' . implode(',', BalanceLogService::$manualRecharge)],
                 'id' => ['required', 'integer', 'min:1'],
             ]);
-            $id = request()->input('id');
-            $params['action'] = request()->route()->getActionName();
-            $amount = request()->input('amount');
-            $remark = request()->input('remark');
-            $changeType = request()->input('change_type');
-            $key = 'api_request_' . md5(json_encode($params));
-            if (Cache::has($key)) throw new Exception("请求太频繁,请稍后再试。", HttpStatus::CUSTOM_ERROR);
-            Cache::put($key, true, 3);
-            $activityUser = ActivityUserService::findOne(['id' => $id, 'status' => 0]);
-            if (!$activityUser) throw new Exception("活动不存在或已完成", HttpStatus::CUSTOM_ERROR);
-            $memberId = $activityUser->member_id;
-            $activityUser->status = 1;
-            $activityUser->finish_time = time();
-            $activityUser->save();
-            $wallet = WalletModel::where('member_id', $memberId)->first();
-            if (!$wallet) throw new Exception('用户不存在', HttpStatus::CUSTOM_ERROR);
-            $availableBalance = bcadd($wallet->available_balance, $amount, 10);
-            BalanceLogService::addLog($memberId, $amount, $wallet->available_balance, $availableBalance, $changeType, null, $remark);
-            $wallet->available_balance = $availableBalance;
-            $wallet->save();
+            ActivityUserService::finish($params['id']);
+            DB::commit();
+        } catch (ValidationException $e) {
+            DB::rollBack();
+            return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());
+        } catch (Exception $e) {
+            DB::rollBack();
+            return $this->error($e->getCode(), $e->getMessage());
+        }
+        return $this->success();
+    }
+
+
+    //赠送金额(充值)
+    public function gift()
+    {
+        DB::beginTransaction();
+        try {
+            $params = request()->validate([
+                'id' => ['required', 'integer', 'min:1'],
+                'amount' => ['required', 'numeric', 'min:0.01'],
+                'betting_amount' => ['required', 'integer', 'min:0', 'max:9999999'],
+            ]);
+            ActivityUserService::gift($params['id'], $params['amount'], $params['betting_amount']);
             DB::commit();
         } catch (ValidationException $e) {
             DB::rollBack();
@@ -56,10 +56,6 @@ class ActivityUser extends Controller
             DB::rollBack();
             return $this->error($e->getCode(), $e->getMessage());
         }
-        $availableBalance = floatval($availableBalance);
-        // 去除多余0后,再用 sprintf 补足两位
-        $availableBalance = sprintf('%.2f', $availableBalance);
-        TopUpService::notifyTransferSuccess($memberId, "完成活动:" . ($amount > 0 ? '+' : '') . "{$amount} \n总余额为:{$availableBalance}");
         return $this->success();
     }
 
@@ -77,9 +73,17 @@ class ActivityUser extends Controller
             $where = ActivityUserService::getWhere($params);
             $query = ActivityUserModel::where($where);
             $count = $query->count();
-            $list = $query->orderByDesc('status')
+            $list = $query->orderBy('status')
+                ->with(['member'])
                 ->orderByDesc('id')
                 ->forPage($page, $limit)->get()->toArray();
+            foreach ($list as &$item)
+            {
+                $item['gift_amount'] = floatval($item['gift_amount']);
+                $item['effective_betting_amount'] = floatval($item['effective_betting_amount']);
+                $item['betting_amount'] = floatval($item['betting_amount']);
+            }
+
             $result = ['total' => $count, 'data' => $list];
         } catch (ValidationException $e) {
             return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());

+ 36 - 37
app/Http/Controllers/admin/Admin.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\admin;
 
 use App\Constants\HttpStatus;
 use App\Http\Controllers\Controller;
+use App\Services\BaseService;
 use App\Services\JwtService;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Cache;
@@ -226,44 +227,42 @@ class Admin extends Controller
      */
     public function store()
     {
-        // try {
-        $params = request()->all();
-        if (isset($params['id']) && $params['id'] == 1) {
-            return $this->error(0, '超级管理员禁止操作');
-        }
-        $validator = [
-            'username' => 'required|string|max:50|alpha_dash|unique:admin,username',
-            'nickname' => 'required|string|max:100',
-            'password' => ['nullable', 'string', 'min:6', 'max:20'],
-            // 'display_name' => 'nullable|string|max:100',
-            // 'description' => 'nullable|string',
-        ];
-        if (isset($params['id']) && !empty($params['id'])) {
-            $validator['username'] = [
-                'required',
-                'string',
-                'max:50',
-                'alpha_dash',
-                Rule::unique('admin', 'username')->ignore($params['id']), // 忽略当前 ID
-            ];
-        } else {
-
-        }
-
-
-        request()->validate($validator);
+        try {
+            $id = request()->input('id');
+            $validator = [
+                'username' => 'required|string|min:5|max:50|alpha_dash|unique:admin,username',
+                'nickname' => 'required|string|max:100',
+                'password' => ['nullable', 'string', 'min:6', 'max:20'],
+                'cellphone' => ['required', 'string'],
+                'email' => ['required', 'email'],
+                'remarks' => ['nullable', 'string'],
+                'roles_ids' => ['nullable', 'array'],
+                'id' => ['nullable', 'integer', 'min:1'],
 
-        $ret = AdminService::submit($params);
-        if ($ret['code'] == AdminService::NOT) {
-            return $this->error($ret['code'], $ret['msg']);
+            ];
+            if (!empty($id)) {
+                if ($id == 1) {
+                    unset($validator['username'], $validator['password'],$validator['roles_ids']);
+                } else {
+                    $validator['roles_ids'] = ['required', 'array', 'min:1'];
+                    $validator['roles_ids.*'] = ['required', 'integer', 'min:1'];
+                    $validator['username'] = ['required', 'string', 'max:50', 'alpha_dash',
+                        Rule::unique('admin', 'username')->ignore($id), // 忽略当前 ID
+                    ];
+                }
+            }
+            $params = request()->validate($validator);
+            if ($id == 1) $params['roles_ids'] = [];
+            $ret = AdminService::submit($params);
+            if ($ret['code'] == BaseService::NOT) {
+                throw new Exception($ret['msg'], HttpStatus::CUSTOM_ERROR);
+            }
+        } catch (ValidationException $e) {
+            return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());
+        } catch (Exception $e) {
+            return $this->error($e->getCode(), $e->getMessage());
         }
-        // } catch (ValidationException $e) {
-        //     return $this->error(HttpStatus::VALIDATION_FAILED, '', $e->errors());
-        // } catch (Exception $e) {
-        //     return $this->error(intval($e->getCode()));
-        // }
-        return $this->success([], $ret['msg']);
-
+        return $this->success();
     }
 
     /**
@@ -280,7 +279,7 @@ class Admin extends Controller
     {
         $id = request()->post('id');
         if ($id == 1) {
-            return $this->error(0, '超级管理员禁止操作');
+            return $this->error(HttpStatus::CUSTOM_ERROR, '超级管理员禁止操作');
         }
         // 示例:通过 ID 删除菜单
         $info = AdminService::findOne(['id' => $id]);

+ 0 - 2
app/Http/Controllers/admin/Balance.php

@@ -42,8 +42,6 @@ class Balance extends Controller
 
 
             $data['change_types'] = BalanceLogService::$RW;
-
-
         } catch (ValidationException $e) {
             return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());
         } catch (Exception $e) {

+ 48 - 123
app/Http/Controllers/admin/Config.php

@@ -296,78 +296,33 @@ class Config extends Controller
      * @apiParam {String} video_caption 视频文案
      * @apiParam {Boolean} [isSend=true] 是否发送
      * @apiParam {Boolean} [isTop=true] 是否置顶
-     * @apiExample {js} button 示例
-     * //button 的数据格式如下
-     * [
-     *   [      //第一行
-     *     {    //第一行按钮 的第一个按钮
-     *       "text": "百度",  //按钮文字
-     *       "url": "https://baidu.com"   //按钮跳转的链接
-     *     },
-     *     {    //第一行按钮 的第二个按钮
-     *       "text": "百度",
-     *       "url": "https://baidu.com"
-     *     }
-     *     //更多按钮...
-     *   ],
-     *   [    //第二行
-     *     {
-     *       "text": "百度",
-     *       "url": "https://baidu.com"
-     *     }
-     *   ]
-     *   //更多行...
-     * ]
      */
     public function sendChannelMessage()
     {
         set_time_limit(0);
         DB::beginTransaction();
         try {
-            $type = request()->input('type', 'image');
-            if ($type == 'image') {
-                request()->validate([
-                    'chatId' => ['required', 'string', 'min:1'],
-                    'image' => ['required', 'url'],
-                    'text' => ['nullable', 'string'],
-                    'button' => ['required', 'array'],
-                    'button.*' => ['array'],
-                    'button.*.*.text' => ['required', 'string'],
-                    'button.*.*.url' => ['required', 'url'],
-                    'isSend' => ['nullable', 'boolean'],
-                    'isTop' => ['nullable', 'boolean'],
-                ]);
-
-
-            } else {
-                request()->validate([
-                    'chatId' => ['required', 'string', 'min:1'],
-                    'video' => ['required', 'url'],
-                    'video_caption' => ['nullable', 'string'],
-                    'isSend' => ['nullable', 'boolean'],
-                    'isTop' => ['nullable', 'boolean'],
-                ]);
-            }
-            $chatId = request()->input('chatId');
-            $image = request()->input('image');
-            $button = request()->input('button');
-            $text = request()->input('text');
-            $isSend = request()->input('isSend', true);
-            $isTop = request()->input('isTop', true);
 
-            $video = request()->input('video');
-            $video_caption = request()->input('video_caption');
-            ConfigModel::where('field', 'channel_message')
-                ->update([
-                    'val' => json_encode([
-                        'chatId' => $chatId,
-                        'image' => $image,
-                        'video' => $video,
-                        'video_caption' => $video_caption,
-                        'text' => $text,
-                        'button' => $button
-                    ])
-                ]);
+            $validate = [
+                'chatId' => ['required', 'string', 'min:1'],
+                'type' => ['required', 'string', 'in:image,video,text'],
+                'text' => ['nullable', 'string'],
+                'isSend' => ['nullable', 'boolean'],
+                'isTop' => ['nullable', 'boolean'],
+                'button' => ['array'],
+                'button.*' => ['required', 'array'],
+                'button.*.*.text' => ['required', 'string'],
+                'button.*.*.url' => ['required', 'url'],
+            ];
+            $type = request()->input('type');
+            if (in_array($type, ['image', 'video'])) $validate[$type] = ['required', 'url'];
+            $params = request()->validate($validate);
+            $params['image'] = request()->input('image', '');
+            $params['video'] = request()->input('video', '');
+            $isSend = request()->input('isSend', false);
+            $isTop = request()->input('isTop', false);
+            unset($params['isTop'], $params['isSend']);
+            ConfigModel::where('field', 'channel_message')->update(['val' => json_encode($params)]);
             DB::commit();
         } catch (ValidationException $e) {
             DB::rollBack();
@@ -379,78 +334,48 @@ class Config extends Controller
 
         if ($isSend) {
             try {
-                $config = ConfigModel::where('field', 'channel_message')
-                    ->first()->val;
+                $config = ConfigModel::where('field', 'channel_message')->first()->val;
                 $config = json_decode($config, true);
                 $telegram = new Api(config('services.telegram.token'));
-                if ($type == 'image') {
-                    // 发送图片消息
-                    $response = $telegram->sendPhoto([
-                        'chat_id' => "@{$config['chatId']}",
-                        'photo' => InputFile::create($config['image']),
-                        'caption' => $config['text'],
-                        'protect_content' => false,
-                        'reply_markup' => json_encode(['inline_keyboard' => $config['button']])
-                    ]);
-                } else {
-                    // 发送视频消息
-                    $response = $telegram->sendVideo([
-                        'chat_id' => "@{$config['chatId']}",
-                        'video' => InputFile::create($config['video']),
-                        'caption' => $config['video_caption'],
-                        'protect_content' => false
-                        // 'reply_markup' => json_encode(['inline_keyboard' => $config['button']])
-                    ]);
+                $msg = [];
+                $msg['chat_id'] = "@{$config['chatId']}";
+                $msg['protect_content'] = false;
+                if (!empty($config['button'])) {
+                    $msg['reply_markup'] = json_encode(['inline_keyboard' => $config['button']]);
                 }
 
-
+                switch ($type) {
+                    case 'image':
+                        $msg['photo'] = InputFile::create($config['image']);
+                        $msg['caption'] = $config['text'];
+                        $response = $telegram->sendPhoto($msg);
+                        break;
+                    case 'video':
+                        $msg['video'] = InputFile::create($config['video']);
+                        $msg['caption'] = $config['text'];
+                        $response = $telegram->sendVideo($msg);
+                        break;
+                    case 'text':
+                        $msg['text'] = $config['text'];
+                        $response = $telegram->sendMessage($msg);
+                        break;
+                    default:
+                        throw new Exception("保存成功,发送失败", HttpStatus::CUSTOM_ERROR);
+                }
+                // 置顶消息
                 if ($isTop) {
-                    // 获取消息ID
                     $messageId = $response->get('message_id');
-                    // 置顶消息
-                    $telegram->pinChatMessage([
-                        'chat_id' => "@{$config['chatId']}",
-                        'message_id' => $messageId
-                    ]);
+                    $telegram->pinChatMessage(['chat_id' => "@{$config['chatId']}", 'message_id' => $messageId]);
                 }
             } catch (TelegramSDKException $e) {
-                return $this->error(HttpStatus::CUSTOM_ERROR, '保存成功,发送失败');
+                return $this->error(HttpStatus::CUSTOM_ERROR, '保存成功,发送失败', $e->getMessage());
             } catch (Exception $e) {
-                return $this->error(intval($e->getCode()), '保存成功,发送失败');
+                return $this->error($e->getCode(), '保存成功,发送失败');
             }
         }
         return $this->success();
     }
 
-// public function sendChannelVideo()
-// {
-//     $chatId = request()->input('chatId');
-//     $video = request()->input('video');
-//     // $config = ConfigModel::where('field', 'channel_message')
-//     //             ->first()->val;
-//     // $config = json_decode($config, true);
-//     $telegram = new Api(config('services.telegram.token'));
-//     // 发送图片消息
-//     $response = $telegram->sendVideo([
-//         'chat_id' => "@{$chatId}",
-//         'caption' => '这是一个视频消息',
-//         'video' => InputFile::create($video),
-//         'protect_content' => false,
-//     ]);
-
-//     // 获取消息ID
-//     $messageId = $response->get('message_id');
-//     // 获取消息ID
-//     $messageId = $response->get('message_id');
-//     // 置顶消息
-//     $telegram->pinChatMessage([
-//         'chat_id' => "@{$chatId}",
-//         'message_id' => $messageId
-//     ]);
-//     return $this->success($messageId);
-// }
-
-
     /**
      * @api {post} /admin/config/set 修改配置
      * @apiGroup 配置

+ 16 - 2
app/Http/Controllers/admin/Home.php

@@ -34,8 +34,14 @@ class Home extends Controller
             $query->whereBetween('created_at', [$start, $end]);
             $query1 = clone $query;
             $totalAmount = (float)$query1->where('type', 2)->sum('amount');
+
+
+            $query1 = clone $query;
+            $totalPending = (float)$query1->where('type', 2)->where('status', 0)->sum('amount');
             $query1 = clone $query;
-            $totalSuccess = (float)$query1->where('type', 2)->whereIn('status', [1, 2])->sum('amount');
+            $totalProcessing = (float)$query1->where('type', 2)->where('status', 1)->sum('amount');
+            $query1 = clone $query;
+            $totalSuccess = (float)$query1->where('type', 2)->where('status', 2)->sum('amount');
             $query1 = clone $query;
             $totalFail = (float)$query1->where('type', 2)->where('status', 3)->sum('amount');
 
@@ -43,7 +49,11 @@ class Home extends Controller
             $query1 = clone $query;
             $rechargeRmbTotalAmount = (float)$query1->where('type', 1)->sum('amount');
             $query1 = clone $query;
-            $rechargeRmbTotalSuccess = (float)$query1->where('type', 1)->whereIn('status', [1, 2])->sum('amount');
+            $rechargeRmbTotalPending = (float)$query1->where('type', 1)->where('status', 0)->sum('amount');
+            $query1 = clone $query;
+            $rechargeRmbTotalProcessing = (float)$query1->where('type', 1)->where('status', 1)->sum('amount');
+            $query1 = clone $query;
+            $rechargeRmbTotalSuccess = (float)$query1->where('type', 1)->where('status', 2)->sum('amount');
             $query1 = clone $query;
             $rechargeRmbTotalFail = (float)$query1->where('type', 1)->where('status', 3)->sum('amount');
 
@@ -79,6 +89,8 @@ class Home extends Controller
                     'total_amount' => $rechargeRmbTotalAmount,
                     'total_success' => $rechargeRmbTotalSuccess,
                     'total_fail' => $rechargeRmbTotalFail,
+                    'total_processing' => $rechargeRmbTotalProcessing,
+                    'total_pending' => $rechargeRmbTotalPending
                 ],
 
                 'withdraw_usdt' => [
@@ -90,6 +102,8 @@ class Home extends Controller
                     'total_fail' => $totalFail,
                     'total_success' => $totalSuccess,
                     'total_amount' => $totalAmount,
+                    'total_processing' => $totalProcessing,
+                    'total_pending' => $totalPending
                 ]
 
             ];

+ 21 - 36
app/Http/Controllers/admin/Keyboard.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\admin;
 
 use App\Constants\HttpStatus;
 use App\Http\Controllers\Controller;
+use App\Services\BaseService;
 use App\Services\KeyboardService;
 use Exception;
 
@@ -40,16 +41,19 @@ class Keyboard extends Controller
     public function index()
     {
         try {
-            request()->validate([
-                'title' => ['nullable', 'string'],
-                'permission_name' => ['nullable', 'string'],
+            $search = request()->validate([
+                'page' => ['nullable', 'integer', 'min:1'],
+                'limit' => ['nullable', 'integer', 'min:1'],
+                'button' => ['nullable', 'string'],
+                'language' => ['nullable', 'string', 'in:zh,vi,en'],
+                'explain' => ['nullable', 'string'],
+                'group_id' => ['nullable', 'integer', 'in:0,1'],
             ]);
-            $search = request()->all();
             $result = KeyboardService::paginate($search);
         } catch (ValidationException $e) {
-            return $this->error(HttpStatus::VALIDATION_FAILED, '', $e->errors());
+            return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());
         } catch (Exception $e) {
-            return $this->error(intval($e->getCode()));
+            return $this->error($e->getCode(), $e->getMessage());
         }
         return $this->success($result);
     }
@@ -67,41 +71,22 @@ class Keyboard extends Controller
      * @apiParam {string} button 关键字
      * @apiParam {string} reply 回复内容
      * @apiParam {array} buttons 操作按钮组
-     * @apiExample {js} button 示例
-     * //button 的数据格式如下
-     * [
-     *   [      //第一行
-     *     {    //第一行按钮 的第一个按钮
-     *       "text": "百度",  //按钮文字
-     *       "url": "https://baidu.com"   //按钮跳转的链接
-     *     },
-     *     {    //第一行按钮 的第二个按钮
-     *       "text": "百度",
-     *       "url": "https://baidu.com"
-     *     }
-     *     //更多按钮...
-     *   ],
-     *   [    //第二行
-     *     {
-     *       "text": "百度",
-     *       "url": "https://baidu.com"
-     *     }
-     *   ]
-     *   //更多行...
-     * ]
      */
     public function store(): JsonResponse
     {
         try {
-            $id = request()->input('id', null);
+            $id = request()->input('id');
             $validator = [
                 'id' => ['required', 'integer'],
-                'reply' => 'required|string',
-                'explain' => 'nullable|string',
-                'language' => 'required|string',
-                'reply' => 'required|string',
+                'reply' => ['required', 'string'],
+                'explain' => ['nullable', 'string', 'max:28'],
+                'language' => ['required', 'string', 'in:zh,vi,en'],
                 'image' => ['nullable', 'url'],
+                'button' => ['nullable', 'string', 'max:100'],
                 'buttons' => ['array'],
+                'buttons.*' => ['array', 'min:1'],
+                'buttons.*.*.text' => ['required', 'string', 'min:1'],
+                'buttons.*.*.url' => ['required', 'string', 'min:1'],
             ];
             if (empty($id)) {
                 unset($validator['id']);
@@ -109,7 +94,7 @@ class Keyboard extends Controller
             }
             $params = request()->validate($validator);
             $ret = KeyboardService::submit($params);
-            if ($ret['code'] == KeyboardService::NOT) {
+            if ($ret['code'] == BaseService::NOT) {
                 throw new Exception($ret['msg'], HttpStatus::CUSTOM_ERROR);
             }
         } catch (ValidationException $e) {
@@ -136,13 +121,13 @@ class Keyboard extends Controller
      */
     public function destroy(): JsonResponse
     {
-        return $this->error(HttpStatus::CUSTOM_ERROR, '禁止删除');
         $id = request()->post('id');
         // 示例:通过 ID 删除回复
         $info = KeyboardService::findOne(['id' => $id]);
         if (!$info) {
-            return $this->error(0, '数据不存在');
+            return $this->error(HttpStatus::CUSTOM_ERROR, '数据不存在');
         }
+        if ($info->group_id != 1) return $this->error(HttpStatus::CUSTOM_ERROR, '系统配置禁止删除');
         $info->delete();
         return $this->success([], '删除成功');
     }

+ 1 - 0
app/Http/Controllers/admin/PaymentOrder.php

@@ -71,6 +71,7 @@ class PaymentOrder extends Controller
                 'limit' => ['nullable', 'integer', 'min:1'],
                 'order_no' => ['nullable', 'string'],
                 'status' => ['nullable', 'integer', 'in:0,1,2,3'],
+                'member_id' => ['nullable', 'integer'],
             ]);
 
             $params['type'] = 1;

+ 24 - 8
app/Http/Controllers/api/ActivityReward.php

@@ -5,8 +5,10 @@ namespace App\Http\Controllers\api;
 use App\Constants\HttpStatus;
 use App\Models\ActivityReward as ActivityRewardModel;
 use App\Models\ActivityUser;
+use App\Models\Config;
 use App\Services\ActivityRewardService;
 use App\Services\ActivityUserService;
+use App\Services\ConfigService;
 use App\Services\PhoneCodeService;
 use App\Services\SmsService;
 use App\Services\UserService;
@@ -20,6 +22,17 @@ use Exception;
 class ActivityReward extends BaseController
 {
 
+    //活动规则
+    public function rule(): JsonResponse
+    {
+        try {
+            $activityRole = ConfigService::getVal("activity_rule");
+        } catch (Exception $e) {
+            return $this->error($e->getMessage(), [], $e->getCode());
+        }
+        return $this->success($activityRole);
+    }
+
     //验证手机号
     public function verifyPhone(): JsonResponse
     {
@@ -82,24 +95,27 @@ class ActivityReward extends BaseController
             $user = UserService::findOne(['member_id' => $memberId]);
             if (empty($user->phone)) throw new Exception('请先绑定手机号', HttpStatus::NOT_BIND_PHONE);
 
-            if (ActivityUser::where('member_id', $memberId)->where('status', 0)->exists()) {
-                throw new Exception('您有正在进行的活动,不可同时参与多个活动', HttpStatus::CUSTOM_ERROR);
-            }
-            $activityId = request()->input('activity_id');
 
+            $activityId = request()->input('activity_id');
             if (ActivityUser::where('member_id', $memberId)->where('activity_id', $activityId)->exists()) {
                 throw new Exception('已参与过此活动,每个活动仅可参加一次', HttpStatus::CUSTOM_ERROR);
             }
 
+            if (ActivityUser::where('member_id', $memberId)->whereIn('status', [ActivityUser::STATUS_APPLY,ActivityUser::STATUS_IN_PROGRESS])->exists()) {
+                throw new Exception('您有正在进行的活动,不可同时参与多个活动', HttpStatus::CUSTOM_ERROR);
+            }
 
             $time = time();
             $activity = ActivityRewardService::findOne([
-                'start_time' => ['<=', $time],
-                'end_time' => ['>=', $time],
+//                'start_time' => ['<=', $time],
+//                'end_time' => ['>=', $time],
                 'status' => ActivityRewardModel::STATUS_UP,
                 'id' => $activityId
             ]);
             if (!$activity) throw new Exception('活动不存在', HttpStatus::CUSTOM_ERROR);
+            if (strtotime($activity->start_time) > $time) throw new Exception("活动未开始$activity->start_time", HttpStatus::CUSTOM_ERROR);
+            if (strtotime($activity->end_time) < $time) throw new Exception('活动已结束', HttpStatus::CUSTOM_ERROR);
+
 
             ActivityUserService::submit([
                 'activity_id' => $activityId,
@@ -126,11 +142,11 @@ class ActivityReward extends BaseController
     public function index(): JsonResponse
     {
         try {
-            request()->validate(['member_id' => ['nullable', 'integer']]);
+            request()->validate(['member_id' => ['nullable', 'string']]);
             $memberId = request()->input('member_id');
             $time = time();
             $query = ActivityRewardModel::where(ActivityRewardService::getWhere([
-                'start_time' => ['<=', $time],
+//                'start_time' => ['<=', $time],
                 'end_time' => ['>=', $time],
                 'status' => ActivityRewardModel::STATUS_UP
             ]));

+ 22 - 2
app/Models/ActivityUser.php

@@ -15,13 +15,33 @@ use App\Constants\Util;
  * @property string start_time
  * @property string end_time
  * @property string part_in_time
+ * @property $effective_betting_amount
+ * @property $gift_amount
+ * @property $betting_amount
  *
  */
 class ActivityUser extends BaseModel
 {
     protected $table = 'activity_user';
-    protected $fillable = ['activity_id', 'finish_time', 'member_id', 'title', 'status', 'sub_title', 'detail_image',
-        'start_time', 'end_time', 'part_in_time'];
+    protected $fillable = ['activity_id',
+        'finish_time', 'member_id', 'title', 'status', 'sub_title', 'detail_image',
+        'start_time', 'end_time', 'part_in_time',
+        'effective_betting_amount', 'gift_amount', 'betting_amount',
+
+    ];
+
+
+    const STATUS_APPLY = 0;
+    const STATUS_IN_PROGRESS = 1;
+    const STATUS_COMPLETE = 2;
+
+
+    public function member()
+    {
+        return $this->belongsTo(User::class, 'member_id', 'member_id')
+            ->select(['id', 'member_id', 'username', 'first_name', 'admin_note', 'status', 'phone', 'visitor_id', 'register_ip']);
+    }
+
 
     protected function getDetailImageAttribute($value)
     {

+ 1 - 1
app/Models/Bet.php

@@ -24,7 +24,7 @@ class Bet extends BaseModel
     public function user()
     {
         return $this->belongsTo(User::class, 'member_id', 'member_id')
-            ->select(['id', 'member_id', 'username', 'first_name']);
+            ->select(['id', 'member_id', 'username', 'first_name','status']);
     }
 
 

+ 12 - 1
app/Models/Keyboard.php

@@ -2,8 +2,19 @@
 
 namespace App\Models;
 
+/**
+ * @property $group_id
+ * @property $id
+ * @property $button
+ * @property $buttons
+ * @property $image
+ * @property $language
+ * @property $explain
+ * @property $reply
+ *
+ */
 class Keyboard extends BaseModel
 {
     protected $table = 'keyboard';
-    protected $fillable = ['button', 'reply', 'id', 'buttons', 'image', 'language', 'explain'];
+    protected $fillable = ['button', 'group_id', 'reply', 'id', 'buttons', 'image', 'language', 'explain'];
 }

+ 5 - 0
app/Models/Recharge.php

@@ -25,6 +25,11 @@ class Recharge extends BaseModel
     const TYPE_AUTO = 1; // 自动
     const TYPE_HAND = 2; // 手动
 
+    public function member()
+    {
+        return $this->belongsTo(User::class, 'member_id', 'member_id')
+            ->select(['id', 'member_id', 'username', 'first_name', 'status']);
+    }
 
     protected function getAmountAttribute($value)
     {

+ 9 - 0
app/Models/User.php

@@ -2,6 +2,8 @@
 
 namespace App\Models;
 
+use Carbon\Carbon;
+
 /**
  * @property int $id
  * @property string $member_id
@@ -12,6 +14,7 @@ namespace App\Models;
  * @property integer $status
  * @property string $visitor_id
  * @property string $phone 用户手机号
+ * @property string $admin_note
  */
 class User extends BaseModel
 {
@@ -22,6 +25,12 @@ class User extends BaseModel
     ];
     protected $hidden = ['updated_at'];
 
+
+    function getCreatedAtAttribute($value): string
+    {
+        return Carbon::parse($value)->setTimezone('Asia/Shanghai')->format('Y-m-d');
+    }
+
     public function wallet()
     {
         return $this->belongsTo(Wallet::class, 'id', 'user_id');

+ 18 - 0
app/Services/ActivityRewardService.php

@@ -5,6 +5,7 @@ namespace App\Services;
 use App\Constants\HttpStatus;
 use App\Constants\Util;
 use App\Models\ActivityReward;
+use App\Models\Config;
 use App\Models\Role;
 use Exception;
 
@@ -97,4 +98,21 @@ class ActivityRewardService extends BaseService
         }
         return true;
     }
+
+
+    public static function promotionalActivity($chatId): array
+    {
+        $keyboard = [];
+        $url = Config::where('field','activity_home_url ')->first()->val;
+        $url.="?member_id=".$chatId;
+        $keyboard[] = [
+            ['text'=>'活动首页','url'=>$url]
+        ];
+        $msg = [];
+        $msg['chat_id'] = $chatId;
+        $msg['text'] = "点击下方按钮进入活动首页";
+        $msg['reply_markup'] = json_encode(['inline_keyboard' => $keyboard]);
+
+        return $msg;
+    }
 }

+ 55 - 0
app/Services/ActivityUserService.php

@@ -3,9 +3,11 @@
 namespace App\Services;
 
 use App\Constants\HttpStatus;
+use App\Constants\System;
 use App\Constants\Util;
 use App\Models\ActivityReward;
 use App\Models\ActivityUser;
+use App\Models\Wallet as WalletModel;
 use Exception;
 use Illuminate\Database\Eloquent\Builder;
 
@@ -67,4 +69,57 @@ class ActivityUserService extends BaseService
         }
         return true;
     }
+
+    public static function updateBettingAmount($memberId, $amount)
+    {
+        $activityUser = static::findOne([
+            'member_id' => $memberId,
+            'status' => static::$MODEL::STATUS_IN_PROGRESS
+        ]);
+        if ($activityUser) {
+            $activityUser->increment('effective_betting_amount', $amount);
+            if ($activityUser->effective_betting_amount >= $activityUser->betting_amount) {
+                $activityUser->status = static::$MODEL::STATUS_COMPLETE;
+                $activityUser->finish_time = time();
+            }
+            $activityUser->save();
+        }
+    }
+
+    public static function finish($id)
+    {
+        $activityUser = static::findOne(['id' => $id]);
+        $activityUser->status = static::$MODEL::STATUS_COMPLETE;
+        $activityUser->finish_time = time();
+        $activityUser->save();
+    }
+
+    /**
+     * @throws Exception
+     */
+    public static function gift($id, $amount, $bettingAmount): void
+    {
+        $activityUser = static::findOne(['id' => $id]);
+        if (!$activityUser) throw new Exception('活动不存在', HttpStatus::CUSTOM_ERROR);
+        if ($activityUser->status == static::$MODEL::STATUS_IN_PROGRESS) throw new Exception('充值失败:活动进行中', HttpStatus::CUSTOM_ERROR);
+        if ($activityUser->status == static::$MODEL::STATUS_COMPLETE) throw new Exception("充值失败:活动已完成", HttpStatus::CUSTOM_ERROR);
+        if ($activityUser->status != static::$MODEL::STATUS_APPLY) throw new Exception('充值失败:状态异常', HttpStatus::CUSTOM_ERROR);
+        $activityUser->status = static::$MODEL::STATUS_IN_PROGRESS;
+        $activityUser->betting_amount = $bettingAmount;
+        $activityUser->gift_amount = $amount;
+        $activityUser->effective_betting_amount = 0;
+        $activityUser->save();
+        $memberId = $activityUser->member_id;
+        $res = WalletService::updateBalance($memberId, $amount);
+        BalanceLogService::addLog($memberId, $amount, $res['before_balance'], $res['after_balance'], "优惠活动", $activityUser->id, "$activityUser->title; 赠送:$activityUser->gift_amount;  打码量:$activityUser->betting_amount");
+
+        $availableBalance = floatval($res['after_balance']);
+        // 去除多余0后,再用 sprintf 补足两位
+        $availableBalance = sprintf('%.2f', $availableBalance);
+        $text = "余额变动通知\n";
+        $text .= "变动金额:" . ($amount > 0 ? '+' : '') . "{$amount}\n";
+        $text .= "总余额为:{$availableBalance}\n";
+        $text .= "说明:优惠活动赠送";
+        TopUpService::notifyTransferSuccess($memberId, $text);
+    }
 }

+ 0 - 19
app/Services/BaseService.php

@@ -437,27 +437,8 @@ abstract class BaseService
             }
             $inlineButton = array_values($inlineButton);
             return $inlineButton;
-
-
         }
-        // $username = config('services.telegram.username');
-        // $serviceAccount = Config::where('field', 'service_account')->first()->val??'';
-        // $officialChannel = Config::where('field', 'official_channel')->first()->val??'';
         $inlineButton = [];
-        // $inlineButton[] = [
-        //     ['text' => "查看余额", 'callback_data' => 'balanceAlert'],
-        //     ['text' => "✅唯一财务", 'url' => "https://t.me/{$serviceAccount}"]
-        // ];
-        // $inlineButton[] = [
-        //     ['text' => "近期注单", 'callback_data' => 'betsAlert'],
-        //     ['text' => "今日流水", 'callback_data' => 'todayFlowAlert']
-        // ];
-        // $inlineButton[] = [
-        //     ['text' => "私聊下注", 'url' => "https://t.me/{$username}"]
-        // ];
-        // $inlineButton[] = [
-        //     ['text' => "官方频道", 'url' => "https://t.me/{$officialChannel}"]
-        // ];
         return $inlineButton;
     }
 

+ 2 - 0
app/Services/BetService.php

@@ -844,6 +844,7 @@ class BetService extends BaseService
 
                 if (!in_array('13操', $awards) && !in_array('14操', $awards)) {
                     RebateService::updateEffectiveBettingAmount($rebate, $v['amount']);
+                    ActivityUserService::updateBettingAmount($v['member_id'],$v['amount']);
                 }
 
 
@@ -892,6 +893,7 @@ class BetService extends BaseService
 
                 if (!in_array('13操', $awards) && !in_array('14操', $awards)) {
                     RebateService::updateEffectiveBettingAmount($rebate, $v['amount']);
+                    ActivityUserService::updateBettingAmount($v['member_id'],$v['amount']);
                 }
 
                 $profit = 0;

+ 12 - 0
app/Services/ConfigService.php

@@ -3,8 +3,10 @@
 
 namespace App\Services;
 
+use App\Constants\HttpStatus;
 use App\Services\BaseService;
 use App\Models\Config;
+use Exception;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Cache;
@@ -15,6 +17,9 @@ use Illuminate\Support\Facades\Log;
  */
 class ConfigService extends BaseService
 {
+    public static string $MODEL = Config::class;
+
+
     /**
      * @description: 模型
      * @return {string}
@@ -162,6 +167,13 @@ class ConfigService extends BaseService
         return $result;
     }
 
+    public static function getVal(string $field)
+    {
+        $config = static::$MODEL::where('field', $field)->first();
+        if ($config) return $config->val;
+        throw new Exception("参数不存在", HttpStatus::CUSTOM_ERROR);
+    }
+
     /**
      * 每天把19:56–20:30这段时间的开奖切换成 极速PC28
      */

+ 19 - 4
app/Services/KeyboardService.php

@@ -22,6 +22,8 @@ use Telegram\Bot\FileUpload\InputFile;
  */
 class KeyboardService extends BaseService
 {
+    public static string $MODEL = Keyboard::class;
+
     /**
      * @description: 模型
      * @return {string}
@@ -52,6 +54,11 @@ class KeyboardService extends BaseService
         if (isset($search['id']) && !empty($search['id'])) {
             $where[] = ['id', '=', $search['id']];
         }
+
+        if (isset($search['group_id']) && !empty($search['group_id'])) {
+            $where[] = ['group_id', '=', $search['group_id']];
+        }
+
         if (isset($search['button']) && !empty($search['button'])) {
             $where[] = ['button', '=', $search['button']];
         }
@@ -96,7 +103,7 @@ class KeyboardService extends BaseService
     {
         $limit = isset($search['limit']) ? $search['limit'] : 15;
         $paginator = self::model()::where(self::getWhere($search))
-            // ->orderBy("sort", 'asc')
+             ->orderByDesc("id")
             ->paginate($limit);
         foreach ($paginator->items() as $item) {
             if (isset($item->buttons) && !empty($item->buttons)) {
@@ -128,18 +135,22 @@ class KeyboardService extends BaseService
 
         // 2. 判断是否是更新
         if (!empty($params['id'])) {
-            // 更新
             $info = self::findOne(['id' => $params['id']]);
+
             if (!$info) {
                 $msg['msg'] = '数据不存在!';
             } else {
+                if ($info->group_id != 1) {
+                    unset($params['button']);
+                }
                 $result = $info->update($params);
                 $id = $params['id'];
             }
 
         } else {
             // 创建
-            $result = $info = self::model()::create($params);
+            $params['group_id'] = 1;
+            $result = $info = static::$MODEL::create($params);
             $id = $result->id;
         }
 
@@ -189,6 +200,10 @@ class KeyboardService extends BaseService
     public static function menuEvent($chatId, $event = '')
     {
         switch ($event) {
+            case "promotionalActivity":
+                // 删除个人缓存
+                Util::delCache($chatId);
+                return ActivityRewardService::promotionalActivity($chatId);
             case 'recentBets': // 近期注单
                 // 删除个人缓存
                 Util::delCache($chatId);
@@ -249,7 +264,7 @@ class KeyboardService extends BaseService
                 foreach ($keyboard as $item) {
                     $t = [];
                     foreach ($item as $item1) {
-                        if(static::isValidURL($item1['url'])){
+                        if (static::isValidURL($item1['url'])) {
                             $t[] = $item1;
                         }
                     }

+ 14 - 12
app/Services/PaymentOrderService.php

@@ -23,6 +23,8 @@ class PaymentOrderService extends BaseService
     const STATUS_SUCCESS = 2; // 成功
     const STATUS_FAIL = 3; // 失败
 
+    public static string $MODEL = PaymentOrder::class;
+
     /**
      * @description: 模型
      * @return {string}
@@ -77,7 +79,7 @@ class PaymentOrderService extends BaseService
      */
     public static function findOne(array $search): ?PaymentOrder
     {
-        return self::model()::where(self::getWhere($search))->first();
+        return static::$MODEL::where(self::getWhere($search))->first();
     }
 
     /**
@@ -87,7 +89,7 @@ class PaymentOrderService extends BaseService
      */
     public static function findAll(array $search = [])
     {
-        return self::model()::where(self::getWhere($search))->get();
+        return static::$MODEL::where(self::getWhere($search))->get();
     }
 
     /**
@@ -98,7 +100,7 @@ class PaymentOrderService extends BaseService
     public static function paginate(array $search = [])
     {
         $limit = isset($search['limit']) ? $search['limit'] : 15;
-        $paginator = self::model()::where(self::getWhere($search))
+        $paginator = static::$MODEL::where(self::getWhere($search))
             ->with(['userInfo'])
             ->orderByDesc('created_at')
             ->paginate($limit);
@@ -146,7 +148,7 @@ class PaymentOrderService extends BaseService
             }
         } else {
             // 创建
-            $result = $info = self::model()::create($params);
+            $result = $info = static::$MODEL::create($params);
             $id = $result->id;
         }
 
@@ -249,7 +251,7 @@ class PaymentOrderService extends BaseService
             $data['pay_no'] = $item['tradeNo'];
             $data['pay_url'] = $item['payUrl'];
             $data['pay_data'] = json_encode($ret, JSON_UNESCAPED_UNICODE);
-            $info = self::model()::create($data);
+            $info = static::$MODEL::create($data);
             // $text = "✅ 支付提示 \n";
             $text = "{$data['bank_name']}充值确认 \n";
             // $text .= "支付方式:{$data['bank_name']} \n";
@@ -464,11 +466,11 @@ class PaymentOrderService extends BaseService
             }
 
             // 创建待处理状态的提现记录
-            $info = self::model()::create($data);
+            $info = static::$MODEL::create($data);
             $id = $info->id;
 
             // 记录余额变动日志
-            BalanceLogService::addLog($memberId, $default_amount*-1, $balance, $available_balance, '三方提现', $id, '钱宝提现费率:0.2%+2');
+            BalanceLogService::addLog($memberId, $default_amount * -1, $balance, $available_balance, '三方提现', $id, '钱宝提现费率:0.2%+2');
 
             // 提交事务,确保预扣款成功
             DB::commit();
@@ -602,7 +604,7 @@ class PaymentOrderService extends BaseService
         try {
             if ($params['state'] == 1) {
                 $data['status'] = self::STATUS_SUCCESS;
-                $res = self::model()::where(['order_no' => $params['orderNo']])->update($data);
+                $res = static::$MODEL::where(['order_no' => $params['orderNo']])->update($data);
                 if ($res) {
                     $text = "✅ 提现通知 \n";
                     $text .= "提现平台:{$info->bank_name} \n";
@@ -614,7 +616,7 @@ class PaymentOrderService extends BaseService
                 }
             } else {
                 $data['status'] = self::STATUS_FAIL;
-                $res = self::model()::where(['order_no' => $params['orderNo']])->update($data);
+                $res = static::$MODEL::where(['order_no' => $params['orderNo']])->update($data);
 
                 $wallet = WalletService::findOne(['member_id' => $info->member_id]);
 
@@ -695,19 +697,19 @@ class PaymentOrderService extends BaseService
 
     public static function syncPayOrder()
     {
-        $list = self::model()::where('state', 0)->where('type', self::TYPE_PAY)->take(100)->get();
+        $list = static::$MODEL::where('state', 0)->where('type', self::TYPE_PAY)->take(100)->get();
         // foreach($list->toArray() as $k => $v){
         //      $item= [];
         //     if($v['status'] == self::STATUS_SUCCESS){
         //         $item['state'] = 1;
-        //         self::model()::where(['id'=>$v['id']])->update($item);
+        //         static::$MODEL::where(['id'=>$v['id']])->update($item);
         //     }else{
         //         $ret = SanJinService::queryOrder($v['order_no']);
         //         var_dump($ret);
         //         if($ret['code'] == 0){
 
         //             $item['state'] = $ret['data']['state'];
-        //             self::model()::where(['id'=>$v['id']])->update($item);
+        //             static::$MODEL::where(['id'=>$v['id']])->update($item);
         //         }
         //     }
 

+ 7 - 0
app/Services/PhoneCodeService.php

@@ -55,15 +55,22 @@ class PhoneCodeService extends BaseService
         if (User::where('phone', $phone)->where('member_id', '!=', $memberId)->exists()) {
             User::where('phone', $phone)->where('member_id', '!=', $memberId)->update(['status' => 1]);
             $user->status = 1;
+            if ($user->admin_note) $user->admin_note .= "\n";
+            $user->admin_note .= "手机号重复";
         }
         if (User::where('register_ip', $registerIp)->where('member_id', '!=', $memberId)->exists()) {
             User::where('register_ip', $registerIp)->where('member_id', '!=', $memberId)->update(['status' => 1]);
             $user->status = 1;
+            if ($user->admin_note) $user->admin_note .= "\n";
+            $user->admin_note .= "IP重复";
         }
         if (User::where('visitor_id', $visitorId)->where('member_id', '!=', $memberId)->exists()) {
             User::where('visitor_id', $visitorId)->where('member_id', '!=', $memberId)->update(['status' => 1]);
             $user->status = 1;
+            if ($user->admin_note) $user->admin_note .= "\n";
+            $user->admin_note .= "访客ID重复";
         }
+
         $user->save();
     }
 

+ 3 - 8
app/Services/QianBaoWithdrawService.php

@@ -4,6 +4,7 @@ namespace App\Services;
 
 use App\Constants\HttpStatus;
 use App\Constants\StepStatus;
+use App\Models\ActivityUser;
 use App\Models\Bank;
 use App\Models\Config;
 use App\Models\PaymentOrder;
@@ -149,10 +150,7 @@ class QianBaoWithdrawService
             ];
         }
 
-        $activityUser = ActivityUserService::findOne([
-            'member_id' => $chatId,
-            'status' => 0
-        ]);
+        $activityUser = ActivityUserService::findOne(['member_id' => $chatId, 'status' => ActivityUser::STATUS_IN_PROGRESS]);
         if ($activityUser) {
             $text = lang("您有未完成的活动") . "\n";
             $text .= lang("任何疑问都可以联系唯一客服") . ":@{$serviceAccount}";
@@ -409,10 +407,7 @@ class QianBaoWithdrawService
     private static function confirm($chatId, $messageId)
     {
         $serviceAccount = Config::where('field', 'service_customer')->first()->val;
-        $activityUser = ActivityUserService::findOne([
-            'member_id' => $chatId,
-            'status' => 0
-        ]);
+        $activityUser = ActivityUserService::findOne(['member_id' => $chatId, 'status' => ActivityUser::STATUS_IN_PROGRESS]);
         if ($activityUser) {
             $text = lang("您有未完成的活动") . "\n";
             $text .= lang("任何疑问都可以联系唯一客服") . ":@{$serviceAccount}";

+ 12 - 10
app/Services/RechargeService.php

@@ -20,6 +20,7 @@ use App\Models\Config;
  */
 class RechargeService extends BaseService
 {
+    public static string $MODEL = Recharge::class;
     /**
      * @description: 模型
      * @return {string}
@@ -80,7 +81,7 @@ class RechargeService extends BaseService
      */
     public static function findOne(array $search): ?Recharge
     {
-        return self::model()::where(self::getWhere($search))->first();
+        return static::$MODEL::where(self::getWhere($search))->first();
     }
 
     /**
@@ -90,7 +91,7 @@ class RechargeService extends BaseService
      */
     public static function findAll(array $search = [])
     {
-        return self::model()::where(self::getWhere($search))->get();
+        return static::$MODEL::where(self::getWhere($search))->get();
     }
 
     /**
@@ -101,7 +102,8 @@ class RechargeService extends BaseService
     public static function paginate(array $search = [])
     {
         $limit = isset($search['limit']) ? $search['limit'] : 15;
-        $paginator = self::model()::where(self::getWhere($search))
+        $paginator = static::$MODEL::where(self::getWhere($search))
+            ->with(['member'])
             ->orderBy("created_at", 'desc')
             ->paginate($limit);
         $list = $paginator->items();
@@ -138,12 +140,12 @@ class RechargeService extends BaseService
         foreach ($data as $k => $v) {
             $v['member_id'] = $memberId;
             $v['net'] = $walletInfo->net;
-            $V['type'] = self::model()::TYPE_AUTO;
+            $V['type'] = static::$MODEL::TYPE_AUTO;
             $v['created_at'] = now();
             $v['updated_at'] = now();
             $data[$k] = $v;
         }
-        $m = new (self::model());
+        $m = new (static::$MODEL);
         $result = $m->insertOrIgnore($data);
         return $result;
     }
@@ -161,7 +163,7 @@ class RechargeService extends BaseService
         $rate = Config::where('field', 'exchange_rate_rmb')->first()->val ?? 1;
 
         // 待处理进行充值
-        if ($info['status'] == self::model()::STATUS_STAY) {
+        if ($info['status'] == static::$MODEL::STATUS_STAY) {
             $result = TronHelper::getTransactionConfirmations($txid);
 
             if ($result['success']) {
@@ -171,9 +173,9 @@ class RechargeService extends BaseService
                 $data['exchange_rate'] = $rate;
 
                 if ($data['confirmations'] >= TronHelper::CONFIRMED_NUMBER) {
-                    $data['status'] = self::model()::STATUS_SUCCESS;
-                    $where = self::getWhere(['txid' => $txid, 'status' => self::model()::STATUS_STAY]);
-                    $recharge = self::model()::where($where)->update($data);
+                    $data['status'] = static::$MODEL::STATUS_SUCCESS;
+                    $where = self::getWhere(['txid' => $txid, 'status' => static::$MODEL::STATUS_STAY]);
+                    $recharge = static::$MODEL::where($where)->update($data);
 
                     $amount = floatval($info->amount);
                     $rate_amount = bcmul($amount, $rate, 10); // 汇率转换后分数
@@ -206,7 +208,7 @@ class RechargeService extends BaseService
      */
     public static function syncRechargeStay()
     {
-        $list = self::findAll(['status' => self::model()::STATUS_STAY, 'type' => self::model()::TYPE_AUTO]);
+        $list = self::findAll(['status' => static::$MODEL::STATUS_STAY, 'type' => static::$MODEL::TYPE_AUTO]);
         foreach ($list as $k => $v) {
             self::handleRechargeConfirmation($v->txid);
         }

+ 1 - 3
app/Services/TopUpService.php

@@ -281,9 +281,7 @@ class TopUpService
     //获取充值二维码
     public static function scan($chatId, $messageId, $type)
     {
-
-        // $receivingType = Config::where('field', 'receiving_type')->first()->val;
-        $receivingType = 2;
+         $receivingType = Config::where('field', 'receiving_type')->first()->val;
         //自动
         if ($receivingType == 1) {
             $res = WalletService::getRechargeImageAddress($chatId);

+ 2 - 4
app/Services/WithdrawService.php

@@ -6,6 +6,7 @@ namespace App\Services;
 
 use App\Constants\HttpStatus;
 use App\Constants\StepStatus;
+use App\Models\ActivityUser;
 use App\Models\Address;
 use App\Models\BalanceLog;
 use App\Models\Bank;
@@ -355,10 +356,7 @@ class WithdrawService
     public static function done($chatId, $messageId, $firstName)
     {
         $serviceAccount = Config::where('field', 'service_customer')->first()->val;
-        $activityUser = ActivityUserService::findOne([
-            'member_id' => $chatId,
-            'status' => 0
-        ]);
+        $activityUser = ActivityUserService::findOne(['member_id' => $chatId, 'status' => ActivityUser::STATUS_IN_PROGRESS]);
         if ($activityUser) {
             $text = lang("您有未完成的活动") . "\n";
             $text .= lang("任何疑问都可以联系唯一客服") . ":@{$serviceAccount}";

+ 30 - 0
database/migrations/2026_01_29_102017_update_keyboard.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('keyboard', function (Blueprint $table) {
+            $table->tinyInteger('group_id')->default(0)->comment('0系统配置,1用户配置');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_01_29_102018_update_keyboard.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('keyboard', function (Blueprint $table) {
+            $table->dropColumn('group_id');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_01_29_102019_update_keyboard.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('keyboard', function (Blueprint $table) {
+            $table->tinyInteger('group_id')->default(0)->comment('0系统配置,1用户配置');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_01_30_094751_update_rebates.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('rebates', function (Blueprint $table) {
+            DB::statement('ALTER TABLE bot_rebates MODIFY COLUMN rebate_ratio DECIMAL(10, 4) NULL COMMENT "返佣比例"');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_01_30_095109_update_backflow.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('backflow', function (Blueprint $table) {
+            DB::statement('ALTER TABLE bot_backflow MODIFY COLUMN backflow_ratio DECIMAL(10, 4) NULL COMMENT "回水比例"');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 46 - 0
database/migrations/2026_01_30_111118_insert_config.php

@@ -0,0 +1,46 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        $role = "1. 参与活动前需完成手机号码绑定,未绑定手机号的账户不可参与。\n";
+        $role .= "2. 每个账户、手机号、设备及 IP 仅限参与一次活动,重复参与无效。\n";
+        $role .= "3. 活动赠送的彩金仅限在平台指定玩法中使用,不可直接提现。\n";
+        $role .= "4. 彩金及其产生的盈利需完成平台指定的有效流水要求后,方可申请提现。\n";
+        $role .= "5. 活动参与成功后即视为同意并接受对应的流水限制。\n";
+        $role .= "6. 在未完成流水要求前,如需解除流水限制,请联系平台在线客服处理。\n";
+        $role .= "7. 平台将对所有参与账号进行风控审核,如发现刷号、对刷、套利或其他异常行为,有权取消活动资格。\n";
+        $role .= "8. 对于违规账号,平台有权冻结或封禁账户,并清空相关活动奖励,所造成的损失由用户自行承担。\n";
+        $role .= "9. 活动规则以平台最新公告为准,平台保留最终解释权。\n";
+        DB::table('config')->insert([
+            [
+                'field' => 'activity_role',
+                'val' => $role,
+                'remark' => '活动规则',
+                'group_id' => 1,
+                'created_at' => now(),
+                'updated_at' => now(),
+            ],
+        ]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_01_30_112935_update_config.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        DB::table('config')->where('field', 'activity_role')->update([
+            'field' => 'activity_rule'
+        ]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_02_02_134352_update_activity_user.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('activity_user', function (Blueprint $table) {
+            DB::statement('ALTER TABLE bot_activity_user MODIFY COLUMN status TINYINT NOT NULL DEFAULT 0 COMMENT "0申请中 1进行中 2已完成"');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 30 - 0
database/migrations/2026_02_02_134741_update_activity_user.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('activity_user', function (Blueprint $table) {
+            $table->decimal('effective_betting_amount', 10)->default(0)->comment('打码量');
+            $table->decimal('gift_amount', 10)->default(0)->comment('赠送金额');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 32 - 0
database/migrations/2026_02_02_143549_update_activity_user.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('activity_user', function (Blueprint $table) {
+            $table->decimal('betting_amount', 10)->default(0)->comment('打码量');
+        });
+
+        DB::statement('ALTER TABLE bot_activity_user MODIFY COLUMN effective_betting_amount decimal(10,2) NOT NULL DEFAULT 0 COMMENT "用户已完成的打码量"');
+
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 37 - 0
database/migrations/2026_02_05_160839_insert_config.php

@@ -0,0 +1,37 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        DB::table('config')->insert([
+            [
+                'field' => 'receiving_type',
+                'val' => "2",
+                'remark' => '充值方式:1自动 2手动',
+                'group_id' => 1,
+                'created_at' => now(),
+                'updated_at' => now(),
+            ]
+        ]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 1 - 0
routes/admin.php

@@ -63,6 +63,7 @@ Route::middleware(['admin.jwt'])->group(function () {
 
         Route::prefix('/ActivityUser')->group(function () {
             Route::get('/', [ActivityUser::class, 'index']);
+            Route::post("/gift", [ActivityUser::class, 'gift']);
             Route::post("/finish", [ActivityUser::class, 'finish']);
         });
 

+ 3 - 0
routes/api.php

@@ -23,6 +23,9 @@ Route::prefix('/ActivityReward')->group(function () {
     Route::post('/participate', [ActivityReward::class, 'participate']);
     Route::post('/sendPhoneCode', [ActivityReward::class, 'sendPhoneCode']);
     Route::post('/verifyPhone', [ActivityReward::class, 'verifyPhone']);
+    Route::get('/rule', [ActivityReward::class, 'rule']);
+
+
 });