diff --git a/Server/application/api/config/route.php b/Server/application/api/config/route.php index 73460811..55f29341 100644 --- a/Server/application/api/config/route.php +++ b/Server/application/api/config/route.php @@ -90,6 +90,10 @@ Route::group('v1', function () { // AllotRule控制器路由 Route::group('allot-rule', function () { Route::get('list', 'app\\api\\controller\\AllotRuleController@getAllRules'); // 获取所有分配规则 √ + Route::post('create', 'app\\api\\controller\\AllotRuleController@createRule');// 创建分配规则 √ + Route::post('edit', 'app\\api\\controller\\AllotRuleController@updateRule');// 编辑分配规则 √ + Route::delete('del', 'app\\api\\controller\\AllotRuleController@deleteRule');// 删除分配规则 √ + Route::get('autoCreate', 'app\\api\\controller\\AllotRuleController@autoCreateAllotRules');// 自动创建分配规则 √ }); }); }); \ No newline at end of file diff --git a/Server/application/api/controller/AllotRuleController.php b/Server/application/api/controller/AllotRuleController.php index 9c3ec1d8..db590d67 100644 --- a/Server/application/api/controller/AllotRuleController.php +++ b/Server/application/api/controller/AllotRuleController.php @@ -4,9 +4,17 @@ namespace app\api\controller; use app\api\model\CompanyAccountModel; use app\api\model\AllotRuleModel; +use app\api\model\WechatAccountModel; +use think\Queue; +use app\job\AllotRuleListJob; +use think\Db; class AllotRuleController extends BaseController { + /************************************ + * 分配规则列表和数据同步相关方法 + ************************************/ + /** * 获取所有分配规则 * @param bool $isInner 是否为内部调用 @@ -35,6 +43,7 @@ class AllotRuleController extends BaseController // 保存数据到数据库 if (!empty($response)) { + AllotRuleModel::where('1=1')->update(['isDel' => 1]); foreach ($response as $item) { $this->saveAllotRule($item); } @@ -53,7 +62,270 @@ class AllotRuleController extends BaseController } } } + + /** + * 手动触发分配规则同步任务 + * @return \think\response\Json + */ + public function startJob() + { + try { + $data = [ + 'time' => time() + ]; + + // 添加到队列,设置任务名为 allotrule_list + $isSuccess = Queue::push(AllotRuleListJob::class, $data, 'allotrule_list'); + + if ($isSuccess !== false) { + return successJson([], '分配规则同步任务已添加到队列'); + } else { + return errorJson('添加分配规则同步任务到队列失败'); + } + } catch (\Exception $e) { + return errorJson('触发分配规则同步任务失败:' . $e->getMessage()); + } + } + + /************************************ + * 分配规则CRUD操作方法 + ************************************/ + + /** + * 创建分配规则 + * @param array $data 请求数据 + * @param bool $isInner 是否为内部调用 + * @return \think\response\Json + */ + public function createRule($data = [], $isInner = false) + { + // 获取授权token + $authorization = trim($this->request->header('authorization', $this->authorization)); + if (empty($authorization)) { + if ($isInner) { + return json_encode(['code' => 500, 'msg' => '缺少授权信息']); + } else { + return errorJson('缺少授权信息'); + } + } + try { + $wechatData = input('wechatData', '[]') ?: []; + $priorityStrategy = input('priorityStrategy', '[]') ?: []; + + // 构建请求数据 + $params = [ + 'allotType' => input('allotType', 1), + 'kefuRange' => input('kefuRange', 5), + 'wechatRange' => input('wechatRange',3), + 'kefuData' => input('kefuData', '[]') ?: [], + 'wechatData' => $wechatData, + 'labels' => input('labels', '[]') ?: [], + 'priorityStrategy' => json_encode($priorityStrategy,256) + ]; + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求到微信接口 + $result = requestCurl($this->baseUrl . 'api/AllotRule/new', $params, 'POST', $header, 'json'); + if (empty($result)) { + // 异步更新所有规则列表 + AllotRuleModel::where('1=1')->update(['isDel' => 1]); + $this->getAllRules(); + $res = AllotRuleModel::where('isDel',0)->order('id','DESC')->find(); + $res->departmentId = !empty($data['departmentId']) ? $data['departmentId'] : 0; + $res->save(); + return successJson($res, '创建分配规则成功'); + } else { + return errorJson($result); + } + } catch (\Exception $e) { + return errorJson('创建分配规则失败:' . $e->getMessage()); + } + } + + /** + * 更新分配规则 + * @param array $data 请求数据 + * @param bool $isInner 是否为内部调用 + * @return \think\response\Json + */ + public function updateRule($data = [], $isInner = false) + { + // 获取授权token + $authorization = trim($this->request->header('authorization', $this->authorization)); + if (empty($authorization)) { + return errorJson('缺少授权信息'); + } + + try { + // 获取请求参数 + $id = !empty($data['id']) ? $data['id'] : input('id',0); + if (empty($id)) { + return errorJson('规则ID不能为空'); + } + + $rule = AllotRuleModel::where('id', $id)->find(); + if (empty($rule)) { + return errorJson('规则不存在'); + } + + // 构建请求数据 + $params = [ + 'id' => $id, + 'tenantId' => $rule['tenantId'], + 'allotType' => !empty($data['allotType']) ? $data['allotType'] : input('allotType',1), + 'allotOnline' => !empty($data['allotOnline']) ? $data['allotOnline'] : input('allotOnline',false), + 'kefuRange' => !empty($data['kefuRange']) ? $data['kefuRange'] : input('kefuRange',5), + 'wechatRange' => !empty($data['wechatRange']) ? $data['wechatRange'] : input('wechatRange',3), + 'kefuData' => !empty($data['kefuData']) ? $data['kefuData'] : input('kefuData',[]), + 'wechatData' => !empty($data['wechatData']) ? $data['wechatData'] : input('wechatData',[]), + 'labels' => !empty($data['labels']) ? $data['labels'] : input('labels',[]), + 'priorityStrategy' => json_encode(!empty($data['priorityStrategy']) ? $data['priorityStrategy'] : input('priorityStrategy',[]),256), + ]; + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求到微信接口 + $result = requestCurl($this->baseUrl . 'api/AllotRule/update', $params, 'PUT', $header, 'json'); + + if (empty($result)) { + $this->getAllRules(); + return successJson([], '更新分配规则成功'); + } else { + return errorJson($result); + } + } catch (\Exception $e) { + return errorJson('更新分配规则失败:' . $e->getMessage()); + } + } + + /** + * 删除分配规则 + * @param array $data 请求数据 + * @param bool $isInner 是否为内部调用 + * @return \think\response\Json + */ + public function deleteRule($data = [], $isInner = false) + { + // 获取授权token + $authorization = trim($this->request->header('authorization', $this->authorization)); + if (empty($authorization)) { + if ($isInner) { + return json_encode(['code' => 500, 'msg' => '缺少授权信息']); + } else { + return errorJson('缺少授权信息'); + } + } + + try { + // 获取请求参数 + $id = !empty($data['id']) ? $data['id'] : input('id', 0); + if (empty($id)) { + return errorJson('规则ID不能为空'); + } + + // 检查规则是否存在 + $rule = AllotRuleModel::where('id', $id)->find(); + if (empty($rule)) { + return errorJson('规则不存在'); + } + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'plain'); + + // 发送请求到微信接口 + $result = requestCurl($this->baseUrl . 'api/AllotRule/delete?id=' . $id, [], 'DELETE', $header); + $response = handleApiResponse($result); + + if (empty($response)) { + // 删除成功,同步本地数据库 + AllotRuleModel::where('id', $id)->update(['isDel' => 1]); + return successJson([], '删除分配规则成功'); + } else { + return errorJson($response); + } + } catch (\Exception $e) { + return errorJson('删除分配规则失败:' . $e->getMessage()); + } + } + + /************************************ + * 数据查询相关方法 + ************************************/ + + /** + * 自动创建分配规则 + * 根据今日新增微信账号自动创建或更新分配规则 + * @param array $data 请求数据 + * @param bool $isInner 是否为内部调用 + * @return \think\response\Json|string + */ + public function autoCreateAllotRules($data = [], $isInner = false) + { + try { + // 获取今天的开始时间和结束时间 + $todayStart = strtotime(date('Y-m-d 00:00:00')); + $todayEnd = strtotime(date('Y-m-d 23:59:59')); + + // 查询今天新增的微信账号 + $newAccounts = Db::table('s2_wechat_account') + ->alias('wa') + ->join(['s2_company_account' => 'ca'], 'wa.deviceAccountId = ca.id', 'LEFT') + ->field([ + 'wa.id', + 'wa.wechatId', + 'wa.nickname', + 'wa.deviceAccountId', + 'wa.alias', + 'wa.createTime', + 'ca.departmentId', + ]) + ->where('wa.createTime', 'BETWEEN', [$todayStart, $todayEnd]) + ->where('wa.isDeleted', 0) + ->order('wa.createTime', 'DESC') + ->select(); + + // 没有今日新增微信账号,直接返回 + if (empty($newAccounts)) { + $result = ['code' => 200, 'msg' => '没有今日新增微信账号,无需创建分配规则', 'data' => []]; + return $isInner ? json_encode($result) : successJson([], '没有今日新增微信账号,无需创建分配规则'); + } + + // 获取所有分配规则 + foreach ($newAccounts as $key => $value) { + $rules = AllotRuleModel::where(['departmentId' => $value['departmentId'],'isDel' => 0])->order('id','DESC')->find(); + if (!empty($rules)) { + $wechatData = json_decode($rules['wechatData'], true); + if (!in_array($value['id'], $wechatData)) { + $wechatData[] = $value['id']; + $kefuData = [$value['deviceAccountId']]; + $this->updateRule(['id' => $rules['id'],'wechatData' => $wechatData,'kefuData' => $kefuData],true); + } + }else{ + $wechatData =[$value['id']]; + $kefuData = [$value['deviceAccountId']]; + $this->createRule(['wechatData' => $wechatData,'kefuData' => $kefuData,'departmentId' => $value['departmentId']],true); + } + } + $result = ['code' => 200, 'msg' => '自动分配规则成功', 'data' => []]; + return $isInner ? json_encode($result) : successJson([], '自动分配规则成功'); + } catch (\Exception $e) { + $error = '自动分配规则失败: ' . $e->getMessage(); + $result = ['code' => 500, 'msg' => $error]; + return $isInner ? json_encode($result) : errorJson($error); + } + } + + /************************************ + * 辅助方法 + ************************************/ + /** * 保存分配规则数据到数据库 * @param array $item 分配规则数据 @@ -68,13 +340,14 @@ class AllotRuleController extends BaseController 'kefuRange' => isset($item['kefuRange']) ? $item['kefuRange'] : 0, 'wechatRange' => isset($item['wechatRange']) ? $item['wechatRange'] : 0, 'kefuData' => isset($item['kefuData']) ? json_encode($item['kefuData']) : json_encode([]), - 'wechatIds' => isset($item['wechatIds']) ? json_encode($item['wechatIds']) : json_encode([]), + 'wechatData' => isset($item['wechatData']) ? json_encode($item['wechatData']) : json_encode([]), 'labels' => isset($item['labels']) ? json_encode($item['labels']) : json_encode([]), 'priorityStrategy' => isset($item['priorityStrategy']) ? json_encode($item['priorityStrategy']) : json_encode([]), 'sortIndex' => isset($item['sortIndex']) ? $item['sortIndex'] : 0, 'creatorAccountId' => isset($item['creatorAccountId']) ? $item['creatorAccountId'] : 0, 'createTime' => isset($item['createTime']) ? (strtotime($item['createTime']) ?: 0) : 0, 'ruleName' => isset($item['ruleName']) ? $item['ruleName'] : '', + 'isDel' => 0, ]; // 使用ID作为唯一性判断 diff --git a/Server/application/api/controller/WebSocketController.php b/Server/application/api/controller/WebSocketController.php index bab39101..946e9ff9 100644 --- a/Server/application/api/controller/WebSocketController.php +++ b/Server/application/api/controller/WebSocketController.php @@ -18,7 +18,7 @@ class WebSocketController extends BaseController public function __construct() { parent::__construct(); - $this->authorized = $this->request->header('authorization', $this->authorization); + $this->authorized = $this->request->header('authorization', ''); $this->accountId = $this->request->param('accountId', ''); if (empty($this->authorized) || empty($this->accountId)) { $data['authorized'] = $this->authorized; diff --git a/Server/application/command.php b/Server/application/command.php index f68f6471..171211bc 100644 --- a/Server/application/command.php +++ b/Server/application/command.php @@ -21,6 +21,8 @@ return [ 'department:list' => 'app\command\DepartmentListCommand', // 部门列表 √ 'content:sync' => 'app\command\SyncContentCommand', // 同步内容库 √ 'groupFriends:list' => 'app\command\GroupFriendsCommand', // 微信群好友列表 - 'allotFriends:run' => 'app\command\AllotFriendCommand', // 自动分配微信好友 - 'allotChatroom:run' => 'app\command\AllotChatroomCommand', // 自动分配微信群聊 + // 'allotFriends:run' => 'app\command\AllotFriendCommand', // 自动分配微信好友 + // 'allotChatroom:run' => 'app\command\AllotChatroomCommand', // 自动分配微信群聊 + 'allotrule:list' => 'app\command\AllotRuleListCommand', // 分配规则列表 √ + 'allotrule:autocreate' => 'app\command\AutoCreateAllotRulesCommand', // 自动创建分配规则 √ ]; diff --git a/Server/application/command/AllotRuleListCommand.php b/Server/application/command/AllotRuleListCommand.php new file mode 100644 index 00000000..4ef93a54 --- /dev/null +++ b/Server/application/command/AllotRuleListCommand.php @@ -0,0 +1,50 @@ +setName('allotrule:list') + ->setDescription('获取分配规则列表,自动同步到数据库'); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('开始处理分配规则列表任务...'); + + try { + // 将任务添加到队列 + $this->addToQueue(); + + $output->writeln('分配规则列表任务已添加到队列'); + } catch (\Exception $e) { + Log::error('分配规则列表任务添加失败:' . $e->getMessage()); + $output->writeln('分配规则列表任务添加失败:' . $e->getMessage()); + return false; + } + + return true; + } + + /** + * 添加任务到队列 + */ + protected function addToQueue() + { + $data = [ + 'time' => time() + ]; + + // 添加到队列,设置任务名为 allotrule_list + Queue::push(AllotRuleListJob::class, $data, 'allotrule_list'); + } +} \ No newline at end of file diff --git a/Server/application/command/AutoCreateAllotRulesCommand.php b/Server/application/command/AutoCreateAllotRulesCommand.php new file mode 100644 index 00000000..3f54726b --- /dev/null +++ b/Server/application/command/AutoCreateAllotRulesCommand.php @@ -0,0 +1,50 @@ +setName('allotrule:autocreate') + ->setDescription('自动创建微信分配规则'); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('开始处理自动创建分配规则任务...'); + + try { + // 将任务添加到队列 + $this->addToQueue(); + + $output->writeln('自动创建分配规则任务已添加到队列'); + } catch (\Exception $e) { + Log::error('自动创建分配规则任务添加失败:' . $e->getMessage()); + $output->writeln('自动创建分配规则任务添加失败:' . $e->getMessage()); + return false; + } + + return true; + } + + /** + * 添加任务到队列 + */ + protected function addToQueue() + { + $data = [ + 'time' => time() + ]; + + // 添加到队列,设置任务名为 autocreate_allotrule + Queue::push(AutoCreateAllotRulesJob::class, $data, 'autocreate_allotrule'); + } +} \ No newline at end of file diff --git a/Server/application/job/AllotRuleListJob.php b/Server/application/job/AllotRuleListJob.php new file mode 100644 index 00000000..52a64373 --- /dev/null +++ b/Server/application/job/AllotRuleListJob.php @@ -0,0 +1,75 @@ +processAllotRuleList($data, $job->attempts())) { + $job->delete(); + Log::info('分配规则列表任务执行成功'); + } else { + if ($job->attempts() > 3) { + // 超过重试次数,删除任务 + Log::error('分配规则列表任务执行失败,已超过重试次数'); + $job->delete(); + } else { + // 任务失败,重新放回队列 + Log::warning('分配规则列表任务执行失败,重试次数:' . $job->attempts()); + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } catch (\Exception $e) { + // 出现异常,记录日志 + Log::error('分配规则列表任务异常:' . $e->getMessage()); + if ($job->attempts() > 3) { + $job->delete(); + } else { + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } + + /** + * 处理分配规则列表获取 + * @param array $data 任务数据 + * @param int $attempts 重试次数 + * @return bool + */ + protected function processAllotRuleList($data, $attempts) + { + Log::info('开始获取分配规则列表'); + + // 实例化控制器 + $allotRuleController = new AllotRuleController(); + + // 调用分配规则列表获取方法 + $result = $allotRuleController->getAllRules([], true); + $response = json_decode($result, true); + + // 判断是否成功 + if ($response['code'] == 200) { + Log::info('获取分配规则列表成功,共获取 ' . (isset($response['data']) ? count($response['data']) : 0) . ' 条记录'); + return true; + } else { + $errorMsg = isset($response['msg']) ? $response['msg'] : '未知错误'; + Log::error('获取分配规则列表失败:' . $errorMsg); + return false; + } + } +} \ No newline at end of file diff --git a/Server/application/job/AutoCreateAllotRulesJob.php b/Server/application/job/AutoCreateAllotRulesJob.php new file mode 100644 index 00000000..5129eba9 --- /dev/null +++ b/Server/application/job/AutoCreateAllotRulesJob.php @@ -0,0 +1,75 @@ +processAutoCreateAllotRules($data, $job->attempts())) { + $job->delete(); + Log::info('自动创建分配规则任务执行成功,时间:' . date('Y-m-d H:i:s')); + } else { + if ($job->attempts() > 3) { + // 超过重试次数,删除任务 + Log::error('自动创建分配规则任务执行失败,已超过重试次数'); + $job->delete(); + } else { + // 任务失败,重新放回队列 + Log::warning('自动创建分配规则任务执行失败,重试次数:' . $job->attempts()); + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } catch (\Exception $e) { + // 出现异常,记录日志 + Log::error('自动创建分配规则任务异常:' . $e->getMessage()); + if ($job->attempts() > 3) { + $job->delete(); + } else { + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } + + /** + * 处理自动创建分配规则 + * @param array $data 任务数据 + * @param int $attempts 重试次数 + * @return bool + */ + protected function processAutoCreateAllotRules($data, $attempts) + { + Log::info('开始执行自动创建分配规则任务,重试次数:' . $attempts); + + // 实例化控制器 + $allotRuleController = new AllotRuleController(); + + // 调用自动创建分配规则方法 + $result = $allotRuleController->autoCreateAllotRules([], true); + $response = json_decode($result, true); + + // 判断是否成功 + if (isset($response['code']) && $response['code'] == 200) { + Log::info('自动创建分配规则成功:' . json_encode($response['data'])); + return true; + } else { + $errorMsg = isset($response['msg']) ? $response['msg'] : '未知错误'; + Log::error('自动创建分配规则失败:' . $errorMsg); + return false; + } + } +} \ No newline at end of file