فهرست منبع

admin_websocket

rkljw 9 ماه پیش
والد
کامیت
c8469ba61a
100فایلهای تغییر یافته به همراه3637 افزوده شده و 52 حذف شده
  1. 34 0
      .gitignore
  2. 18 0
      app/Amqp/Producer/MqProducer.php
  3. 20 0
      app/Cache/Contracts/HashRedisInterface.php
  4. 18 0
      app/Cache/Contracts/ListRedisInterface.php
  5. 10 0
      app/Cache/Contracts/LockRedisInterface.php
  6. 20 0
      app/Cache/Contracts/SetRedisInterface.php
  7. 20 0
      app/Cache/Contracts/StreamRedisInterface.php
  8. 16 0
      app/Cache/Contracts/StringRedisInterface.php
  9. 26 0
      app/Cache/Contracts/ZSetRedisInterface.php
  10. 57 0
      app/Command/DelayCommand.php
  11. 29 0
      app/Command/FooCommand.php
  12. 51 0
      app/Constant/TalkEventConstant.php
  13. 38 0
      app/Constant/TalkMessageType.php
  14. 30 0
      app/Constant/TalkModeConstant.php
  15. 5 3
      app/Controller/AbstractController.php
  16. 206 9
      app/Controller/AdController.php
  17. 9 8
      app/Controller/AuthorityController.php
  18. 247 0
      app/Controller/ChatController.php
  19. 28 0
      app/Controller/IndexController.php
  20. 112 0
      app/Controller/LinkController.php
  21. 14 1
      app/Controller/LoginController.php
  22. 318 0
      app/Controller/NewsController.php
  23. 111 0
      app/Controller/WebSocketController.php
  24. 29 0
      app/Event/TalkEvent.php
  25. 67 5
      app/JsonRpc/AdService.php
  26. 45 4
      app/JsonRpc/AdServiceInterface.php
  27. 335 0
      app/JsonRpc/ChatService.php
  28. 222 0
      app/JsonRpc/ChatServiceInterface.php
  29. 56 0
      app/JsonRpc/LinkService.php
  30. 28 0
      app/JsonRpc/LinkServiceInterface.php
  31. 110 0
      app/JsonRpc/NewsService.php
  32. 56 0
      app/JsonRpc/NewsServiceInterface.php
  33. 1 1
      app/Middleware/Auth/FooMiddleware.php
  34. 63 0
      app/Middleware/JWTAuthMiddleware.php
  35. 56 0
      app/Middleware/WebSocketAuthMiddleware.php
  36. 87 0
      app/Service/Message/ReceiveHandleService.php
  37. 35 0
      app/Service/RedisInterface.php
  38. 72 0
      app/Service/RedisService.php
  39. 89 0
      app/Service/SocketClientService.php
  40. 9 0
      app/Tools/CommonService.php
  41. 27 1
      app/Tools/PublicData.php
  42. 5 1
      composer.json
  43. 674 8
      composer.lock
  44. 35 0
      config/autoload/amqp.php
  45. 1 0
      config/autoload/dependencies.php
  46. 3 0
      config/autoload/middlewares.php
  47. 2 2
      config/autoload/redis.php
  48. 12 0
      config/autoload/server.php
  49. 50 5
      config/autoload/services.php
  50. 23 0
      config/autoload/snowflake.php
  51. 8 4
      config/routes.php
  52. BIN
      public/image/20240701/171980475880998.png
  53. BIN
      public/image/20240701/1719804797525391.png
  54. BIN
      public/image/20240701/171980486022785.png
  55. BIN
      public/image/20240701/1719814246170673.png
  56. BIN
      public/image/20240701/1719821095401452.png
  57. BIN
      public/image/20240701/1719821117962271.png
  58. BIN
      public/image/20240701/1719821162245282.png
  59. BIN
      public/image/20240701/171982121662014.png
  60. BIN
      public/image/20240701/1719821685532250.png
  61. BIN
      public/image/20240701/1719822293283470.png
  62. BIN
      public/image/20240701/1719822555366246.png
  63. BIN
      public/image/20240701/1719822852277219.png
  64. BIN
      public/image/20240701/1719823060348423.png
  65. BIN
      public/image/20240701/1719823485800981.png
  66. BIN
      public/image/20240701/171982366157844.png
  67. BIN
      public/image/20240701/1719823907487697.png
  68. BIN
      public/image/20240701/1719823988808424.png
  69. BIN
      public/image/20240701/1719824474422655.png
  70. BIN
      public/image/20240701/1719824610588298.png
  71. BIN
      public/image/20240701/171982573350041.png
  72. BIN
      public/image/20240701/1719825849433783.jpg
  73. BIN
      public/image/20240701/1719825875489029.png
  74. BIN
      public/image/20240701/1719825904104745.png
  75. BIN
      public/image/20240701/171982593655238.png
  76. BIN
      public/image/20240701/1719826014111488.jpg
  77. BIN
      public/image/20240701/1719827075515168.png
  78. BIN
      public/image/20240701/171982714652839.jpg
  79. BIN
      public/image/20240701/1719832332463752.png
  80. BIN
      public/image/20240701/1719832635693656.png
  81. BIN
      public/image/20240703/1719986589727690.png
  82. BIN
      public/image/20240703/171998663958838.png
  83. BIN
      public/image/20240703/1719986788801847.png
  84. BIN
      public/image/20240703/1719987104955969.png
  85. BIN
      public/image/20240704/1720053228201114.jpg
  86. BIN
      public/image/20240704/1720053282400602.jpg
  87. BIN
      public/image/20240704/1720057766796487.jpg
  88. BIN
      public/image/20240704/1720057806971205.jpg
  89. BIN
      public/image/20240704/1720057911521482.jpg
  90. BIN
      public/image/20240704/1720058234717205.jpg
  91. BIN
      public/image/20240704/1720060330124061.jpg
  92. BIN
      public/image/20240704/1720061591267295.jpg
  93. BIN
      public/image/20240704/1720063364683465.jpg
  94. BIN
      public/image/20240704/1720063418294166.jpg
  95. BIN
      public/image/20240704/172008405373300.jpg
  96. BIN
      public/image/20240704/1720085834599076.jpg
  97. BIN
      public/image/20240704/1720085992384760.jpg
  98. BIN
      public/image/20240719/1721372280562912.jpg
  99. BIN
      public/image/20240719/1721372309952084.jpg
  100. BIN
      public/image/20240719/1721372470477268.jpg

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Amqp\Consumer;
+
+use Hyperf\Amqp\Result;
+use Hyperf\Amqp\Annotation\Consumer;
+use Hyperf\Amqp\Message\ConsumerMessage;
+use Hyperf\Di\Annotation\Inject;
+use PhpAmqpLib\Message\AMQPMessage;
+use App\JsonRpc\ChatServiceInterface;
+#[Consumer(exchange: 'hyperf', routingKey: 'hyperf', queue: 'hyperf', name: "MqConsumer", nums: 1)]
+class MqConsumer extends ConsumerMessage
+{
+    /**
+     * @var ChatServiceInterface
+     */
+    #[Inject]
+    private  $chatServiceClient;
+    public function consumeMessage($data, AMQPMessage $message): Result
+    {
+        //数据存储
+        var_dump($data,$message->getBodySize());
+        $result = $this->chatServiceClient->addTalkRecords($data);
+        var_dump("消费成功:",$result);
+        return Result::ACK;
+    }
+
+//    public function isEnable(): bool
+//    {
+//        return false;
+//    }
+}

+ 18 - 0
app/Amqp/Producer/MqProducer.php

@@ -0,0 +1,18 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Amqp\Producer;
+
+use Hyperf\Amqp\Annotation\Producer;
+use Hyperf\Amqp\Message\ProducerMessage;
+
+#[Producer(exchange: 'hyperf', routingKey: 'hyperf')]
+class MqProducer extends ProducerMessage
+{
+    public function __construct($data)
+    {
+//        $this->poolName = 'default';
+        $this->payload = $data;
+    }
+}

+ 20 - 0
app/Cache/Contracts/HashRedisInterface.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface SetRedisInterface
+{
+    public function count();
+
+    public function add(string ...$member);
+
+    public function rem(string ...$member);
+
+    public function isMember(string $member);
+
+    public function randMember($count = 1);
+
+    public function all();
+
+    public function delete();
+}

+ 18 - 0
app/Cache/Contracts/ListRedisInterface.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface ListRedisInterface
+{
+    public function push(string ...$value);
+
+    public function pop();
+
+    public function count();
+
+    public function clear();
+
+    public function all();
+
+    public function delete();
+}

+ 10 - 0
app/Cache/Contracts/LockRedisInterface.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface LockRedisInterface
+{
+    public function lock(string $key, $expired = 1, int $timeout = 0);
+
+    public function delete(string $key);
+}

+ 20 - 0
app/Cache/Contracts/SetRedisInterface.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface SetRedisInterface
+{
+    public function count();
+
+    public function add(string ...$member);
+
+    public function rem(string ...$member);
+
+    public function isMember(string $member);
+
+    public function randMember($count = 1);
+
+    public function all();
+
+    public function delete();
+}

+ 20 - 0
app/Cache/Contracts/StreamRedisInterface.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface SetRedisInterface
+{
+    public function count();
+
+    public function add(string ...$member);
+
+    public function rem(string ...$member);
+
+    public function isMember(string $member);
+
+    public function randMember($count = 1);
+
+    public function all();
+
+    public function delete();
+}

+ 16 - 0
app/Cache/Contracts/StringRedisInterface.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface StringRedisInterface
+{
+    public function set(string $key, string $value, $expires = null);
+
+    public function get(string $key);
+
+    public function delete(string $key);
+
+    public function isExist(string $key);
+
+    public function ttl(string $key);
+}

+ 26 - 0
app/Cache/Contracts/ZSetRedisInterface.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Cache\Contracts;
+
+interface ZSetRedisInterface
+{
+    public function add(string $member, float $score);
+
+    public function rem(string ...$member);
+
+    public function incr(string $member, float $score);
+
+    public function isMember(string $member);
+
+    public function count();
+
+    public function all($asc = true, $is_score = true);
+
+    public function rank($page = 1, $size = 10, $asc = true);
+
+    public function getMemberRank(string $member, $asc = true);
+
+    public function getMemberScore(string $member);
+
+    public function delete();
+}

+ 57 - 0
app/Command/DelayCommand.php

@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Command;
+
+use App\Amqp\Producer\DelayDirectProducer;
+use App\Amqp\Producer\MqProducer;
+use Hyperf\Amqp\Producer;
+use Hyperf\Command\Command as HyperfCommand;
+use Hyperf\Command\Annotation\Command;
+use Hyperf\Context\ApplicationContext as ContextApplicationContext;
+use Hyperf\Utils\ApplicationContext;
+use Psr\Container\ContainerInterface;
+
+/**
+ * @Command
+ */
+#[Command]
+class DelayCommand extends HyperfCommand
+{
+    /**
+     * @var ContainerInterface
+     */
+    protected $container;
+
+    public function __construct(ContainerInterface $container)
+    {
+        $this->container = $container;
+
+        parent::__construct('demo:queue');
+    }
+
+    public function configure()
+    {
+        parent::configure();
+        $this->setDescription('生产消息发布 ');
+    }
+
+    public function handle()
+    {
+        for ($i = 0; $i < 100; $i++) {
+            $data = [
+                "ss" => 122,
+                "num" => $i,
+                "number" => mt_rand(1111, 9999),
+                "time" => time(),
+            ];
+            $message = new MqProducer($data);
+            $producer = ContextApplicationContext::getContainer()->get(Producer::class);
+            $ret = $producer->produce($message);
+        }
+        print_r($ret);
+        $this->line('Hello Hyperf!', 'info');
+        exit();
+    }
+}

+ 29 - 0
app/Command/FooCommand.php

