diff --git a/Server/application/devices/model/Device.php b/Server/application/devices/model/Device.php index 91a41857..49df0cf0 100755 --- a/Server/application/devices/model/Device.php +++ b/Server/application/devices/model/Device.php @@ -11,30 +11,7 @@ class Device extends Model { // 设置表名 protected $name = 'device'; - - // 设置主键 - protected $pk = 'id'; - - // 自动写入时间戳 - protected $autoWriteTimestamp = 'int'; - - // 定义时间戳字段名 - protected $createTime = 'createTime'; - protected $updateTime = 'updateTime'; - protected $deleteTime = 'deleteTime'; - - // 定义字段类型 - protected $type = [ - 'id' => 'integer', - 'createTime' => 'integer', - 'updateTime' => 'integer', - 'deleteTime' => 'integer', - 'alive' => 'integer', - 'isDeleted' => 'integer', - 'tenantId' => 'integer', - 'groupId' => 'integer' - ]; - + /** * 获取设备总数 * @param array $where 查询条件 diff --git a/Server/application/devices/model/DeviceHandleLog.php b/Server/application/devices/model/DeviceHandleLog.php index 70ef7b11..5964e23a 100755 --- a/Server/application/devices/model/DeviceHandleLog.php +++ b/Server/application/devices/model/DeviceHandleLog.php @@ -11,27 +11,7 @@ class DeviceHandleLog extends Model { // 设置表名 protected $name = 'device_handle_log'; - protected $prefix = 'tk_'; - - // 设置主键 - protected $pk = 'id'; - - // 自动写入时间戳 - protected $autoWriteTimestamp = 'datetime'; - - // 定义时间戳字段名 - protected $createTime = 'createTime'; - protected $updateTime = false; - - // 定义字段类型 - protected $type = [ - 'id' => 'integer', - 'userId' => 'integer', - 'deviceId' => 'integer', - 'companyId' => 'integer', - 'createTime' => 'datetime' - ]; - + /** * 添加设备操作日志 * @param array $data 日志数据 diff --git a/Server/application/devices/model/DeviceWechatLogin.php b/Server/application/devices/model/DeviceWechatLogin.php index 138d5cd0..cb7f39e0 100755 --- a/Server/application/devices/model/DeviceWechatLogin.php +++ b/Server/application/devices/model/DeviceWechatLogin.php @@ -11,23 +11,6 @@ class DeviceWechatLogin extends Model // 设置表名 protected $name = 'device_wechat_login'; - // 设置主键 - protected $pk = 'id'; - - // 自动写入时间戳 - protected $autoWriteTimestamp = 'int'; - - // 定义时间戳字段名 - protected $createTime = 'createTime'; - - // 定义字段类型 - protected $type = [ - 'id' => 'integer', - 'deviceId' => 'integer', - 'companyId' => 'integer', - 'createTime' => 'integer' - ]; - /** * 查询设备关联的微信ID列表 * @param int $deviceId 设备ID diff --git a/Server/application/devices/model/FriendTask.php b/Server/application/devices/model/FriendTask.php index 899ad0b6..6b9e47c4 100755 --- a/Server/application/devices/model/FriendTask.php +++ b/Server/application/devices/model/FriendTask.php @@ -14,44 +14,6 @@ class FriendTask extends Model */ protected $table = 'tk_friend_task'; - /** - * 主键 - * @var string - */ - protected $pk = 'id'; - - /** - * 自动写入时间戳 - * @var bool - */ - protected $autoWriteTimestamp = true; - - /** - * 创建时间字段 - * @var string - */ - protected $createTime = 'createTime'; - - /** - * 更新时间字段 - * @var string - */ - protected $updateTime = 'updateTime'; - - /** - * 字段类型 - * @var array - */ - protected $type = [ - 'id' => 'integer', - 'tenantId' => 'integer', - 'operatorAccountId' => 'integer', - 'status' => 'integer', - 'wechatAccountId' => 'integer', - 'createTime' => 'integer', - 'updateTime' => 'integer' - ]; - /** * 状态常量 */ diff --git a/Server/application/devices/model/WechatAccount.php b/Server/application/devices/model/WechatAccount.php index 11aaaf78..8f65332f 100755 --- a/Server/application/devices/model/WechatAccount.php +++ b/Server/application/devices/model/WechatAccount.php @@ -12,36 +12,6 @@ class WechatAccount extends Model // 设置表名 protected $name = 'wechat_account'; - // 设置主键 - protected $pk = 'id'; - - // 自动写入时间戳 - protected $autoWriteTimestamp = 'datetime'; - - // 定义时间戳字段名 - protected $createTime = 'createTime'; - protected $updateTime = 'updateTime'; - - // 定义字段类型 - protected $type = [ - 'id' => 'integer', - 'deviceAccountId' => 'integer', - 'keFuAlive' => 'integer', - 'deviceAlive' => 'integer', - 'wechatAlive' => 'integer', - 'yesterdayMsgCount' => 'integer', - 'sevenDayMsgCount' => 'integer', - 'thirtyDayMsgCount' => 'integer', - 'totalFriend' => 'integer', - 'maleFriend' => 'integer', - 'femaleFriend' => 'integer', - 'gender' => 'integer', - 'currentDeviceId' => 'integer', - 'isDeleted' => 'integer', - 'groupId' => 'integer', - 'status' => 'integer' - ]; - /** * 获取在线微信账号数量 * diff --git a/Server/application/devices/model/WechatFriend.php b/Server/application/devices/model/WechatFriend.php index c166d922..a9fdb751 100644 --- a/Server/application/devices/model/WechatFriend.php +++ b/Server/application/devices/model/WechatFriend.php @@ -11,34 +11,7 @@ class WechatFriend extends Model { // 设置表名 protected $name = 'wechat_friend'; - protected $prefix = 'tk_'; - - // 设置主键 - protected $pk = 'id'; - - // 自动写入时间戳 - protected $autoWriteTimestamp = 'datetime'; - - // 定义时间戳字段名 - protected $createTime = 'createTime'; - protected $updateTime = 'updateTime'; - - // 定义字段类型 - protected $type = [ - 'id' => 'integer', - 'wechatAccountId' => 'integer', - 'gender' => 'integer', - 'addFrom' => 'integer', - 'isDeleted' => 'integer', - 'isPassed' => 'integer', - 'accountId' => 'integer', - 'groupId' => 'integer', - 'labels' => 'json', - 'deleteTime' => 'datetime', - 'passTime' => 'datetime', - 'createTime' => 'datetime' - ]; - + /** * 根据微信账号ID获取好友列表 * diff --git a/Server/application/plan/config/route.php b/Server/application/plan/config/route.php index d6bee8cf..6cd861c8 100644 --- a/Server/application/plan/config/route.php +++ b/Server/application/plan/config/route.php @@ -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'); // 获取场景详情 }); // 流量标签相关 diff --git a/Server/application/plan/model/PlanScene.php b/Server/application/plan/model/PlanScene.php index de84e9e0..14787132 100644 --- a/Server/application/plan/model/PlanScene.php +++ b/Server/application/plan/model/PlanScene.php @@ -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(); - } } \ No newline at end of file diff --git a/Server/application/plan/model/PlanTask.php b/Server/application/plan/model/PlanTask.php index df854b42..7b550cd4 100644 --- a/Server/application/plan/model/PlanTask.php +++ b/Server/application/plan/model/PlanTask.php @@ -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'); - } } \ No newline at end of file diff --git a/Server/application/plan/model/TrafficPool.php b/Server/application/plan/model/TrafficPool.php new file mode 100644 index 00000000..ff971597 --- /dev/null +++ b/Server/application/plan/model/TrafficPool.php @@ -0,0 +1,13 @@ + 'integer', - 'tagName' => 'string', - 'companyId' => 'integer', - 'createTime' => 'integer', - 'deleteTime' => 'integer' - ]; - + /** * 获取标签列表,支持分页和搜索 * diff --git a/Server/application/plan/service/SceneHandler.php b/Server/application/plan/service/SceneHandler.php deleted file mode 100644 index 56f6ca0f..00000000 --- a/Server/application/plan/service/SceneHandler.php +++ /dev/null @@ -1,239 +0,0 @@ - 处理器名称 - 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() - ]; - } - } -} \ No newline at end of file diff --git a/Server/application/plan/service/TaskRunner.php b/Server/application/plan/service/TaskRunner.php deleted file mode 100644 index 5abaa558..00000000 --- a/Server/application/plan/service/TaskRunner.php +++ /dev/null @@ -1,675 +0,0 @@ -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 - ] - ]; - } -} \ No newline at end of file diff --git a/Server/application/plan/sql/tables.sql b/Server/application/plan/sql/tables.sql deleted file mode 100644 index 58c2312b..00000000 --- a/Server/application/plan/sql/tables.sql +++ /dev/null @@ -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='标签表'; \ No newline at end of file