266 lines
9.8 KiB
PHP
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] ?? '未知';
|
|
}
|
|
}
|