Files
cunkebao_v3/Server/application/cunkebao/controller/plan/PostExternalApiV1Controller.php

288 lines
10 KiB
PHP
Raw Normal View History

2025-06-19 15:14:41 +08:00
<?php
namespace app\cunkebao\controller\plan;
use library\ResponseHelper;
use think\Controller;
use think\Db;
2025-12-17 16:20:46 +08:00
use app\cunkebao\service\DistributionRewardService;
2025-06-19 15:14:41 +08:00
/**
* 对外API接口控制器
*/
class PostExternalApiV1Controller extends Controller
{
2025-06-27 10:03:28 +08:00
2025-06-19 15:14:41 +08:00
/**
* 验证签名
*
* @param array $params 请求参数
* @param string $apiKey API密钥
* @param string $sign 签名
* @return bool
*/
private function validateSign($params, $apiKey, $sign)
{
// 1. 从参数中移除sign和apiKey
2025-06-21 14:24:45 +08:00
unset($params['sign'], $params['apiKey'],$params['portrait']);
2025-06-19 15:14:41 +08:00
// 2. 移除空值
$params = array_filter($params, function($value) {
return !is_null($value) && $value !== '';
});
// 3. 参数按键名升序排序
ksort($params);
// 4. 直接拼接参数值
$stringToSign = implode('', array_values($params));
// 5. 第一次MD5加密
$firstMd5 = md5($stringToSign);
// 6. 拼接apiKey并第二次MD5加密
$expectedSign = md5($firstMd5 . $apiKey);
// 7. 比对签名
return $expectedSign === $sign;
}
/**
* 对外API接口入口
*
* @return \think\response\Json
*/
public function index()
{
try {
$params = $this->request->param();
// 验证必填参数
if (empty($params['apiKey'])) {
return ResponseHelper::error('apiKey不能为空', 400);
}
if (empty($params['sign'])) {
return ResponseHelper::error('sign不能为空', 400);
}
if (empty($params['timestamp'])) {
return ResponseHelper::error('timestamp不能为空', 400);
}
// 验证时间戳允许5分钟误差
if (abs(time() - intval($params['timestamp'])) > 300) {
return ResponseHelper::error('请求已过期', 400);
}
// 查询API密钥是否存在
$plan = Db::name('customer_acquisition_task')
->where('apiKey', $params['apiKey'])
->where('status', 1)
->find();
if (!$plan) {
return ResponseHelper::error('无效的apiKey', 401);
}
// 验证签名
if (!$this->validateSign($params,$params['apiKey'], $params['sign'])) {
return ResponseHelper::error('签名验证失败', 401);
}
$identifier = !empty($params['wechatId']) ? $params['wechatId'] : $params['phone'];
2025-12-17 16:20:46 +08:00
// 渠道IDcid对应 distribution_channel.id
$channelId = !empty($params['cid']) ? intval($params['cid']) : 0;
2025-06-19 15:14:41 +08:00
$trafficPool = Db::name('traffic_pool')->where('identifier', $identifier)->find();
if (!$trafficPool) {
2025-06-21 14:24:45 +08:00
$trafficPoolId =Db::name('traffic_pool')->insertGetId([
2025-06-19 15:14:41 +08:00
'identifier' => $identifier,
2025-07-21 15:08:12 +08:00
'mobile' => !empty($params['phone']) ? $params['phone'] : '',
'createTime' => time()
2025-06-19 15:14:41 +08:00
]);
2025-06-21 14:24:45 +08:00
}else{
$trafficPoolId = $trafficPool['id'];
2025-06-19 15:14:41 +08:00
}
2025-12-17 16:20:46 +08:00
$taskCustomer = Db::name('task_customer')
->where('task_id', $plan['id'])
->where('phone', $identifier)
->find();
2025-06-21 14:24:45 +08:00
// 处理用户画像
if(!empty($params['portrait']) && is_array($params['portrait'])){
2025-06-26 17:54:09 +08:00
$this->updatePortrait($params['portrait'],$trafficPoolId,$plan['companyId']);
2025-06-21 14:24:45 +08:00
}
2025-06-19 15:14:41 +08:00
if (!$taskCustomer) {
2025-12-17 16:20:46 +08:00
$tags = !empty($params['tags']) ? explode(',', $params['tags']) : [];
$siteTags = !empty($params['siteTags']) ? explode(',', $params['siteTags']) : [];
// 处理渠道ID只有在分销配置中允许、且渠道本身正常时才记录到task_customer
$finalChannelId = 0;
if ($channelId > 0) {
$sceneConf = json_decode($plan['sceneConf'], true) ?: [];
$distributionConfig = $sceneConf['distribution'] ?? null;
$allowedChannelIds = $distributionConfig['channels'] ?? [];
if (!empty($distributionConfig) && !empty($distributionConfig['enabled']) && in_array($channelId, $allowedChannelIds)) {
// 验证渠道是否存在且正常
$channel = Db::name('distribution_channel')
->where([
['id', '=', $channelId],
['companyId', '=', $plan['companyId']],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->find();
if ($channel) {
$finalChannelId = intval($channelId);
}
}
}
$customerId = Db::name('task_customer')->insertGetId([
2025-06-19 15:14:41 +08:00
'task_id' => $plan['id'],
2025-12-17 16:20:46 +08:00
'channelId' => $finalChannelId,
2025-06-20 16:46:23 +08:00
'phone' => $identifier,
2025-06-20 17:23:23 +08:00
'name' => !empty($params['name']) ? $params['name'] : '',
2025-06-20 17:18:45 +08:00
'source' => !empty($params['source']) ? $params['source'] : '',
'remark' => !empty($params['remark']) ? $params['remark'] : '',
2025-06-20 16:46:23 +08:00
'tags' => json_encode($tags,256),
2025-06-26 17:15:50 +08:00
'siteTags' => json_encode($siteTags,256),
2025-07-28 17:40:50 +08:00
'createTime' => time(),
2025-06-19 15:14:41 +08:00
]);
2025-12-17 16:20:46 +08:00
// 记录获客奖励(异步处理,不影响主流程)
if ($customerId) {
try {
// 只有在存在有效渠道ID时才触发分佣
if ($finalChannelId > 0) {
DistributionRewardService::recordCustomerReward($plan['id'], $customerId, $identifier, $finalChannelId);
}
} catch (\Exception $e) {
// 记录错误但不影响主流程
\think\facade\Log::error('记录获客奖励失败:' . $e->getMessage());
}
}
2025-06-19 15:14:41 +08:00
return json([
'code' => 200,
'message' => '新增成功',
'data' => $identifier
]);
}else{
2025-06-26 17:54:09 +08:00
$siteTags = !empty($params['siteTags']) ? explode(',',$params['siteTags']) : [];
// 更新新老标签数据,实现去重
$this->updateSiteTags($taskCustomer['id'], $siteTags);
2025-06-19 15:14:41 +08:00
return json([
'code' => 200,
'message' => '已存在',
'data' => $identifier
]);
}
} catch (\Exception $e) {
return ResponseHelper::error('系统错误: ' . $e->getMessage(), 500);
}
}
2025-06-21 14:24:45 +08:00
/**
* 用户画像
* @param array $data 用户画像数据
* @param int $trafficPoolId 流量池id
*/
2025-06-26 17:54:09 +08:00
public function updatePortrait($data,$trafficPoolId,$companyId)
2025-06-21 14:24:45 +08:00
{
if(empty($data) || empty($trafficPoolId) || !is_array($data)){
return;
}
$type = !empty($data['type']) ? $data['type'] : 0;
$source = !empty($data['source']) ? $data['source'] : 0;
2025-06-25 11:42:26 +08:00
$sourceData = !empty($data['sourceData']) ? $data['sourceData'] : [];
2025-06-21 14:24:45 +08:00
$remark = !empty($data['remark']) ? $data['remark'] : '';
2025-06-25 14:28:42 +08:00
$uniqueId = !empty($data['uniqueId']) ? $data['uniqueId'] : 0;
2025-06-25 11:42:26 +08:00
ksort($sourceData);
$sourceData = json_encode($sourceData,256);
2025-06-21 14:24:45 +08:00
$data = [
2025-06-26 17:54:09 +08:00
'companyId' => $companyId,
2025-06-21 14:24:45 +08:00
'trafficPoolId' => $trafficPoolId,
'type' => $type,
'source' => $source,
2025-06-25 11:42:26 +08:00
'sourceData' => $sourceData,
2025-06-21 14:24:45 +08:00
'remark' => $remark,
2025-06-25 14:28:42 +08:00
'uniqueId' => $uniqueId,
2025-06-21 14:24:45 +08:00
'count' => 1,
'createTime' => time(),
'updateTime' => time(),
];
$res= Db::name('user_portrait')
2025-06-25 14:28:42 +08:00
->where(['trafficPoolId'=>$trafficPoolId,'type'=>$type,'source'=>$source,'uniqueId'=>$uniqueId])
2025-06-21 14:24:45 +08:00
->where('createTime','>',time()-1800)
->find();
if($res){
$count = $res['count'] + 1;
Db::name('user_portrait')->where(['id'=>$res['id']])->update(['count'=>$count,'updateTime'=>time()]);
}else{
Db::name('user_portrait')->insert($data);
}
}
2025-06-26 17:54:09 +08:00
/**
* 更新站点标签数据,实现去重
* @param int $taskCustomerId 任务客户ID
* @param array $newSiteTags 新的站点标签数组
*/
private function updateSiteTags($taskCustomerId, $newSiteTags)
{
2025-06-27 10:03:28 +08:00
2025-06-26 17:54:09 +08:00
if (empty($taskCustomerId) || empty($newSiteTags) || !is_array($newSiteTags)) {
return;
}
try {
// 获取当前任务客户的站点标签
$taskCustomer = Db::name('task_customer')->where('id', $taskCustomerId)->find();
2025-06-27 10:03:28 +08:00
2025-06-26 17:54:09 +08:00
if (!$taskCustomer) {
return;
}
// 解析现有的站点标签
$existingSiteTags = [];
if (!empty($taskCustomer['siteTags'])) {
$existingSiteTags = json_decode($taskCustomer['siteTags'], true);
if (!is_array($existingSiteTags)) {
$existingSiteTags = [];
}
}
// 合并新老标签并去重
$mergedSiteTags = array_merge($existingSiteTags, $newSiteTags);
$uniqueSiteTags = array_unique($mergedSiteTags);
// 过滤空值并重新索引数组
$uniqueSiteTags = array_values(array_filter($uniqueSiteTags, function($tag) {
return !empty(trim($tag));
}));
2025-06-27 10:03:28 +08:00
2025-06-26 17:54:09 +08:00
// 更新数据库中的站点标签
Db::name('task_customer')->where('id', $taskCustomerId)->update([
'siteTags' => json_encode($uniqueSiteTags, JSON_UNESCAPED_UNICODE),
'updateTime' => time()
2025-06-26 17:54:09 +08:00
]);
} catch (\Exception $e) {
// 记录错误日志,但不影响主流程
\think\facade\Log::error('更新站点标签失败: ' . $e->getMessage());
}
}
2025-06-19 15:14:41 +08:00
}