setName('wechat:calculate-score') ->setDescription('统一计算微信账号健康分(包含初始化、更新评分记录、批量计算)'); } protected function execute(Input $input, Output $output) { $output->writeln("=========================================="); $output->writeln("开始统一计算微信账号健康分..."); $output->writeln("=========================================="); $startTime = time(); $service = new WechatAccountHealthScoreService(); try { // 步骤1: 初始化未计算基础分的账号 $output->writeln("\n[步骤1] 初始化未计算基础分的账号..."); $initStats = $this->initUncalculatedAccounts($service, $output); $output->writeln("初始化完成:成功 {$initStats['success']} 条,失败 {$initStats['failed']} 条"); // 步骤2: 更新评分记录(根据wechatId和alias不一致情况) $output->writeln("\n[步骤2] 更新评分记录(根据wechatId和alias不一致情况)..."); $updateStats = $this->updateScoreRecords($service, $output); $output->writeln("更新完成:处理了 {$updateStats['total']} 条记录"); // 步骤3: 批量更新健康分(只更新动态分,不重新计算基础分) $output->writeln("\n[步骤3] 批量更新健康分(只更新动态分)..."); $batchStats = $this->batchUpdateHealthScore($service, $output); $output->writeln("批量更新完成:成功 {$batchStats['success']} 条,失败 {$batchStats['failed']} 条"); // 统计信息 $endTime = time(); $duration = $endTime - $startTime; $output->writeln("\n=========================================="); $output->writeln("任务完成!"); $output->writeln("=========================================="); $output->writeln("总耗时: {$duration} 秒"); $output->writeln("初始化: 成功 {$initStats['success']} 条,失败 {$initStats['failed']} 条"); $output->writeln("更新评分记录: {$updateStats['total']} 条"); $output->writeln("批量更新: 成功 {$batchStats['success']} 条,失败 {$batchStats['failed']} 条"); if (!empty($initStats['errors'])) { $output->writeln("\n初始化错误详情:"); foreach (array_slice($initStats['errors'], 0, 10) as $error) { $output->writeln(" 账号ID {$error['accountId']}: {$error['error']}"); } if (count($initStats['errors']) > 10) { $output->writeln(" ... 还有 " . (count($initStats['errors']) - 10) . " 个错误"); } } if (!empty($batchStats['errors'])) { $output->writeln("\n批量更新错误详情:"); foreach (array_slice($batchStats['errors'], 0, 10) as $error) { $output->writeln(" 账号ID {$error['accountId']}: {$error['error']}"); } if (count($batchStats['errors']) > 10) { $output->writeln(" ... 还有 " . (count($batchStats['errors']) - 10) . " 个错误"); } } } catch (\Exception $e) { $output->writeln("\n错误: " . $e->getMessage()); $output->writeln($e->getTraceAsString()); } } /** * 初始化未计算基础分的账号 * * @param WechatAccountHealthScoreService $service * @param Output $output * @return array */ private function initUncalculatedAccounts($service, $output) { $stats = [ 'total' => 0, 'success' => 0, 'failed' => 0, 'errors' => [] ]; // 获取所有未计算基础分的账号 $accounts = Db::table('s2_wechat_account') ->alias('a') ->leftJoin(['s2_wechat_account_score' => 's'], 's.accountId = a.id') ->where('a.isDeleted', 0) ->where(function($query) { $query->whereNull('s.id') ->whereOr('s.baseScoreCalculated', 0); }) ->field('a.id, a.wechatId') ->select(); $stats['total'] = count($accounts); if ($stats['total'] == 0) { $output->writeln("没有需要初始化的账号"); return $stats; } $output->writeln("找到 {$stats['total']} 个需要初始化的账号"); $batchSize = 100; $batches = array_chunk($accounts, $batchSize); foreach ($batches as $batchIndex => $batch) { foreach ($batch as $account) { try { $service->calculateAndUpdate($account['id']); $stats['success']++; if ($stats['success'] % 100 == 0) { $output->write("."); } } catch (\Exception $e) { $stats['failed']++; $stats['errors'][] = [ 'accountId' => $account['id'], 'error' => $e->getMessage() ]; } } if (($batchIndex + 1) % 10 == 0) { $output->writeln(" 已处理 " . ($batchIndex + 1) * $batchSize . " 条"); } } return $stats; } /** * 更新评分记录(根据wechatId和alias不一致情况) * * @param WechatAccountHealthScoreService $service * @param Output $output * @return array */ private function updateScoreRecords($service, $output) { $stats = ['total' => 0]; // 查找wechatId和alias不一致的账号 $inconsistentAccounts = Db::table('s2_wechat_account') ->where('isDeleted', 0) ->where('wechatId', '<>', '') ->where('alias', '<>', '') ->whereRaw('wechatId != alias') ->field('id, wechatId, alias') ->select(); // 查找wechatId和alias一致的账号 $consistentAccounts = Db::table('s2_wechat_account') ->where('isDeleted', 0) ->where('wechatId', '<>', '') ->where('alias', '<>', '') ->whereRaw('wechatId = alias') ->field('id, wechatId, alias') ->select(); $allAccounts = array_merge($inconsistentAccounts, $consistentAccounts); $stats['total'] = count($allAccounts); if ($stats['total'] == 0) { $output->writeln("没有需要更新的账号"); return $stats; } $output->writeln("找到 {$stats['total']} 个需要更新的账号(不一致: " . count($inconsistentAccounts) . ",一致: " . count($consistentAccounts) . ")"); $updatedCount = 0; foreach ($allAccounts as $account) { $isModifiedAlias = in_array($account['id'], array_column($inconsistentAccounts, 'id')); $this->updateScoreRecord($account['id'], $isModifiedAlias, $service); $updatedCount++; if ($updatedCount % 100 == 0) { $output->write("."); } } if ($updatedCount > 0 && $updatedCount % 100 == 0) { $output->writeln(""); } return $stats; } /** * 批量更新健康分(只更新动态分) * * @param WechatAccountHealthScoreService $service * @param Output $output * @return array */ private function batchUpdateHealthScore($service, $output) { // 获取所有已计算基础分的账号 $accountIds = Db::table('s2_wechat_account_score') ->where('baseScoreCalculated', 1) ->column('accountId'); $total = count($accountIds); if ($total == 0) { $output->writeln("没有需要更新的账号"); return ['success' => 0, 'failed' => 0, 'errors' => []]; } $output->writeln("找到 {$total} 个需要更新动态分的账号"); $stats = $service->batchCalculateAndUpdate($accountIds, 100, false); return $stats; } /** * 更新评分记录 * * @param int $accountId 账号ID * @param bool $isModifiedAlias 是否已修改微信号 * @param WechatAccountHealthScoreService $service 评分服务 */ private function updateScoreRecord($accountId, $isModifiedAlias, $service) { // 获取账号数据 $accountData = Db::table('s2_wechat_account') ->where('id', $accountId) ->find(); if (empty($accountData)) { return; } // 确保评分记录存在 $scoreRecord = Db::table('s2_wechat_account_score') ->where('accountId', $accountId) ->find(); if (empty($scoreRecord)) { // 如果记录不存在,创建并计算基础分 $service->calculateAndUpdate($accountId); $scoreRecord = Db::table('s2_wechat_account_score') ->where('accountId', $accountId) ->find(); } if (empty($scoreRecord)) { return; } // 更新isModifiedAlias字段 $updateData = [ 'isModifiedAlias' => $isModifiedAlias ? 1 : 0, 'updateTime' => time() ]; // 如果基础分已计算,需要更新基础信息分和基础分 if ($scoreRecord['baseScoreCalculated']) { $oldBaseInfoScore = $scoreRecord['baseInfoScore'] ?? 0; $newBaseInfoScore = $isModifiedAlias ? 10 : 0; // 已修改微信号得10分 if ($oldBaseInfoScore != $newBaseInfoScore) { $oldBaseScore = $scoreRecord['baseScore'] ?? 60; $newBaseScore = $oldBaseScore - $oldBaseInfoScore + $newBaseInfoScore; $updateData['baseInfoScore'] = $newBaseInfoScore; $updateData['baseScore'] = $newBaseScore; // 重新计算健康分 $dynamicScore = $scoreRecord['dynamicScore'] ?? 0; $healthScore = $newBaseScore + $dynamicScore; $healthScore = max(0, min(100, $healthScore)); $updateData['healthScore'] = $healthScore; $updateData['maxAddFriendPerDay'] = (int)floor($healthScore * 0.2); } } else { // 基础分未计算,只更新标记和基础信息分 $updateData['baseInfoScore'] = $isModifiedAlias ? 10 : 0; } Db::table('s2_wechat_account_score') ->where('accountId', $accountId) ->update($updateData); } }