lockFile = App::getRuntimePath() . 'migrate_traffic_pool_v2.lock'; } protected function configure() { $this->setName('migrate:trafficPoolV2') ->setDescription('迁移数据到 V2 流量池系统') ->addOption('step', 's', Option::VALUE_OPTIONAL, '执行指定步骤(1-7),不指定则执行全部', null); } protected function execute(Input $input, Output $output) { // 检查锁文件 if (file_exists($this->lockFile)) { $lockTime = filectime($this->lockFile); if (time() - $lockTime < 7200) { // 2小时内 $output->writeln('迁移任务已在运行中,跳过本次执行'); return false; } unlink($this->lockFile); } file_put_contents($this->lockFile, time()); try { $step = $input->getOption('step'); $adapter = new ChuKeBaoAdapter(); $output->writeln('===================================='); $output->writeln(' V2 流量池数据迁移开始'); $output->writeln('===================================='); $output->writeln(''); $startTime = microtime(true); if ($step === null) { // 执行完整迁移 $results = $this->runFullMigration($adapter, $output); } else { // 执行指定步骤 $results = $this->runStep((int)$step, $adapter, $output); } $endTime = microtime(true); $duration = round($endTime - $startTime, 2); $output->writeln(''); $output->writeln('===================================='); $output->writeln(' 迁移完成'); $output->writeln('===================================='); $output->writeln("耗时: {$duration} 秒"); $output->writeln(''); $output->writeln('结果统计:'); foreach ($results as $key => $value) { $output->writeln(" - {$key}: {$value} 条"); } return true; } catch (\Exception $e) { $output->writeln('迁移异常: ' . $e->getMessage() . ''); Log::error('V2流量池迁移异常:' . $e->getMessage() . "\n" . $e->getTraceAsString()); return false; } finally { if (file_exists($this->lockFile)) { unlink($this->lockFile); } } } /** * 执行完整迁移 */ protected function runFullMigration(ChuKeBaoAdapter $adapter, Output $output) { $results = [ 'friend_pool' => 0, 'friend_pool_company' => 0, 'friend_pool_source' => 0, 'chatroom_pool' => 0, 'chatroom_pool_company' => 0, 'chatroom_pool_source' => 0, 'pool_tags' => 0, ]; // === 好友数据迁移 === $output->writeln('【好友数据迁移】'); // Step 1: 好友同步到流量池总表 $output->writeln('[1/7] 同步好友到流量池总表 ck_traffic_pool ...'); $results['friend_pool'] = $adapter->syncToTrafficPoolV2(); $output->writeln(" 完成,影响行数: {$results['friend_pool']}"); // Step 2: 好友同步到公司流量详情表 $output->writeln('[2/7] 同步好友到公司流量详情表 ck_traffic_pool_company ...'); $results['friend_pool_company'] = $adapter->syncToTrafficPoolCompanyV2(); $output->writeln(" 完成,影响行数: {$results['friend_pool_company']}"); // Step 3: 好友同步到流量来源表 $output->writeln('[3/7] 同步好友到流量来源表 ck_traffic_pool_source ...'); $results['friend_pool_source'] = $adapter->syncToTrafficPoolSourceV2(); $output->writeln(" 完成,影响行数: {$results['friend_pool_source']}"); // === 群成员数据迁移 === $output->writeln(''); $output->writeln('【群成员数据迁移】'); // Step 4: 群成员同步到流量池总表 $output->writeln('[4/7] 同步群成员到流量池总表 ck_traffic_pool ...'); $results['chatroom_pool'] = $adapter->syncChatroomMembersToTrafficPoolV2(); $output->writeln(" 完成,影响行数: {$results['chatroom_pool']}"); // Step 5: 群成员同步到公司流量详情表 $output->writeln('[5/7] 同步群成员到公司流量详情表 ck_traffic_pool_company ...'); $results['chatroom_pool_company'] = $adapter->syncChatroomMembersToTrafficPoolCompanyV2(); $output->writeln(" 完成,影响行数: {$results['chatroom_pool_company']}"); // Step 6: 群成员同步到流量来源表 $output->writeln('[6/7] 同步群成员到流量来源表 ck_traffic_pool_source ...'); $results['chatroom_pool_source'] = $adapter->syncChatroomMembersToTrafficPoolSourceV2(); $output->writeln(" 完成,影响行数: {$results['chatroom_pool_source']}"); // === 标签数据迁移 === $output->writeln(''); $output->writeln('【标签数据迁移】'); // Step 7: 同步微信标签 $output->writeln('[7/7] 同步微信标签 ck_traffic_pool_tag ...'); $results['pool_tags'] = $adapter->syncWechatTagsToV2(); $output->writeln(" 完成,影响行数: {$results['pool_tags']}"); return $results; } /** * 执行指定步骤 */ protected function runStep(int $step, ChuKeBaoAdapter $adapter, Output $output) { $results = []; switch ($step) { case 1: $output->writeln('[Step 1] 同步好友到流量池总表 ck_traffic_pool ...'); $results['friend_pool'] = $adapter->syncToTrafficPoolV2(); $output->writeln(" 完成,影响行数: {$results['friend_pool']}"); break; case 2: $output->writeln('[Step 2] 同步好友到公司流量详情表 ck_traffic_pool_company ...'); $results['friend_pool_company'] = $adapter->syncToTrafficPoolCompanyV2(); $output->writeln(" 完成,影响行数: {$results['friend_pool_company']}"); break; case 3: $output->writeln('[Step 3] 同步好友到流量来源表 ck_traffic_pool_source ...'); $results['friend_pool_source'] = $adapter->syncToTrafficPoolSourceV2(); $output->writeln(" 完成,影响行数: {$results['friend_pool_source']}"); break; case 4: $output->writeln('[Step 4] 同步群成员到流量池总表 ck_traffic_pool ...'); $results['chatroom_pool'] = $adapter->syncChatroomMembersToTrafficPoolV2(); $output->writeln(" 完成,影响行数: {$results['chatroom_pool']}"); break; case 5: $output->writeln('[Step 5] 同步群成员到公司流量详情表 ck_traffic_pool_company ...'); $results['chatroom_pool_company'] = $adapter->syncChatroomMembersToTrafficPoolCompanyV2(); $output->writeln(" 完成,影响行数: {$results['chatroom_pool_company']}"); break; case 6: $output->writeln('[Step 6] 同步群成员到流量来源表 ck_traffic_pool_source ...'); $results['chatroom_pool_source'] = $adapter->syncChatroomMembersToTrafficPoolSourceV2(); $output->writeln(" 完成,影响行数: {$results['chatroom_pool_source']}"); break; case 7: $output->writeln('[Step 7] 同步微信标签 ck_traffic_pool_tag ...'); $results['pool_tags'] = $adapter->syncWechatTagsToV2(); $output->writeln(" 完成,影响行数: {$results['pool_tags']}"); break; default: $output->writeln('无效的步骤编号,请输入 1-7'); $output->writeln(''); $output->writeln('步骤说明:'); $output->writeln(' 1 - 同步好友到流量池总表'); $output->writeln(' 2 - 同步好友到公司流量详情表'); $output->writeln(' 3 - 同步好友到流量来源表'); $output->writeln(' 4 - 同步群成员到流量池总表'); $output->writeln(' 5 - 同步群成员到公司流量详情表'); $output->writeln(' 6 - 同步群成员到流量来源表'); $output->writeln(' 7 - 同步微信标签'); break; } return $results; } }