Files
zyt/server/app/adminapi/logic/qywx/CustomerLogic.php
T
2026-04-11 18:06:02 +08:00

266 lines
9.8 KiB
PHP

<?php
declare(strict_types=1);
namespace app\adminapi\logic\qywx;
use app\common\logic\BaseLogic;
use app\common\model\QywxExternalContact;
use app\common\model\QywxSyncSettings;
use app\common\service\wechat\WechatWorkService;
use think\facade\Db;
use think\facade\Log;
/**
* 企业微信客户逻辑层
*/
class CustomerLogic extends BaseLogic
{
/**
* @notes 同步企业微信客户
*/
public static function syncCustomers()
{
try {
$service = new WechatWorkService();
// 1. 获取部门成员列表(从根部门开始,递归获取所有成员)
$departmentId = config('project.qywx_sync_department_id', 1);
Log::info('开始同步企业微信客户 - 部门ID: ' . $departmentId);
$userList = $service->getDepartmentUserList($departmentId, true);
Log::info('获取到企业成员数量: ' . count($userList));
if (empty($userList)) {
Log::error('未获取到企业成员列表');
self::$error = '未获取到企业成员列表';
return false;
}
$syncCount = 0;
$updateCount = 0;
$newCount = 0;
$processedCustomers = []; // 记录已处理的客户,避免重复
Db::startTrans();
try {
// 2. 遍历每个成员,获取其客户列表
foreach ($userList as $user) {
$userId = $user['userid'] ?? '';
if (empty($userId)) {
continue;
}
Log::info('获取成员客户列表 - userId: ' . $userId . ', name: ' . ($user['name'] ?? ''));
// 获取该成员的客户列表
$customerList = $service->getExternalContactList($userId);
// 如果返回false,说明API调用失败(权限问题)
if ($customerList === false) {
Log::error('获取客户列表失败 - 可能是API权限未开启(错误码48002)');
throw new \Exception('企业微信API权限不足,请在企业微信管理后台开启"客户联系"权限');
}
Log::info('成员 ' . $userId . ' 的客户数量: ' . count($customerList));
if (empty($customerList)) {
continue;
}
// 3. 遍历客户列表,获取详情并保存
foreach ($customerList as $externalUserId) {
// 避免重复处理同一个客户
if (isset($processedCustomers[$externalUserId])) {
continue;
}
$processedCustomers[$externalUserId] = true;
// 获取客户详情
$detail = $service->getExternalContactDetail($externalUserId);
if (empty($detail)) {
continue;
}
$externalContact = $detail['external_contact'] ?? [];
$followUsers = $detail['follow_user'] ?? [];
// 保存或更新客户信息
$data = [
'external_userid' => $externalContact['external_userid'] ?? '',
'name' => $externalContact['name'] ?? '',
'avatar' => $externalContact['avatar'] ?? '',
'type' => $externalContact['type'] ?? 1,
'gender' => $externalContact['gender'] ?? 0,
'unionid' => $externalContact['unionid'] ?? '',
'position' => $externalContact['position'] ?? '',
'corp_name' => $externalContact['corp_name'] ?? '',
'corp_full_name' => $externalContact['corp_full_name'] ?? '',
'external_profile' => json_encode($externalContact['external_profile'] ?? [], JSON_UNESCAPED_UNICODE),
'follow_users' => json_encode($followUsers, JSON_UNESCAPED_UNICODE),
'update_time' => time(),
];
$existing = QywxExternalContact::where('external_userid', $data['external_userid'])->find();
if ($existing) {
$existing->save($data);
$updateCount++;
} else {
$data['create_time'] = time();
QywxExternalContact::create($data);
$newCount++;
}
$syncCount++;
}
}
// 4. 更新同步设置
self::updateSyncStatus('success', $syncCount);
Db::commit();
Log::info('同步完成 - 总数: ' . $syncCount . ', 新增: ' . $newCount . ', 更新: ' . $updateCount);
return [
'sync_count' => $syncCount,
'new_count' => $newCount,
'update_count' => $updateCount,
];
} catch (\Throwable $e) {
Db::rollback();
Log::error('同步企业微信客户失败: ' . $e->getMessage());
self::$error = '同步失败: ' . $e->getMessage();
self::updateSyncStatus('failed', 0, $e->getMessage());
return false;
}
} catch (\Throwable $e) {
Log::error('同步企业微信客户异常: ' . $e->getMessage());
self::$error = '同步异常: ' . $e->getMessage();
self::updateSyncStatus('failed', 0, $e->getMessage());
return false;
}
}
/**
* @notes 获取统计信息
*/
public static function getStats()
{
$total = QywxExternalContact::whereNull('delete_time')->count();
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$today = QywxExternalContact::where('create_time', '>=', $todayStart)
->whereNull('delete_time')
->count();
$settings = self::getSyncSettings();
$lastSyncTime = $settings['last_sync_time'] ?? 0;
$lastSync = $lastSyncTime > 0 ? date('Y-m-d H:i:s', $lastSyncTime) : '';
return [
'total' => $total,
'today' => $today,
'lastSync' => $lastSync,
'syncStatus' => $settings['sync_status'] ?? 'idle',
'syncStatusText' => self::getSyncStatusText($settings['sync_status'] ?? 'idle'),
];
}
/**
* @notes 获取同步设置
*/
public static function getSyncSettings()
{
$setting = QywxSyncSettings::where('setting_key', 'customer_sync')->find();
if (!$setting) {
return [
'auto_sync' => false,
'interval' => 3600,
'last_sync_time' => 0,
'sync_status' => 'idle',
];
}
$value = json_decode($setting->setting_value, true);
return $value ?: [
'auto_sync' => false,
'interval' => 3600,
'last_sync_time' => 0,
'sync_status' => 'idle',
];
}
/**
* @notes 保存同步设置
*/
public static function saveSyncSettings(array $params)
{
try {
$currentSettings = self::getSyncSettings();
$newSettings = array_merge($currentSettings, [
'auto_sync' => (bool)($params['auto_sync'] ?? false),
'interval' => (int)($params['interval'] ?? 3600),
]);
$setting = QywxSyncSettings::where('setting_key', 'customer_sync')->find();
if ($setting) {
$setting->setting_value = json_encode($newSettings, JSON_UNESCAPED_UNICODE);
$setting->update_time = time();
$setting->save();
} else {
QywxSyncSettings::create([
'setting_key' => 'customer_sync',
'setting_value' => json_encode($newSettings, JSON_UNESCAPED_UNICODE),
'create_time' => time(),
'update_time' => time(),
]);
}
return true;
} catch (\Throwable $e) {
self::$error = '保存失败: ' . $e->getMessage();
return false;
}
}
/**
* @notes 更新同步状态
*/
private static function updateSyncStatus(string $status, int $syncCount = 0, string $error = '')
{
try {
$settings = self::getSyncSettings();
$settings['sync_status'] = $status;
$settings['last_sync_time'] = time();
$settings['last_sync_count'] = $syncCount;
if ($error) {
$settings['last_error'] = $error;
}
$setting = QywxSyncSettings::where('setting_key', 'customer_sync')->find();
if ($setting) {
$setting->setting_value = json_encode($settings, JSON_UNESCAPED_UNICODE);
$setting->update_time = time();
$setting->save();
}
} catch (\Throwable $e) {
Log::error('更新同步状态失败: ' . $e->getMessage());
}
}
/**
* @notes 获取同步状态文本
*/
private static function getSyncStatusText(string $status): string
{
$map = [
'idle' => '未同步',
'syncing' => '同步中',
'success' => '同步成功',
'failed' => '同步失败',
];
return $map[$status] ?? '未知';
}
}