155 lines
5.2 KiB
PHP
155 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace app\inquiry\utils;
|
|
|
|
use support\exception\BusinessException;
|
|
|
|
class FbLeadHeaderMapper
|
|
{
|
|
/**
|
|
* Excel 原始表头 => DB 字段名
|
|
* 注意:key 用的是“原始表头字符串”(包括下划线)
|
|
*/
|
|
protected array $headerMap = [
|
|
// ===== 基础公共字段 =====
|
|
'id' => 'fb_lead_id',
|
|
'created_time' => 'fb_created_time',
|
|
'ad_id' => 'ad_id',
|
|
'ad_name' => 'ad_name',
|
|
'adset_id' => 'adset_id',
|
|
'adset_name' => 'adset_name',
|
|
'campaign_id' => 'campaign_id',
|
|
'campaign_name' => 'campaign_name',
|
|
'form_id' => 'form_id',
|
|
'form_name' => 'form_name',
|
|
'is_organic' => 'is_organic',
|
|
'platform' => 'platform',
|
|
|
|
'full_name' => 'full_name',
|
|
'phone' => 'phone',
|
|
'phone_number' => 'phone', // 兼容写法
|
|
'email' => 'email',
|
|
'lead_status' => 'lead_status',
|
|
'inbox_url' => 'inbox_url',
|
|
|
|
// ===== 车型相关:全部归到 car_model =====
|
|
'which_model_of_this_car_would_you_like_to_purchase?_' => 'car_model',
|
|
'which_model_of_this_car_would_you_like_to_purchase?' => 'car_model',
|
|
'which_car_model_would_you_like_to_purchase?' => 'car_model',
|
|
'which_model_do_you_want_to_purchase?' => 'car_model',
|
|
'which_model_would_you_like_to_purchase?' => 'car_model',
|
|
'which_version_do_you_want_to_buy?' => 'car_model', // 这里也归到车型/版本字段
|
|
|
|
// ===== 数量相关:全部归到 car_quantity =====
|
|
'how_many_cars_would_you_like_to_buy?_' => 'car_quantity',
|
|
'how_many_cars_would_you_like_to_buy?' => 'car_quantity',
|
|
'_how_many_cars_would_you_like_to_buy?' => 'car_quantity',
|
|
'how_many_cars_do_you_buy?' => 'car_quantity',
|
|
'how_many_cars_do_you_want_to_purchase?' => 'car_quantity',
|
|
'how_many_cars_do_you_want_to_buy?' => 'car_quantity',
|
|
'what_quantity_do_you_want_to_buy?' => 'car_quantity',
|
|
|
|
// ===== 颜色相关:归到 favorite_color =====
|
|
'what_color_do_you_like?' => 'favorite_color',
|
|
'which_color_would_you_like_to_purchase?' => 'favorite_color',
|
|
|
|
// ===== 用途相关:归到 usage_type =====
|
|
'are_you_using_it_for_business_or_personal_use?' => 'usage_type',
|
|
'business_use_or_personal_use?' => 'usage_type',
|
|
'personal_use_or_business_use?' => 'usage_type',
|
|
|
|
// ===== 座位数相关 =====
|
|
'do_you_want_to_buy_six_seats_or_seven_seats?' => 'seat_preference',
|
|
];
|
|
|
|
/**
|
|
* 返回所有支持的 Excel 表头
|
|
*/
|
|
public function getSupportedHeaders(): array
|
|
{
|
|
return array_keys($this->headerMap);
|
|
}
|
|
|
|
/**
|
|
* 单个表头映射:原始表头 -> DB 字段名
|
|
*/
|
|
public function mapHeader(string $rawHeader): ?string
|
|
{
|
|
$key = $this->normalizeHeader($rawHeader);
|
|
|
|
return $this->headerMap[$key] ?? null;
|
|
}
|
|
|
|
/**
|
|
* 校验一整行表头:
|
|
* - 有任何不认识的表头,就抛 BusinessException
|
|
*/
|
|
public function validateHeaders(array $rawHeaders): void
|
|
{
|
|
$unsupported = [];
|
|
|
|
foreach ($rawHeaders as $header) {
|
|
$header = (string)$header;
|
|
$key = $this->normalizeHeader($header);
|
|
|
|
// 允许空表头(多余空列)
|
|
if ($key === '') {
|
|
continue;
|
|
}
|
|
|
|
if (!isset($this->headerMap[$key])) {
|
|
$unsupported[] = $header;
|
|
}
|
|
}
|
|
|
|
if (!empty($unsupported)) {
|
|
$msg = 'Excel 表头包含未兼容字段:' . implode('、', $unsupported)
|
|
. '。请检查这些字段是否需要加入映射配置。';
|
|
throw new BusinessException($msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据第一行表头,构建 “列索引 => DB 字段” 映射
|
|
*/
|
|
public function buildColumnFieldMap(array $rawHeaders): array
|
|
{
|
|
// 先做一遍校验(发现问题直接抛异常)
|
|
$this->validateHeaders($rawHeaders);
|
|
|
|
$colToField = [];
|
|
|
|
foreach ($rawHeaders as $index => $header) {
|
|
$key = $this->normalizeHeader((string)$header);
|
|
if ($key === '') {
|
|
continue;
|
|
}
|
|
|
|
$field = $this->headerMap[$key] ?? null;
|
|
if ($field === null) {
|
|
continue; // 理论上不会到这儿,双保险
|
|
}
|
|
|
|
$colToField[$index] = $field;
|
|
}
|
|
|
|
return $colToField;
|
|
}
|
|
|
|
/**
|
|
* 表头标准化:
|
|
* 目前只去 BOM + trim,保持和 headerMap 中 key 完全一致
|
|
* 如果后面再出现“有空格/大小写”的版本,我们可以在这里做 strtolower / 替换空格 为 _
|
|
*/
|
|
protected function normalizeHeader(string $header): string
|
|
{
|
|
// 去掉 UTF-8 BOM
|
|
$header = preg_replace('/^\xEF\xBB\xBF/', '', $header);
|
|
|
|
// 去掉前后空白
|
|
$header = trim($header);
|
|
|
|
return $header;
|
|
}
|
|
}
|