diff --git a/Cunkebao/app/workspace/auto-like/[id]/edit/page.tsx b/Cunkebao/app/workspace/auto-like/[id]/edit/page.tsx index f51a421f..4665dbb3 100644 --- a/Cunkebao/app/workspace/auto-like/[id]/edit/page.tsx +++ b/Cunkebao/app/workspace/auto-like/[id]/edit/page.tsx @@ -2,15 +2,19 @@ import { useState, useEffect, use } from "react" import { useRouter } from "next/navigation" -import { ChevronLeft, Search } from "lucide-react" +import { ChevronLeft, Search, Users } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { StepIndicator } from "../../components/step-indicator" import { BasicSettings } from "../../components/basic-settings" import { DeviceSelectionDialog } from "../../components/device-selection-dialog" import { TagSelector } from "../../components/tag-selector" +import { WechatGroupMemberSelector } from "@/components/WechatGroupMemberSelector" +import { WechatFriendSelector } from "@/components/WechatFriendSelector" import { api, ApiResponse } from "@/lib/api" import { showToast } from "@/lib/toast" +import { WechatGroupMember } from "@/types/wechat" +import { WechatFriend } from "@/components/WechatFriendSelector" interface TaskConfig { id: number @@ -43,6 +47,11 @@ export default function EditAutoLikePage({ params }: { params: Promise<{ id: str const router = useRouter() const [currentStep, setCurrentStep] = useState(1) const [deviceDialogOpen, setDeviceDialogOpen] = useState(false) + const [isGroupMemberSelectorOpen, setIsGroupMemberSelectorOpen] = useState(false) + const [currentGroupId, setCurrentGroupId] = useState("") + const [selectedGroupMembers, setSelectedGroupMembers] = useState([]) + const [isFriendSelectorOpen, setIsFriendSelectorOpen] = useState(false) + const [selectedFriends, setSelectedFriends] = useState([]) const [loading, setLoading] = useState(true) const [formData, setFormData] = useState({ taskName: "", @@ -52,8 +61,7 @@ export default function EditAutoLikePage({ params }: { params: Promise<{ id: str contentTypes: ["text", "image", "video"], enabled: true, selectedDevices: [] as number[], - selectedTags: [] as string[], - tagOperator: "and" as "and" | "or", + friends: [] as string[], }) useEffect(() => { @@ -78,8 +86,7 @@ export default function EditAutoLikePage({ params }: { params: Promise<{ id: str contentTypes: task.config.contentTypes, enabled: task.status === 1, selectedDevices: task.config.devices, - selectedTags: task.config.targetGroups, - tagOperator: task.config.tagOperator === 1 ? "and" : "or" + friends: Array.isArray(task.config.friends) ? task.config.friends : [], }) } else { showToast(response.msg || "获取任务信息失败", "error") @@ -121,8 +128,7 @@ export default function EditAutoLikePage({ params }: { params: Promise<{ id: str contentTypes: formData.contentTypes, enabled: formData.enabled, devices: formData.selectedDevices, - targetGroups: formData.selectedTags, - tagOperator: formData.tagOperator === 'and' ? 1 : 2 + friends: formData.friends, }); if (response.code === 200) { @@ -140,6 +146,17 @@ export default function EditAutoLikePage({ params }: { params: Promise<{ id: str } }; + const handleSelectFriends = () => { + setIsFriendSelectorOpen(true) + } + + const handleSaveSelectedFriends = (friends: WechatFriend[]) => { + const ids = friends.map(f => f.id) + setSelectedFriends(friends) + handleUpdateFormData({ friends: ids }) + setIsFriendSelectorOpen(false) + } + if (loading) { return null; } @@ -207,15 +224,19 @@ export default function EditAutoLikePage({ params }: { params: Promise<{ id: str {currentStep === 3 && (
- handleUpdateFormData({ selectedTags: tags })} - onOperatorChange={(operator) => handleUpdateFormData({ tagOperator: operator })} - onBack={handlePrev} - onComplete={handleComplete} - /> - +
+ + 0 ? `已选择 ${formData.friends.length} 个好友` : ""} + /> +
+ {formData.friends.length > 0 && ( +
已选好友:{formData.friends.length} 个
+ )}
+
)} diff --git a/Cunkebao/components/WechatFriendSelector.tsx b/Cunkebao/components/WechatFriendSelector.tsx index 4219f427..a9aa5c58 100644 --- a/Cunkebao/components/WechatFriendSelector.tsx +++ b/Cunkebao/components/WechatFriendSelector.tsx @@ -10,7 +10,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { api } from "@/lib/api" import { showToast } from "@/lib/toast" -interface WechatFriend { +export interface WechatFriend { id: string nickname: string wechatId: string diff --git a/Server/application/api/controller/WebSocketController.php b/Server/application/api/controller/WebSocketController.php index ff6f4167..b07a8b58 100644 --- a/Server/application/api/controller/WebSocketController.php +++ b/Server/application/api/controller/WebSocketController.php @@ -220,8 +220,8 @@ class WebSocketController extends BaseController $maxPages = 20; // 最大页数限制为20 $currentPage = 1; // 当前页码 $allMoments = []; // 存储所有朋友圈数据 - - //过滤消息 + + //过滤消息 if (empty($wechatAccountId)) { return json_encode(['code'=>400,'msg'=>'指定账号不能为空']); } @@ -243,12 +243,39 @@ class WebSocketController extends BaseController $message = $this->sendMessage($params); Log::info('获取朋友圈信成功:' . json_encode($message, 256)); + + // 检查是否遇到频率限制 + if (isset($message['extra']) && strpos($message['extra'], '朋友圈太频繁了') !== false) { + Log::info('遇到频率限制,休息10秒后继续'); + sleep(10); + continue; + } + + // 检查返回结果 if (!isset($message['result']) || empty($message['result']) || !is_array($message['result'])) { break; } + + // 检查是否遇到旧数据 + $hasOldData = false; + foreach ($message['result'] as $moment) { + $momentId = WechatMoments::where('snsId', $moment['snsId']) + ->where('wechatAccountId', $wechatAccountId) + ->value('id'); + + if (!empty($momentId)) { + $hasOldData = true; + break; + } + } + // 如果遇到旧数据,结束本次任务 + if ($hasOldData) { + // Log::info('遇到旧数据,结束本次任务'); + // break; + } // 合并朋友圈数据 $allMoments = array_merge($allMoments, $message['result']); @@ -299,40 +326,36 @@ class WebSocketController extends BaseController * 朋友圈点赞 * @return \think\response\Json */ - public function momentInteract() + public function momentInteract($data = []) { - if ($this->request->isPost()) { - $data = $this->request->param(); + + $snsId = !empty($data['snsId']) ? $data['snsId'] : ''; + $wechatAccountId = !empty($data['wechatAccountId']) ? $data['wechatAccountId'] : ''; + $wechatFriendId = !empty($data['wechatFriendId']) ? $data['wechatFriendId'] : 0; - if (empty($data)) { - return json_encode(['code'=>400,'msg'=>'参数缺失']); - } - //过滤消息 - if (empty($data['snsId'])) { - return json_encode(['code'=>400,'msg'=>'snsId不能为空']); - } - if (empty($data['wechatAccountId'])) { - return json_encode(['code'=>400,'msg'=>'微信id不能为空']); - } + //过滤消息 + if (empty($snsId)) { + return json_encode(['code'=>400,'msg'=>'snsId不能为空']); + } + if (empty($wechatAccountId)) { + return json_encode(['code'=>400,'msg'=>'微信id不能为空']); + } - try { + try { $result = [ "cmdType" => "CmdMomentInteract", "momentInteractType" => 1, "seq" => time(), - "snsId" => $data['snsId'], - "wechatAccountId" => $data['wechatAccountId'], - "wechatFriendId" => 0, - ]; + "snsId" => $snsId, + "wechatAccountId" => $wechatAccountId, + "wechatFriendId" => $wechatFriendId, + ]; - $message = $this->sendMessage($result); - return json_encode(['code'=>200,'msg'=>'点赞成功','data'=>$message]); - } catch (\Exception $e) { - return json_encode(['code'=>500,'msg'=>$e->getMessage()]); - } - } else { - return json_encode(['code'=>400,'msg'=>'非法请求']); + $message = $this->sendMessage($result); + return json_encode(['code'=>200,'msg'=>'点赞成功','data'=>$message]); + } catch (\Exception $e) { + return json_encode(['code'=>500,'msg'=>$e->getMessage()]); } } diff --git a/Server/application/command.php b/Server/application/command.php index b8edec40..ae098aaa 100644 --- a/Server/application/command.php +++ b/Server/application/command.php @@ -27,4 +27,5 @@ return [ 'allotrule:autocreate' => 'app\command\AutoCreateAllotRulesCommand', // 自动创建分配规则 √ 'content:collect' => 'app\command\ContentCollectCommand', // 内容采集任务 √ 'moments:collect' => 'app\command\WechatMomentsCommand', // 朋友圈采集任务 + 'workbench:run' => 'app\command\WorkbenchCommand', // 工作台任务 ]; diff --git a/Server/application/command/WorkbenchCommand.php b/Server/application/command/WorkbenchCommand.php new file mode 100644 index 00000000..ce09c5a9 --- /dev/null +++ b/Server/application/command/WorkbenchCommand.php @@ -0,0 +1,77 @@ +setName('workbench:run') + ->setDescription('工作台任务队列') + ->addOption('jobId', null, Option::VALUE_OPTIONAL, '任务ID,用于区分不同实例', date('YmdHis') . rand(1000, 9999)); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('开始处理工作台任务...'); + + try { + // 获取任务ID + $jobId = $input->getOption('jobId'); + + $output->writeln('任务ID: ' . $jobId); + + // 检查队列是否已经在运行 + $queueLockKey = "queue_lock:{$this->queueName}"; + Cache::rm($queueLockKey); + if (Cache::get($queueLockKey)) { + $output->writeln("队列 {$this->queueName} 已经在运行中,跳过执行"); + Log::warning("队列 {$this->queueName} 已经在运行中,跳过执行"); + return false; + } + + // 设置队列运行锁,有效期1小时 + Cache::set($queueLockKey, $jobId, 3600); + $output->writeln("已设置队列运行锁,键名:{$queueLockKey},值:{$jobId},有效期:1小时"); + + // 将任务添加到队列 + $this->addToQueue($jobId, $queueLockKey); + + $output->writeln('工作台任务已添加到队列'); + } catch (\Exception $e) { + Log::error('工作台任务添加失败:' . $e->getMessage()); + $output->writeln('工作台任务添加失败:' . $e->getMessage()); + return false; + } + + return true; + } + + /** + * 添加任务到队列 + * @param string $jobId 任务ID + * @param string $queueLockKey 队列锁键名 + */ + public function addToQueue($jobId = '', $queueLockKey = '') + { + $data = [ + 'jobId' => $jobId, + 'queueLockKey' => $queueLockKey + ]; + + // 添加到队列,设置任务名为 workbench + Queue::push(WorkbenchJob::class, $data, $this->queueName); + } +} \ No newline at end of file diff --git a/Server/application/common/service/AuthService.php b/Server/application/common/service/AuthService.php index a2eac90e..7f7188f3 100644 --- a/Server/application/common/service/AuthService.php +++ b/Server/application/common/service/AuthService.php @@ -10,7 +10,7 @@ use think\facade\Log; class AuthService { - const TOKEN_EXPIRE = 7200; + const TOKEN_EXPIRE = 86400; protected $smsService; diff --git a/Server/application/cunkebao/controller/WorkbenchController.php b/Server/application/cunkebao/controller/WorkbenchController.php index 5516aeb0..2aee6075 100644 --- a/Server/application/cunkebao/controller/WorkbenchController.php +++ b/Server/application/cunkebao/controller/WorkbenchController.php @@ -71,8 +71,9 @@ class WorkbenchController extends Controller $config->endTime = $param['endTime']; $config->contentTypes = json_encode($param['contentTypes']); $config->devices = json_encode($param['devices']); - $config->targetGroups = json_encode($param['targetGroups']); - $config->tagOperator = $param['tagOperator']; + $config->friends = json_encode($param['friends']); + // $config->targetGroups = json_encode($param['targetGroups']); + // $config->tagOperator = $param['tagOperator']; $config->createTime = time(); $config->updateTime = time(); $config->save(); @@ -156,7 +157,7 @@ class WorkbenchController extends Controller // 定义关联关系 $with = [ 'autoLike' => function($query) { - $query->field('workbenchId,interval,maxLikes,startTime,endTime,contentTypes,devices,targetGroups'); + $query->field('workbenchId,interval,maxLikes,startTime,endTime,contentTypes,devices,friends'); }, 'momentsSync' => function($query) { $query->field('workbenchId,syncInterval,syncCount,syncType,startTime,endTime,accountType,devices,contentLibraries'); @@ -179,8 +180,9 @@ class WorkbenchController extends Controller if (!empty($item->autoLike)) { $item->config = $item->autoLike; $item->config->devices = json_decode($item->config->devices, true); - $item->config->targetGroups = json_decode($item->config->targetGroups, true); + //$item->config->targetGroups = json_decode($item->config->targetGroups, true); $item->config->contentTypes = json_decode($item->config->contentTypes, true); + $item->config->friends = json_decode($item->config->friends, true); } unset($item->autoLike,$item->auto_like); break; @@ -256,7 +258,7 @@ class WorkbenchController extends Controller // 定义关联关系 $with = [ 'autoLike' => function($query) { - $query->field('workbenchId,interval,maxLikes,startTime,endTime,contentTypes,devices,targetGroups'); + $query->field('workbenchId,interval,maxLikes,startTime,endTime,contentTypes,devices,friends'); }, 'momentsSync' => function($query) { $query->field('workbenchId,syncInterval,syncCount,syncType,startTime,endTime,accountType,devices,contentLibraries'); @@ -288,7 +290,8 @@ class WorkbenchController extends Controller if (!empty($workbench->autoLike)) { $workbench->config = $workbench->autoLike; $workbench->config->devices = json_decode($workbench->config->devices, true); - $workbench->config->targetGroups = json_decode($workbench->config->targetGroups, true); + $workbench->config->friends = json_decode($workbench->config->friends, true); + //$workbench->config->targetGroups = json_decode($workbench->config->targetGroups, true); $workbench->config->contentTypes = json_decode($workbench->config->contentTypes, true); unset($workbench->autoLike,$workbench->auto_like); } @@ -372,8 +375,9 @@ class WorkbenchController extends Controller $config->endTime = $param['endTime']; $config->contentTypes = json_encode($param['contentTypes']); $config->devices = json_encode($param['devices']); - $config->targetGroups = json_encode($param['targetGroups']); - $config->tagOperator = $param['tagOperator']; + $config->friends = json_encode($param['friends']); + // $config->targetGroups = json_encode($param['targetGroups']); + // $config->tagOperator = $param['tagOperator']; $config->updateTime = time(); $config->save(); } @@ -540,7 +544,8 @@ class WorkbenchController extends Controller $newConfig->endTime = $config->endTime; $newConfig->contentTypes = $config->contentTypes; $newConfig->devices = $config->devices; - $newConfig->targetGroups = $config->targetGroups; + $newConfig->friends = $config->friends; + //$newConfig->targetGroups = $config->targetGroups; $newConfig->save(); } break; diff --git a/Server/application/cunkebao/validate/Workbench.php b/Server/application/cunkebao/validate/Workbench.php index 9ba771d0..17860452 100644 --- a/Server/application/cunkebao/validate/Workbench.php +++ b/Server/application/cunkebao/validate/Workbench.php @@ -25,7 +25,7 @@ class Workbench extends Validate 'startTime' => 'requireIf:type,1|dateFormat:H:i', 'endTime' => 'requireIf:type,1|dateFormat:H:i', 'contentTypes' => 'requireIf:type,1|array|contentTypeEnum:text,image,video', - 'targetGroups' => 'requireIf:type,1|array', + //'targetGroups' => 'requireIf:type,1|array', // 朋友圈同步特有参数 'syncInterval' => 'requireIf:type,2|number|min:1', 'syncCount' => 'requireIf:type,2|number|min:1', diff --git a/Server/application/job/WorkbenchJob.php b/Server/application/job/WorkbenchJob.php new file mode 100644 index 00000000..d144abda --- /dev/null +++ b/Server/application/job/WorkbenchJob.php @@ -0,0 +1,460 @@ +logJobStart($jobId, $queueLockKey); + + $workbenches = $this->getActiveWorkbenches(); + if ($workbenches->isEmpty()) { + $this->handleEmptyWorkbenches($job, $queueLockKey); + return true; + } + + $this->processWorkbenches($workbenches); + + $this->handleJobSuccess($job, $queueLockKey); + return true; + + } catch (\Exception $e) { + return $this->handleJobError($e, $job, $queueLockKey); + } + } + + /** + * 获取活跃的工作台 + * @return \think\Collection + */ + protected function getActiveWorkbenches() + { + return Workbench::where([ + ['status', '=', 1], + ['isDel', '=', 0] + ])->order('id DESC')->select(); + } + + /** + * 处理空工作台情况 + * @param Job $job + * @param string $queueLockKey + */ + protected function handleEmptyWorkbenches(Job $job, $queueLockKey) + { + Log::info('没有需要处理的工作台任务'); + $job->delete(); + Cache::rm($queueLockKey); + } + + /** + * 处理工作台列表 + * @param \think\Collection $workbenches + */ + protected function processWorkbenches($workbenches) + { + foreach ($workbenches as $workbench) { + try { + $this->processSingleWorkbench($workbench); + } catch (\Exception $e) { + Log::error("处理工作台 {$workbench->id} 失败: " . $e->getMessage()); + } + } + } + + /** + * 处理单个工作台 + * @param Workbench $workbench + */ + protected function processSingleWorkbench($workbench) + { + $config = $this->getWorkbenchConfig($workbench); + if (!$config) { + Log::error("工作台 {$workbench->id} 配置获取失败"); + return; + } + + $handler = $this->getWorkbenchHandler($workbench->type); + if ($handler) { + $handler($workbench, $config); + } + } + + /** + * 获取工作台处理器 + * @param int $type + * @return callable|null + */ + protected function getWorkbenchHandler($type) + { + $handlers = [ + self::TYPE_AUTO_LIKE => [$this, 'handleAutoLike'], + self::TYPE_MOMENTS_SYNC => [$this, 'handleMomentsSync'], + self::TYPE_GROUP_PUSH => [$this, 'handleGroupPush'], + self::TYPE_GROUP_CREATE => [$this, 'handleGroupCreate'] + ]; + + return $handlers[$type] ?? null; + } + + /** + * 处理自动点赞任务 + * @param Workbench $workbench + * @param WorkbenchAutoLike $config + */ + protected function handleAutoLike($workbench, $config) + { + if (!$this->validateAutoLikeConfig($workbench, $config)) { + return; + } + + $likeCount = $this->getTodayLikeCount($workbench, $config); + if ($likeCount >= $config['maxLikes']) { + Log::info("工作台 {$workbench->id} 点赞次数已达上限"); + return; + } + + if (!$this->isWithinLikeTimeRange($config)) { + return; + } + + $friendList = $this->getFriendList($config['friends']); + foreach ($friendList as $friend) { + $this->processFriendMoments($workbench, $config, $friend, $likeCount); + } + } + + /** + * 验证自动点赞配置 + * @param Workbench $workbench + * @param WorkbenchAutoLike $config + * @return bool + */ + protected function validateAutoLikeConfig($workbench, $config) + { + $requiredFields = ['friends', 'contentTypes', 'interval', 'maxLikes', 'startTime', 'endTime']; + foreach ($requiredFields as $field) { + if (empty($config[$field])) { + Log::error("工作台 {$workbench->id} 配置字段 {$field} 为空"); + return false; + } + } + + $friends = json_decode($config['friends'], true); + if (!is_array($friends) || empty($friends)) { + Log::error("工作台 {$workbench->id} 点赞的好友为空"); + return false; + } + + return true; + } + + /** + * 获取今日点赞次数 + * @param Workbench $workbench + * @param WorkbenchAutoLike $config + * @return int + */ + protected function getTodayLikeCount($workbench, $config) + { + return Db::name('workbench_auto_like_item') + ->where('workbenchId', $workbench->id) + ->whereTime('createTime', 'between', [ + strtotime(date('Y-m-d') . ' ' . $config['startTime'] . ':00'), + strtotime(date('Y-m-d') . ' ' . $config['endTime'] . ':00') + ]) + ->count(); + } + + /** + * 检查是否在点赞时间范围内 + * @param WorkbenchAutoLike $config + * @return bool + */ + protected function isWithinLikeTimeRange($config) + { + $currentTime = date('H:i'); + if ($currentTime < $config['startTime'] || $currentTime > $config['endTime']) { + Log::info("当前时间 {$currentTime} 不在点赞时间范围内 ({$config['startTime']} - {$config['endTime']})"); + return false; + } + return true; + } + + /** + * 获取好友列表 + * @param string $friendsJson + * @return array + */ + protected function getFriendList($friendsJson) + { + $friends = json_decode($friendsJson, true); + return Db::table('s2_company_account') + ->alias('ca') + ->join(['s2_wechat_account' => 'wa'], 'ca.id = wa.deviceAccountId') + ->join(['s2_wechat_friend' => 'wf'], 'ca.id = wf.accountId') + ->where('ca.passwordLocal', '<>', '') + ->where([ + 'ca.status' => 0, + 'wf.isDeleted' => 0, + 'wa.deviceAlive' => 1, + 'wa.wechatAlive' => 1 + ]) + ->whereIn('wf.id', $friends) + ->field([ + 'ca.id as accountId', + 'ca.userName', + 'ca.passwordLocal', + 'wf.id as friendId', + 'wf.wechatId', + 'wf.wechatAccountId' + ]) + ->group('wf.wechatAccountId DESC') + ->order('ca.id DESC') + ->select() + ->toArray(); + } + + /** + * 处理好友朋友圈 + * @param Workbench $workbench + * @param WorkbenchAutoLike $config + * @param array $friend + * @param int &$likeCount + */ + protected function processFriendMoments($workbench, $config, $friend, &$likeCount) + { + $moments = $this->getUnlikedMoments($friend['friendId']); + if ($moments->isEmpty()) { + Log::info("好友 {$friend['friendId']} 没有需要点赞的朋友圈"); + return; + } + + foreach ($moments as $moment) { + if ($likeCount >= $config['maxLikes']) { + break; + } + + $this->likeMoment($workbench, $config, $friend, $moment, $likeCount); + } + } + + /** + * 获取未点赞的朋友圈 + * @param int $friendId + * @return \think\Collection + */ + protected function getUnlikedMoments($friendId) + { + return Db::table('s2_wechat_moments') + ->alias('wm') + ->join('workbench_auto_like_item wali', 'wali.momentsId = wm.id', 'left') + ->where([ + ['wm.wechatFriendId', '=', $friendId], + ['wali.id', 'null', null] + ]) + ->field('wm.id, wm.snsId') + ->order('wm.id DESC') + ->select(); + } + + /** + * 点赞朋友圈 + * @param Workbench $workbench + * @param WorkbenchAutoLike $config + * @param array $friend + * @param array $moment + * @param int &$likeCount + */ + protected function likeMoment($workbench, $config, $friend, $moment, &$likeCount) + { + try { + $wsController = new WebSocketController([ + 'userName' => $friend['userName'], + 'password' => localDecrypt($friend['passwordLocal']), + 'accountId' => $friend['accountId'] + ]); + + $result = $wsController->momentInteract([ + 'snsId' => $moment['snsId'], + 'wechatAccountId' => $friend['wechatAccountId'], + ]); + + $result = json_decode($result, true); + + if ($result['code'] == 200) { + $this->recordLike($workbench, $moment, $friend); + $likeCount++; + sleep($config['interval']); + } else { + Log::error("工作台 {$workbench->id} 点赞失败: " . ($result['msg'] ?? '未知错误')); + } + } catch (\Exception $e) { + Log::error("工作台 {$workbench->id} 点赞异常: " . $e->getMessage()); + } + } + + /** + * 记录点赞 + * @param Workbench $workbench + * @param array $moment + * @param array $friend + */ + protected function recordLike($workbench, $moment, $friend) + { + Db::name('workbench_auto_like_item')->insert([ + 'workbenchId' => $workbench->id, + 'momentsId' => $moment['id'], + 'snsId' => $moment['snsId'], + 'wechatAccountId' => $friend['wechatAccountId'], + 'wechatFriendId' => $friend['friendId'], + 'createTime' => time() + ]); + Log::info("工作台 {$workbench->id} 点赞成功: {$moment['snsId']}"); + } + + /** + * 记录任务开始 + * @param string $jobId + * @param string $queueLockKey + */ + protected function logJobStart($jobId, $queueLockKey) + { + Log::info('开始处理工作台任务: ' . json_encode([ + 'jobId' => $jobId, + 'queueLockKey' => $queueLockKey + ])); + } + + /** + * 处理任务成功 + * @param Job $job + * @param string $queueLockKey + */ + protected function handleJobSuccess($job, $queueLockKey) + { + $job->delete(); + Cache::rm($queueLockKey); + Log::info('工作台任务执行成功'); + } + + /** + * 处理任务错误 + * @param \Exception $e + * @param Job $job + * @param string $queueLockKey + * @return bool + */ + protected function handleJobError(\Exception $e, $job, $queueLockKey) + { + Log::error('工作台任务异常:' . $e->getMessage()); + + if (!empty($queueLockKey)) { + Cache::rm($queueLockKey); + Log::info("由于异常释放队列锁: {$queueLockKey}"); + } + + if ($job->attempts() > self::MAX_RETRY_ATTEMPTS) { + $job->delete(); + } else { + $job->release(Config::get('queue.failed_delay', 10)); + } + + return false; + } + + /** + * 获取工作台配置 + * @param Workbench $workbench 工作台实例 + * @return mixed + */ + protected function getWorkbenchConfig($workbench) + { + switch ($workbench->type) { + case self::TYPE_AUTO_LIKE: + return WorkbenchAutoLike::where('workbenchId', $workbench->id)->find(); + + case self::TYPE_MOMENTS_SYNC: + return WorkbenchMomentsSync::where('workbenchId', $workbench->id)->find(); + + case self::TYPE_GROUP_PUSH: + return WorkbenchGroupPush::where('workbenchId', $workbench->id)->find(); + + case self::TYPE_GROUP_CREATE: + return WorkbenchGroupCreate::where('workbenchId', $workbench->id)->find(); + + default: + return null; + } + } + + /** + * 处理朋友圈同步任务 + * @param Workbench $workbench 工作台实例 + * @param WorkbenchMomentsSync $config 配置实例 + */ + protected function handleMomentsSync($workbench, $config) + { + // TODO: 实现朋友圈同步逻辑 + Log::info("处理朋友圈同步任务: {$workbench->id}"); + } + + /** + * 处理群消息推送任务 + * @param Workbench $workbench 工作台实例 + * @param WorkbenchGroupPush $config 配置实例 + */ + protected function handleGroupPush($workbench, $config) + { + // TODO: 实现群消息推送逻辑 + Log::info("处理群消息推送任务: {$workbench->id}"); + } + + /** + * 处理自动建群任务 + * @param Workbench $workbench 工作台实例 + * @param WorkbenchGroupCreate $config 配置实例 + */ + protected function handleGroupCreate($workbench, $config) + { + // TODO: 实现自动建群逻辑 + Log::info("处理自动建群任务: {$workbench->id}"); + } +} \ No newline at end of file