Files
zyt/server/app/command/QywxSyncCustomer.php
2026-05-11 17:49:38 +08:00

112 lines
4.7 KiB
PHP
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\command;
use app\adminapi\logic\qywx\CustomerLogic;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Log;
/**
* 企业微信客户同步定时任务
*
* 使用方法:
* php think qywx:sync-customer
* php think qywx:sync-customer --force --today # 仅落库「今日首次加为外部联系人」的客户(app.default_timezone
* php think qywx:sync-customer --force --today --today-any-follow # 任一条跟进在今天即落库(旧逻辑,命中多)
*
* 说明:企微无「只拉今日客户」接口,--today 仍需翻完各成员 batch 分页;开启后会流式筛候选 id,只对候选 get+写库(省内存与 UPSERT)。增量实时请配客户联系回调。
*
* 配置crontab(每小时执行一次):
* 0 * * * * cd /path/to/project && php think qywx:sync-customer >> /dev/null 2>&1
*/
class QywxSyncCustomer extends Command
{
protected function configure()
{
$this->setName('qywx:sync-customer')
->addOption('force', 'f', \think\console\input\Option::VALUE_NONE, '强制同步,忽略自动同步设置')
->addOption(
'today',
't',
\think\console\input\Option::VALUE_NONE,
'仅落库「企微首次添加时间」在今日的客户(min(createtime),时区见 app.default_timezone);仍会拉全量列表与详情'
)
->addOption(
'today-any-follow',
null,
\think\console\input\Option::VALUE_NONE,
'需与 --today 同时使用:任一条跟进 createtime 在今日即落库(旧行为,容易大量命中)'
)
->setDescription('同步企业微信客户数据');
}
protected function execute(Input $input, Output $output)
{
$output->writeln('开始同步企业微信客户...');
try {
$force = $input->getOption('force');
if (!$force) {
// 检查是否开启自动同步
$settings = CustomerLogic::getSyncSettings();
if (!($settings['auto_sync'] ?? false)) {
$output->writeln('自动同步未开启,跳过(使用 --force 强制同步)');
return 0;
}
// 检查距离上次同步是否超过间隔时间
$lastSyncTime = $settings['last_sync_time'] ?? 0;
$interval = $settings['interval'] ?? 3600;
$now = time();
if ($now - $lastSyncTime < $interval) {
$output->writeln('距离上次同步时间不足,跳过(使用 --force 强制同步)');
return 0;
}
}
// 执行同步
$syncOptions = [];
if ($input->getOption('today')) {
[$syncOptions['follow_createtime_from'], $syncOptions['follow_createtime_to']] = CustomerLogic::todayCreatetimeWindowBounds();
$syncOptions['follow_createtime_mode'] = $input->getOption('today-any-follow') ? 'any' : 'first';
$tz = (string) config('app.default_timezone', 'Asia/Shanghai');
$output->writeln(sprintf(
'今日窗口(%s): %s ~ %s | 模式: %s',
$tz,
date('Y-m-d H:i:s', $syncOptions['follow_createtime_from']),
date('Y-m-d H:i:s', $syncOptions['follow_createtime_to']),
$syncOptions['follow_createtime_mode'] === 'any' ? '任一条跟进在今天' : '仅首次添加在今天(今日新客)'
));
}
$result = CustomerLogic::syncCustomers($syncOptions);
if ($result === false) {
$error = CustomerLogic::getError();
$output->writeln('同步失败: ' . $error);
Log::error('企业微信客户同步失败: ' . $error);
return 1;
}
$output->writeln('同步成功!');
$output->writeln('同步数量: ' . ($result['sync_count'] ?? 0));
$output->writeln('新增数量: ' . ($result['new_count'] ?? 0));
$output->writeln('更新数量: ' . ($result['update_count'] ?? 0));
$skipped = (int) ($result['skipped_count'] ?? 0);
if ($skipped > 0) {
$output->writeln('跳过数量(非指定日期内新建跟进): ' . $skipped);
}
return 0;
} catch (\Throwable $e) {
$output->writeln('同步异常: ' . $e->getMessage());
Log::error('企业微信客户同步异常: ' . $e->getMessage());
return 1;
}
}
}