From da63930f5ed552a429762038637152adff6961dd Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Tue, 14 Oct 2025 17:03:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/AccountController.php | 63 +++-- .../controller/WechatChatroomController.php | 83 +++---- Server/application/common.php | 32 +++ Server/application/cunkebao/config/route.php | 6 +- .../cunkebao/controller/RFMController.php | 55 +++++ .../cunkebao/controller/TrafficController.php | 68 ++++++ ...PotentialListWithInCompanyV1Controller.php | 32 --- .../application/job/WorkbenchMomentsJob.php | 216 +++++++++++------- .../Adapters/ChuKeBao/Adapter.php | 2 +- 9 files changed, 369 insertions(+), 188 deletions(-) create mode 100644 Server/application/cunkebao/controller/RFMController.php create mode 100644 Server/application/cunkebao/controller/TrafficController.php diff --git a/Server/application/api/controller/AccountController.php b/Server/application/api/controller/AccountController.php index f239be006..02281e17e 100644 --- a/Server/application/api/controller/AccountController.php +++ b/Server/application/api/controller/AccountController.php @@ -62,9 +62,7 @@ class AccountController extends BaseController // 保存数据到数据库 if (!empty($response['results'])) { - foreach ($response['results'] as $item) { - $this->saveAccount($item); - } + $this->saveAccount($response['results']); } if ($isInner) { @@ -703,42 +701,41 @@ class AccountController extends BaseController * 保存账号数据到数据库 * @param array $item 账号数据 */ - private function saveAccount($item) + private function saveAccount($data) { // 将日期时间字符串转换为时间戳 $createTime = isset($item['createTime']) ? strtotime($item['createTime']) : null; $deleteTime = isset($item['deleteTime']) ? strtotime($item['deleteTime']) : null; + $sqlData = []; + foreach ($data as $item) { + $sqlData[] = [ + 'id' => $item['id'], + 'accountType' => isset($item['accountType']) ? $item['accountType'] : 0, + 'status' => isset($item['status']) ? $item['status'] : 0, + 'tenantId' => isset($item['tenantId']) ? $item['tenantId'] : 0, + 'userName' => isset($item['userName']) ? $item['userName'] : '', + 'realName' => isset($item['realName']) ? $item['realName'] : '', + 'nickname' => isset($item['nickname']) ? $item['nickname'] : '', + 'avatar' => isset($item['avatar']) ? $item['avatar'] : '', + 'phone' => isset($item['phone']) ? $item['phone'] : '', + 'memo' => isset($item['memo']) ? $item['memo'] : '', + 'createTime' => $createTime, + 'creator' => isset($item['creator']) ? $item['creator'] : 0, + 'creatorUserName' => isset($item['creatorUserName']) ? $item['creatorUserName'] : '', + 'creatorRealName' => isset($item['creatorRealName']) ? $item['creatorRealName'] : '', + 'departmentId' => isset($item['departmentId']) ? $item['departmentId'] : 0, + 'departmentName' => isset($item['departmentName']) ? $item['departmentName'] : '', + 'privilegeIds' => isset($item['privilegeIds']) ? json_encode($item['privilegeIds']) : json_encode([]), + 'alive' => isset($item['alive']) ? $item['alive'] : false, + 'hasXiakeAccount' => isset($item['hasXiakeAccount']) ? $item['hasXiakeAccount'] : false, + 'isDeleted' => isset($item['isDeleted']) ? $item['isDeleted'] : false, + 'deleteTime' => $deleteTime + ]; + } - $data = [ - 'id' => $item['id'], - 'accountType' => isset($item['accountType']) ? $item['accountType'] : 0, - 'status' => isset($item['status']) ? $item['status'] : 0, - 'tenantId' => isset($item['tenantId']) ? $item['tenantId'] : 0, - 'userName' => isset($item['userName']) ? $item['userName'] : '', - 'realName' => isset($item['realName']) ? $item['realName'] : '', - 'nickname' => isset($item['nickname']) ? $item['nickname'] : '', - 'avatar' => isset($item['avatar']) ? $item['avatar'] : '', - 'phone' => isset($item['phone']) ? $item['phone'] : '', - 'memo' => isset($item['memo']) ? $item['memo'] : '', - 'createTime' => $createTime, - 'creator' => isset($item['creator']) ? $item['creator'] : 0, - 'creatorUserName' => isset($item['creatorUserName']) ? $item['creatorUserName'] : '', - 'creatorRealName' => isset($item['creatorRealName']) ? $item['creatorRealName'] : '', - 'departmentId' => isset($item['departmentId']) ? $item['departmentId'] : 0, - 'departmentName' => isset($item['departmentName']) ? $item['departmentName'] : '', - 'privilegeIds' => isset($item['privilegeIds']) ? json_encode($item['privilegeIds']) : json_encode([]), - 'alive' => isset($item['alive']) ? $item['alive'] : false, - 'hasXiakeAccount' => isset($item['hasXiakeAccount']) ? $item['hasXiakeAccount'] : false, - 'isDeleted' => isset($item['isDeleted']) ? $item['isDeleted'] : false, - 'deleteTime' => $deleteTime - ]; // 使用tenantId作为唯一性判断 - $account = CompanyAccountModel::where('id', $item['id'])->find(); - if ($account) { - $account->save($data); - } else { - CompanyAccountModel::create($data); - } + $account = new CompanyAccountModel(); + $account->saveAll($account); } } \ No newline at end of file diff --git a/Server/application/api/controller/WechatChatroomController.php b/Server/application/api/controller/WechatChatroomController.php index 744ad822e..af43bfe57 100644 --- a/Server/application/api/controller/WechatChatroomController.php +++ b/Server/application/api/controller/WechatChatroomController.php @@ -54,11 +54,9 @@ class WechatChatroomController extends BaseController // 保存数据到数据库 if (!empty($response['results'])) { $isUpdate = false; - foreach ($response['results'] as $item) { - $updated = $this->saveChatroom($item); - if($updated && $isDel == 0){ - $isUpdate = true; - } + $updated = $this->saveChatroom($response['results']); + if($updated && $isDel == 0){ + $isUpdate = true; } } @@ -80,44 +78,51 @@ class WechatChatroomController extends BaseController * 保存群聊数据到数据库 * @param array $item 群聊数据 */ - private function saveChatroom($item) + private function saveChatroom($data) { - $data = [ - 'id' => $item['id'], - 'wechatAccountId' => $item['wechatAccountId'], - 'wechatAccountAlias' => $item['wechatAccountAlias'], - 'wechatAccountWechatId' => $item['wechatAccountWechatId'], - 'wechatAccountAvatar' => $item['wechatAccountAvatar'], - 'wechatAccountNickname' => $item['wechatAccountNickname'], - 'chatroomId' => $item['chatroomId'], - 'hasMe' => $item['hasMe'], - 'chatroomOwnerNickname' => isset($item['chatroomOwnerNickname']) ? $item['chatroomOwnerNickname'] : '', - 'chatroomOwnerAvatar' => isset($item['chatroomOwnerAvatar']) ? $item['chatroomOwnerAvatar'] : '', - 'conRemark' => isset($item['conRemark']) ? $item['conRemark'] : '', - 'nickname' => isset($item['nickname']) ? $item['nickname'] : '', - 'pyInitial' => isset($item['pyInitial']) ? $item['pyInitial'] : '', - 'quanPin' => isset($item['quanPin']) ? $item['quanPin'] : '', - 'chatroomAvatar' => isset($item['chatroomAvatar']) ? $item['chatroomAvatar'] : '', - 'members' => is_array($item['members']) ? json_encode($item['members']) : json_encode([]), - 'isDeleted' => isset($item['isDeleted']) ? $item['isDeleted'] : 0, - 'deleteTime' => !empty($item['isDeleted']) ? strtotime($item['deleteTime']) : 0, - 'createTime' => isset($item['createTime']) ? strtotime($item['createTime']) : 0, - 'accountId' => isset($item['accountId']) ? $item['accountId'] : 0, - 'accountUserName' => isset($item['accountUserName']) ? $item['accountUserName'] : '', - 'accountRealName' => isset($item['accountRealName']) ? $item['accountRealName'] : '', - 'accountNickname' => isset($item['accountNickname']) ? $item['accountNickname'] : '', - 'groupId' => isset($item['groupId']) ? $item['groupId'] : 0, - 'updateTime' => time() - ]; + + $sqlData = []; + foreach ($data as $item) { + $sqlData[] = [ + 'id' => $item['id'], + 'wechatAccountId' => $item['wechatAccountId'], + 'wechatAccountAlias' => $item['wechatAccountAlias'], + 'wechatAccountWechatId' => $item['wechatAccountWechatId'], + 'wechatAccountAvatar' => $item['wechatAccountAvatar'], + 'wechatAccountNickname' => $item['wechatAccountNickname'], + 'chatroomId' => $item['chatroomId'], + 'hasMe' => $item['hasMe'], + 'chatroomOwnerNickname' => isset($item['chatroomOwnerNickname']) ? $item['chatroomOwnerNickname'] : '', + 'chatroomOwnerAvatar' => isset($item['chatroomOwnerAvatar']) ? $item['chatroomOwnerAvatar'] : '', + 'conRemark' => isset($item['conRemark']) ? $item['conRemark'] : '', + 'nickname' => isset($item['nickname']) ? $item['nickname'] : '', + 'pyInitial' => isset($item['pyInitial']) ? $item['pyInitial'] : '', + 'quanPin' => isset($item['quanPin']) ? $item['quanPin'] : '', + 'chatroomAvatar' => isset($item['chatroomAvatar']) ? $item['chatroomAvatar'] : '', + 'members' => is_array($item['members']) ? json_encode($item['members']) : json_encode([]), + 'isDeleted' => isset($item['isDeleted']) ? $item['isDeleted'] : 0, + 'deleteTime' => !empty($item['isDeleted']) ? strtotime($item['deleteTime']) : 0, + 'createTime' => isset($item['createTime']) ? strtotime($item['createTime']) : 0, + 'accountId' => isset($item['accountId']) ? $item['accountId'] : 0, + 'accountUserName' => isset($item['accountUserName']) ? $item['accountUserName'] : '', + 'accountRealName' => isset($item['accountRealName']) ? $item['accountRealName'] : '', + 'accountNickname' => isset($item['accountNickname']) ? $item['accountNickname'] : '', + 'groupId' => isset($item['groupId']) ? $item['groupId'] : 0, + 'updateTime' => time() + ]; + } // 使用chatroomId和wechatAccountId的组合作为唯一性判断 - $chatroom = WechatChatroomModel::where('id',$item['id'])->find(); - + $chatroom = new WechatChatroomModel(); + $chatroom->saveAll($sqlData); if ($chatroom) { - $chatroom->save($data); - return true; - } else { - WechatChatroomModel::create($data); + if ($chatroom->isUpdate()){ + return true; + }else{ + return false; + } + + }else{ return false; } diff --git a/Server/application/common.php b/Server/application/common.php index 3f0239ca7..37a12739f 100644 --- a/Server/application/common.php +++ b/Server/application/common.php @@ -488,6 +488,38 @@ if (!function_exists('getUserAction')) { } } +if (!function_exists('formatRelativeTime')) { + /** + * 将时间戳格式化为相对时间(中文) + * 例:半年前 / 1个月前 / 3周前 / 1天前 / 5小时前 / 5分钟前 / 刚刚 + * @param int $timestamp Unix 时间戳(秒) + * @return string + */ + function formatRelativeTime($timestamp) + { + if (empty($timestamp) || !is_numeric($timestamp)) { + return ''; + } + $now = time(); + $diff = max(0, $now - (int)$timestamp); + + $minute = 60; + $hour = 60 * $minute; + $day = 24 * $hour; + $week = 7 * $day; + $month = 30 * $day; // 近似 + $halfYear = 6 * $month; // 近似 + + if ($diff >= $halfYear) return '半年前'; + if ($diff >= $month) return floor($diff / $month) . '个月前'; + if ($diff >= $week) return floor($diff / $week) . '周前'; + if ($diff >= $day) return floor($diff / $day) . '天前'; + if ($diff >= $hour) return floor($diff / $hour) . '小时前'; + if ($diff >= $minute) return floor($diff / $minute) . '分钟前'; + return '刚刚'; + } +} + if (!function_exists('exit_data')) { diff --git a/Server/application/cunkebao/config/route.php b/Server/application/cunkebao/config/route.php index 1843f07b8..025198442 100644 --- a/Server/application/cunkebao/config/route.php +++ b/Server/application/cunkebao/config/route.php @@ -62,14 +62,18 @@ Route::group('v1/', function () { // 流量池相关 Route::group('traffic/pool', function () { + Route::get('getPackage', 'app\cunkebao\controller\TrafficController@getPackage'); + + Route::get('', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@index'); Route::get('getUserJourney', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getUserJourney'); Route::get('getUserTags', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getUserTags'); Route::get('getUserInfo', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getUser'); - Route::get('getPackage', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getPackage'); Route::post('addPackage', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@addPackage'); + + Route::get('converted', 'app\cunkebao\controller\traffic\GetConvertedListWithInCompanyV1Controller@index'); Route::get('types', 'app\cunkebao\controller\traffic\GetPotentialTypeSectionV1Controller@index'); Route::get('sources', 'app\cunkebao\controller\traffic\GetTrafficSourceSectionV1Controller@index'); diff --git a/Server/application/cunkebao/controller/RFMController.php b/Server/application/cunkebao/controller/RFMController.php new file mode 100644 index 000000000..d6f0b42ed --- /dev/null +++ b/Server/application/cunkebao/controller/RFMController.php @@ -0,0 +1,55 @@ + self::scoreR_Default($recencyDays), + 'F' => self::scoreF_Default($frequency), + 'M' => self::scoreM_Default($monetary), + ]; + } + + // 默认规则 + protected static function scoreR_Default(int $days): int + { + if ($days <= 30) return 5; + if ($days <= 60) return 4; + if ($days <= 90) return 3; + if ($days <= 120) return 2; + return 1; + } + protected static function scoreF_Default(int $times): int + { + if ($times >= 10) return 5; + if ($times >= 6) return 4; + if ($times >= 3) return 3; + if ($times >= 2) return 2; + if ($times >= 1) return 1; + return 0; + } + protected static function scoreM_Default(float $amount): int + { + if ($amount >= 2000) return 5; + if ($amount >= 1000) return 4; + if ($amount >= 500) return 3; + if ($amount >= 200) return 2; + if ($amount > 0) return 1; + return 0; + } +} + + diff --git a/Server/application/cunkebao/controller/TrafficController.php b/Server/application/cunkebao/controller/TrafficController.php new file mode 100644 index 000000000..4dfa1441d --- /dev/null +++ b/Server/application/cunkebao/controller/TrafficController.php @@ -0,0 +1,68 @@ +request->param('page', 1); + $limit = $this->request->param('limit', 10); + $keyword = $this->request->param('keyword', ''); + + $companyId = $this->getUserInfo('companyId'); + $package = Db::name('traffic_source_package')->alias('tsp') + ->join('traffic_source_package_item tspi', 'tspi.packageId=tsp.id', 'left') + ->whereIn('tsp.companyId', [$companyId, 0]) + ->field('tsp.id,tsp.name,tsp.description,tsp.pic,tsp.isSys as type,tsp.createTime,count(tspi.id) as num') + ->group('tsp.id'); + + if (!empty($keyword)) { + $package->where('tsp.name|tsp.description', 'like', '%' . $keyword . '%'); + } + + $list = $package->page($page, $limit)->order('isSys ASC,id DESC')->select(); + $total = $package->count(); + + $rfmRule = 'default'; + foreach ($list as $k => &$v) { + if ($v['type'] != 1) { + $v['createTime'] = !empty($v['createTime']) ? formatRelativeTime($v['createTime']) : ''; + }else{ + $v['createTime'] = ''; + } + + // RFM 评分(示例:以创建时间近似最近活跃,num 近似频次;金额若无则为 0) + $recencyDays = isset($v['createTime']) && is_numeric($v['createTime']) ? floor((time() - (int)$v['createTime']) / 86400) : null; + // 如果上方被格式化为文本,则尝试从原始结果集取原值 + if (!is_numeric($recencyDays) || $recencyDays === null) { + $rawCreate = isset($list[$k]['createTime']) ? $list[$k]['createTime'] : null; + $recencyDays = is_numeric($rawCreate) ? floor((time() - (int)$rawCreate) / 86400) : 9999; + } + $frequency = (int)($v['num'] ?? 0); + $monetary = (float)($v['monetary'] ?? 0); + + $scores = RFMController::calcRfmScores($recencyDays, $frequency, $monetary); + $v['R'] = $scores['R']; + $v['F'] = $scores['F']; + $v['M'] = $scores['M']; + $v['RFM'] = $scores['R'] + $scores['F'] + $scores['M']; + + } + unset($v); + + $data = [ + 'total' => $total, + 'list' => $list, + ]; + + return ResponseHelper::success($data); + } + +} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php b/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php index 84137be82..434a1281d 100644 --- a/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php +++ b/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php @@ -359,39 +359,7 @@ class GetPotentialListWithInCompanyV1Controller extends BaseController } - public function getPackage() - { - $page = $this->request->param('page', 1); - $limit = $this->request->param('limit', 10); - $keyword = $this->request->param('keyword', ''); - - $companyId = $this->getUserInfo('companyId'); - $package = Db::name('traffic_source_package')->alias('tsp') - ->join('traffic_source_package_item tspi', 'tspi.packageId=tsp.id', 'left') - ->whereIn('tsp.companyId', [$companyId, 0]) - ->field('tsp.id,tsp.name,tsp.description,tsp.createTime,count(tspi.id) as num') - ->group('tsp.id'); - - if (!empty($keyword)) { - $package->where('tsp.name|tsp.description', 'like', '%' . $keyword . '%'); - } - - $list = $package->page($page, $limit)->select(); - $total = $package->count(); - - foreach ($list as $k => &$v) { - $v['createTime'] = !empty($v['createTime']) ? date('Y-m-d H:i:s', $v['createTime']) : ''; - } - unset($v); - - $data = [ - 'total' => $total, - 'list' => $list, - ]; - - return ResponseHelper::success($data); - } public function addPackage() diff --git a/Server/application/job/WorkbenchMomentsJob.php b/Server/application/job/WorkbenchMomentsJob.php index 4d82739c4..6a3bb474c 100644 --- a/Server/application/job/WorkbenchMomentsJob.php +++ b/Server/application/job/WorkbenchMomentsJob.php @@ -108,93 +108,33 @@ class WorkbenchMomentsJob public function execute2() { try { - // 每日重置发送次数(允许10分钟误差) - $now = time(); - $todayStart = strtotime(date('Y-m-d 00:00:00')); - if ($now - $todayStart >= 0 && $now - $todayStart <= 600) { - $cacheKey = 'moments_settings_reset_' . date('Ymd'); - if (!Cache::has($cacheKey)) { - Db::table('ck_kf_moments_settings')->where('sendNum', '<>', 0) - ->update(['sendNum' => 0, 'updateTime' => $now]); - Cache::set($cacheKey, 1, 7200); // 2小时缓存,防止重复重置 - } - } - // 获取所有工作台 - $kfMoments = KfMoments::where(['isSend' => 0, 'isDel' => 0])->where('sendTime', '<=', time() + 120)->order('id desc')->select(); + // 1) 每日重置 + $this->resetDailyCountersIfNeeded(); + + // 2) 获取发送窗口内的任务 + [$nowTs, $kfMoments] = $this->getWindowTasks(); foreach ($kfMoments as $val) { - $sendData = json_decode($val->sendData,true); - $endTime = strtotime($sendData['endTime']); - if ($endTime <= time() + 1800){ - $endTime = time() + 3600; - $sendData['endTime'] = date('Y-m-d H:i:s', $endTime); - } - switch ($sendData['momentContentType']) { - case 1: - $sendData['link'] = ['image' => '']; - $sendData['picUrlList'] = []; - $sendData['videoUrl'] = ''; - break; - case 2: - $sendData['link'] = ['image' => '']; - $sendData['videoUrl'] = ''; - break; - case 3: - $sendData['link'] = ['image' => '']; - $sendData['picUrlList'] = []; - break; - case 4: - $sendData['picUrlList'] = []; - $sendData['videoUrl'] = ''; - break; - default: - $sendData['link'] = ['image' => '']; - $sendData['picUrlList'] = []; - $sendData['videoUrl'] = ''; - break; - } + $companyId = (int)($val['companyId'] ?? 0); + $userId = (int)($val['userId'] ?? 0); + + // 2.1) 数据规范化 + $sendData = json_decode($val->sendData, true); + $sendData = $this->normalizeSendData($sendData); + + // 2.2) 账号额度过滤 + $items = $sendData['jobPublishWechatMomentsItems'] ?? []; + if (empty($items)) { continue; } + $allowed = $this->filterAccountsByQuota($companyId, $userId, $items); + if (empty($allowed)) { continue; } + $sendData['jobPublishWechatMomentsItems'] = $allowed; + + // 3) 下发 $moments = new Moments(); $moments->addJob($sendData); KfMoments::where(['id' => $val['id']])->update(['isSend' => 1]); - // 统计发送次数(ck_kf_moments_settings) - try { - $nowTs = time(); - $companyId = (int)($val['companyId'] ?? 0); - $userId = (int)($val['userId'] ?? 0); - $items = $sendData['jobPublishWechatMomentsItems'] ?? []; - foreach ($items as $it) { - $wechatId = (int)($it['wechatAccountId'] ?? 0); - if ($wechatId <= 0) { continue; } - - $cond = [ - 'companyId' => $companyId, - 'userId' => $userId, - 'wechatId' => $wechatId, - ]; - - $setting = Db::table('ck_kf_moments_settings')->where($cond)->find(); - if ($setting) { - Db::table('ck_kf_moments_settings') - ->where('id', $setting['id']) - ->update([ - 'sendNum' => Db::raw('sendNum + 1'), - 'updateTime' => $nowTs, - ]); - } else { - Db::table('ck_kf_moments_settings')->insert([ - 'companyId' => $companyId, - 'userId' => $userId, - 'wechatId' => $wechatId, - 'max' => 5, - 'sendNum' => 1, - 'createTime' => $nowTs, - 'updateTime' => $nowTs, - ]); - } - } - } catch (\Throwable $statE) { - Log::error('朋友圈发送统计失败: ' . $statE->getMessage()); - } + // 4) 统计 + $this->incrementSendStats($companyId, $userId, $allowed); } } catch (\Exception $e) { Log::error("朋友圈同步任务异常: " . $e->getMessage()); @@ -202,6 +142,118 @@ class WorkbenchMomentsJob } } + protected function resetDailyCountersIfNeeded() + { + $now = time(); + $todayStart = strtotime(date('Y-m-d 00:00:00')); + if ($now - $todayStart >= 0 && $now - $todayStart <= 600) { + $cacheKey = 'moments_settings_reset_' . date('Ymd'); + if (!Cache::has($cacheKey)) { + Db::table('ck_kf_moments_settings')->where('sendNum', '<>', 0) + ->update(['sendNum' => 0, 'updateTime' => $now]); + Cache::set($cacheKey, 1, 7200); + } + } + } + + protected function getWindowTasks() + { + $nowTs = time(); + $windowStart = $nowTs - 300; + $windowEnd = $nowTs + 300; + $kfMoments = KfMoments::where(['isSend' => 0, 'isDel' => 0]) + ->whereBetween('sendTime', [$windowStart, $windowEnd]) + ->order('id desc')->select(); + return [$nowTs, $kfMoments]; + } + + protected function normalizeSendData(array $sendData) + { + $endTime = strtotime($sendData['endTime'] ?? ''); + if ($endTime <= time() + 1800) { + $endTime = time() + 3600; + $sendData['endTime'] = date('Y-m-d H:i:s', $endTime); + } + switch ($sendData['momentContentType'] ?? 1) { + case 1: + $sendData['link'] = ['image' => '']; + $sendData['picUrlList'] = []; + $sendData['videoUrl'] = ''; + break; + case 2: + $sendData['link'] = ['image' => '']; + $sendData['videoUrl'] = ''; + break; + case 3: + $sendData['link'] = ['image' => '']; + $sendData['picUrlList'] = []; + break; + case 4: + $sendData['picUrlList'] = []; + $sendData['videoUrl'] = ''; + break; + default: + $sendData['link'] = ['image' => '']; + $sendData['picUrlList'] = []; + $sendData['videoUrl'] = ''; + break; + } + return $sendData; + } + + protected function filterAccountsByQuota(int $companyId, int $userId, array $items) + { + $wechatIds = array_values(array_filter(array_map(function($it){ return (int)($it['wechatAccountId'] ?? 0); }, $items))); + if (empty($wechatIds)) { return []; } + $settings = Db::table('ck_kf_moments_settings') + ->where('companyId', $companyId) + ->where('userId', $userId) + ->whereIn('wechatId', $wechatIds) + ->column('id,max,sendNum', 'wechatId'); + $allowed = []; + foreach ($items as $it) { + $wid = (int)($it['wechatAccountId'] ?? 0); + if ($wid <= 0) { continue; } + if (isset($settings[$wid])) { + $max = (int)$settings[$wid]['max']; + $sent = (int)$settings[$wid]['sendNum']; + if ($sent < ($max > 0 ? $max : 5)) { $allowed[] = $it; } + } else { + $allowed[] = $it; + } + } + return $allowed; + } + + protected function incrementSendStats(int $companyId, int $userId, array $items) + { + try { + $nowTs = time(); + foreach ($items as $it) { + $wechatId = (int)($it['wechatAccountId'] ?? 0); + if ($wechatId <= 0) { continue; } + $cond = ['companyId' => $companyId, 'userId' => $userId, 'wechatId' => $wechatId]; + $setting = Db::table('ck_kf_moments_settings')->where($cond)->find(); + if ($setting) { + Db::table('ck_kf_moments_settings')->where('id', $setting['id']) + ->update(['sendNum' => Db::raw('sendNum + 1'), 'updateTime' => $nowTs]); + } else { + Db::table('ck_kf_moments_settings')->insert([ + 'companyId' => $companyId, + 'userId' => $userId, + 'wechatId' => $wechatId, + 'max' => 5, + 'sendNum' => 1, + 'createTime' => $nowTs, + 'updateTime' => $nowTs, + ]); + } + } + } catch (\Throwable $e) { + Log::error('朋友圈发送统计失败: ' . $e->getMessage()); + } + } + /** * 处理内容发送 diff --git a/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php b/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php index 7c347c427..08f720ead 100644 --- a/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php +++ b/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php @@ -157,7 +157,7 @@ class Adapter implements WeChatServiceInterface { $task = Db::name('customer_acquisition_task') ->where(['status' => 1, 'deleteTime' => 0]) - ->whereRaw("id % $process_count_for_status_0 = {$current_worker_id}") + /* ->whereRaw("id % $process_count_for_status_0 = {$current_worker_id}")*/ ->order('id desc') ->select();