@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Command;
+
+use Hyperf\Command\Command as HyperfCommand;
+use Hyperf\Command\Annotation\Command;
+use Psr\Container\ContainerInterface;
+
+#[Command]
+class FooCommand extends HyperfCommand
+{
+    public function __construct(protected ContainerInterface $container)
+    {
+        parent::__construct('demo:command');
+    }
+
+    public function configure()
+    {
+        parent::configure();
+        $this->setDescription('Hyperf Demo Command');
+    }
+
+    public function handle()
+    {
+        $this->line('Hello Hyperf!', 'info');
+    }
+}

+ 51 - 0
app/Constant/TalkEventConstant.php

@@ -0,0 +1,51 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Constant;
+
+/**
+ * WebSocket 消息事件枚举
+ *
+ * @package App\Constants
+ */
+class TalkEventConstant
+{
+    /**
+     * 对话消息通知 - 事件名
+     */
+    const EVENT_TALK = 'event_talk';
+
+    /**
+     * 键盘输入事件通知 - 事件名
+     */
+    const EVENT_TALK_KEYBOARD = 'event_talk_keyboard';
+
+    /**
+     * 用户在线状态通知 - 事件名
+     */
+    const EVENT_LOGIN = 'event_login';
+
+    /**
+     * 聊天消息撤销通知 - 事件名
+     */
+    const EVENT_TALK_REVOKE = 'event_talk_revoke';
+
+    /**
+     * 好友申请消息通知 - 事件名
+     */
+    const EVENT_CONTACT_APPLY = 'event_contact_apply';
+
+    /**
+     * @return array
+     */
+    public static function getMap(): array
+    {
+        return [
+            self::EVENT_TALK          => '对话消息通知',
+            self::EVENT_TALK_KEYBOARD => '键盘输入事件通知',
+            self::EVENT_LOGIN         => '用户在线状态通知',
+            self::EVENT_TALK_REVOKE   => '聊天消息撤销通知',
+            self::EVENT_CONTACT_APPLY => '好友申请消息通知'
+        ];
+    }
+}

+ 38 - 0
app/Constant/TalkMessageType.php

@@ -0,0 +1,38 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Constant;
+
+/**
+ * Class TalkMessageType
+ *
+ * @package App\Constants
+ */
+class TalkMessageType
+{
+    const SYSTEM_TEXT_MESSAGE  = 0;  //系统文本消息
+    const TEXT_MESSAGE         = 1;  //文本消息
+    const FILE_MESSAGE         = 2;  //文件消息
+    const FORWARD_MESSAGE      = 3;  //会话消息
+    const CODE_MESSAGE         = 4;  //代码消息
+    const VOTE_MESSAGE         = 5;  //投票消息
+    const GROUP_NOTICE_MESSAGE = 6;  //群组公告
+    const FRIEND_APPLY_MESSAGE = 7;  //好友申请
+    const USER_LOGIN_MESSAGE   = 8;  //登录通知
+    const GROUP_INVITE_MESSAGE = 9;  //入群退群消息
+    const LOCATION_MESSAGE     = 10; //位置消息(预留)
+
+    /**
+     * 获取可转发的消息类型列表
+     *
+     * @return array
+     */
+    public static function getForwardTypes(): array
+    {
+        return [
+            self::TEXT_MESSAGE,
+            self::FILE_MESSAGE,
+            self::CODE_MESSAGE
+        ];
+    }
+}

+ 30 - 0
app/Constant/TalkModeConstant.php

@@ -0,0 +1,30 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Constant;
+
+/**
+ * 聊天对话模式
+ *
+ * @package App\Constants
+ */
+class TalkModeConstant
+{
+    /**
+     * 私信
+     */
+    const PRIVATE_CHAT = 1;
+
+    /**
+     * 群聊
+     */
+    const GROUP_CHAT = 2;
+
+    public static function getTypes(): array
+    {
+        return [
+            self::PRIVATE_CHAT,
+            self::GROUP_CHAT
+        ];
+    }
+}

+ 5 - 3
app/Controller/AbstractController.php

@@ -38,16 +38,18 @@ abstract class AbstractController
 
     protected $UserId;
 
+    protected $websiteId;
+
+
     public function __construct(LoggerFactory $loggerFactory)
     {
         // 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key
         $this->logger = $loggerFactory->get('admin_consumer:', 'default');
-
-         $headers = $this->request->getHeaders();
-//        var_dump( $headers['token'][0]!='null');
+        $headers = $this->request->getHeaders();
         if($headers &&  isset($headers['token']) && $headers['token'][0]!='null' && isset($headers['token'][0])){
             $userInfo = $this->jwt->getClaimsByToken($headers['token'][0]);
             $this->UserId = $userInfo['uid'];
+            $this->websiteId = $userInfo['website_id']??0;
         }
 
     }

+ 206 - 9
app/Controller/AdController.php

@@ -5,12 +5,14 @@ declare(strict_types=1);
 namespace App\Controller;
 
 use App\JsonRpc\AdServiceInterface;
-//use Hyperf\Contract\StdoutLoggerInterface;
+use App\Tools\PublicData;
 use Hyperf\Di\Annotation\Inject;
 use Hyperf\HttpServer\Annotation\AutoController;
 use App\Tools\Result;
 use App\Constants\ErrorCode;
 use Hyperf\Logger;
+use Hyperf\Validation\Contract\ValidatorFactoryInterface;
+
 /**
  * Class AdController
  * @package App\Controller
@@ -18,18 +20,36 @@ use Hyperf\Logger;
 #[AutoController]
 class AdController extends AbstractController
 {
-
+    #[Inject]
+    protected ValidatorFactoryInterface $validationFactory;
     /**
      * @var AdServiceInterface
      */
     #[Inject]
-    private  $adServiceInterface;
+    private  $adServiceClient;
 
     public function createAd()
     {
-        $name = (string)$this->request->input('name', '');
-        $gender = (string)$this->request->input('url', 0);
-        $result = $this->adServiceInterface->createAd($name, $gender);
+
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'name' => 'required',
+                'website_id' => 'required',
+                'price' => 'required',
+            ],
+            [
+                'name.required' => '名称不能为空',
+                'website_id.required' => '站点不能为空',
+                'price.required' => '价格不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $result = $this->adServiceClient->createAd($requireData);
         return $result?Result::success($result['data']):Result::error($result['message']);
     }
 
@@ -38,12 +58,189 @@ class AdController extends AbstractController
      */
     public function getAdInfo()
     {
-        $id = (int)$this->request->input('id');
-        $result =  $this->adServiceInterface->getAdInfo($id);
-//        $this->logger->info("ceshi--");
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id' => 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $id = (int)$requireData['id'];
+        $result =  $this->adServiceClient->getAdInfo($id);
         if ($result['code'] != ErrorCode::SUCCESS) {
             return Result::error($result['message'],0);
         }
         return Result::success($result['data']);
     }
