精简模型

This commit is contained in:
柳清爽
2025-04-08 16:30:20 +08:00
parent 880d132849
commit 1cc150472c
15 changed files with 31 additions and 1359 deletions

View File

@@ -10,7 +10,6 @@ Route::group('v1/', function () {
// 获客场景相关
Route::group('plan/scenes', function () {
Route::get('', 'app\\plan\\controller\\Scene@index'); // 获取场景列表
Route::get(':id', 'app\\plan\\controller\\Scene@read'); // 获取场景详情
});
// 流量标签相关

View File

@@ -10,28 +10,7 @@ class PlanScene extends Model
{
// 设置表名
protected $name = 'plan_scene';
protected $prefix = 'tk_';
// 设置主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createTime';
protected $updateTime = 'updateTime';
protected $deleteTime = 'deleteTime';
// 定义字段类型
protected $type = [
'id' => 'integer',
'status' => 'integer',
'createTime' => 'integer',
'updateTime' => 'integer',
'deleteTime' => 'integer'
];
/**
* 获取场景列表
*
@@ -61,15 +40,4 @@ class PlanScene extends Model
'limit' => $limit
];
}
/**
* 获取单个场景信息
*
* @param int $id 场景ID
* @return array|null 场景信息
*/
public static function getSceneInfo($id)
{
return self::where('id', $id)->find();
}
}

View File

@@ -10,140 +10,4 @@ class PlanTask extends Model
{
// 设置表名
protected $name = 'plan_task';
protected $prefix = 'tk_';
// 设置主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createTime';
protected $updateTime = 'updateTime';
protected $deleteTime = 'deleteTime';
// 定义字段类型
protected $type = [
'id' => 'integer',
'device_id' => 'integer',
'scene_id' => 'integer',
'scene_config' => 'json',
'status' => 'integer',
'current_step' => 'integer',
'priority' => 'integer',
'created_by' => 'integer',
'createTime' => 'integer',
'updateTime' => 'integer',
'deleteTime' => 'integer'
];
/**
* 状态文本获取器
* @param int $value 状态值
* @return string 状态文本
*/
public function getStatusTextAttr($value, $data)
{
$status = [
0 => '停用',
1 => '启用',
2 => '完成',
3 => '失败'
];
return isset($status[$data['status']]) ? $status[$data['status']] : '未知';
}
/**
* 获取待执行的任务列表
* @param int $limit 限制数量
* @return array 任务列表
*/
public static function getPendingTasks($limit = 10)
{
return self::where('status', 1)
->order('priority DESC, id ASC')
->limit($limit)
->select();
}
/**
* 更新任务状态
* @param int $id 任务ID
* @param int $status 新状态
* @param int $currentStep 当前步骤
* @return bool 更新结果
*/
public static function updateTaskStatus($id, $status, $currentStep = null)
{
$data = ['status' => $status];
if ($currentStep !== null) {
$data['current_step'] = $currentStep;
}
return self::where('id', $id)->update($data);
}
/**
* 获取任务详情
* @param int $id 任务ID
* @return array|null 任务详情
*/
public static function getTaskDetail($id)
{
return self::where('id', $id)->find();
}
/**
* 获取任务列表
* @param array $where 查询条件
* @param string $order 排序
* @param int $page 页码
* @param int $limit 每页数量
* @return array 任务列表和总数
*/
public static function getTaskList($where = [], $order = 'id desc', $page = 1, $limit = 10)
{
// 构建查询
$query = self::where($where);
// 计算总数
$total = $query->count();
// 分页查询数据
$list = $query->page($page, $limit)
->order($order)
->select();
return [
'list' => $list,
'total' => $total,
'page' => $page,
'limit' => $limit
];
}
/**
* 关联场景
*/
public function scene()
{
return $this->belongsTo('PlanScene', 'scene_id');
}
/**
* 关联设备
*/
public function device()
{
return $this->belongsTo('app\devices\model\Device', 'device_id');
}
/**
* 关联执行记录
*/
public function executions()
{
return $this->hasMany('PlanExecution', 'plan_id');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace app\plan\model;
use think\Model;
/**
* 流量池模型
*/
class TrafficPool extends Model
{
// 设置表名
protected $name = 'traffic_pool';
}

View File

@@ -0,0 +1,13 @@
<?php
namespace app\plan\model;
use think\Model;
/**
* 流量来源模型
*/
class TrafficSource extends Model
{
// 设置表名
protected $name = 'traffic_source';
}

View File

@@ -10,31 +10,7 @@ class TrafficTag extends Model
{
// 设置表名
protected $name = 'traffic_tag';
protected $prefix = 'tk_';
// 设置主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createTime';
protected $updateTime = false; // 没有更新时间字段
protected $deleteTime = 'deleteTime';
// 定义软删除
protected $defaultSoftDelete = 0;
// 定义字段类型
protected $type = [
'id' => 'integer',
'tagName' => 'string',
'companyId' => 'integer',
'createTime' => 'integer',
'deleteTime' => 'integer'
];
/**
* 获取标签列表,支持分页和搜索
*

View File

@@ -1,239 +0,0 @@
<?php
namespace app\plan\service;
use app\plan\model\TrafficPool;
use app\plan\model\TrafficSource;
use app\plan\model\PlanScene;
use think\Exception;
use think\facade\Log;
/**
* 场景处理服务
*/
class SceneHandler
{
/**
* 获取场景处理器
* @param int $sceneId 场景ID
* @return object 场景处理器
*/
public static function getHandler($sceneId)
{
$scene = PlanScene::getSceneInfo($sceneId);
if (empty($scene)) {
throw new Exception('场景不存在');
}
$handlerMap = [
// 场景ID => 处理器名称
1 => 'PosterScene',
2 => 'OrderScene',
3 => 'DouyinScene',
4 => 'XiaohongshuScene',
5 => 'PhoneScene',
6 => 'WechatScene',
7 => 'GroupScene',
8 => 'PaymentScene',
9 => 'ApiScene',
];
if (!isset($handlerMap[$sceneId])) {
throw new Exception('未找到场景处理器');
}
$handlerClass = '\\app\\plan\\scene\\' . $handlerMap[$sceneId];
if (!class_exists($handlerClass)) {
throw new Exception('场景处理器不存在');
}
return new $handlerClass($scene);
}
/**
* 处理海报扫码获客
* @param string $mobile 手机号
* @param int $sceneId 场景ID
* @param int $planId 计划ID
* @param array $extra 额外数据
* @return array 处理结果
*/
public static function handlePosterScan($mobile, $sceneId, $planId = null, $extra = [])
{
if (empty($mobile)) {
return [
'success' => false,
'message' => '手机号不能为空'
];
}
try {
// 添加或更新流量信息
$trafficId = TrafficPool::addOrUpdateTraffic($mobile, [
'name' => $extra['name'] ?? '',
'gender' => $extra['gender'] ?? 0,
'region' => $extra['region'] ?? ''
]);
// 添加流量来源记录
TrafficSource::addSource($trafficId, 'poster', [
'plan_id' => $planId,
'scene_id' => $sceneId,
'source_detail' => json_encode($extra)
]);
return [
'success' => true,
'message' => '海报扫码获客处理成功',
'data' => [
'traffic_id' => $trafficId
]
];
} catch (Exception $e) {
Log::error('海报扫码获客处理失败', [
'mobile' => $mobile,
'scene_id' => $sceneId,
'plan_id' => $planId,
'error' => $e->getMessage()
]);
return [
'success' => false,
'message' => '处理失败:' . $e->getMessage()
];
}
}
/**
* 处理订单导入获客
* @param array $orders 订单数据
* @param int $sceneId 场景ID
* @param int $planId 计划ID
* @return array 处理结果
*/
public static function handleOrderImport($orders, $sceneId, $planId = null)
{
if (empty($orders) || !is_array($orders)) {
return [
'success' => false,
'message' => '订单数据格式不正确'
];
}
$success = 0;
$failed = 0;
$errors = [];
foreach ($orders as $order) {
if (empty($order['mobile'])) {
$failed++;
$errors[] = '订单缺少手机号';
continue;
}
try {
// 添加或更新流量信息
$trafficId = TrafficPool::addOrUpdateTraffic($order['mobile'], [
'name' => $order['name'] ?? '',
'gender' => $order['gender'] ?? 0,
'region' => $order['region'] ?? ''
]);
// 添加流量来源记录
TrafficSource::addSource($trafficId, 'order', [
'plan_id' => $planId,
'scene_id' => $sceneId,
'source_detail' => json_encode($order),
'sub_channel' => $order['order_source'] ?? ''
]);
$success++;
} catch (Exception $e) {
$failed++;
$errors[] = '处理订单失败:' . $e->getMessage();
Log::error('订单导入获客处理失败', [
'order' => $order,
'scene_id' => $sceneId,
'plan_id' => $planId,
'error' => $e->getMessage()
]);
}
}
return [
'success' => $success > 0,
'message' => "导入完成,成功{$success}条,失败{$failed}",
'data' => [
'success_count' => $success,
'failed_count' => $failed,
'errors' => $errors
]
];
}
/**
* 通用渠道获客处理
* @param string $mobile 手机号
* @param string $channel 渠道
* @param int $sceneId 场景ID
* @param int $planId 计划ID
* @param array $extra 额外数据
* @return array 处理结果
*/
public static function handleChannelTraffic($mobile, $channel, $sceneId, $planId = null, $extra = [])
{
if (empty($mobile)) {
return [
'success' => false,
'message' => '手机号不能为空'
];
}
if (empty($channel)) {
return [
'success' => false,
'message' => '渠道不能为空'
];
}
try {
// 添加或更新流量信息
$trafficId = TrafficPool::addOrUpdateTraffic($mobile, [
'name' => $extra['name'] ?? '',
'gender' => $extra['gender'] ?? 0,
'region' => $extra['region'] ?? ''
]);
// 添加流量来源记录
TrafficSource::addSource($trafficId, $channel, [
'plan_id' => $planId,
'scene_id' => $sceneId,
'source_detail' => json_encode($extra),
'sub_channel' => $extra['sub_channel'] ?? ''
]);
return [
'success' => true,
'message' => $channel . '获客处理成功',
'data' => [
'traffic_id' => $trafficId
]
];
} catch (Exception $e) {
Log::error($channel . '获客处理失败', [
'mobile' => $mobile,
'scene_id' => $sceneId,
'plan_id' => $planId,
'error' => $e->getMessage()
]);
return [
'success' => false,
'message' => '处理失败:' . $e->getMessage()
];
}
}
}

View File

@@ -1,675 +0,0 @@
<?php
namespace app\plan\service;
use app\plan\model\PlanTask;
use app\plan\model\PlanExecution;
use app\plan\model\TrafficPool;
use app\plan\model\TrafficSource;
use app\plan\model\Tag;
use think\Db;
use think\facade\Log;
use think\Exception;
/**
* 任务运行器服务
*/
class TaskRunner
{
protected $task;
protected $stepHandlers = [];
/**
* 构造函数
* @param PlanTask|int $task 任务对象或ID
*/
public function __construct($task)
{
if (is_numeric($task)) {
$this->task = PlanTask::getTaskDetail($task);
} else {
$this->task = $task;
}
if (empty($this->task)) {
throw new Exception('任务不存在');
}
// 注册步骤处理器
$this->registerStepHandlers();
}
/**
* 注册步骤处理器
*/
protected function registerStepHandlers()
{
// 基础配置
$this->stepHandlers[1] = function() {
return $this->handleBasicConfig();
};
// 加友计划
$this->stepHandlers[2] = function() {
return $this->handleAddFriend();
};
// API调用
$this->stepHandlers[3] = function() {
return $this->handleApiCall();
};
// 标签处理
$this->stepHandlers[4] = function() {
return $this->handleTagging();
};
}
/**
* 运行任务
* @return array 执行结果
*/
public function run()
{
if ($this->task['status'] != 1) {
return [
'success' => false,
'message' => '任务未启用,无法运行'
];
}
// 获取当前步骤
$currentStep = $this->task['current_step'];
// 检查是否需要初始化第一步
if ($currentStep == 0) {
$currentStep = 1;
PlanTask::updateTaskStatus($this->task['id'], 1, $currentStep);
$this->task['current_step'] = $currentStep;
}
// 执行当前步骤
if (isset($this->stepHandlers[$currentStep])) {
try {
$result = call_user_func($this->stepHandlers[$currentStep]);
if ($result['success']) {
// 检查是否需要进入下一步
if ($result['completed'] && $currentStep < 4) {
$nextStep = $currentStep + 1;
PlanTask::updateTaskStatus($this->task['id'], 1, $nextStep);
} else if ($result['completed'] && $currentStep == 4) {
// 所有步骤已完成,标记任务为完成状态
PlanTask::updateTaskStatus($this->task['id'], 2, $currentStep);
}
} else {
// 如果步骤执行失败,记录错误并可能更新任务状态
Log::error('任务执行失败:', [
'task_id' => $this->task['id'],
'step' => $currentStep,
'error' => $result['message']
]);
// 视情况决定是否将任务标记为失败
if ($result['fatal']) {
PlanTask::updateTaskStatus($this->task['id'], 3, $currentStep);
}
}
return $result;
} catch (Exception $e) {
// 捕获并记录异常
Log::error('任务执行异常:', [
'task_id' => $this->task['id'],
'step' => $currentStep,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return [
'success' => false,
'message' => '任务执行异常:' . $e->getMessage(),
'fatal' => true
];
}
} else {
return [
'success' => false,
'message' => '未知的任务步骤:' . $currentStep,
'fatal' => true
];
}
}
/**
* 处理基础配置步骤
* @return array 处理结果
*/
protected function handleBasicConfig()
{
// 创建执行记录
$executionId = PlanExecution::createExecution($this->task['id'], 1, [
'status' => 1 // 设置为进行中
]);
try {
// 检查设备状态
if (empty($this->task['device_id'])) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '未设置设备'
]);
return [
'success' => false,
'message' => '未设置设备',
'fatal' => true
];
}
// 检查场景配置
if (empty($this->task['scene_id'])) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '未设置获客场景'
]);
return [
'success' => false,
'message' => '未设置获客场景',
'fatal' => true
];
}
// 检查场景配置
if (empty($this->task['scene_config'])) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '场景配置为空'
]);
return [
'success' => false,
'message' => '场景配置为空',
'fatal' => true
];
}
// 标记基础配置步骤为完成
PlanExecution::updateExecution($executionId, 2, [
'result' => [
'device_id' => $this->task['device_id'],
'scene_id' => $this->task['scene_id'],
'config_valid' => true
]
]);
return [
'success' => true,
'message' => '基础配置验证通过',
'completed' => true
];
} catch (Exception $e) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '基础配置异常:' . $e->getMessage()
]);
throw $e;
}
}
/**
* 处理加友计划步骤
* @return array 处理结果
*/
protected function handleAddFriend()
{
// 创建执行记录
$executionId = PlanExecution::createExecution($this->task['id'], 2, [
'status' => 1 // 设置为进行中
]);
try {
// 从流量池中选择符合条件的流量
$trafficConditions = $this->getTrafficConditions();
$trafficData = TrafficPool::getAvailableTraffic($trafficConditions, 'last_used_time ASC', 1, 1);
if (empty($trafficData['list'])) {
// 没有符合条件的流量,标记为等待状态
PlanExecution::updateExecution($executionId, 0, [
'error' => '没有符合条件的流量'
]);
return [
'success' => true,
'message' => '没有符合条件的流量,等待下次执行',
'completed' => false // 不算失败,但也不进入下一步
];
}
$traffic = $trafficData['list'][0];
// 调用设备服务执行加好友操作
$addFriendResult = $this->callDeviceAddFriend($traffic);
if ($addFriendResult['success']) {
// 更新流量使用状态
TrafficPool::setTrafficUsed($traffic['id']);
// 标记执行记录为成功
PlanExecution::updateExecution($executionId, 2, [
'traffic_id' => $traffic['id'],
'result' => $addFriendResult['data']
]);
return [
'success' => true,
'message' => '加友成功:' . $traffic['mobile'],
'completed' => true,
'traffic' => $traffic
];
} else {
// 标记执行记录为失败
PlanExecution::updateExecution($executionId, 3, [
'traffic_id' => $traffic['id'],
'error' => $addFriendResult['message'],
'result' => $addFriendResult['data'] ?? null
]);
return [
'success' => false,
'message' => '加友失败:' . $addFriendResult['message'],
'fatal' => false // 加友失败不算致命错误,可以下次继续
];
}
} catch (Exception $e) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '加友计划异常:' . $e->getMessage()
]);
throw $e;
}
}
/**
* 处理API调用步骤
* @return array 处理结果
*/
protected function handleApiCall()
{
// 创建执行记录
$executionId = PlanExecution::createExecution($this->task['id'], 3, [
'status' => 1 // 设置为进行中
]);
try {
// 获取上一步成功处理的流量信息
$lastExecution = PlanExecution::getLatestExecution($this->task['id'], 2);
if (empty($lastExecution) || $lastExecution['status'] != 2) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '上一步未成功完成'
]);
return [
'success' => false,
'message' => '上一步未成功完成无法进行API调用',
'fatal' => true
];
}
$trafficId = $lastExecution['traffic_id'];
if (empty($trafficId)) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '未找到有效的流量ID'
]);
return [
'success' => false,
'message' => '未找到有效的流量ID',
'fatal' => true
];
}
// 获取流量详情
$traffic = TrafficPool::getTrafficDetail($trafficId);
if (empty($traffic)) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '未找到流量信息'
]);
return [
'success' => false,
'message' => '未找到流量信息',
'fatal' => true
];
}
// 根据场景配置调用相应的API
$apiCallResult = $this->callSceneApi($traffic);
if ($apiCallResult['success']) {
// 标记执行记录为成功
PlanExecution::updateExecution($executionId, 2, [
'traffic_id' => $trafficId,
'result' => $apiCallResult['data']
]);
return [
'success' => true,
'message' => 'API调用成功',
'completed' => true,
'traffic' => $traffic
];
} else {
// 标记执行记录为失败
PlanExecution::updateExecution($executionId, 3, [
'traffic_id' => $trafficId,
'error' => $apiCallResult['message'],
'result' => $apiCallResult['data'] ?? null
]);
return [
'success' => false,
'message' => 'API调用失败' . $apiCallResult['message'],
'fatal' => $apiCallResult['fatal'] ?? false
];
}
} catch (Exception $e) {
PlanExecution::updateExecution($executionId, 3, [
'error' => 'API调用异常' . $e->getMessage()
]);
throw $e;
}
}
/**
* 处理标签步骤
* @return array 处理结果
*/
protected function handleTagging()
{
// 创建执行记录
$executionId = PlanExecution::createExecution($this->task['id'], 4, [
'status' => 1 // 设置为进行中
]);
try {
// 获取上一步成功处理的流量信息
$lastExecution = PlanExecution::getLatestExecution($this->task['id'], 3);
if (empty($lastExecution) || $lastExecution['status'] != 2) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '上一步未成功完成'
]);
return [
'success' => false,
'message' => '上一步未成功完成,无法进行标签处理',
'fatal' => true
];
}
$trafficId = $lastExecution['traffic_id'];
if (empty($trafficId)) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '未找到有效的流量ID'
]);
return [
'success' => false,
'message' => '未找到有效的流量ID',
'fatal' => true
];
}
// 获取流量详情
$traffic = TrafficPool::getTrafficDetail($trafficId);
if (empty($traffic)) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '未找到流量信息'
]);
return [
'success' => false,
'message' => '未找到流量信息',
'fatal' => true
];
}
// 获取并应用标签
$taggingResult = $this->applyTags($traffic);
if ($taggingResult['success']) {
// 标记执行记录为成功
PlanExecution::updateExecution($executionId, 2, [
'traffic_id' => $trafficId,
'result' => $taggingResult['data']
]);
return [
'success' => true,
'message' => '标签处理成功',
'completed' => true,
'traffic' => $traffic
];
} else {
// 标记执行记录为失败
PlanExecution::updateExecution($executionId, 3, [
'traffic_id' => $trafficId,
'error' => $taggingResult['message'],
'result' => $taggingResult['data'] ?? null
]);
return [
'success' => false,
'message' => '标签处理失败:' . $taggingResult['message'],
'fatal' => $taggingResult['fatal'] ?? false
];
}
} catch (Exception $e) {
PlanExecution::updateExecution($executionId, 3, [
'error' => '标签处理异常:' . $e->getMessage()
]);
throw $e;
}
}
/**
* 获取流量筛选条件
* @return array 条件数组
*/
protected function getTrafficConditions()
{
$conditions = [];
// 根据场景配置获取筛选条件
if (isset($this->task['scene_config']) && is_array($this->task['scene_config'])) {
$config = $this->task['scene_config'];
// 添加性别筛选
if (isset($config['gender']) && in_array($config['gender'], [0, 1, 2])) {
$conditions[] = ['gender', '=', $config['gender']];
}
// 添加年龄筛选
if (isset($config['age_min']) && is_numeric($config['age_min'])) {
$conditions[] = ['age', '>=', intval($config['age_min'])];
}
if (isset($config['age_max']) && is_numeric($config['age_max'])) {
$conditions[] = ['age', '<=', intval($config['age_max'])];
}
// 添加区域筛选
if (isset($config['region']) && !empty($config['region'])) {
$conditions[] = ['region', 'like', '%' . $config['region'] . '%'];
}
}
return $conditions;
}
/**
* 调用设备加好友操作
* @param array $traffic 流量信息
* @return array 调用结果
*/
protected function callDeviceAddFriend($traffic)
{
// 模拟调用设备操作
// 实际项目中应该调用实际的设备API
// 记录设备调用日志
Log::info('设备加好友操作', [
'task_id' => $this->task['id'],
'device_id' => $this->task['device_id'],
'mobile' => $traffic['mobile']
]);
// 模拟成功率
$success = mt_rand(0, 10) > 2;
if ($success) {
return [
'success' => true,
'message' => '加好友操作成功',
'data' => [
'add_time' => date('Y-m-d H:i:s'),
'device_id' => $this->task['device_id'],
'mobile' => $traffic['mobile']
]
];
} else {
return [
'success' => false,
'message' => '加好友操作失败:' . ['设备繁忙', '用户拒绝', '网络异常'][mt_rand(0, 2)],
'data' => [
'attempt_time' => date('Y-m-d H:i:s'),
'device_id' => $this->task['device_id'],
'mobile' => $traffic['mobile']
]
];
}
}
/**
* 根据场景调用相应API
* @param array $traffic 流量信息
* @return array 调用结果
*/
protected function callSceneApi($traffic)
{
// 根据场景类型调用不同API
if (empty($this->task['scene_id'])) {
return [
'success' => false,
'message' => '场景未设置',
'fatal' => true
];
}
// 记录API调用日志
Log::info('场景API调用', [
'task_id' => $this->task['id'],
'scene_id' => $this->task['scene_id'],
'traffic_id' => $traffic['id']
]);
// 模拟成功率
$success = mt_rand(0, 10) > 1;
if ($success) {
return [
'success' => true,
'message' => 'API调用成功',
'data' => [
'call_time' => date('Y-m-d H:i:s'),
'scene_id' => $this->task['scene_id'],
'traffic_id' => $traffic['id']
]
];
} else {
return [
'success' => false,
'message' => 'API调用失败' . ['参数错误', 'API超时', '系统异常'][mt_rand(0, 2)],
'data' => [
'attempt_time' => date('Y-m-d H:i:s'),
'scene_id' => $this->task['scene_id'],
'traffic_id' => $traffic['id']
],
'fatal' => false // API调用失败通常不算致命错误
];
}
}
/**
* 应用标签
* @param array $traffic 流量信息
* @return array 处理结果
*/
protected function applyTags($traffic)
{
// 获取需要应用的标签
$tags = [];
// 从场景配置中获取标签
if (isset($this->task['scene_config']) && is_array($this->task['scene_config']) && isset($this->task['scene_config']['tags'])) {
$configTags = $this->task['scene_config']['tags'];
if (is_array($configTags)) {
$tags = array_merge($tags, $configTags);
} else if (is_string($configTags)) {
$tags[] = $configTags;
}
}
// 从场景获取标签
if (!empty($this->task['scene_id'])) {
$tags[] = '场景_' . $this->task['scene_id'];
}
// 如果没有标签,返回成功
if (empty($tags)) {
return [
'success' => true,
'message' => '没有需要应用的标签',
'data' => []
];
}
// 处理标签
$tagIds = [];
foreach ($tags as $tagName) {
$tagId = Tag::getOrCreate($tagName, 'friend');
$tagIds[] = $tagId;
Tag::updateCount($tagId);
}
// 记录标签应用日志
Log::info('应用标签', [
'task_id' => $this->task['id'],
'traffic_id' => $traffic['id'],
'tag_ids' => $tagIds
]);
// 更新流量标签
$existingTags = empty($traffic['tag_ids']) ? [] : explode(',', $traffic['tag_ids']);
$allTags = array_unique(array_merge($existingTags, $tagIds));
TrafficPool::where('id', $traffic['id'])->update([
'tag_ids' => implode(',', $allTags)
]);
return [
'success' => true,
'message' => '标签应用成功',
'data' => [
'tag_ids' => $tagIds,
'tag_names' => $tags
]
];
}
}

