From c9589602ebbefdb2226d26f5ac2862b31b78959f Mon Sep 17 00:00:00 2001 From: ASUS <515617283@qq.com> Date: Thu, 18 Sep 2025 17:38:47 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A1=AE=E7=9F=AD=E4=BF=A1=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/IndexController.php | 15 +- app/functions.php | 45 +++++ app/model/MessagePushTask.php | 267 +++++++++++++++++++++++------ config/cons.php | 1 + 4 files changed, 276 insertions(+), 52 deletions(-) diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index 5148b9b..0c94835 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -9,7 +9,20 @@ class IndexController { public function index(Request $request) { - return '哈啰'; + + $url = 'http://192.168.1.31/market/admin/coupon/grant'; + $res = http_post($url, [ + 'userId' => 1, + 'couponId' => 1, + 'num' => 1, + 'shopId' => 1, + ]); + p($res); + + +// $data = \app\model\MessagePushTask::send_push_msg(); +// $data = \app\model\MessagePushTask::send_sms_msg(); + return json($data); } public function view(Request $request) diff --git a/app/functions.php b/app/functions.php index 1b63623..89ada6f 100644 --- a/app/functions.php +++ b/app/functions.php @@ -51,3 +51,48 @@ function uniqueMultidimensionalArray($array, $k = 'user_id') { // 重新索引数组(从0开始的连续数字键) return array_values($unique); } +if(!function_exists('http_post')) { + function http_post($url, $data, $headers = [], $timeout = 30, $contentType = 'application/json') + { + // 初始化cURL + $ch = curl_init(); + + // 处理请求数据 + if ($contentType === 'application/json') { + $data = json_encode($data); + } elseif (is_array($data)) { + $data = http_build_query($data); + } + + // 设置请求头 + $defaultHeaders = [ + "Content-Type: $contentType", + "Content-Length: " . strlen($data) + ]; + $headers = array_merge($defaultHeaders, $headers); + + // 设置cURL选项 + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + + // 执行请求 + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = curl_error($ch); + + // 关闭cURL + curl_close($ch); + + // 处理错误 + if ($response === false) { + return $error; + } + return $response; + } +} \ No newline at end of file diff --git a/app/model/MessagePushTask.php b/app/model/MessagePushTask.php index 5481ea1..0108887 100644 --- a/app/model/MessagePushTask.php +++ b/app/model/MessagePushTask.php @@ -9,10 +9,12 @@ use EasyWeChat\Factory; class MessagePushTask { - public static function send_msg() + + // 推送模版消息 + public static function send_push_msg() { - // 查询任务 - $event_list = Db::name('tb_push_event')->where(['status' => 0])->select(); + // 查询模版任务 + $event_list = Db::name('tb_push_event')->where(['status' => 0, 'push_type' => 1])->select()->toArray(); if($event_list) { try { Db::startTrans(); @@ -23,23 +25,30 @@ class MessagePushTask foreach ($res as $rk => &$rv) { if(empty($rv['open_id'])) { unset($res[$rk]); + }else { + $rv['push_event_id'] = $event['id']; + $rv['template_id'] = $event['template_id']; + $rv['keyword1'] = $event['keyword1']; + $rv['keyword2'] = $event['keyword2']; + $rv['keyword3'] = $event['keyword3']; + $rv['keyword4'] = $event['keyword4']; + $rv['keyword5'] = $event['keyword5']; } - $rv['push_event_id'] = $event['id']; - $rv['template_id'] = $event['template_id']; - $rv['keyword1'] = $event['keyword1']; - $rv['keyword2'] = $event['keyword2']; - $rv['keyword3'] = $event['keyword3']; - $rv['keyword4'] = $event['keyword4']; - $rv['keyword5'] = $event['keyword5']; } $user_list = uniqueMultidimensionalArray($res); // 需要接收推送的用户 准备发送 foreach ($user_list as $k => $user) { + $data = [ + 'thing2' => $user['keyword1'], + 'amount3' => $user['keyword2'], + 'time6' => $user['keyword3'], + ]; $user_push_list_res_id = Db::name('tb_user_push_event')->insertGetId([ 'push_event_id' => $user['push_event_id'], 'user_id' => $user['user_id'], 'create_time' => date("Y-m-d H:i:s"), + 'content' => json_encode($data), ]); if($user_push_list_res_id) { $app = Factory::officialAccount([ @@ -47,11 +56,7 @@ class MessagePushTask 'secret' => config('cons.secret'), 'response_type' => 'array', ]); - $data = [ - 'thing2' => $user['keyword1'], - 'amount3' => $user['keyword2'], - 'time6' => $user['keyword3'], - ]; + // 正式推送 $push = $app->template_message->send([ 'touser' => $user['open_id'], @@ -61,6 +66,11 @@ class MessagePushTask Log::info('用户-' . $user['user_id'] . ' 推送模版ID:'. $user['template_id'] .' 内容:' . json_encode($data, 256) . ' 推送结果:' . json_encode($push)); if($push['errcode'] == 0) { Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => 1]); + // 送券 + if(isset($event['coupon'])) { + $coupon = json_decode($event['coupon'], true); + self::sendUserCoupon($event['shop_id'], $user['user_id'], $coupon['id'], $coupon['num']); + } }else { Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => -1, 'error' => json_encode($push)]); } @@ -81,6 +91,117 @@ class MessagePushTask } + + // 推送短信消息 + public static function send_sms_msg() + { + // 查询短信任务 + $event_list = Db::name('tb_push_event')->where(['status' => 0, 'push_type' => 2])->select()->toArray(); + if($event_list) { + try { + Db::startTrans(); + foreach ($event_list as $k => $event) { + Db::name('tb_push_event')->where(['id' => $event['id']])->update(['status' => 1, 'start_time' => date('Y-m-d H:i:s')]); + $res = self::getPullInfoUser($event); + if($res) { + foreach ($res as $rk => &$rv) { + if(empty($rv['phone'])) { + unset($res[$rk]); + }else { + $rv['push_event_id'] = $event['id']; + $rv['sms_sign'] = $event['sms_sign']; + $rv['sms_code'] = $event['sms_code']; + $rv['sms_content'] = $event['sms_content']; + } + } + + $user_list = uniqueMultidimensionalArray($res); + // 需要接收推送的用户 准备发送 + foreach ($user_list as $k => $user) { + // 查询商家短信余额 + $sms_shop = Db::name('tb_shop_sms_money')->where(['shop_id' => $event['shop_id']])->find(); + if (!$sms_shop) { + $sms_shop_res_id = Db::name('tb_shop_sms_money')->insertGetId([ + 'shop_id' => $user['push_event_id'], + 'create_time' => date("Y-m-d H:i:s"), + ]); + log::info('商户' . $event['shop_id'] . '不存在或余额不足,停止发送'); + continue 2; + } else { + // 一条短信的价格 + $one_sms_price = config('cons.sms_price'); + if($sms_shop['money'] < $one_sms_price) { + log::info('商户' . $event['shop_id'] . '余额不足,停止发送'); + continue 2; + }else { + $user_push_list_res_id = Db::name('tb_user_push_event')->insertGetId([ + 'push_event_id' => $user['push_event_id'], + 'user_id' => $user['user_id'], + 'create_time' => date("Y-m-d H:i:s"), + 'content' => json_encode($user), + ]); + if ($user_push_list_res_id) { + + // 发送短信空位置 + + + Log::info('用户-' . $user['user_id'] . ' 短信发送ID:' . $user['template_id'] . ' 内容:' . json_encode($data, 256) . ' 推送结果:' . json_encode($push)); + if ($push['errcode'] == 0) { + Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => 1]); + // 加入明细 + $tb_shop_sms_money = Db::name('tb_shop_sms_money_detail')->insertGetId([ + 'shop_id' => $event['shop_id'], + 'type' => 2, + 'money' => $one_sms_price, + 'create_time' => date("Y-m-d H:i:s"), + ]); + if($tb_shop_sms_money) { + // 扣掉余额 + Db::name('tb_shop_sms_money')->where([ + 'shop_id' => $event['shop_id'], + ])->dec('money', $one_sms_price)->update(); + } + // 送券 + if(isset($event['coupon'])) { + $coupon = json_decode($event['coupon'], true); + self::sendUserCoupon($event['shop_id'], $user['user_id'], $coupon['id'], $coupon['num']); + } + + } else { + Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => -1, 'error' => json_encode($push)]); + } + } + sleep(1); + } + } + } + Db::name('tb_push_event')->where(['id' => $event['id']])->update(['status' => 2, 'send_time' => date('Y-m-d H:i:s')]); + } + } + Db::commit(); + }catch (\Exception $e) { + Log::info('执行出错--' . $e->getMessage()); + Db::rollback(); + } + } + Log::info('没有推送任务可执行'); + return true; + } + + + + + + + + + + + + + + + /** * 找到可以接收订阅消息的用户 * @param $type类型 1按次数发送 2自定义 3按标签 @@ -90,12 +211,15 @@ class MessagePushTask { $user_arr = []; switch ($event['type']) { + // 按可接收次数发送(模版推送)/全部绑定手机用户(短信推送) case 1; $user_arr = self::getPullInfoUserToNumber($event); break; + // 自定义 case 2; $user_arr = self::getPullInfoUserToCustom($event); break; + // 按标签 case 3; $user_arr = self::getPullInfoUserToLabel($event); break; @@ -108,13 +232,19 @@ class MessagePushTask public static function getPullInfoUserToNumber($event) { $user_num = []; - if($event['can_send_times'] > 0) { + if($event['push_type'] == 1 && $event['can_send_times'] > 0) { $user_num = Db::name('tb_user_push_event_num')->alias('upen')->where('upen.num', '>=', $event['can_send_times']) ->join('tb_user_info u', 'upen.user_id = u.id') ->field('upen.user_id as user_id, upen.open_id as open_id') ->select() ->toArray(); } + if($event['push_type'] == 2) { + $user_num = Db::name('tb_user_info')->where('phone', '<>', '') + ->field('id as user_id, wechat_ac_open_id as open_id, phone') + ->select() + ->toArray(); + } return $user_num; } @@ -131,21 +261,21 @@ class MessagePushTask // 未知 if($gender == 0) { $gender_data_res = Db::name('tb_user_info')->whereNotIn('sex', [0,1]) - ->field('id as user_id, wechat_ac_open_id as open_id') + ->field('id as user_id, wechat_ac_open_id as open_id, phone') ->select() ->toArray(); } // 男 if($gender == 1) { $gender_data_res = Db::name('tb_user_info')->where('sex', 1) - ->field('id as user_id, wechat_ac_open_id as open_id') + ->field('id as user_id, wechat_ac_open_id as open_id, phone') ->select() ->toArray(); } // 女 if($gender == 2) { $gender_data_res = Db::name('tb_user_info')->where('sex', 0) - ->field('id as user_id, wechat_ac_open_id as open_id') + ->field('id as user_id, wechat_ac_open_id as open_id, phone') ->select() ->toArray(); } @@ -174,7 +304,7 @@ class MessagePushTask ->leftJoin('tb_order_info o', 'u.id = o.user_id') ->where('o.user_id', 'null') ->distinct() - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->select() ->toArray(); } @@ -189,7 +319,7 @@ class MessagePushTask // 筛选出订单数量为1的用户 ->having('COUNT(o.id) = 1') // 选择需要的用户字段,同时查询订单数量(可选) - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->select() ->toArray(); } @@ -203,7 +333,7 @@ class MessagePushTask ->group('u.id') // 筛选出订单数量为1的用户 ->having('COUNT(o.id) BETWEEN 2 AND 5') - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->select() ->toArray(); } @@ -217,7 +347,7 @@ class MessagePushTask ->group('u.id') // 筛选出订单数量为1的用户 ->having('COUNT(o.id) >= 5') - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->select() ->toArray(); } @@ -246,7 +376,7 @@ class MessagePushTask ->join('tb_order_info o', 'u.id = o.user_id') ->where('o.create_time', '>=', date('Y-m-d 00:00:00')) ->where('o.create_time', '<=', date('Y-m-d 23:59:59')) - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->distinct() ->select() ->toArray(); @@ -258,7 +388,7 @@ class MessagePushTask ->join('tb_order_info o', 'u.id = o.user_id') ->where('o.create_time', '>=', date('Y-m-d 00:00:00', strtotime('-1 day'))) ->where('o.create_time', '<=', date('Y-m-d 23:59:59', strtotime('-1 day'))) - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->distinct() ->select() ->toArray(); @@ -272,7 +402,7 @@ class MessagePushTask ->leftJoin('tb_order_info o', 'u.id = o.user_id') ->where('o.create_time', '>=', $twoWeeksAgo) ->where('o.id', 'null') - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->distinct() ->select() ->toArray(); @@ -289,7 +419,7 @@ class MessagePushTask ->group('u.id') // 筛选最后下单时间在30天前到15天前之间的用户 ->having('MAX(o.create_time) >="'. $startTime .'" AND MAX(o.create_time) <= "' . $endTime . '"') - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->select() ->toArray(); } @@ -305,7 +435,7 @@ class MessagePushTask // 筛选最后下单时间在1个月前及更早 ->having('MAX(o.create_time) <= "' . $oneMonthAgo . '"') // ->field('u.id as user_id, u.wechat_ac_open_id as open_id, MAX(o.create_time) as last_order_time') - ->field('u.id as user_id, u.wechat_ac_open_id as open_id') + ->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone') ->select() ->toArray(); } @@ -329,21 +459,52 @@ class MessagePushTask // 非会员 if($vip == 0) { $vip_data_res = Db::name('tb_user_info')->whereNotIn('is_vip', 0) - ->field('id as user_id, wechat_ac_open_id as open_id') + ->field('id as user_id, wechat_ac_open_id as open_id,phone') ->select() ->toArray(); } // 会员 if($vip == 1) { - $vip_data_res = Db::name('tb_user_info')->where('is_vip', 1) - ->field('id as user_id, wechat_ac_open_id as open_id') - ->select() - ->toArray(); + if($event['push_type'] == 1) { + $vip_data_res = Db::name('tb_user_info')->where('is_vip', 1) + ->field('id as user_id, wechat_ac_open_id as open_id,phone') + ->select() + ->toArray(); + } + // 推送类型为短信推送 + if($event['push_type'] == 2) { + // 全部会员 + if($event['vip_lavel'] == 0) { + $vip_data_res = Db::name('tb_user_info')->where('is_vip', 1) + ->field('id as user_id, wechat_ac_open_id as open_id,phone') + ->select() + ->toArray(); + } + // 仅限等级 + if($event['vip_lavel'] == 1) { + $vip_data_res = Db::name('tb_user_info')->where(['is_vip' => 1, 'member_level_id' => $event['vip_lavel_id']]) + ->field('id as user_id, wechat_ac_open_id as open_id,phone') + ->select() + ->toArray(); + } + // 以上等级 + if($event['vip_lavel'] == 2) { + // 找到会员详情 + $vip_config_info = Db::name('tb_member_level_config')->where(['id' => $event['vip_lavel_id']])->find(); + if($vip_config_info) { + $vip_config_info = Db::name('tb_member_level_config')->where('experience_value', '>', $vip_config_info['experience_value'])->column('id'); + if($vip_config_info) { + $vip_data_res = Db::name('tb_user_info')->where(['is_vip' => 1])->whereIn('member_level_id', $vip_config_info) + ->field('id as user_id, wechat_ac_open_id as open_id,phone') + ->select() + ->toArray(); + } + } + } + } } - if($vip_data_arr) { $vip_data_arr = array_merge($vip_data_arr, $vip_data_res); - }else { $vip_data_arr = $vip_data_res; } @@ -372,7 +533,7 @@ class MessagePushTask // 已绑定 if($telphone == 1) { $telphone_data_res = Db::name('tb_user_info')->where('phone', '<>', '') - ->field('id as user_id, wechat_ac_open_id as open_id') + ->field('id as user_id, wechat_ac_open_id as open_id, phone') ->select() ->toArray(); } @@ -401,7 +562,7 @@ class MessagePushTask ->column('user_id'); if($label) { $data_arr = Db::name('tb_user_info')->whereIn('id', $label) - ->field('id as user_id, wechat_ac_open_id as open_id') + ->field('id as user_id, wechat_ac_open_id as open_id, phone') ->select() ->toArray(); } @@ -410,23 +571,27 @@ class MessagePushTask // 给用户送送优惠券 - public static function sendUserCoupon(int | array $user_id, $coupon_id, $number = 1) + public static function sendUserCoupon($shop_id, int | array $user_id, $coupon_id, $number = 1) { - try { - Db::startTrans(); - if(is_int($user_id)) { - - }elseif (is_array($user_id)) { - - } - Db::commit(); - return true; - }catch (\Exception $e) { - Db::rollback(); - Log::info('用户送券异常-->' . $e->getMessage()); + if ($number === null || $number <= 0) { + Log::info('推送用户送券发放数量不能小于0'); return false; } - + $url = 'http://192.168.1.31/market/admin/coupon/grant'; + $res = http_post($url, [ + 'userId' => $user_id, + 'couponId' => $coupon_id, + 'num' => $number, + 'shopId' => $shop_id, + ]); + Log::info('发券:' . $res); + $res = json_decode($res, true); + if($res['code'] == 200) { + Log::info('userId:' . $user_id . ' couponId:' . $coupon_id . ' shopId:' . $shop_id . '发券成功'); + }else { + Log::info('userId:' . $user_id . ' couponId:' . $coupon_id . ' shopId:' . $shop_id . '发券失败' . ' 信息:' . $res['msg']); + } + return true; } diff --git a/config/cons.php b/config/cons.php index 3fdb4f0..c27d3bf 100644 --- a/config/cons.php +++ b/config/cons.php @@ -5,4 +5,5 @@ return [ 'app_id' => 'wx1fb600d0f5ea6279', // 银收客czg 'secret' => 'b4c0534c9b5e6c84a7fe5c2078dff876', + 'sms_price' => 0.055, // 短信发送价格 ];