Files
fdesk/app/inquiry/service/FbLeadSyncService.php
T
mzl92 eea13a2a58 Merge branch 'develop'
# Conflicts:
#	app/command/InquiryImportFbCommand.php
#	app/inquiry/utils/FbLeadHeaderMapper.php
2025-12-12 17:52:20 +08:00

241 lines
8.2 KiB
PHP
Raw 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
namespace app\inquiry\service;
use app\inquiry\utils\PhoneCountryHelper;
use support\Db;
class FbLeadSyncService
{
/**
* 同步指定渠道的 fb_leads.sync_status=0 数据到 inquiry_log
* 并将对应 fb_leads.sync_status 更新为 1
*
* @param int $enterUserId 录入人ID
* @param int $channelId 渠道ID(既用于 fb_leads.channel,也用于 inquiry_log.channel)
* @return int 同步条数
*/
public function syncToInquiryLog(int $enterUserId, int $channelId): int
{
$leads = Db::table('fb_leads')
->where('sync_status', 0)
->where('channel', $channelId)
->get();
if ($leads->isEmpty()) {
return 0;
}
$now = time();
// 转数组,后面循环更快
$leadArrList = [];
foreach ($leads as $lead) {
$leadArrList[] = (array)$lead;
}
// ① 收集本批手机号(去重)
$phoneList = $this->collectPhonesFromLeads($leadArrList);
// ② 批量查出 inquiry_log 已存在手机号集合(索引加持)
$existingTelSet = $this->getExistingTelSet($phoneList);
$insert = [];
$idsToMarkProcessed = []; // 插入成功 or 重复跳过,统一标记已处理
$insertCount = 0;
Db::transaction(function () use (
$leadArrList, $existingTelSet, $enterUserId, $channelId, $now,
&$insert, &$idsToMarkProcessed, &$insertCount
) {
foreach ($leadArrList as $lead) {
$leadId = (int)($lead['id'] ?? 0);
$tel = trim((string)($lead['phone'] ?? ''));
// 如果手机号存在于 inquiry_log,跳过同步(但要标记 fb_leads 已处理)
if ($tel !== '' && isset($existingTelSet[$tel])) {
if ($leadId > 0) {
$idsToMarkProcessed[] = $leadId;
}
continue;
}
$insert[] = $this->mapLeadToInquiry($lead, $now, $enterUserId, $channelId);
if ($leadId > 0) {
$idsToMarkProcessed[] = $leadId;
}
}
if (!empty($insert)) {
Db::table('inquiry_log')->insert($insert);
$insertCount = count($insert);
}
if (!empty($idsToMarkProcessed)) {
Db::table('fb_leads')
->whereIn('id', $idsToMarkProcessed)
->update([
'sync_status' => 1,
'updated_at' => $now,
]);
}
});
return $insertCount;
}
/**
* 从本批 leads 中收集手机号(tel),去重后返回
*/
protected function collectPhonesFromLeads(array $leadArrList): array
{
$phones = [];
foreach ($leadArrList as $lead) {
$tel = trim((string)($lead['phone'] ?? ''));
if ($tel !== '') {
// 先用原值精确匹配(你后续要做归一化再改这里即可)
$phones[$tel] = true;
}
}
return array_keys($phones);
}
/**
* 批量查出 inquiry_log 已存在手机号集合(返回 set:tel => true)
* - 自动分块 whereIn,避免 SQL 过长
* - 建议给 inquiry_log.tel 加索引 idx_tel
*/
protected function getExistingTelSet(array $phoneList, int $chunkSize = 800): array
{
$phoneList = array_values(array_unique(array_filter(array_map('trim', $phoneList))));
if (empty($phoneList)) {
return [];
}
$existingTelSet = [];
foreach (array_chunk($phoneList, $chunkSize) as $chunk) {
$rows = Db::table('inquiry_log')
->select('tel')
->where('tel', '<>', '')
->whereIn('tel', $chunk)
->get();
foreach ($rows as $r) {
$t = trim((string)($r->tel ?? ''));
if ($t !== '') {
$existingTelSet[$t] = true;
}
}
}
return $existingTelSet;
}
/**
* 映射一条 fb_leads -> inquiry_log
*/
protected function mapLeadToInquiry(array $lead, int $now, int $enterUserId, int $channelId): array
{
$email = (string)($lead['email'] ?? '');
$tel = (string)($lead['phone'] ?? '');
$wa = $tel;
$countryId = PhoneCountryHelper::detectCountryId($tel ?: $wa);
return [
'order_no' => $this->orderNum(),
'enter_user_id' => $enterUserId,
'recipient' => 0,
'quality' => 2,
'channel' => $channelId, // 👈 inquiry_log 里同样用这个渠道ID
'email' => $email,
'tel' => $tel,
'whatsapp' => $wa,
'country' => $countryId ?: 0,
'contacts' => (string)($lead['full_name'] ?? ''),
'content' => $this->buildContentHtml($lead),
'status' => 0,
'r_time' => 0,
't_time' => 0,
'sync_crm' => 0,
'created_at' => $now,
'updated_at' => $now,
];
}
protected function orderNum(): string
{
return 'SN' . date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
}
/**
* 富文本内容拼装 —— 基于你之前的版本
*/
protected function buildContentHtml(array $lead): string
{
$e = function ($v) {
return htmlspecialchars((string)$v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
};
$lines = [];
if (!empty($lead['car_model'])) {
$lines[] = '<p><strong>意向车型:</strong>' . $e($lead['car_model']) . '</p>';
}
if (!empty($lead['car_quantity']) || !empty($lead['car_quantity_text'])) {
$qty = $lead['car_quantity'] ?? $lead['car_quantity_text'] ?? '';
$lines[] = '<p><strong>意向数量:</strong>' . $e($qty) . '</p>';
}
if (!empty($lead['favorite_color'])) {
$lines[] = '<p><strong>意向颜色:</strong>' . $e($lead['favorite_color']) . '</p>';
}
if (!empty($lead['usage_type'])) {
$lines[] = '<p><strong>用途:</strong>' . $e($lead['usage_type']) . '</p>';
}
if (!empty($lead['seat_preference'])) {
$lines[] = '<p><strong>座位数偏好:</strong>' . $e($lead['seat_preference']) . '</p>';
}
if (!empty($lead['drive_type'])) {
$lines[] = '<p><strong>驱动形式偏好:</strong>' . $e($lead['drive_type']) . '</p>';
}
if (!empty($lead['extra_data'])) {
$extra = json_decode((string)$lead['extra_data'], true);
if (is_array($extra) && $extra) {
$lines[] = '<hr />';
$lines[] = '<p><strong>补充问答信息:</strong></p>';
foreach ($extra as $k => $v) {
$lines[] = '<p>' . $e($k) . ':' . $e($v) . '</p>';
}
}
}
$lines[] = '<hr />';
$lines[] = '<p><strong>广告与表单信息:</strong></p>';
$lines[] = '<p>平台:' . $e($lead['platform'] ?? '') . '</p>';
$lines[] = '<p>Campaign:' . $e($lead['campaign_name'] ?? '') . ' (#' . $e($lead['campaign_id'] ?? '') . ')</p>';
$lines[] = '<p>Adset:' . $e($lead['adset_name'] ?? '') . ' (#' . $e($lead['adset_id'] ?? '') . ')</p>';
$lines[] = '<p>Ad:' . $e($lead['ad_name'] ?? '') . ' (#' . $e($lead['ad_id'] ?? '') . ')</p>';
$lines[] = '<p>Form:' . $e($lead['form_name'] ?? '') . ' (#' . $e($lead['form_id'] ?? '') . ')</p>';
$lines[] = '<hr />';
$lines[] = '<p><strong>Meta 信息:</strong></p>';
$lines[] = '<p>Lead ID:' . $e($lead['fb_lead_id'] ?? '') . '</p>';
$lines[] = '<p>FB 创建时间原始值:' . $e($lead['fb_created_time'] ?? '') . '</p>';
if (!empty($lead['inbox_url'])) {
$url = $e($lead['inbox_url']);
$lines[] = '<p>Inbox 链接:<a href="' . $url . '" target="_blank">' . $url . '</a></p>';
}
return implode("\n", $lines);
}
}