+
+    public function getAdList()
+    {
+
+        $requireData = $this->request->all();
+
+        $nowTime = date("Y-m-d H:i:s");
+        $result = $this->adServiceClient->getAdList($requireData);
+        if($result['data']){
+            $typeList = ['1'=>'文字','2'=>'图文'];
+            $statusName = ['1'=>'通过','2'=>'待审'];
+            foreach ($result['data']['rows'] as $k=>$v) {
+                $result['data']['rows'][$k]['type_name'] = $typeList[$v['typeid']];
+                $result['data']['rows'][$k]['status_name'] = $statusName[$v['status']];
+                $result['data']['rows'][$k]['day'] = PublicData::residueDay(date("Y-m-d H:i:s"),$v['totime']);
+                if($nowTime<$v['fromtime']){
+                    $result['data']['rows'][$k]['runing_name'] = '未开始';
+                }else if($nowTime>$v['totime']){
+                    $result['data']['rows'][$k]['runing_name'] = '已过期';
+                }else{
+                    $result['data']['rows'][$k]['runing_name'] = '投放中';
+                }
+
+            }
+        }
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    public function updateAd()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'name' => 'required',
+                'status' => 'required',
+            ],
+            [
+                'name.required' => '名称不能为空',
+                'status.required' => '状态不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $requireData = $this->request->all();
+        $result = $this->adServiceClient->updateAd($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    public function delAd()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id' => 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $result = $this->adServiceClient->delAd($requireData);
+        var_dump($result);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 获取广告位列表
+     * @return array
+     */
+    public function getAdPlaceList()
+    {
+
+        $requireData = $this->request->all();
+        var_dump($requireData);
+        $result = $this->adServiceClient->getAdPlaceList($requireData);
+        if($result['data']){
+            $typeList = ['1'=>'文字','2'=>'图文'];
+            $statusName = ['1'=>'通过','2'=>'待审'];
+            foreach ($result['data']['rows'] as $k=>$v) {
+                $result['data']['rows'][$k]['type_name'] = $typeList[$v['typeid']];
+                $result['data']['rows'][$k]['status_name'] = $statusName[$v['status']];
+            }
+        }
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    public function createAdPlace()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'name' => 'required',
+                'website_id' => 'required',
+                'price' => 'required',
+            ],
+            [
+                'name.required' => '名称不能为空',
+                'website_id.required' => '站点不能为空',
+                'price.required' => '价格不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $result = $this->adServiceClient->createAdPlace($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    public function updateAdPlace()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id' => 'required',
+                'name' => 'required',
+                'website_id' => 'required',
+                'price' => 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+                'name.required' => '名称不能为空',
+                'website_id.required' => '站点不能为空',
+                'price.required' => '价格不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $result = $this->adServiceClient->updateAdPlace($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    public function delAdPlace()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id' => 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+
+        $result = $this->adServiceClient->delAdPlace($requireData);
+        var_dump($result);
+        return $result['code']==200?Result::success($result['data']):Result::error($result['message']);
+    }
 }

+ 9 - 8
app/Controller/AuthorityController.php

@@ -80,15 +80,10 @@ class AuthorityController extends AbstractController
         $validator = $this->validationFactory->make(
             $requireData,
             [
-
                 'label' => 'required',
-//                'url' => 'required',
-
             ],
             [
-
                 'label.required' => '菜单名称不能为空',
-//                'url.required' => '路由地址不能为空',
             ]
         );
         if ($validator->fails()){
@@ -159,9 +154,15 @@ class AuthorityController extends AbstractController
      */
     public  function  getRecursionMenu()
     {
-       $result =  $this->authorityServiceClient->getRecursionMenu([]);
-       $rep = PublicData::buildMenuTree($result['data']);
-       return $rep?Result::success($rep):Result::error("查询失败");
+        $header = $this->request->getHeaders();
+
+        $reqData = [
+            'user_id' => $this->UserId,
+            'logindevice' => $header['logindevice'][0]
+        ];
+        $result =  $this->authorityServiceClient->getRecursionMenu($reqData);
+        $rep = PublicData::buildMenuTree($result['data']);
+        return $rep?Result::success($rep):Result::error("查询失败");
     }
 
 }

+ 247 - 0
app/Controller/ChatController.php

@@ -0,0 +1,247 @@
+<?php
+
+declare(strict_types=1);
+namespace App\Controller;
+
+use App\JsonRpc\ChatServiceInterface;
+use App\Tools\PublicData;
+use Hyperf\Di\Annotation\Inject;
+use Hyperf\HttpServer\Annotation\AutoController;
+use App\Tools\Result;
+use Hyperf\Validation\Contract\ValidatorFactoryInterface;
+use App\Amqp\Producer\DemoProducer;
+use Hyperf\Context\ApplicationContext;
+use App\Amqp\Producer;
+use Hyperf\Snowflake\IdGeneratorInterface;
+/**
+ *
+ * Class ChatController
+ * @package App\Controller
+ */
+#[AutoController]
+class ChatController extends AbstractController
+{
+    #[Inject]
+    protected ValidatorFactoryInterface $validationFactory;
+    /**
+     * @var ChatServiceInterface
+     */
+    #[Inject]
+    private  $chatServiceClient;
+
+    /**
+     * 申请添加好友
+     * @return array
+     */
+    public function addContactApply()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'friend_id' => 'required',
+            ],
+            [
+                'friend_id.required' => '好友ID不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $requireData['user_id'] = $this->UserId;
+        $result = $this->chatServiceClient->addContactApply($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 获取我的好友申请列表
+     * @return array
+     */
+    public function getContactApplyList()
+    {
+        $requireData = [];
+        $requireData['user_id'] = $this->UserId;
+        $result = $this->chatServiceClient->getContactApplyList($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 好有审核通过或拒绝
+     * @return void
+     */
+    public function updateContactApply()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'friend_id' => 'required',
+                'type'=>'required'
+            ],
+            [
+                'friend_id.required' => '好友ID不能为空',
+                'type.required' => '操作状态不能为空',
+
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $requireData['user_id'] = $this->UserId;
+        //type==1 同意 type==2 拒绝
+        $result = $this->chatServiceClient->updateContactApply($requireData);
+        if($requireData['type']==1){
+
+        }
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 删除好友
+     * @return array
+     */
+    public function delContact()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'friend_id' => 'required',
+            ],
+            [
+                'friend_id.required' => '好友ID不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $requireData['user_id'] = $this->UserId;
+        $result = $this->chatServiceClient->delContact($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 获取好友列表
+     * @return array
+     */
+    public function getContactList()
+    {
+        $requireData = $this->request->all();
+        $requireData['user_id'] = $this->UserId;
+        $requireData['keyWord'] = $this->request->input('keyWord','');
+        $result = $this->chatServiceClient->getContactList($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 获取会话列表
+     * @return array
+     */
+      public function getTalkSessionList()
+      {
+          $requireData = $this->request->all();
+          $requireData['user_id'] = $this->UserId;
+          $result = $this->chatServiceClient->getTalkSessionList($requireData);
+          var_dump($result);
+          if($result['data']['row']){
+              foreach ($result['data']['row'] as $k=>$v){
+                  $result['data']['row'][$k]['messages'] = [];
+              }
+          }
+          return $result?Result::success($result['data']):Result::error($result['message']);
+      }
+
+    /**
+     * 创建用户群
+     * @return array
+     */
+      public function addTalkGroup()
+      {
+          $requireData = $this->request->all();
+          $validator = $this->validationFactory->make(
+              $requireData,
+              [
+                  'group_name' => 'required',
+                  'user_id_arr' => 'required'
+              ],
+              [
+                  'group_name.required' => '群名称不能为空',
+                  'user_id_arr.required' => '好友ID不能为空',
+              ]
+          );
+          if ($validator->fails()){
+              $errorMessage = $validator->errors()->first();
+              return Result::error($errorMessage);
+          }
+          $requireData['user_id'] = $this->UserId;
+          $userIdArr = array(json_decode($requireData['user_id_arr']));
+          $requireData['user_id_arr'] = $userIdArr[0];
+          $requireData['user_id_arr'][] = $this->UserId;
+          var_dump($requireData);
+          $result = $this->chatServiceClient->addTalkGroup($requireData);
+          return $result['code']==200?Result::success($result['data']):Result::error($result['message']);
+
+      }
+
+    /**
+     * 会话详情
+     * @return void
+     */
+      public function getTalkRecordsList()
+      {
+          $requireData = $this->request->all();
+          $validator = $this->validationFactory->make(
+              $requireData,
+              [
+                  'session_id' => 'required',
+                  'talk_type' => 'required'
+              ],
+              [
+                  'session_id.required' => '会话ID不能为空',
+                  'talk_type.required' => '会话类型不能为空',
+              ]
+          );
+          if ($validator->fails()){
+              $errorMessage = $validator->errors()->first();
+              return Result::error($errorMessage);
+          }
+          $requireData['page'] = $requireData['page']??1;
+          $requireData['pageSize'] = $requireData['pageSize']??30;
+          $result = $this->chatServiceClient->getTalkRecordsList($requireData);
+          return $result['code']==200?Result::success($result['data']):Result::error($result['message']);
+      }
+
+    /**
+     * 添加聊天
+     * @return void
+     */
+      public function addTalkRecords()
+      {
+          $requireData = $this->request->all();
+          $validator = $this->validationFactory->make(
+              $requireData,
+              [
+                  'type' => 'required',
+                  'content' => 'required',
+                  'receiver'=>'required',
+
+              ],
+              [
+                  'type.required' => '消息类型不能为空',
+                  'content.required' => '内容不能为空',
+                  'receiver.required' => '会话信息不能为空',
+              ]
+          );
+          if ($validator->fails()){
+              $errorMessage = $validator->errors()->first();
+              return Result::error($errorMessage);
+          }
+          $requireData['user_id'] = $this->UserId;
+          $result = $this->chatServiceClient->addTalkRecords($requireData);
+          return $result['code']==200?Result::success($result['data']):Result::error($result['message']);
+      }
+
+}

+ 28 - 0
app/Controller/IndexController.php

@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace App\Controller;
 
+use App\Tools\CommonService;
 use Hyperf\Di\Annotation\Inject;
 use Hyperf\HttpServer\Contract\RequestInterface;
 use Hyperf\Validation\Contract\ValidatorFactoryInterface;
@@ -35,4 +36,31 @@ class IndexController extends AbstractController
             var_dump($errorMessage);
         }
     }
+
+    public function verifyCode()
+    {
+        $comm = new CommonService();
+        $ip = $comm->userIp();
+        $redis = $this->container->get(\Hyperf\Redis\Redis::class);
+
+        $config = new \EasySwoole\VerifyCode\Config();
+        $code = new \EasySwoole\VerifyCode\VerifyCode($config);
+        $img_code = '';
+        $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+        $charLength = strlen($characters);
+        for ($i = 0; $i < 4; $i++) {
+            $img_code .= $characters[rand(0, $charLength - 1)];
+        }
+        //重写验证码
+        $result = $code->DrawCode((string)$img_code);
+        $img_code = $result->getImageCode();
+        //写入缓存 用于其他方法验证 并且设置过期时间
+        $redis->set('code'.$ip,$img_code,60000);
+        return $result->getImageBase64();
+
+    }
+
+
+
+
 }

+ 112 - 0
app/Controller/LinkController.php

@@ -0,0 +1,112 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controller;
+
+use App\JsonRpc\LinkServiceInterface;
+use Hyperf\Di\Annotation\Inject;
+use Hyperf\HttpServer\Annotation\AutoController;
+use App\Tools\Result;
+
+use Hyperf\Logger;
+use Hyperf\Validation\Contract\ValidatorFactoryInterface;
+
+/**
+ * Class LinkController
+ * @package App\Controller
+ */
+#[AutoController]
+class LinkController extends AbstractController
+{
+    #[Inject]
+    protected ValidatorFactoryInterface $validationFactory;
+    /**
+     * @var LinkServiceInterface
+     */
+    #[Inject]
+    private $linkServiceClient;
+
+    /**
+     * 友情链接列表
+     * @return array
+     */
+    public function getLinkList()
+    {
+        $requireData = $this->request->all();
+        $result = $this->linkServiceClient->getLinkList($requireData);
+        if($result['data']){
+            $statusList = ['1'=>"通过",'2'=>"待审"];
+            foreach ($result['data']['rows'] as $k=>$v) {
+                $result['data']['rows'][$k]['status_name'] =$statusList[$v['status']];
+            }
+        }
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 创建友情链接
+     * @return array
+     */
+    public function createLink()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'title' => 'required',
+            ],
+            [
+                'title.required' => '名称不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $result = $this->linkServiceClient->createLink($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 更新友情链接
+     * @return array
+     */
+    public function updateLink()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id' => 'required',
+                'title' => 'required',
+                'url' => 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+                'title.required' => '名称不能为空',
+                'url.required' => 'url不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $requireData = $this->request->all();
+        $result = $this->linkServiceClient->updateLink($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+    /**
+     * 删除友情链接
+     * @return array
+     */
+    public function delLink()
+    {
+        $requireData = $this->request->all();
+        $result = $this->linkServiceClient->delLink($requireData);
+        return $result?Result::success($result['data']):Result::error($result['message']);
+    }
+
+
+}

+ 14 - 1
app/Controller/LoginController.php

@@ -7,7 +7,7 @@ use Hyperf\HttpServer\Annotation\AutoController;
 use Hyperf\Validation\Contract\ValidatorFactoryInterface;
 use App\Tools\Result;
 use App\JsonRpc\UserServiceInterface;
-
+use App\Tools\CommonService;
 /**
  * @AutoController()
  */
@@ -25,6 +25,7 @@ class LoginController extends AbstractController
     public function login(Jwt $jwt)
     {
         $this->logger->info("验证之前");
+
         $reqData =  $this->request->all();
         $validator = $this->validationFactory->make(
             $reqData,
@@ -44,6 +45,18 @@ class LoginController extends AbstractController
             $errorMessage = $validator->errors()->first();
             return Result::error($errorMessage);
         }
+        $comm = new CommonService();
+        $ip = $comm->userIp();
+        $redis = $this->container->get(\Hyperf\Redis\Redis::class);
+        $code = $redis->get('code'.$ip);
+        if(empty($code)){
+            return Result::error("验证码已过期");
+        }
+        var_dump("验证码:",$code);
+        if(strtolower($code)!=$reqData['captcha']){
+            return Result::error("验证码错误");
+        }
+            //$reqData
         $where = [];
         if($reqData['type'] ==1){//密码登录
             $where = [

+ 318 - 0
app/Controller/NewsController.php

@@ -0,0 +1,318 @@
+<?php
+declare(strict_types=1);
+namespace App\Controller;
+
+use App\JsonRpc\NewsServiceInterface;
+use App\Tools\PublicData;
+use Hyperf\Di\Annotation\Inject;
+use Hyperf\HttpServer\Annotation\AutoController;
+use App\Tools\Result;
+use Hyperf\Validation\Contract\ValidatorFactoryInterface;
+
+/**
+ * Class NewsController
+ * @package App\Controller
+ */
+#[AutoController]
+class NewsController extends AbstractController
+{
+    #[Inject]
+    protected ValidatorFactoryInterface $validationFactory;
+
+    /**
+     * @var NewsServiceInterface
+     */
+    #[Inject]
+    private $newsServiceClient;
+
+    /**
+     * 分类列表
+     * @return void
+     */
+    public function getCategoryList()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'pid'=> 'required',
+            ],
+            [
+                'pid.required' => 'pid不能为空',
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        $requireData['website_id'] = $this->websiteId;
+
+        $result = $this->newsServiceClient->getCategoryList($requireData);
+        if($result['data']){
+            foreach ($result['data']['rows'] as $k=>$v) {
+                $result['data']['rows'][$k]['pid_arr'] = $v['pid_arr']?json_decode($v['pid_arr']):[0];
+            }
+        }
+        return $result['code'] == 200 ? Result::success($result['data']) : Result::error($result['message']);
+    }
+    /**
+     * 分类列表
+     * @return void
+     */
+    public function categoryList()
+    {
+        $requireData['website_id'] = $this->websiteId;
+        $result = $this->newsServiceClient->categoryList($requireData);
+        var_dump($result);
+        $rep = PublicData::buildMenuTree($result['data']);
+        return $result ? Result::success($rep) : Result::error($result['message']);
+    }
+
+    /**
+     * 添加分类
+     * @return array|void
+     */
+    public function addCategory()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'name'=> 'required',
+            ],
+            [
+                'name.required' => '分类名称不能为空',
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        if(isset($requireData['pid']) && is_array($requireData['pid'])){
+            $requireData['pid_arr'] = json_encode($requireData['pid']);
+            $requireData['pid'] = end($requireData['pid']);
+        }else{
+            $id = [0];
+            $requireData['pid_arr'] = json_encode($id);
+            $requireData['pid'] = end($id);
+        }
+        $requireData['website_id'] = $this->websiteId;
+        $result = $this->newsServiceClient->addCategory($requireData);
+        return $result ? Result::success($result['data']) : Result::error($result['message']);
+    }
+
+
+    public function updateCategory()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id'=>'required',
+                'name'=> 'required',
+            ],
+            [
+                'name.required' => '分类名称不能为空',
+                'id.required' =>'ID不能为空'
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        if(isset($requireData['pid']) && is_array($requireData['pid'])){
+            $requireData['pid_arr'] = json_encode($requireData['pid']);
+            $requireData['pid'] = end($requireData['pid']);
+        }else{
+            $id = [0];
+            $requireData['pid_arr'] = json_encode($id);
+            $requireData['pid'] = end($id);
+        }
+        $requireData['website_id'] = $this->websiteId;
+        $result = $this->newsServiceClient->updateCategory($requireData);
+        return $result['code']==200? Result::success($result['data']) : Result::error($result['message']);
+    }
+    /**
+     * 删除分类
+     * @return array
+     */
+    public function delCategory()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id'=> 'required',
+
+            ],
+            [
+                'id.required' => 'id不能为空',
+
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+
+        $requireData['website_id'] = $this->websiteId;
+        $result = $this->newsServiceClient->delCategory($requireData);
+        return $result['code']==200 ? Result::success($result['data']) : Result::error($result['message']);
+    }
+
+    /**
+     * 资讯列表
+     * @return void
+     */
+    public function getArticleList()
+    {
+        $requireData = $this->request->all();
+        $requireData['website_id'] = $this->websiteId;
+        var_dump("资讯:",$requireData);
+        $result = $this->newsServiceClient->getArticleList($requireData);
+        //1通过,2待审核,3待发 4,拒绝 5删除
+        $statusList = [
+            '1'=>'通过',
+            '2'=>'待审核',
+            '3'=>'待发',
+            '4'=>'拒绝',
+            '5'=>'删除',
+        ];
+        if($result['data']){
+            foreach ($result['data']['rows'] as $k=>$v) {
+                $result['data']['rows'][$k]['cat_arr_id'] = $v['cat_arr_id']?json_decode($v['cat_arr_id']):[0];
+                $result['data']['rows'][$k]['tag'] = $v['tag']?json_decode($v['tag']):[];
+                $result['data']['rows'][$k]['status_name'] = $statusList[$v['status']];
+                $result['data']['rows'][$k]['level'] = (string)$v['level'];
+                $result['data']['rows'][$k]['islink'] = isset($v['islink']) && $v['islink']>0?true:false;
+            }
+        }
+        return $result['code'] == 200 ? Result::success($result['data']) : Result::error($result['message']);
+    }
+
+
+    /**
+     * 添加分类
+     * @return array|void
+     */
+    public function addArticle()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'title'=> 'required',
+                'catid'=> 'required',
+                'author'=> 'required',
+
+            ],
+            [
+                'title.required' => '标题不能为空',
+                'catid.required' => '分类不能为空',
+                'author.required' => '作者不能为空',
+            ]
+        );
+        if ($validator->fails()){
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        if(isset($requireData['catid']) && is_array($requireData['catid'])){
+            $requireData['cat_arr_id'] = json_encode($requireData['catid']);
+            $requireData['catid'] = end($requireData['catid']);
+        }else{
+            $id = [0];
+            $requireData['cat_arr_id'] = json_encode($id);
+            $requireData['catid'] = end($id);
+        }
+        $loginIp = $this->request->getHeader('x-forwarded-for')[0] ?? $this->request->getHeader('x-real-ip')[0] ?? $this->request->getServerParams()['remote_addr'] ?? '0.0.0.0';
+        $requireData['ip'] = $loginIp;
+        $requireData['website_id'] = $this->websiteId;
+        $requireData['admin_user_id'] = $this->UserId;
+        $result = $this->newsServiceClient->addArticle($requireData);
+
+        return $result ? Result::success($result['data']) : Result::error($result['message']);
+    }
+
+
+    public function updateArticle()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id'=>'required',
+                'name'=> 'required',
+            ],
+            [
+                'name.required' => '分类名称不能为空',
+                'id.required' =>'ID不能为空'
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+        if(isset($requireData['pid']) && is_array($requireData['pid'])){
+            $requireData['pid_arr'] = json_encode($requireData['pid']);
+            $requireData['pid'] = end($requireData['pid']);
+        }else{
+            $id = [0];
+            $requireData['pid_arr'] = json_encode($id);
+            $requireData['pid'] = end($id);
+        }
+        $requireData['website_id'] = $this->websiteId;
+        $result = $this->newsServiceClient->updateArticle($requireData);
+        return $result['code']==200? Result::success($result['data']) : Result::error($result['message']);
+    }
+    /**
+     * 删除分类
+     * @return array
+     */
+    public function delArticle()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id'=> 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+
+        $requireData['website_id'] = $this->websiteId;
+        $result = $this->newsServiceClient->delArticle($requireData);
+        return $result['code']==200 ? Result::success($result['data']) : Result::error($result['message']);
+    }
+
+    /**
+     * 获取资讯信息
+     * @return array
+     */
+    public function  getArticleInfo()
+    {
+        $requireData = $this->request->all();
+        $validator = $this->validationFactory->make(
+            $requireData,
+            [
+                'id'=> 'required',
+            ],
+            [
+                'id.required' => 'id不能为空',
+            ]
+        );
+        if ($validator->fails()) {
+            $errorMessage = $validator->errors()->first();
+            return Result::error($errorMessage);
+        }
+
+        $result = $this->newsServiceClient->getArticleInfo($requireData);
+        return $result['code']==200 ? Result::success($result['data']) : Result::error($result['message']);
+    }
+
+}

+ 111 - 0
app/Controller/WebSocketController.php

@@ -0,0 +1,111 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Controller;
+
+use App\Amqp\Producer\MqProducer;
+use Hyperf\Amqp\Producer;
+use Hyperf\Context\ApplicationContext as ContextApplicationContext;
+use Hyperf\Contract\OnCloseInterface;
+use Hyperf\Contract\OnMessageInterface;
+use Hyperf\Contract\OnOpenInterface;
+use Hyperf\Engine\WebSocket\Frame;
+use Hyperf\Engine\WebSocket\Response;
+use Hyperf\WebSocketServer\Annotation\MessageHandler;
+use Hyperf\WebSocketServer\Context\WebSocketContext;
+use Hyperf\WebSocketServer\Message\Text;
+use Hyperf\Di\Annotation\Inject;
+use Phper666\JWTAuth\JWT;
+use App\JsonRpc\ChatServiceInterface;
+use Hyperf\WebSocketServer\Constant\Opcode;
+use App\Service\RedisService;
+use App\Service\Message\ReceiveHandleService;
+use http\Client\Request;
+use App\Controller\AbstractController;
+
+class WebSocketController extends AbstractController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
+{
+
+    #[Inject]
+    protected JWT $jwt;
+    /**
+     * @var ChatServiceInterface
+     */
+    #[Inject]
+    private $chatServiceClient;
+
+
+    /**
+     * @Inject
+     * @var ReceiveHandleService
+     */
+    protected $receiveHandle;
+
+    public function onMessage($server, $frame): void
+    {
+
+        //把数据推给前端
+        $redisClient = new RedisService();
+        $userId = $redisClient->findUser((string)$frame->fd);
+        var_dump("用户ID:::",$userId);
+        //存入队列
+        $result = json_decode($frame->data, true);
+        $result['user_id'] = $userId;
+        var_dump("接收到的数据:",$result);
+        $message = new MqProducer($result);
+        $producer = ContextApplicationContext::getContainer()->get(Producer::class);
+        $producer->produce($message);
+
+
+
+
+        foreach ($server->connections as $fd) {
+            if ($server->isEstablished($fd)) {
+                var_dump($fd);
+                $server->push($fd, $frame->data);
+            }
+        }
+    }
+
+    public function onClose($server, int $fd, int $reactorId): void
+    {
+        var_dump('closed::::::::::::::::::',$fd,"======",$reactorId,"+++++++++++");
+//        $data = [
+//            'fd'=>$fd
+//        ];
+//        $this->chatServiceClient->delChatChannel($data);
+
+        $redisClient = new RedisService();
+        $userId = $redisClient->findUser((string)$fd);
+        $redisClient->unbind((string)$fd,(int)$userId);
+    }
+
+    public function onOpen($server, $request): void
+    {
+
+        $token = $request->get['token'];
+        $userInfo = $this->jwt->getClaimsByToken($token);
+        $response = (new Response($server))->init($request);
+        $fd = $response->getFd();
+//        var_dump("管道ID:",$fd);
+//        $data = [
+//            'user_id'=>$userInfo['uid'],
+//            'fd'=>$fd
+//        ];
+//        var_dump(SERVER_RUN_ID,"+++++++++++++");
+//      $this->chatServiceClient->addChatChannel($data);
+
+        $server->bind($fd,$userInfo['uid']);
+        $redisClient = new RedisService();
+        $redisClient->bind((string)$fd,$userInfo['uid']);
+        $server->push($request->fd, json_encode([
+            "event"   => "connect",
+            "content" => [
+                "ping_interval" => 20,
+                "ping_timeout"  => 20 * 3,
+                "content" =>"连接成功"
+            ],
+        ]));
+    }
+
+}

+ 29 - 0
app/Event/TalkEvent.php

@@ -0,0 +1,29 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Event;
+
+class TalkEvent
+{
+    /**
+     * @var string 消息事件名
+     */
+    public $event_name;
+
+    /**
+     * @var array 消息数据
+     */
+    public $data;
+
+    /**
+     * TalkMessageEvent constructor.
+     *
+     * @param string $event_name
+     * @param array  $data
+     */
+    public function __construct(string $event_name, array $data = [])
+    {
+        $this->event_name = $event_name;
+        $this->data       = $data;
+    }
+}

+ 67 - 5
app/JsonRpc/AdService.php

@@ -18,13 +18,12 @@ class AdService extends AbstractServiceClient implements AdServiceInterface
     protected string $protocol = 'jsonrpc-http';
 
     /**
-     * @param string $name
-     * @param string $url
-     * @return mixed|string
+     * @param array $data
+     * @return array|mixed
      */
-    public function createAd(string $name, string $url)
+    public function createAd(array $data)
     {
-        return $this->__request(__FUNCTION__, compact('name', 'url'));
+        return $this->__request(__FUNCTION__, $data);
     }
 
     /**
@@ -35,4 +34,67 @@ class AdService extends AbstractServiceClient implements AdServiceInterface
     {
         return $this->__request(__FUNCTION__, compact('id'));
     }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function getAdList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function updateAd(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function delAd(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function getAdPlaceList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function createAdPlace(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function updateAdPlace(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function delAdPlace(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
 }

+ 45 - 4
app/JsonRpc/AdServiceInterface.php

@@ -4,15 +4,56 @@ namespace App\JsonRpc;
 interface AdServiceInterface
 {
     /**
-     * @param string $name
-     * @param string $url
-     * @return string
+     * @param array $data
+     * @return array
      */
-    public function createAd(string $name, string $url);
+    public function createAd(array $data);
 
     /**
      * @param int $id
      * @return array
      */
     public function getAdInfo(int $id);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function getAdList(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function updateAd(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function delAd(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function getAdPlaceList(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function createAdPlace(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function updateAdPlace(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function delAdPlace(array $data);
 }

+ 335 - 0
app/JsonRpc/ChatService.php

@@ -0,0 +1,335 @@
+<?php
+
+namespace App\JsonRpc;
+
+use Hyperf\RpcClient\AbstractServiceClient;
+
+class ChatService extends AbstractServiceClient implements ChatServiceInterface
+{
+    /**
+     * 定义对应服务提供者的服务名称
+     * @var string
+     */
+    protected string $serviceName = 'ChatService';
+    /**
+     * 定义对应服务提供者的服务协议
+     * @var string
+     */
+    protected string $protocol = 'jsonrpc-http';
+
+    /**
+     * @param array $data
+     * @return array|mixed
+     */
+    public function getChatChannelList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function delChatChannel(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function addChatChannel(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 添加申请
+     * @param array $data
+     * @return array
+     */
+    public function addContactApply(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 更新申请
+     * @param array $data
+     * @return array
+     */
+    public function updateContactApply(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 好友申请列表
+     * @param array $data
+     * @return array
+     */
+    public function getContactApplyList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 好有查询
+     * @param array $data
+     * @return array
+     */
+    public function getContactList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    /**
+     * 添加好友
+     * @param array $data
+     * @return array
+     */
+    public function addContact(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 更新好友
+     * @param array $data
+     * @return array
+     */
+    public function updateContact(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 删除好友
+     * @param array $data
+     * @return array
+     */
+    public function delContact(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 会话列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkSessionList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    /**
+     * 添加会话
+     * @param array $data
+     * @return array
+     */
+    public function addTalkSession(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 更新会话
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkSession(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 删除会话
+     * @param array $data
+     * @return array
+     */
+    public function delTalkSession(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+
+    /**
+     * 聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function getTalkRecordsList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    /**
+     * 添加聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function addTalkRecords(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 更新聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkRecords(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 删除聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function delTalkRecords(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+
+    /**
+     * 聊天内容-附件列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkRecordsFileList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    /**
+     * 聊天内容-添加附件
+     * @param array $data
+     * @return array
+     */
+    public function addTalkRecordsFile(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 聊天内容 - 更新附件
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkRecordsFile(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 聊天内容 - 删除附件
+     * @param array $data
+     * @return array
+     */
+    public function delTalkRecordsFile(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 群组 - 群列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkGroupList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    /**
+     * 群组 - 创建群
+     * @param array $data
+     * @return array
+     */
+    public function addTalkGroup(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 群组 - 更新群
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkGroup(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 群组 - 删除群
+     * @param array $data
+     * @return array
+     */
+    public function delTalkGroup(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+
+    /**
+     * 群组 - 群用户列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkGroupMember(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    /**
+     * 群组 - 创建群用户
+     * @param array $data
+     * @return array
+     */
+    public function addTalkGroupMember(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 群组 - 更新群用户
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkGroupMember(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * 群组 - 删除群用户
+     * @param array $data
+     * @return array
+     */
+    public function delTalkGroupMember(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array|mixed
+     */
+    public function addTalkSessionAssociation(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array|mixed
+     */
+    public function updateTalkSessionAssociation(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+    
+
+
+}

+ 222 - 0
app/JsonRpc/ChatServiceInterface.php

@@ -0,0 +1,222 @@
+<?php
+
+namespace App\JsonRpc;
+interface ChatServiceInterface
+{
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function getChatChannelList(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function delChatChannel(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function addChatChannel(array $data);
+
+    /**
+     * 添加申请
+     * @param array $data
+     * @return array
+     */
+    public function addContactApply(array $data);
+
+    /**
+     * 更新申请
+     * @param array $data
+     * @return array
+     */
+    public function updateContactApply(array $data);
+
+    /**
+     * 好友申请列表
+     * @param array $data
+     * @return array
+     */
+    public function getContactApplyList(array $data);
+
+    /**
+     * 好有查询
+     * @param array $data
+     * @return array
+     */
+    public function getContactList(array $data);
+    /**
+     * 添加好友
+     * @param array $data
+     * @return array
+     */
+    public function addContact(array $data);
+
+    /**
+     * 更新好友
+     * @param array $data
+     * @return array
+     */
+    public function updateContact(array $data);
+
+    /**
+     * 删除好友
+     * @param array $data
+     * @return array
+     */
+    public function delContact(array $data);
+
+    /**
+     * 会话列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkSessionList(array $data);
+    /**
+     * 添加会话
+     * @param array $data
+     * @return array
+     */
+    public function addTalkSession(array $data);
+
+    /**
+     * 更新会话
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkSession(array $data);
+
+    /**
+     * 删除会话
+     * @param array $data
+     * @return array
+     */
+    public function delTalkSession(array $data);
+
+
+    /**
+     * 聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function getTalkRecordsList(array $data);
+    /**
+     * 添加聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function addTalkRecords(array $data);
+
+    /**
+     * 更新聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkRecords(array $data);
+
+    /**
+     * 删除聊天内容
+     * @param array $data
+     * @return array
+     */
+    public function delTalkRecords(array $data);
+
+
+    /**
+     * 聊天内容-附件列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkRecordsFileList(array $data);
+    /**
+     * 聊天内容-添加附件
+     * @param array $data
+     * @return array
+     */
+    public function addTalkRecordsFile(array $data);
+
+    /**
+     * 聊天内容 - 更新附件
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkRecordsFile(array $data);
+
+    /**
+     * 聊天内容 - 删除附件
+     * @param array $data
+     * @return array
+     */
+    public function delTalkRecordsFile(array $data);
+
+    /**
+     * 群组 - 群列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkGroupList(array $data);
+    /**
+     * 群组 - 创建群
+     * @param array $data
+     * @return array
+     */
+    public function addTalkGroup(array $data);
+
+    /**
+     * 群组 - 更新群
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkGroup(array $data);
+
+    /**
+     * 群组 - 删除群
+     * @param array $data
+     * @return array
+     */
+    public function delTalkGroup(array $data);
+
+
+    /**
+     * 群组 - 群用户列表
+     * @param array $data
+     * @return array
+     */
+    public function getTalkGroupMember(array $data);
+    /**
+     * 群组 - 创建群用户
+     * @param array $data
+     * @return array
+     */
+    public function addTalkGroupMember(array $data);
+
+    /**
+     * 群组 - 更新群用户
+     * @param array $data
+     * @return array
+     */
+    public function updateTalkGroupMember(array $data);
+
+    /**
+     * 群组 - 删除群用户
+     * @param array $data
+     * @return array
+     */
+    public function delTalkGroupMember(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function addTalkSessionAssociation(array $data);
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function updateTalkSessionAssociation(array $data);
+
+}

+ 56 - 0
app/JsonRpc/LinkService.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace App\JsonRpc;
+
+use Hyperf\RpcClient\AbstractServiceClient;
+
+class LinkService extends AbstractServiceClient implements LinkServiceInterface
+{
+    /**
+     * 定义对应服务提供者的服务名称
+     * @var string
+     */
+    protected string $serviceName = 'LinkService';
+    /**
+     * 定义对应服务提供者的服务协议
+     * @var string
+     */
+    protected string $protocol = 'jsonrpc-http';
+
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function getLinkList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function createLink(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function updateLink(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function delLink(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+}

+ 28 - 0
app/JsonRpc/LinkServiceInterface.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\JsonRpc;
+interface LinkServiceInterface
+{
+
+    /**
+     * @param array $data
+     */
+    public function getLinkList(array $data);
+    /**
+     * @param array $data
+     */
+    public function createLink(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function updateLink(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function delLink(array $data);
+
+
+
+}

+ 110 - 0
app/JsonRpc/NewsService.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace App\JsonRpc;
+
+use Hyperf\RpcClient\AbstractServiceClient;
+
+class NewsService extends AbstractServiceClient implements NewsServiceInterface
+{
+    /**
+     * 定义对应服务提供者的服务名称
+     * @var string
+     */
+    protected string $serviceName = 'NewsService';
+    /**
+     * 定义对应服务提供者的服务协议
+     * @var string
+     */
+    protected string $protocol = 'jsonrpc-http';
+
+
+    /**
+     * @param array $data
+     * @return mixed
+     */
+    public function getCategoryList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function categoryList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function addCategory(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function delCategory(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function updateCategory(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function getArticleList(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function addArticle(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function delArticle(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function updateArticle(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    public function getArticleInfo(array $data)
+    {
+        return $this->__request(__FUNCTION__, $data);
+    }
+}

+ 56 - 0
app/JsonRpc/NewsServiceInterface.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace App\JsonRpc;
+interface NewsServiceInterface
+{
+
+    /**
+     * @param array $data
+     */
+    public function getCategoryList(array $data);
+    /**
+     * @param array $data
+     */
+    public function categoryList(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function addCategory(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function delCategory(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function updateCategory(array $data);
+
+    /**
+     * @param array $data
+    */
+    public function getArticleList(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function addArticle(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function delArticle(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function updateArticle(array $data);
+
+    /**
+     * @param array $data
+     */
+    public function getArticleInfo(array $data);
+
+}

+ 1 - 1
app/Middleware/Auth/FooMiddleware.php

@@ -36,7 +36,7 @@ class FooMiddleware implements MiddlewareInterface
     {
 
         $header = $request->getHeaders();
-        if($this->request->getUri()->getPath()=="/api/login"){
+        if($this->request->getUri()->getPath()=="/api/login" || $this->request->getUri()->getPath()=="/verifyCode"){
             return $handler->handle($request);
         }
         try {

+ 63 - 0
app/Middleware/JWTAuthMiddleware.php

@@ -0,0 +1,63 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This is my open source code, please do not use it for commercial applications.
+ * For the full copyright and license information,
+ * please view the LICENSE file that was distributed with this source code
+ *
+ * @author Yuandong<837215079@qq.com>
+ * @link   https://github.com/gzydong/hyperf-chat
+ */
+
+namespace App\Middleware;
+
+use Hyperf\HttpServer\Contract\RequestInterface;
+use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+
+/**
+ * Http Token 授权验证中间件
+ *
+ * @package App\Middleware
+ */
+class JWTAuthMiddleware implements MiddlewareInterface
+{
+    /**
+     * @var RequestInterface
+     */
+    protected $request;
+
+    /**
+     * @var HttpResponse
+     */
+    protected $response;
+
+    /**
+     * 授权验证守卫
+     *
+     * @var string
+     */
+    private $guard = 'jwt';
+
+    public function __construct(HttpResponse $response, RequestInterface $request)
+    {
+        $this->response = $response;
+        $this->request  = $request;
+    }
+
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        if (auth($this->guard)->guest()) {
+            return $this->response->withStatus(401)->json([
+                'code'    => 401,
+                'message' => 'Token authentication does not pass !',
+            ]);
+        }
+
+        return $handler->handle($request);
+    }
+}

+ 56 - 0
app/Middleware/WebSocketAuthMiddleware.php

@@ -0,0 +1,56 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This is my open source code, please do not use it for commercial applications.
+ * For the full copyright and license information,
+ * please view the LICENSE file that was distributed with this source code
+ *
+ * @author Yuandong<837215079@qq.com>
+ * @link   https://github.com/gzydong/hyperf-chat
+ */
+
+namespace App\Middleware;
+
+use Hyperf\Di\Annotation\Inject;
+use Psr\Container\ContainerInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+
+
+/**
+ * WebSocket token 授权验证中间件
+ *
+ * @package App\Middleware
+ */
+class WebSocketAuthMiddleware implements MiddlewareInterface
+{
+    /**
+     * @var ContainerInterface
+     */
+    protected $container;
+
+    /**
+     * 授权验证守卫
+     *
+     * @var string
+     */
+    private $guard = 'jwt';
+
+    public function __construct(ContainerInterface $container)
+    {
+        $this->container = $container;
+    }
+
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        // 授权验证拦截握手请求并实现权限检查
+//        if (auth($this->guard)->guest()) {
+//            return $this->container->get(\Hyperf\HttpServer\Contract\ResponseInterface::class)->raw('Forbidden');
+//        }
+
+        return $handler->handle($request);
+    }
+}

+ 87 - 0
app/Service/Message/ReceiveHandleService.php

@@ -0,0 +1,87 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Message;
+
+
+use App\Service\SocketClientService;
+
+use Swoole\Http\Response;
+use Swoole\WebSocket\Frame;
+use Swoole\WebSocket\Server;
+
+class ReceiveHandleService
+{
+    /**
+     * @var SocketClientService
+     */
+    private $client;
+
+    // 消息事件绑定
+    const EVENTS = [
+        EVENT_TALK          => 'onTalk',
+        EVENT_TALK_KEYBOARD => 'onKeyboard',
+    ];
+
+    /**
+     * ReceiveHandleService constructor.
+     *
+     * @param SocketClientService $client
+     */
+//    public function __construct(SocketClientService $client)
+//    {
+//        $this->client = $client;
+//    }
+
+    /**
+     * 对话文本消息
+     *
+     * @param Response|Server $server
+     * @param Frame           $frame
+     * @param array|string    $data 解析后数据
+     * @return void
+     */
+    public function onTalk($server, Frame $frame, $data)
+    {
+
+        var_dump("测试数据发送==========");
+        return true;
+//        $user_id = $this->client->findFdUserId($frame->fd);
+//        if ($user_id != $data['sender_id']) return;
+//
+//        // 验证消息类型
+//        if (!in_array($data['talk_type'], TalkModeConstant::getTypes())) return;
+//
+//        // 验证发送消息用户与接受消息用户之间是否存在好友或群聊关系
+//        $isTrue = UserRelation::isFriendOrGroupMember($user_id, (int)$data['receiver_id'], (int)$data['talk_type']);
+//        if (!$isTrue) {
+//            $server->push($frame->fd, json_encode(['event_error', [
+//                'message' => '暂不属于好友关系或群聊成员,无法发送聊天消息!'
+//            ]]));
+//            return;
+//        }
+
+//        di()->get(TalkMessageService::class)->insertText([
+//            'talk_type'   => $data['talk_type'],
+//            'user_id'     => $data['sender_id'],
+//            'receiver_id' => $data['receiver_id'],
+//            'content'     => $data['text_message'],
+//        ]);
+    }
+
+    /**
+     * 键盘输入消息
+     *
+     * @param Response|Server $server
+     * @param Frame           $frame
+     * @param array|string    $data 解析后数据
+     * @return void
+     */
+//    public function onKeyboard($server, Frame $frame, $data)
+//    {
+//        event()->dispatch(new TalkEvent(TalkEventConstant::EVENT_TALK_KEYBOARD, [
+//            'sender_id'   => (int)$data['sender_id'],
+//            'receiver_id' => (int)$data['receiver_id'],
+//        ]));
+//    }
+}

+ 35 - 0
app/Service/RedisInterface.php

@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * This file is part of Hyperf.
+ *
+ * @link     https://www.hyperf.io
+ * @document https://hyperf.wiki
+ * @contact  group@hyperf.io
+ * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
+ */
+
+namespace App\Service;
+
+use Hyperf\Di\Annotation\Inject;
+use Psr\Container\ContainerInterface;
+abstract class RedisInterface
+{
+
+    protected $redis;
+    #[Inject]
+    protected ContainerInterface $container;
+    public function __construct()
+    {
+        /**
+         * 生成图片验证码
+         * @return string
+         * @throws \Psr\Container\ContainerExceptionInterface
+         * @throws \Psr\Container\NotFoundExceptionInterface
+         * @throws \RedisException
+         */
+       $this->redis =  $this->container->get(\Hyperf\Redis\Redis::class);
+
+    }
+}

+ 72 - 0
app/Service/RedisService.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace App\Service;
+
+use App\Cache\SocketFdBindUser;
+use App\Cache\SocketUserBindFds;
+
+/**
+ * websocket关系存储
+ *
+ * @package App\Service
+ */
+class RedisService extends RedisInterface
+{
+    protected $prefix_fn = 'chat_fn';
+    protected $prefix_user = 'chat_user';
+
+    /**
+     * 绑定fd和用户关系
+     * @param string $fid
+     * @param int $userId
+     * @param $run_id
+     * @return void
+     * @throws \RedisException
+     */
+    public function bind(string $fid,int $userId, $run_id = SERVER_RUN_ID)
+    {
+        //站点通道+用户
+        $this->redis->hSet($run_id,$this->prefix_fn.$fid,$userId);
+        //站点用户+通道
+        $this->redis->hSet($run_id,$this->prefix_user.$userId,$fid);
+    }
+
+    /**
+     * 解绑通道和用户关系
+     * @param string $fid
+     * @param int $userId
+     * @param $run_id
+     * @return void
+     * @throws \RedisException
+     */
+    public function unbind(string $fid,int $userId, $run_id = SERVER_RUN_ID)
+    {
+        $this->redis->hDel($run_id,$this->prefix_fn.$fid);
+
+        $this->redis->hDel($run_id,$this->prefix_user.$userId);
+    }
+
+    /**
+     * 通过FD获取userID
+     * @param string $fid
+     * @param $run_id
+     * @return false|\Redis|string
+     * @throws \RedisException
+     */
+    public function findUser(string $fid, $run_id = SERVER_RUN_ID)
+    {
+        return $this->redis->hGet($run_id,$this->prefix_fn.$fid);
+    }
+
+    /**
+     * 通过UserID 获取fd
+     * @param int $userId
+     * @param $run_id
+     * @return false|\Redis|string
+     * @throws \RedisException
+     */
+    public function findFd(int $userId, $run_id = SERVER_RUN_ID)
+    {
+        return $this->redis->hGet($run_id,$this->prefix_user.$userId);
+    }
+}

+ 89 - 0
app/Service/SocketClientService.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace App\Service;
+
+//use App\Cache\SocketFdBindUser;
+//use App\Cache\SocketUserBindFds;
+
+/**
+ * Socket客户端ID服务
+ *
+ * @package App\Service
+ */
+class SocketClientService
+{
+    /**
+     * 客户端fd与用户ID绑定关系
+     *
+     * @param int    $fd      客户端fd
+     * @param int    $user_id 用户ID
+     * @param string $run_id  服务运行ID(默认当前服务ID)
+     */
+//    public function bind(int $fd, int $user_id, $run_id = SERVER_RUN_ID)
+//    {
+//        SocketFdBindUser::getInstance()->bind($fd, $user_id, $run_id);
+//        SocketUserBindFds::getInstance()->bind($fd, $user_id, $run_id);
+//    }
+
+    /**
+     * 解除指定的客户端fd与用户绑定关系
+     *
+     * @param int    $fd     客户端ID
+     * @param string $run_id 服务运行ID(默认当前服务ID)
+     */
+//    public function unbind(int $fd, $run_id = SERVER_RUN_ID)
+//    {
+//        $user_id = $this->findFdUserId($fd);
+//
+//        SocketFdBindUser::getInstance()->unBind($fd, $run_id);
+//        SocketUserBindFds::getInstance()->unBind($fd, $user_id, $run_id);
+//    }
+
+    /**
+     * 检测用户当前是否在线(指定运行服务器)
+     *
+     * @param int    $user_id 用户ID
+     * @param string $run_id  服务运行ID(默认当前服务ID)
+     * @return bool
+     */
+//    public function isOnline(int $user_id, $run_id = SERVER_RUN_ID): bool
+//    {
+//        return SocketUserBindFds::getInstance()->isOnline($user_id, $run_id);
+//    }
+
+    /**
+     * 检测用户当前是否在线(查询所有在线服务器)
+     *
+     * @param int   $user_id 用户ID
+     * @param array $run_ids 服务运行ID
+     * @return bool
+     */
+//    public function isOnlineAll(int $user_id, array $run_ids = []): bool
+//    {
+//        return SocketUserBindFds::getInstance()->isOnlineAll($user_id, $run_ids);
+//    }
+
+    /**
+     * 查询客户端fd对应的用户ID
+     *
+     * @param int    $fd     客户端ID
+     * @param string $run_id 服务运行ID(默认当前服务ID)
+     * @return int
+     */
+    public function findFdUserId(int $fd, $run_id = SERVER_RUN_ID): int
+    {
+//        return SocketFdBindUser::getInstance()->findUserId($fd, $run_id);
+    }
+
+    /**
+     * 查询用户的客户端fd集合(用户可能存在多端登录)
+     *
+     * @param int    $user_id 用户ID
+     * @param string $run_id  服务运行ID(默认当前服务ID)
+     * @return array
+     */
+//    public function findUserFds(int $user_id, $run_id = SERVER_RUN_ID): array
+//    {
+//        return SocketUserBindFds::getInstance()->findFds($user_id, $run_id);
+//    }
+}

+ 9 - 0
app/Tools/CommonService.php

@@ -83,6 +83,15 @@ class CommonService
         return $url;
     }
 
+    /**
+     * 获取用户IP
+     * @return mixed|string
+     */
+    public  function userIp()
+    {
+        $Ip = $this->request->getHeader('x-forwarded-for')[0] ?? $this->request->getHeader('x-real-ip')[0] ?? $this->request->getServerParams()['remote_addr'] ?? '0.0.0.0';
+        return $Ip;
+    }
 
 
 }

+ 27 - 1
app/Tools/PublicData.php

@@ -1,8 +1,16 @@
 <?php
 namespace App\Tools;
 use App\Constants\ErrorCode;
+use Hyperf\Snowflake\IdGeneratorInterface;
+use Hyperf\Context\ApplicationContext;
 class PublicData
 {
+    /**
+     * 递归查询
+     * @param $menuItems
+     * @param $parentId
+     * @return array
+     */
     public static  function buildMenuTree($menuItems, $parentId = 0) {
         $tree = [];
         foreach ($menuItems as $item) {
@@ -20,8 +28,26 @@ class PublicData
         return $tree;
     }
 
+    /**
+     * 计算两个时间差的天数
+     * @param $sTime
+     * @param $eTime
+     * @return float
+     */
+    public static function residueDay($sTime,$eTime)
+    {
+        $startTime = strtotime($sTime);
+        $endTime = strtotime($eTime);
+        $diffDays = floor(($endTime - $startTime) / (60 * 60 * 24));
+        return $diffDays;
+    }
 
+    public static function uuid()
+    {
+        $container = ApplicationContext::getContainer();
+        $generator = $container->get(IdGeneratorInterface::class);
 
-
+        return $generator->generate();
+    }
 
 }

+ 5 - 1
composer.json

@@ -15,8 +15,10 @@
         "php": ">=8.1",
         "death_satan/hyperf-validate": "^3.71",
         "doctrine/annotations": "^2.0",
+        "easyswoole/verifycode": "3.x",
+        "hyperf/amqp": "^3.1",
         "hyperf/cache": "~3.1.0",
-        "hyperf/command": "~3.1.0",
+        "hyperf/command": "^3.1",
         "hyperf/config": "~3.1.0",
         "hyperf/config-nacos": "^3.1",
         "hyperf/constants": "^3.1",
@@ -38,8 +40,10 @@
         "hyperf/service-governance": "^3.1",
         "hyperf/service-governance-consul": "^3.1",
         "hyperf/service-governance-nacos": "^3.1",
+        "hyperf/snowflake": "^3.1",
         "hyperf/translation": "^3.1",
         "hyperf/validation": "^3.1",
+        "hyperf/websocket-server": "^3.1",
         "phper666/jwt-auth": "^4.0"
     },
     "require-dev": {

+ 674 - 8
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "98144e888acaa7c93e0bfe5f64885565",
+    "content-hash": "e71f383836139c57d31eb8084467a897",
     "packages": [
         {
             "name": "carbonphp/carbon-doctrine-types",
@@ -496,6 +496,106 @@
             ],
             "time": "2024-02-05T11:35:39+00:00"
         },
+        {
+            "name": "easyswoole/spl",
+            "version": "2.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/easy-swoole/spl.git",
+                "reference": "bc90f12574f8c69e72afd8e61de9bfd186802077"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/easy-swoole/spl/zipball/bc90f12574f8c69e72afd8e61de9bfd186802077",
+                "reference": "bc90f12574f8c69e72afd8e61de9bfd186802077",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-simplexml": "*",
+                "php": ">=8.1.0"
+            },
+            "require-dev": {
+                "easyswoole/phpunit": "^1.0",
+                "easyswoole/swoole-ide-helper": "^1.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "EasySwoole\\Spl\\": "src/",
+                    "EasySwoole\\Spl\\Test\\": "test/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "YF",
+                    "email": "291323003@qq.com"
+                }
+            ],
+            "description": "php stander lib",
+            "homepage": "https://www.easyswoole.com/",
+            "keywords": [
+                "async",
+                "easyswoole",
+                "framework",
+                "swoole"
+            ],
+            "support": {
+                "issues": "https://github.com/easy-swoole/spl/issues",
+                "source": "https://github.com/easy-swoole/spl/tree/2.1.2"
+            },
+            "time": "2024-03-19T06:53:52+00:00"
+        },
+        {
+            "name": "easyswoole/verifycode",
+            "version": "3.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/easy-swoole/verify-code.git",
+                "reference": "cfd7c1a7218e8b5f2319d9b3b73cf7a588c22ee6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/easy-swoole/verify-code/zipball/cfd7c1a7218e8b5f2319d9b3b73cf7a588c22ee6",
+                "reference": "cfd7c1a7218e8b5f2319d9b3b73cf7a588c22ee6",
+                "shasum": ""
+            },
+            "require": {
+                "easyswoole/spl": "^2.0",
+                "ext-gd": "*",
+                "php": ">=8.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "EasySwoole\\VerifyCode\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "YF",
+                    "email": "291323003@qq.com"
+                },
+                {
+                    "name": "evalor",
+                    "email": "mipone@foxmail.com"
+                }
+            ],
+            "support": {
+                "issues": "https://github.com/easy-swoole/verify-code/issues",
+                "source": "https://github.com/easy-swoole/verify-code/tree/3.1.2"
+            },
+            "time": "2023-09-06T06:45:56+00:00"
+        },
         {
             "name": "egulias/email-validator",
             "version": "3.2.6",
@@ -1006,6 +1106,88 @@
             ],
             "time": "2023-12-03T20:05:35+00:00"
         },
+        {
+            "name": "hyperf/amqp",
+            "version": "v3.1.28",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hyperf/amqp.git",
+                "reference": "c96e294e99e68113ed3e237db8f976308ee42ba7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hyperf/amqp/zipball/c96e294e99e68113ed3e237db8f976308ee42ba7",
+                "reference": "c96e294e99e68113ed3e237db8f976308ee42ba7",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "doctrine/instantiator": "^1.2.0",
+                "hyperf/codec": "~3.1.0",
+                "hyperf/contract": "~3.1.0",
+                "hyperf/coroutine": "~3.1.0",
+                "hyperf/pool": "~3.1.0",
+                "hyperf/process": "~3.1.0",
+                "hyperf/support": "~3.1.0",
+                "hyperf/utils": "~3.1.0",
+                "php": ">=8.1",
+                "php-amqplib/php-amqplib": "^3.5",
+                "psr/container": "^1.0 || ^2.0",
+                "psr/event-dispatcher": "^1.0",
+                "psr/log": "^1.0 || ^2.0 || ^3.0"
+            },
+            "suggest": {
+                "hyperf/di": "Required to use annotations.",
+                "hyperf/event": "Declare queue and start consumers automatically."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                },
+                "hyperf": {
+                    "config": "Hyperf\\Amqp\\ConfigProvider"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Hyperf\\Amqp\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A amqplib for hyperf.",
+            "homepage": "https://hyperf.io",
+            "keywords": [
+                "AMQP",
+                "hyperf",
+                "php"
+            ],
+            "support": {
+                "docs": "https://hyperf.wiki",
+                "issues": "https://github.com/hyperf/hyperf/issues",
+                "pull-request": "https://github.com/hyperf/hyperf/pulls",
+                "source": "https://github.com/hyperf/hyperf"
+            },
+            "funding": [
+                {
+                    "url": "https://hyperf.wiki/#/zh-cn/donate",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://opencollective.com/hyperf",
+                    "type": "open_collective"
+                }
+            ],
+            "time": "2024-06-24T01:53:39+00:00"
+        },
         {
             "name": "hyperf/cache",
             "version": "v3.1.23",
@@ -1273,17 +1455,23 @@
         },
         {
             "name": "hyperf/command",
-            "version": "v3.1.24",
+            "version": "v3.1.22",
             "source": {
                 "type": "git",
                 "url": "https://github.com/hyperf/command.git",
-                "reference": "b1ca85876f35f85fe3f52b0cc75bcc3da418769d"
+                "reference": "dce46ba82cae52f0e78bf95d8adb5ec8f23fcd27"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/hyperf/command/zipball/b1ca85876f35f85fe3f52b0cc75bcc3da418769d",
-                "reference": "b1ca85876f35f85fe3f52b0cc75bcc3da418769d",
-                "shasum": ""
+                "url": "https://api.github.com/repos/hyperf/command/zipball/dce46ba82cae52f0e78bf95d8adb5ec8f23fcd27",
+                "reference": "dce46ba82cae52f0e78bf95d8adb5ec8f23fcd27",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
             },
             "require": {
                 "hyperf/collection": "~3.1.0",
@@ -1328,7 +1516,7 @@
             ],
             "support": {
                 "issues": "https://github.com/hyperf/command/issues",
-                "source": "https://github.com/hyperf/command/tree/v3.1.24"
+                "source": "https://github.com/hyperf/command/tree/v3.1.22"
             },
             "funding": [
                 {
@@ -1340,7 +1528,7 @@
                     "type": "open_collective"
                 }
             ],
-            "time": "2024-05-27T12:37:07+00:00"
+            "time": "2024-05-15T05:22:10+00:00"
         },
         {
             "name": "hyperf/conditionable",
@@ -4139,6 +4327,77 @@
             ],
             "time": "2024-03-23T11:28:51+00:00"
         },
+        {
+            "name": "hyperf/snowflake",
+            "version": "v3.1.15",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hyperf/snowflake.git",
+                "reference": "a77b0d4c9215ef257781967a11334d2b9366390f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hyperf/snowflake/zipball/a77b0d4c9215ef257781967a11334d2b9366390f",
+                "reference": "a77b0d4c9215ef257781967a11334d2b9366390f",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "hyperf/contract": "~3.1.0",
+                "php": ">=8.1"
+            },
+            "suggest": {
+                "hyperf/config": "Required to read snowflake config.",
+                "hyperf/redis": "Required to use RedisMilliSecondMetaGenerator or RedisSecondMetaGenerator.",
+                "psr/container": "Required to use MetaGeneratorFactory."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                },
+                "hyperf": {
+                    "config": "Hyperf\\Snowflake\\ConfigProvider"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Hyperf\\Snowflake\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A snowflake library",
+            "homepage": "https://hyperf.io",
+            "keywords": [
+                "php",
+                "snowflake"
+            ],
+            "support": {
+                "docs": "https://hyperf.wiki",
+                "issues": "https://github.com/hyperf/hyperf/issues",
+                "pull-request": "https://github.com/hyperf/hyperf/pulls",
+                "source": "https://github.com/hyperf/hyperf"
+            },
+            "funding": [
+                {
+                    "url": "https://hyperf.wiki/#/zh-cn/donate",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://opencollective.com/hyperf",
+                    "type": "open_collective"
+                }
+            ],
+            "time": "2024-03-23T11:28:51+00:00"
+        },
         {
             "name": "hyperf/stdlib",
             "version": "v3.1.15",
@@ -4605,6 +4864,81 @@
             ],
             "time": "2024-05-30T08:59:48+00:00"
         },
+        {
+            "name": "hyperf/websocket-server",
+            "version": "v3.1.16",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hyperf/websocket-server.git",
+                "reference": "b4b0903ff87a1763941c014bf755b352663d73d4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hyperf/websocket-server/zipball/b4b0903ff87a1763941c014bf755b352663d73d4",
+                "reference": "b4b0903ff87a1763941c014bf755b352663d73d4",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "hyperf/collection": "~3.1.0",
+                "hyperf/contract": "~3.1.0",
+                "hyperf/exception-handler": "~3.1.0",
+                "hyperf/http-server": "~3.1.0",
+                "hyperf/support": "~3.1.0",
+                "hyperf/utils": "~3.1.0",
+                "php": ">=8.1",
+                "psr/container": "^1.0|^2.0",
+                "psr/event-dispatcher": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                },
+                "hyperf": {
+                    "config": "Hyperf\\WebSocketServer\\ConfigProvider"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Hyperf\\WebSocketServer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A websocket server library for Hyperf.",
+            "homepage": "https://hyperf.io",
+            "keywords": [
+                "hyperf",
+                "php",
+                "swoole",
+                "websocket"
+            ],
+            "support": {
+                "docs": "https://hyperf.wiki",
+                "issues": "https://github.com/hyperf/hyperf/issues",
+                "pull-request": "https://github.com/hyperf/hyperf/pulls",
+                "source": "https://github.com/hyperf/hyperf"
+            },
+            "funding": [
+                {
+                    "url": "https://hyperf.wiki/#/zh-cn/donate",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://opencollective.com/hyperf",
+                    "type": "open_collective"
+                }
+            ],
+            "time": "2024-04-02T02:40:09+00:00"
+        },
         {
             "name": "jetbrains/phpstorm-attributes",
             "version": "1.1",
@@ -5294,6 +5628,222 @@
             },
             "time": "2024-03-17T08:10:35+00:00"
         },
+        {
+            "name": "paragonie/constant_time_encoding",
+            "version": "v3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/constant_time_encoding.git",
+                "reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
+                "reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": "^8"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9",
+                "vimeo/psalm": "^4|^5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ParagonIE\\ConstantTime\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com",
+                    "role": "Maintainer"
+                },
+                {
+                    "name": "Steve 'Sc00bz' Thomas",
+                    "email": "steve@tobtu.com",
+                    "homepage": "https://www.tobtu.com",
+                    "role": "Original Developer"
+                }
+            ],
+            "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+            "keywords": [
+                "base16",
+                "base32",
+                "base32_decode",
+                "base32_encode",
+                "base64",
+                "base64_decode",
+                "base64_encode",
+                "bin2hex",
+                "encoding",
+                "hex",
+                "hex2bin",
+                "rfc4648"
+            ],
+            "support": {
+                "email": "info@paragonie.com",
+                "issues": "https://github.com/paragonie/constant_time_encoding/issues",
+                "source": "https://github.com/paragonie/constant_time_encoding"
+            },
+            "time": "2024-05-08T12:36:18+00:00"
+        },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v9.99.100",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">= 7"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*",
+                "vimeo/psalm": "^1"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "polyfill",
+                "pseudorandom",
+                "random"
+            ],
+            "support": {
+                "email": "info@paragonie.com",
+                "issues": "https://github.com/paragonie/random_compat/issues",
+                "source": "https://github.com/paragonie/random_compat"
+            },
+            "time": "2020-10-15T08:29:30+00:00"
+        },
+        {
+            "name": "php-amqplib/php-amqplib",
+            "version": "v3.6.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-amqplib/php-amqplib.git",
+                "reference": "76eee289e98b0b309a761787e65cbe1acbaf8c72"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/76eee289e98b0b309a761787e65cbe1acbaf8c72",
+                "reference": "76eee289e98b0b309a761787e65cbe1acbaf8c72",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-sockets": "*",
+                "php": "^7.2||^8.0",
+                "phpseclib/phpseclib": "^2.0|^3.0"
+            },
+            "conflict": {
+                "php": "7.4.0 - 7.4.1"
+            },
+            "replace": {
+                "videlalvaro/php-amqplib": "self.version"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "nategood/httpful": "^0.2.20",
+                "phpunit/phpunit": "^7.5|^9.5",
+                "squizlabs/php_codesniffer": "^3.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpAmqpLib\\": "PhpAmqpLib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Alvaro Videla",
+                    "role": "Original Maintainer"
+                },
+                {
+                    "name": "Raúl Araya",
+                    "email": "nubeiro@gmail.com",
+                    "role": "Maintainer"
+                },
+                {
+                    "name": "Luke Bakken",
+                    "email": "luke@bakken.io",
+                    "role": "Maintainer"
+                },
+                {
+                    "name": "Ramūnas Dronga",
+                    "email": "github@ramuno.lt",
+                    "role": "Maintainer"
+                }
+            ],
+            "description": "Formerly videlalvaro/php-amqplib.  This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
+            "homepage": "https://github.com/php-amqplib/php-amqplib/",
+            "keywords": [
+                "message",
+                "queue",
+                "rabbitmq"
+            ],
+            "support": {
+                "issues": "https://github.com/php-amqplib/php-amqplib/issues",
+                "source": "https://github.com/php-amqplib/php-amqplib/tree/v3.6.1"
+            },
+            "time": "2024-02-07T17:21:26+00:00"
+        },
         {
             "name": "php-di/phpdoc-reader",
             "version": "2.2.1",
@@ -5474,6 +6024,122 @@
             ],
             "time": "2023-11-12T21:59:55+00:00"
         },
+        {
+            "name": "phpseclib/phpseclib",
+            "version": "3.0.39",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpseclib/phpseclib.git",
+                "reference": "211ebc399c6e73c225a018435fe5ae209d1d1485"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/211ebc399c6e73c225a018435fe5ae209d1d1485",
+                "reference": "211ebc399c6e73c225a018435fe5ae209d1d1485",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "paragonie/constant_time_encoding": "^1|^2|^3",
+                "paragonie/random_compat": "^1.4|^2.0|^9.99.99",
+                "php": ">=5.6.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "*"
+            },
+            "suggest": {
+                "ext-dom": "Install the DOM extension to load XML formatted public keys.",
+                "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
+                "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
+                "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
+                "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "phpseclib/bootstrap.php"
+                ],
+                "psr-4": {
+                    "phpseclib3\\": "phpseclib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jim Wigginton",
+                    "email": "terrafrost@php.net",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Patrick Monnerat",
+                    "email": "pm@datasphere.ch",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Andreas Fischer",
+                    "email": "bantu@phpbb.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Hans-Jürgen Petrich",
+                    "email": "petrich@tronic-media.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
+            "homepage": "http://phpseclib.sourceforge.net",
+            "keywords": [
+                "BigInteger",
+                "aes",
+                "asn.1",
+                "asn1",
+                "blowfish",
+                "crypto",
+                "cryptography",
+                "encryption",
+                "rsa",
+                "security",
+                "sftp",
+                "signature",
+                "signing",
+                "ssh",
+                "twofish",
+                "x.509",
+                "x509"
+            ],
+            "support": {
+                "issues": "https://github.com/phpseclib/phpseclib/issues",
+                "source": "https://github.com/phpseclib/phpseclib/tree/3.0.39"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/terrafrost",
+                    "type": "github"
+                },
+                {
+                    "url": "https://www.patreon.com/phpseclib",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-06-24T06:27:33+00:00"
+        },
         {
             "name": "psr/cache",
             "version": "3.0.0",

+ 35 - 0
config/autoload/amqp.php

@@ -0,0 +1,35 @@
+<?php
+
+return [
+    'enable' => true,
+    'default' => [
+        'host' => '192.168.1.193',
+        'port' => 5672,
+        'user' => 'admin',
+        'password' => '123456',
+        'vhost' => '/',
+        'concurrent' => [
+            'limit' => 1,
+        ],
+        'pool' => [
+            'connections' => 1,
+        ],
+        'params' => [
+            'insist' => false,
+            'login_method' => 'AMQPLAIN',
+            'login_response' => null,
+            'locale' => 'en_US',
+            'connection_timeout' => 3.0,
+            // 尽量保持是 heartbeat 数值的两倍
+            'read_write_timeout' => 6.0,
+            'context' => null,
+            'keepalive' => false,
+            // 尽量保证每个消息的消费时间小于心跳时间
+            'heartbeat' => 3,
+            'close_on_destruct' => false,
+        ],
+    ],
+    'pool2' => [
+
+    ]
+];

+ 1 - 0
config/autoload/dependencies.php

@@ -13,5 +13,6 @@ return [
 //    App\JsonRpc\UserServiceInterface::class => App\JsonRpc\UserService::class,
 //    App\JsonRpc\AdServiceInterface::class => App\JsonRpc\AdService::class,
 //    App\JsonRpc\WebsiteServiceInterface::class => App\JsonRpc\WebsiteService::class,
+//    App\JsonRpc\NewsServiceInterface::class => App\JsonRpc\NewsService::class,
 ];
 

+ 3 - 0
config/autoload/middlewares.php

@@ -5,4 +5,7 @@ return [
         \App\Middleware\Auth\FooMiddleware::class,
         \Hyperf\Validation\Middleware\ValidationMiddleware::class,
     ],
+    'ws' => [
+        \App\Middleware\WebSocketAuthMiddleware::class
+    ]
 ];

+ 2 - 2
config/autoload/redis.php

@@ -13,8 +13,8 @@ use function Hyperf\Support\env;
 
 return [
     'default' => [
-        'host' => env('REDIS_HOST', 'localhost'),
-        'auth' => env('REDIS_AUTH', null),
+        'host' => env('REDIS_HOST', '192.168.1.193'),
+        'auth' => env('REDIS_AUTH', '123456'),
         'port' => (int) env('REDIS_PORT', 6379),
         'db' => (int) env('REDIS_DB', 0),
         'pool' => [

+ 12 - 0
config/autoload/server.php

@@ -26,6 +26,18 @@ return [
                 Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
             ],
         ],
+        [
+            'name' => 'ws',
+            'type' => Server::SERVER_WEBSOCKET,
+            'host' => '0.0.0.0',
+            'port' => 9506,
+            'sock_type' => SWOOLE_SOCK_TCP,
+            'callbacks' => [
+                Event::ON_HAND_SHAKE => [Hyperf\WebSocketServer\Server::class, 'onHandShake'],
+                Event::ON_MESSAGE => [Hyperf\WebSocketServer\Server::class, 'onMessage'],
+                Event::ON_CLOSE => [Hyperf\WebSocketServer\Server::class, 'onClose'],
+            ],
+        ],
     ],
     'settings' => [
         Constant::OPTION_ENABLE_COROUTINE => true,

+ 50 - 5
config/autoload/services.php

@@ -8,7 +8,7 @@ return [
             'service' => \App\JsonRpc\UserServiceInterface::class,
             // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
             'nodes' => [
-                ['host' => '192.168.31.193', 'port' => 9504],
+                ['host' => '192.168.1.193', 'port' => 9504],
             ],
         ],
         [
@@ -17,7 +17,25 @@ return [
             'service' => \App\JsonRpc\AuthorityServiceInterface::class,
             // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
             'nodes' => [
-                ['host' => '192.168.31.193', 'port' => 9504],
+                ['host' => '192.168.1.193', 'port' =>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                    9504],
             ],
         ],
         [
@@ -26,7 +44,7 @@ return [
             'service' => \App\JsonRpc\AdServiceInterface::class,
             // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
             'nodes' => [
-                ['host' => '192.168.31.193', 'port' => 9503],
+                ['host' => '192.168.1.193', 'port' => 9503],
             ],
         ],
         [
@@ -35,7 +53,7 @@ return [
             'service' => \App\JsonRpc\WebsiteServiceInterface::class,
             // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
             'nodes' => [
-                ['host' => '192.168.31.193', 'port' => 9502],
+                ['host' => '192.168.1.193', 'port' => 9502],
             ],
         ],
         [
@@ -44,7 +62,34 @@ return [
             'service' => \App\JsonRpc\PublicRpcServiceInterface::class,
             // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
             'nodes' => [
-                ['host' => '192.168.31.193', 'port' => 9502],
+                ['host' => '192.168.1.193', 'port' => 9502],
+            ],
+        ],
+        [
+            //资讯-新闻
+            'name' => 'NewsService',
+            'service' => \App\JsonRpc\NewsServiceInterface::class,
+            // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
+            'nodes' => [
+                ['host' => '192.168.1.193', 'port' => 9505],
+            ],
+        ],
+        [
+            //友情链接服务
+            'name' => 'LinkService',
+            'service' => \App\JsonRpc\LinkServiceInterface::class,
+            // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
+            'nodes' => [
+                ['host' => '192.168.1.193', 'port' => 9502],
+            ],
+        ],
+        [
+            //友情链接服务
+            'name' => 'ChatService',
+            'service' => \App\JsonRpc\ChatServiceInterface::class,
+            // 直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
+            'nodes' => [
+                ['host' => '192.168.1.193', 'port' => 9507],
             ],
         ],
     ],

+ 23 - 0
config/autoload/snowflake.php

@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator;
+use Hyperf\Snowflake\MetaGenerator\RedisSecondMetaGenerator;
+use Hyperf\Snowflake\MetaGeneratorInterface;
+
+return [
+    'begin_second' => MetaGeneratorInterface::DEFAULT_BEGIN_SECOND,
+    RedisMilliSecondMetaGenerator::class => [
+        // Redis Pool
+        'pool' => 'default',
+        // 用于计算 WorkerId 的 Key 键
+        'key' => RedisMilliSecondMetaGenerator::DEFAULT_REDIS_KEY
+    ],
+    RedisSecondMetaGenerator::class => [
+        // Redis Pool
+        'pool' => 'default',
+        // 用于计算 WorkerId 的 Key 键
+        'key' => RedisMilliSecondMetaGenerator::DEFAULT_REDIS_KEY
+    ],
+];

+ 8 - 4
config/routes.php

@@ -11,12 +11,10 @@ declare(strict_types=1);
  */
 use Hyperf\HttpServer\Router\Router;
 Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
-//Router::addRoute(['POST'], '/website/createWebsite', 'App\Controller\WebsiteController@createWebsite');
+Router::addRoute(['GET', 'POST', 'HEAD'], '/verifyCode', 'App\Controller\IndexController@verifyCode');
+
 Router::post('/api/login', 'App\Controller\LoginController@login');
 Router::get('/api/getData', 'App\Controller\LoginController@getData');
-//Router::addGroup('/user', function () {
-//    Router::get('/getMenuList', 'App\Controller\UserController@getMenuList');
-//}, ['middleware' => [\App\Middleware\Auth\FooMiddleware::class]]);
 
 
 
@@ -24,3 +22,9 @@ Router::get('/api/getData', 'App\Controller\LoginController@getData');
 Router::get('/favicon.ico', function () {
     return '';
 });
+
+Router::addServer('ws', function () {
+    Router::get('/', 'App\Controller\WebSocketController');
+
+
+});

BIN
public/image/20240701/171980475880998.png


BIN
public/image/20240701/1719804797525391.png


BIN
public/image/20240701/171980486022785.png


BIN
public/image/20240701/1719814246170673.png


BIN
public/image/20240701/1719821095401452.png


BIN
public/image/20240701/1719821117962271.png


BIN
public/image/20240701/1719821162245282.png


BIN
public/image/20240701/171982121662014.png


BIN
public/image/20240701/1719821685532250.png


BIN
public/image/20240701/1719822293283470.png


BIN
public/image/20240701/1719822555366246.png


BIN
public/image/20240701/1719822852277219.png


BIN
public/image/20240701/1719823060348423.png


BIN
public/image/20240701/1719823485800981.png


BIN
public/image/20240701/171982366157844.png


BIN
public/image/20240701/1719823907487697.png


BIN
public/image/20240701/1719823988808424.png


BIN
public/image/20240701/1719824474422655.png


BIN
public/image/20240701/1719824610588298.png


BIN
public/image/20240701/171982573350041.png


BIN
public/image/20240701/1719825849433783.jpg


BIN
public/image/20240701/1719825875489029.png


BIN
public/image/20240701/1719825904104745.png


BIN
public/image/20240701/171982593655238.png


BIN
public/image/20240701/1719826014111488.jpg


BIN
public/image/20240701/1719827075515168.png


BIN
public/image/20240701/171982714652839.jpg


BIN
public/image/20240701/1719832332463752.png


BIN
public/image/20240701/1719832635693656.png


BIN
public/image/20240703/1719986589727690.png


BIN
public/image/20240703/171998663958838.png


BIN
public/image/20240703/1719986788801847.png


BIN
public/image/20240703/1719987104955969.png


BIN
public/image/20240704/1720053228201114.jpg


BIN
public/image/20240704/1720053282400602.jpg


BIN
public/image/20240704/1720057766796487.jpg


BIN
public/image/20240704/1720057806971205.jpg


BIN
public/image/20240704/1720057911521482.jpg


BIN
public/image/20240704/1720058234717205.jpg


BIN
public/image/20240704/1720060330124061.jpg


BIN
public/image/20240704/1720061591267295.jpg


BIN
public/image/20240704/1720063364683465.jpg


BIN
public/image/20240704/1720063418294166.jpg


BIN
public/image/20240704/172008405373300.jpg


BIN
public/image/20240704/1720085834599076.jpg


BIN
public/image/20240704/1720085992384760.jpg


BIN
public/image/20240719/1721372280562912.jpg


BIN
public/image/20240719/1721372309952084.jpg


BIN
public/image/20240719/1721372470477268.jpg


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است