cqp 7 mesi fa
parent
commit
5a9926392b
3 ha cambiato i file con 145 aggiunte e 2 eliminazioni
  1. 18 2
      app/Console/Commands/ToDoReminder.php
  2. 125 0
      app/Jobs/TodoRemindJob.php
  3. 2 0
      app/Model/TodoList.php

+ 18 - 2
app/Console/Commands/ToDoReminder.php

@@ -2,6 +2,7 @@
 
 namespace App\Console\Commands;
 
+use App\Jobs\TodoRemindJob;
 use App\Model\TodoList;
 use App\Model\WxEmployeeOfficial;
 use App\Service\Weixin\WxTemplateMessageService;
@@ -50,6 +51,22 @@ class ToDoReminder extends Command
         }
     }
 
+    public function handleReminders()
+    {
+        $now = time();
+
+        TodoList::where('status', '<', TodoList::status_two)
+            ->where('del_time', 0)
+            ->where('remind_start', '<=', $now)
+            ->orderBy('remind_start')
+            ->chunkById(50, function ($list) {
+                foreach ($list as $todo) {
+                    dispatch(new TodoRemindJob($todo->id))->onQueue(TodoList::$job);
+                }
+            });
+    }
+
+    //弃用-----------------------------------------------------------
     public function handleReminders1()
     {
         $now = time();
@@ -110,7 +127,7 @@ class ToDoReminder extends Command
             });
     }
 
-    public function handleReminders()
+    public function handleReminders2()
     {
         $now     = time();
         $appid   = config("wx_msg.f_appid");
@@ -216,5 +233,4 @@ class ToDoReminder extends Command
         ]);
         return [$status, $msg];
     }
-
 }

+ 125 - 0
app/Jobs/TodoRemindJob.php

@@ -0,0 +1,125 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Model\TodoList;
+use App\Model\WxEmployeeOfficial;
+use App\Service\Weixin\WxTemplateMessageService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Redis;
+use MongoDB\Driver\Exception\Exception;
+use Symfony\Component\Console\Output\ConsoleOutput;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class TodoRemindJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    public $todoId;
+    public $tries = 1;
+
+    public function __construct($todoId)
+    {
+        $this->todoId = $todoId;
+    }
+
+    public function handle()
+    {
+        $this->doJob();
+    }
+
+    private function doJob(){
+        $now   = time();
+        $appid = config("wx_msg.f_appid");
+        $wxSrv = new WxTemplateMessageService();
+
+        $todo = TodoList::find($this->todoId);
+        if (!$todo || $todo->del_time != 0 || $todo->status >= TodoList::status_two) {
+            return;
+        }
+
+        // 分布式锁
+        $lockKey = "todo_remind_lock:" . $todo->id;
+        $lock = Cache::lock($lockKey, 5);
+
+        if (! $lock->get()) {
+            return; // 其他进程在处理,直接跳过
+        }
+
+        try {
+            // ======================
+            // 1. 是否应该提醒
+            // ======================
+            if (! $this->shouldRemind($todo, $now)) {
+                return;
+            }
+
+            // 查 openid
+            $openid = WxEmployeeOfficial::where('employee_id', $todo->crt_id)
+                ->where('type', WxEmployeeOfficial::login_type_two)
+                ->where('appid', $appid)
+                ->value('openid');
+
+            if (!$openid) {
+                $this->updateTodoStatus($todo, $now, '无openid');
+                return;
+            }
+
+            // ======================
+            // 2. 调微信接口发送
+            // ======================
+            list($ok, $msg) = $wxSrv->sendTemplateMessage('to_do', [
+                'title' => $todo->title ?? '待办提醒',
+                'time'  => date('Y-m-d H:i:00', $todo->remind_start),
+            ], [
+                'openid'   => $openid,
+                'pagepath' => 'pages/todoManage/add?type=4&id=' . $todo->id,
+            ]);
+
+            $this->updateTodoStatus($todo, $now, $msg);
+
+        } finally {
+            $lock->release();
+        }
+    }
+
+    private function shouldRemind($todo, $now)
+    {
+        if ($todo->remind_interval == 0 && empty($todo->last_remind_time)) {
+            return true;
+        }
+
+        if ($todo->remind_interval > 0) {
+            if (empty($todo->last_remind_time)) return true;
+            return ($now - $todo->last_remind_time) >= $todo->remind_interval;
+        }
+
+        return false;
+    }
+
+    private function updateTodoStatus($todo, $now, $msg)
+    {
+        $msg = is_scalar($msg) ? $msg : json_encode($msg, JSON_UNESCAPED_UNICODE);
+
+        TodoList::where('id', $todo->id)
+            ->where('last_remind_time', $todo->last_remind_time ?? 0)
+            ->update([
+                'last_remind_time' => $now,
+                'status'           => TodoList::status_one,
+                'last_time_result' => $msg,
+            ]);
+    }
+
+    protected function echoMessage(OutputInterface $output)
+    {
+        //输出消息
+        $output->writeln(json_encode($this->data));
+    }
+}

+ 2 - 0
app/Model/TodoList.php

@@ -12,6 +12,8 @@ class TodoList extends UseScopeBaseModel
 
     public static $field = ['title','id','type','remind_start','man_type','organization_name','crt_id','crt_time','contact','address','content','status','remind_interval','last_remind_time','last_time_result'];
 
+    public static $job = 'todo_remind';
+
     const type_one = 1;
     const type_two = 2;
     const type_three = 3;