View File

@@ -1,92 +0,0 @@
-- 获客计划主表
CREATE TABLE `tk_plan_task` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(100) NOT NULL COMMENT '计划名称',
`device_id` int(10) unsigned DEFAULT NULL COMMENT '关联设备ID',
`scene_id` int(10) unsigned DEFAULT NULL COMMENT '获客场景ID',
`scene_config` text DEFAULT NULL COMMENT '场景配置(JSON格式)',
`status` tinyint(3) unsigned DEFAULT 0 COMMENT '状态0=停用1=启用2=完成3=失败',
`current_step` tinyint(3) unsigned DEFAULT 0 COMMENT '当前执行步骤',
`priority` tinyint(3) unsigned DEFAULT 5 COMMENT '优先级1-10数字越大优先级越高',
`created_by` int(10) unsigned NOT NULL COMMENT '创建人ID',
`createTime` int(11) DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) DEFAULT NULL COMMENT '更新时间',
`deleteTime` int(11) DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`),
KEY `idx_status` (`status`),
KEY `idx_device` (`device_id`),
KEY `idx_scene` (`scene_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='获客计划主表';
-- 流量池表
CREATE TABLE `tk_traffic_pool` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`mobile` varchar(20) NOT NULL COMMENT '手机号',
`name` varchar(50) DEFAULT NULL COMMENT '姓名',
`gender` tinyint(1) DEFAULT NULL COMMENT '性别0=未知1=男2=女',
`age` int(3) DEFAULT NULL COMMENT '年龄',
`region` varchar(100) DEFAULT NULL COMMENT '区域',
`status` tinyint(3) unsigned DEFAULT 1 COMMENT '状态0=无效1=有效',
`tag_ids` varchar(255) DEFAULT NULL COMMENT '标签ID逗号分隔',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`last_used_time` int(11) DEFAULT NULL COMMENT '最后使用时间',
`createTime` int(11) DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) DEFAULT NULL COMMENT '更新时间',
`deleteTime` int(11) DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_mobile` (`mobile`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流量池表';
-- 流量来源表
CREATE TABLE `tk_traffic_source` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`traffic_id` int(10) unsigned NOT NULL COMMENT '关联流量池ID',
`plan_id` int(10) unsigned DEFAULT NULL COMMENT '关联计划ID',
`scene_id` int(10) unsigned DEFAULT NULL COMMENT '场景ID',
`channel` varchar(50) NOT NULL COMMENT '渠道poster=海报, order=订单, douyin=抖音, xiaohongshu=小红书, phone=电话, wechat=公众号, group=微信群, payment=付款码, api=API接口',
`sub_channel` varchar(50) DEFAULT NULL COMMENT '子渠道',
`source_detail` text DEFAULT NULL COMMENT '来源详情(JSON格式)',
`ip` varchar(50) DEFAULT NULL COMMENT '来源IP',
`user_agent` varchar(255) DEFAULT NULL COMMENT '用户代理',
`createTime` int(11) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_traffic` (`traffic_id`),
KEY `idx_plan` (`plan_id`),
KEY `idx_scene` (`scene_id`),
KEY `idx_channel` (`channel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流量来源表';
-- 计划执行记录表
CREATE TABLE `tk_plan_execution` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`plan_id` int(10) unsigned NOT NULL COMMENT '关联计划ID',
`traffic_id` int(10) unsigned DEFAULT NULL COMMENT '关联流量ID',
`step` tinyint(3) unsigned NOT NULL COMMENT '执行步骤1=基础配置2=加友计划3=API调用4=标签处理',
`sub_step` varchar(50) DEFAULT NULL COMMENT '子步骤标识',
`status` tinyint(3) unsigned DEFAULT 0 COMMENT '状态0=等待1=进行中2=成功3=失败',
`result` text DEFAULT NULL COMMENT '执行结果(JSON格式)',
`error` varchar(255) DEFAULT NULL COMMENT '错误信息',
`start_time` int(11) DEFAULT NULL COMMENT '开始时间',
`end_time` int(11) DEFAULT NULL COMMENT '结束时间',
`createTime` int(11) DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_plan` (`plan_id`),
KEY `idx_traffic` (`traffic_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='计划执行记录表';
-- 标签表
CREATE TABLE `tk_tag` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(50) NOT NULL COMMENT '标签名称',
`color` varchar(20) DEFAULT NULL COMMENT '标签颜色',
`type` varchar(20) DEFAULT 'traffic' COMMENT '标签类型traffic=流量标签friend=好友标签',
`count` int(11) DEFAULT 0 COMMENT '使用次数',
`status` tinyint(3) unsigned DEFAULT 1 COMMENT '状态0=停用1=启用',
`createTime` int(11) DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_name_type` (`name`, `type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='标签表';