Merge remote-tracking branch 'origin/master' into akun
正在显示
39 个修改的文件
包含
1066 行增加
和
292 行删除
| @@ -48,8 +48,9 @@ class AuthorityScore extends Command | @@ -48,8 +48,9 @@ class AuthorityScore extends Command | ||
| 48 | continue; | 48 | continue; |
| 49 | } | 49 | } |
| 50 | echo '执行的项目id'.$item.PHP_EOL; | 50 | echo '执行的项目id'.$item.PHP_EOL; |
| 51 | - $url = $url.$domainInfo['domain']; | ||
| 52 | - $data = http_get($url); | 51 | + $urls = $url.$domainInfo['domain']; |
| 52 | + echo $urls.PHP_EOL; | ||
| 53 | + $data = http_get($urls); | ||
| 53 | if(!empty($data) && !empty($data['data'])){ | 54 | if(!empty($data) && !empty($data['data'])){ |
| 54 | echo json_encode($data).PHP_EOL; | 55 | echo json_encode($data).PHP_EOL; |
| 55 | $data = $data['data']; | 56 | $data = $data['data']; |
| @@ -34,87 +34,127 @@ class GeoQuestionRes extends Command | @@ -34,87 +34,127 @@ class GeoQuestionRes extends Command | ||
| 34 | */ | 34 | */ |
| 35 | protected $description = 'geo设置请求获取结果'; | 35 | protected $description = 'geo设置请求获取结果'; |
| 36 | 36 | ||
| 37 | - public function handle(){ | ||
| 38 | - while (true){ | 37 | + |
| 38 | + /** | ||
| 39 | + * @return bool | ||
| 40 | + */ | ||
| 41 | + public function handle() | ||
| 42 | + { | ||
| 43 | + while (true) { | ||
| 39 | $task_id = $this->getTaskId(); | 44 | $task_id = $this->getTaskId(); |
| 40 | - if(empty($task_id)){ | ||
| 41 | - echo '无数据'.PHP_EOL; | ||
| 42 | - sleep(30); | 45 | + if (empty($task_id)) { |
| 46 | + sleep(300); | ||
| 47 | + continue; | ||
| 48 | + } | ||
| 49 | + echo date('Y-m-d H:i:s').'执行的任务id:'.$task_id.PHP_EOL; | ||
| 50 | + $geoQuestionModel = new GeoQuestion(); | ||
| 51 | + $taskInfo = $geoQuestionModel->read(['id'=>$task_id]); | ||
| 52 | + if ($taskInfo === false) { | ||
| 53 | + $this->output('当前任务详情为空!'); | ||
| 43 | continue; | 54 | continue; |
| 44 | } | 55 | } |
| 45 | - $questionModel = new GeoQuestion();//问题 | ||
| 46 | - $info = $questionModel->read(['id'=>$task_id]); | ||
| 47 | - //获取当前项目的执行频率 | ||
| 48 | $projectModel = new Project(); | 56 | $projectModel = new Project(); |
| 49 | - $projectInfo = $projectModel->read(['id'=>$info['project_id']],['geo_status','geo_frequency']); | ||
| 50 | - if($projectInfo['geo_status'] == 0){ | ||
| 51 | - $questionModel->edit(['status'=>0],['id'=>$task_id]); | 57 | + $projectInfo = $projectModel->read(['id' => $taskInfo['project_id']],['geo_status', 'geo_frequency']); |
| 58 | + if ($projectInfo === false) { | ||
| 59 | + $this->output('未获取到项目详情!'); | ||
| 60 | + $geoQuestionModel->edit(['status'=>$geoQuestionModel::STATUS_CLOSE],['id'=>$task_id]); | ||
| 52 | continue; | 61 | continue; |
| 53 | } | 62 | } |
| 54 | - $questionArr = $info['question']; | ||
| 55 | - if(empty($questionArr)){ | ||
| 56 | - echo date('Y-m-d H:i:s').'当前任务不存在问题。'.PHP_EOL; | ||
| 57 | - $questionModel->edit(['status'=>0],['id'=>$task_id]); | 63 | + if(empty($taskInfo['question']) || empty($taskInfo['keywords']) || empty($taskInfo['url'])){ |
| 64 | + $this->output('task id: ' . $task_id . ', error: 任务数据缺失, continue!'); | ||
| 65 | + $geoQuestionModel->edit(['status'=>$geoQuestionModel::STATUS_CLOSE],['id'=>$task_id]); | ||
| 66 | + continue; | ||
| 58 | } | 67 | } |
| 59 | - //获取平台信息 | ||
| 60 | - $platformModel = new GeoPlatform();//平台 | ||
| 61 | - $platformArr = $platformModel->selectField(['status'=>$platformModel::STATUS_ON],'en_name'); | ||
| 62 | - if(empty($platformArr)){ | ||
| 63 | - echo date('Y-m-d H:i:s').'请求平台为空。'.PHP_EOL; | 68 | + $geoPlatformModel = new GeoPlatform(); |
| 69 | + $platformsArr = $geoPlatformModel->selectField(['status' => GeoPlatform::STATUS_ON],'en_name'); | ||
| 70 | + if (empty($platformsArr)) { | ||
| 71 | + $this->output('未设置AI模型!'); | ||
| 64 | continue; | 72 | continue; |
| 65 | } | 73 | } |
| 66 | - $geoService = new GeoService(); | ||
| 67 | - $keywordArr = $info['keywords'] ?? []; | ||
| 68 | - $urlArr = $info['url'] ?? []; | 74 | + $geo_service = new GeoService(); |
| 69 | $geoResultModel = new GeoQuestionResult(); | 75 | $geoResultModel = new GeoQuestionResult(); |
| 70 | - foreach ($questionArr as $q_item){ | ||
| 71 | - foreach ($platformArr as $p_item){ | ||
| 72 | - $keywords = [];//命中的关键词 | ||
| 73 | - $urls = [];//命中的网址 | 76 | + $geoLogModel = new GeoQuestionLog(); |
| 77 | + foreach ($taskInfo['question'] as $question) { | ||
| 78 | + foreach ($platformsArr as $platform) { | ||
| 79 | + $data = $hit_data = []; | ||
| 80 | + $error_num = 0; | ||
| 81 | + // 设置重试, 有的平台不一定能正常获取到数据 | ||
| 82 | + GET_RESULT: | ||
| 83 | + $error_num++; | ||
| 74 | try { | 84 | try { |
| 75 | - $result_data = $geoService->setWebSearchChatAction($q_item,$p_item); | ||
| 76 | - echo 'success:'.$result_data['code'].PHP_EOL; | ||
| 77 | - if(isset($result_data) && $result_data['code'] == 200){ | ||
| 78 | - $keywords = $this->getKeywords($keywordArr,$result_data['text'] ?? []); | ||
| 79 | - $urls = $this->getUrl($urlArr,$result_data['annotations'] ?? []); | 85 | + echo '执行次数:'.$error_num.PHP_EOL; |
| 86 | + if ($error_num >= 5) { | ||
| 87 | + continue; | ||
| 88 | + } | ||
| 89 | + echo '执行平台:'.$platform.PHP_EOL; | ||
| 90 | + if ($platform == 'Google AI Overview') { | ||
| 91 | + // overview 数据结构不确定, 需要单独处理数据 | ||
| 92 | + $data = $geo_service->getGooglePlatformResult($question); | ||
| 93 | + $result = $this->dealGoogleData($data); | ||
| 94 | + } else { | ||
| 95 | + $result = $geo_service->getAiPlatformResult($question, $platform); | ||
| 96 | + } | ||
| 97 | + if (empty($result['text'])){ | ||
| 98 | + goto GET_RESULT; | ||
| 80 | } | 99 | } |
| 81 | - }catch (\Exception $e){ | ||
| 82 | - echo $e->getMessage().PHP_EOL; | ||
| 83 | - continue; | 100 | + } catch (\Exception $e) { |
| 101 | + $this->output('task id:' . $task_id . ', question: ' . $question . ', platform: ' . $platform . ', error: ' . $e->getMessage()); | ||
| 102 | + goto GET_RESULT; | ||
| 84 | } | 103 | } |
| 85 | - //查询当前是否已有执行保存记录 | ||
| 86 | - $resultInfo = $geoResultModel->read(['project_id'=>$info['project_id'],'question_id'=>$info['id'],'platform'=>$p_item,'question'=>$q_item],['id']); | ||
| 87 | - //保存一条结果记录 | ||
| 88 | - $data = [ | ||
| 89 | - 'project_id'=>$info['project_id'], | ||
| 90 | - 'question_id'=>$info['id'], | ||
| 91 | - 'platform'=>$p_item, | ||
| 92 | - 'question'=>$q_item, | ||
| 93 | - 'keywords'=>json_encode($keywords ?? [],true),//命中的关键词 | ||
| 94 | - 'text'=>json_encode($result_data ?? [],true), | ||
| 95 | - 'url'=>json_encode($urls ?? [],true),//命中的网址 | ||
| 96 | - 'type'=>$info['type'] ?? 1 | 104 | + // 命中文案 |
| 105 | + $hit_data[] = $result['text']; | ||
| 106 | + if(!empty($result['annotations'])){ | ||
| 107 | + $url = array_column(array_column($result['annotations'], 'url_citation'), 'url'); | ||
| 108 | + $title = array_column(array_column($result['annotations'], 'url_citation'), 'title'); | ||
| 109 | + $hit_data = array_merge($url, $title, $hit_data); | ||
| 110 | + } | ||
| 111 | + // 命中关键词和路由 | ||
| 112 | + $hit_keyword = $hit_url = []; | ||
| 113 | + $hit = 0; | ||
| 114 | + if (!empty($taskInfo['keywords'])) { | ||
| 115 | + $hit_keyword = $this->getKeywords($taskInfo['keywords'],$hit_data); | ||
| 116 | + if (!empty($hit_keyword)) { | ||
| 117 | + $hit++; | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + if (!empty($taskInfo['url'])) { | ||
| 121 | + $hit_url = $this->getUrl($taskInfo['url'],$hit_data); | ||
| 122 | + if (!empty($hit_url)) { | ||
| 123 | + $hit++; | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + echo 'MZ-url'.json_encode($hit_url).PHP_EOL; | ||
| 127 | + // 保存数据结果 | ||
| 128 | + $geo_result = $geoResultModel->read(['project_id' => $taskInfo['project_id'], 'question_id' => $task_id, 'platform' => $platform, 'question' => $question],['id']); | ||
| 129 | + $save_data = [ | ||
| 130 | + 'project_id' => $taskInfo['project_id'], | ||
| 131 | + 'question_id' => $task_id, | ||
| 132 | + 'type' => $taskInfo['type'] ?? $geoQuestionModel::TYPE_BRAND, | ||
| 133 | + 'platform' => $platform, | ||
| 134 | + 'question' => $question, | ||
| 135 | + 'keywords' => json_encode($hit_keyword,true),//命中的关键词 | ||
| 136 | + 'url' => json_encode($hit_url,true),//命中的网址 | ||
| 137 | + 'text' => json_encode($result,true), | ||
| 138 | + 'hit' => $hit, | ||
| 139 | + 'created_at'=>date('Y-m-d H:i:s'), | ||
| 140 | + 'updated_at'=>date('Y-m-d H:i:s'), | ||
| 97 | ]; | 141 | ]; |
| 98 | - if($resultInfo === false){ | ||
| 99 | - $geoResultModel->addReturnId($data); | 142 | +// echo '当前数据INFO:'.json_encode($save_data,true).PHP_EOL; |
| 143 | + if($geo_result === false){ | ||
| 144 | + $id= $geoResultModel->insertGetId($save_data); | ||
| 145 | + echo '当前数据id:'.$id.PHP_EOL; | ||
| 100 | }else{ | 146 | }else{ |
| 101 | - $geoResultModel->edit($data,['id'=>$resultInfo['id']]); | 147 | + $geoResultModel->edit($save_data, ['id' => $geo_result['id']]); |
| 102 | } | 148 | } |
| 103 | - $data_log = [ | ||
| 104 | - 'project_id'=>$info['project_id'], | ||
| 105 | - 'question_id'=>$info['id'], | ||
| 106 | - 'platform'=>$p_item, | ||
| 107 | - 'question'=>$q_item, | ||
| 108 | - 'text'=>json_encode($result_data ?? [],true), | ||
| 109 | - 'type'=>$info['type'] ?? 1 | ||
| 110 | - ]; | ||
| 111 | - $geoLogModel = new GeoQuestionLog(); | ||
| 112 | - $geoLogModel->addReturnId($data_log); | 149 | + $save_data['text'] = json_encode(!empty($data) ? $data : $result,true); |
| 150 | + $geoLogModel->addReturnId($save_data); | ||
| 151 | + echo '执行结束:'.$platform.PHP_EOL; | ||
| 113 | } | 152 | } |
| 114 | } | 153 | } |
| 115 | - //更新下次执行时间 | ||
| 116 | - $questionModel->edit(['current_time'=>date('Y-m-d'),'next_time'=>date('Y-m-d', strtotime(date('Y-m-d') . ' +'.(int)$projectInfo['geo_frequency'].' days'))],['id'=>$info['id']]); | 154 | + $next_time = date('Y-m-d', strtotime('+' . ($projectInfo['geo_frequency'] ?? 3) . ' days')); |
| 155 | + $geoQuestionModel->edit(['current_time'=>date('Y-m-d'),'next_time'=>$next_time],['id'=>$task_id]); | ||
| 117 | } | 156 | } |
| 157 | + return true; | ||
| 118 | } | 158 | } |
| 119 | 159 | ||
| 120 | /** | 160 | /** |
| @@ -124,22 +164,13 @@ class GeoQuestionRes extends Command | @@ -124,22 +164,13 @@ class GeoQuestionRes extends Command | ||
| 124 | * @method :post | 164 | * @method :post |
| 125 | * @time :2025/7/3 16:38 | 165 | * @time :2025/7/3 16:38 |
| 126 | */ | 166 | */ |
| 127 | - public function getUrl($urlArr = [],$result_annotations = [],$result_text = []){ | 167 | + public function getUrl($urlArr = [],$result_annotations = []){ |
| 128 | $url = []; | 168 | $url = []; |
| 129 | if(!empty($urlArr)){ | 169 | if(!empty($urlArr)){ |
| 170 | + $str = implode(',',$result_annotations); | ||
| 130 | foreach ($urlArr as $u_item){ | 171 | foreach ($urlArr as $u_item){ |
| 131 | - if(!empty($result_text)){ | ||
| 132 | - if (str_contains($result_text, $u_item)) { | ||
| 133 | - $url[] = $u_item; | ||
| 134 | - } | ||
| 135 | - } | ||
| 136 | - if(!empty($result_annotations)){ | ||
| 137 | - foreach ($result_annotations as $a_item){ | ||
| 138 | - echo 'url'.$a_item['url_citation']['url'].PHP_EOL.'当前的url:'.$u_item; | ||
| 139 | - if (str_contains($a_item['url_citation']['url'], $u_item)) { | ||
| 140 | - $url[] = $u_item; | ||
| 141 | - } | ||
| 142 | - } | 172 | + if (str_contains($str, $u_item)) { |
| 173 | + $url[] = $u_item; | ||
| 143 | } | 174 | } |
| 144 | } | 175 | } |
| 145 | } | 176 | } |
| @@ -156,8 +187,9 @@ class GeoQuestionRes extends Command | @@ -156,8 +187,9 @@ class GeoQuestionRes extends Command | ||
| 156 | public function getKeywords($keywordArr = [],$result_text = []){ | 187 | public function getKeywords($keywordArr = [],$result_text = []){ |
| 157 | $keywords = []; | 188 | $keywords = []; |
| 158 | if(!empty($keywordArr) && !empty($result_text)){ | 189 | if(!empty($keywordArr) && !empty($result_text)){ |
| 190 | + $str = implode(',',$result_text); | ||
| 159 | foreach ($keywordArr as $k_item){ | 191 | foreach ($keywordArr as $k_item){ |
| 160 | - if (str_contains($result_text, $k_item)) { | 192 | + if (str_contains($str, $k_item)) { |
| 161 | $keywords[] = $k_item; | 193 | $keywords[] = $k_item; |
| 162 | } | 194 | } |
| 163 | } | 195 | } |
| @@ -166,24 +198,94 @@ class GeoQuestionRes extends Command | @@ -166,24 +198,94 @@ class GeoQuestionRes extends Command | ||
| 166 | } | 198 | } |
| 167 | 199 | ||
| 168 | /** | 200 | /** |
| 169 | - * @remark :拉取任务id | ||
| 170 | - * @name :getTaskId | ||
| 171 | - * @author :lyh | ||
| 172 | - * @method :post | ||
| 173 | - * @time :2025/7/3 15:15 | 201 | + * 整合Google平台数据 |
| 202 | + * @param $data | ||
| 203 | + * @return array | ||
| 204 | + */ | ||
| 205 | + public function dealGoogleData($data) | ||
| 206 | + { | ||
| 207 | + $result = [ | ||
| 208 | + 'code' => 200, | ||
| 209 | + 'model' => 'Google AI Overview', | ||
| 210 | + 'text' => '', | ||
| 211 | + ]; | ||
| 212 | + $texts = []; | ||
| 213 | + if(!empty($data['data']['text_parts']) && is_array($data['data']['text_parts'])){ | ||
| 214 | + foreach ($data['data']['text_parts'] as $item){ | ||
| 215 | + switch ($item['type']){ | ||
| 216 | + case 'paragraph': | ||
| 217 | + if(isset($item['text']) && !empty($item['text'])){ | ||
| 218 | + array_push($texts, $item['text']); | ||
| 219 | + } | ||
| 220 | + break; | ||
| 221 | + case 'title': | ||
| 222 | + if(isset($item['text']) && !empty($item['text'])) { | ||
| 223 | + array_unshift($texts, $item['text']); | ||
| 224 | + } | ||
| 225 | + break; | ||
| 226 | + case 'list': | ||
| 227 | + if(!empty($item['list'])){ | ||
| 228 | + foreach ($item['list'] as $sonItem){ | ||
| 229 | + if(isset($sonItem['text']) && !empty($sonItem['text'])) { | ||
| 230 | + array_push($texts, $sonItem['text']); | ||
| 231 | + } | ||
| 232 | + if(isset($item['title']) && !empty($item['title'])) { | ||
| 233 | + array_push($texts, $sonItem['title']); | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | + } | ||
| 237 | + break; | ||
| 238 | + default: | ||
| 239 | + break; | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + if(!empty($data['data']['reference_links']) && is_array($data['data']['reference_links'])){ | ||
| 244 | + foreach ($data['data']['reference_links'] as $link) { | ||
| 245 | + if (isset($link['title']) && !empty($link['title']) && isset($link['link']) && !empty($link['link'])) { | ||
| 246 | + $result['annotations'][] = [ | ||
| 247 | + 'type' => 'url_citation', | ||
| 248 | + 'url_citation' => [ | ||
| 249 | + 'url' => $link['link'], | ||
| 250 | + 'title' => $link['title'] | ||
| 251 | + ], | ||
| 252 | + ]; | ||
| 253 | + } | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + $text = implode(PHP_EOL, $texts); | ||
| 257 | + $result['text'] = $text; | ||
| 258 | + return $result; | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + /** | ||
| 262 | + * 获取待执行任务ID | ||
| 263 | + * @return mixed | ||
| 174 | */ | 264 | */ |
| 175 | public function getTaskId(){ | 265 | public function getTaskId(){ |
| 176 | - $task_id = Redis::rpop('geo_question_result'); | 266 | + $key = 'geo_task_list'; |
| 267 | + $task_id = Redis::rpop($key); | ||
| 177 | if(empty($task_id)){ | 268 | if(empty($task_id)){ |
| 178 | $questionModel = new GeoQuestion(); | 269 | $questionModel = new GeoQuestion(); |
| 179 | - $ids = $questionModel->selectField(['status'=>1,'next_time'=>['<=',date('Y-m-d')]],'id'); | 270 | + $ids = $questionModel->selectField(['status'=>$questionModel::STATUS_OPEN,'next_time'=>['<=',date('Y-m-d')]],'id'); |
| 180 | if(!empty($ids)){ | 271 | if(!empty($ids)){ |
| 181 | foreach ($ids as $id) { | 272 | foreach ($ids as $id) { |
| 182 | - Redis::lpush('geo_question_result', $id); | 273 | + Redis::lpush($key, $id); |
| 183 | } | 274 | } |
| 184 | } | 275 | } |
| 185 | - $task_id = Redis::rpop('geo_question_result'); | 276 | + $task_id = Redis::rpop($key); |
| 186 | } | 277 | } |
| 187 | return $task_id; | 278 | return $task_id; |
| 188 | } | 279 | } |
| 280 | + | ||
| 281 | + /** | ||
| 282 | + * 输出日志 | ||
| 283 | + * @param $message | ||
| 284 | + * @return bool | ||
| 285 | + */ | ||
| 286 | + public function output($message) | ||
| 287 | + { | ||
| 288 | + echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL; | ||
| 289 | + return true; | ||
| 290 | + } | ||
| 189 | } | 291 | } |
| @@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
| 10 | namespace App\Console\Commands\LyhTest; | 10 | namespace App\Console\Commands\LyhTest; |
| 11 | 11 | ||
| 12 | use App\Models\Ai\AiBlog; | 12 | use App\Models\Ai\AiBlog; |
| 13 | +use App\Models\News\News; | ||
| 13 | use App\Models\Product\Category; | 14 | use App\Models\Product\Category; |
| 14 | use App\Models\Project\AggregateKeywordAffix; | 15 | use App\Models\Project\AggregateKeywordAffix; |
| 15 | use App\Models\Project\AiBlogTask; | 16 | use App\Models\Project\AiBlogTask; |
| @@ -41,6 +42,15 @@ class lyhDemo extends Command | @@ -41,6 +42,15 @@ class lyhDemo extends Command | ||
| 41 | protected $description = '更新路由'; | 42 | protected $description = '更新路由'; |
| 42 | 43 | ||
| 43 | public function handle(){ | 44 | public function handle(){ |
| 45 | + ProjectServer::useProject(3531); | ||
| 46 | + $newsModel = new News(); | ||
| 47 | + $rows = $newsModel->select('id', 'text')->get(); | ||
| 48 | + foreach ($rows as $row) { | ||
| 49 | + echo '执行数据id:'.$row->id.PHP_EOL; | ||
| 50 | + $newText = preg_replace('/<h1 class="t">.*?<\/h1>/is', '', $row->text); | ||
| 51 | + $newsModel->where('id', $row->id)->update(['text' => $newText]); | ||
| 52 | + } | ||
| 53 | + DB::disconnect('custom_mysql'); | ||
| 44 | return true; | 54 | return true; |
| 45 | } | 55 | } |
| 46 | 56 |
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * @remark : | ||
| 4 | + * @name :InitKeywordComment.php | ||
| 5 | + * @author :lyh | ||
| 6 | + * @method :post | ||
| 7 | + * @time :2025/6/3 15:38 | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | +namespace App\Console\Commands\Project; | ||
| 11 | + | ||
| 12 | +use App\Helper\Common; | ||
| 13 | +use App\Helper\Gpt; | ||
| 14 | +use App\Models\Ai\AiCommand; | ||
| 15 | +use App\Models\Com\NoticeLog; | ||
| 16 | +use App\Models\Project\AggregateKeywordComment; | ||
| 17 | +use App\Models\Project\Project; | ||
| 18 | +use Illuminate\Console\Command; | ||
| 19 | + | ||
| 20 | +class ProjectComment extends Command | ||
| 21 | +{ | ||
| 22 | + /** | ||
| 23 | + * The name and signature of the console command. | ||
| 24 | + * | ||
| 25 | + * @var string | ||
| 26 | + */ | ||
| 27 | + protected $signature = 'project_comment'; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * The console command description. | ||
| 31 | + * | ||
| 32 | + * @var string | ||
| 33 | + */ | ||
| 34 | + protected $description = '初始化关键字评论'; | ||
| 35 | + | ||
| 36 | + public $number = 100; | ||
| 37 | + | ||
| 38 | + public function handle(){ | ||
| 39 | + $projectModel = new Project(); | ||
| 40 | + $ids = $projectModel->selectField(['delete_status' => 0,'project_type'=>0,'extend_type'=>0,'type'=>['in',[1,2,3,4,6]]], 'id'); | ||
| 41 | + foreach ($ids as $id){ | ||
| 42 | + echo date('Y-m-d H:i:s').'start:' . $id . PHP_EOL; | ||
| 43 | + $project_id = $id; | ||
| 44 | + echo date('Y-m-d H:i:s').'执行的项目id:' . $project_id . PHP_EOL; | ||
| 45 | + try { | ||
| 46 | + $this->_action($project_id); | ||
| 47 | + }catch (\Exception $e){ | ||
| 48 | + echo date('Y-m-d H:i:s').'错误信息:'.$e->getMessage().PHP_EOL; | ||
| 49 | + continue; | ||
| 50 | + } | ||
| 51 | + echo date('Y-m-d H:i:s').'end:' . $id . PHP_EOL; | ||
| 52 | + } | ||
| 53 | + return true; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * @remark :执行的方法 | ||
| 58 | + * @name :_action | ||
| 59 | + * @author :lyh | ||
| 60 | + * @method :post | ||
| 61 | + * @time :2025/6/3 15:42 | ||
| 62 | + */ | ||
| 63 | + public function _action($project_id){ | ||
| 64 | + $aiCommonModel = new AiCommand(); | ||
| 65 | + $info = $aiCommonModel->read(['key'=>'tag_comment']); | ||
| 66 | + $info['ai'] = str_replace('50', '100', $info['ai']); | ||
| 67 | + $text = Gpt::instance()->openai_chat_qqs($info['ai']); | ||
| 68 | + $text = Common::deal_keywords($text); | ||
| 69 | + preg_match_all('/\{[^{}]*\}/', $text, $matches); | ||
| 70 | + if(!empty($text)){ | ||
| 71 | + $data = []; | ||
| 72 | + foreach ($matches[0] as $item){ | ||
| 73 | + $item = str_replace("'", '"', $item); | ||
| 74 | + // 解码成 PHP 关联数组 | ||
| 75 | + $item = json_decode($item, true); | ||
| 76 | + if(!isset($item['name']) || !isset($item['comment'])){ | ||
| 77 | + continue; | ||
| 78 | + } | ||
| 79 | + $twoMonthsAgo = strtotime('-2 months'); | ||
| 80 | + $randomTimestamp = rand($twoMonthsAgo, time()); | ||
| 81 | + $randomDateTime = date('Y-m-d H:i:s', $randomTimestamp); | ||
| 82 | + $data[] = [ | ||
| 83 | + 'nickname'=>$item['name'], | ||
| 84 | + 'text'=>$item['comment'], | ||
| 85 | + 'project_id'=>$project_id, | ||
| 86 | + 'type'=>1, | ||
| 87 | + 'uid'=>0, | ||
| 88 | + 'start_time'=>$randomDateTime, | ||
| 89 | + 'created_at'=>date('Y-m-d H:i:s'), | ||
| 90 | + 'updated_at'=>date('Y-m-d H:i:s') | ||
| 91 | + ]; | ||
| 92 | + } | ||
| 93 | + $keywordCommentModel = new AggregateKeywordComment(); | ||
| 94 | + $keywordCommentModel->insertAll($data); | ||
| 95 | + } | ||
| 96 | + return true; | ||
| 97 | + } | ||
| 98 | +} |
app/Console/Commands/Statistics/Flow.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: zhl | ||
| 5 | + * Date: 2025/7/4 | ||
| 6 | + * Time: 11:14 | ||
| 7 | + */ | ||
| 8 | +namespace App\Console\Commands\Statistics; | ||
| 9 | + | ||
| 10 | +use App\Models\Project\ProjectFlow; | ||
| 11 | +use App\Services\UpyunService; | ||
| 12 | +use Illuminate\Console\Command; | ||
| 13 | +use Illuminate\Support\Str; | ||
| 14 | + | ||
| 15 | +class Flow extends Command | ||
| 16 | +{ | ||
| 17 | + /** | ||
| 18 | + * The name and signature of the console command. | ||
| 19 | + * | ||
| 20 | + * @var string | ||
| 21 | + */ | ||
| 22 | + protected $signature = 'project_flow_statistics'; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * The console command description. | ||
| 26 | + * | ||
| 27 | + * @var string | ||
| 28 | + */ | ||
| 29 | + protected $description = '项目流量统计'; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * Create a new command instance. | ||
| 33 | + * | ||
| 34 | + * @return void | ||
| 35 | + */ | ||
| 36 | + public function __construct() | ||
| 37 | + { | ||
| 38 | + parent::__construct(); // 确保调用父类构造函数 | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public function handle() | ||
| 42 | + { | ||
| 43 | + $this->cdnStatistics(); | ||
| 44 | + return true; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public function cdnStatistics() | ||
| 48 | + { | ||
| 49 | + $class = new UpyunService(); | ||
| 50 | + | ||
| 51 | + list($start_at, $end_at) = $this->getTime(); | ||
| 52 | + $date = date('Y-m-d', strtotime($end_at)); | ||
| 53 | + echo 'start_at: ' . $start_at . PHP_EOL; | ||
| 54 | + echo 'end_at: ' . $end_at . PHP_EOL; | ||
| 55 | + $result = $class->realTimeStatistics($start_at, $end_at); | ||
| 56 | + | ||
| 57 | + file_put_contents(storage_path('logs/flow/' . date('YmdHis', strtotime($start_at)) . '.json'), $result); | ||
| 58 | +// $result = file_get_contents(storage_path('logs/flow/' . date('YmdHis', strtotime($start_at)) . '.json')); | ||
| 59 | + $result = json_decode($result, true); | ||
| 60 | + $flow = []; | ||
| 61 | + if (FALSE == empty($result['data']) && is_array($result['data'])) { | ||
| 62 | + // 结算 所有项目 流量 | ||
| 63 | + foreach ($result['data'] as $item) { | ||
| 64 | + if (Str::startsWith($item['key'], '/upload/p/')) { | ||
| 65 | + $tmp = explode('/', $item['key']); | ||
| 66 | + $flow[$tmp[3]] = FALSE == empty($flow[$tmp[3]]) ? $flow[$tmp[3]] + $item['val'] : $item['val']; | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + ksort($flow); | ||
| 72 | + $total_flow = 0; | ||
| 73 | + foreach ($flow as $project_id=>$val) { | ||
| 74 | + ProjectFlow::flowInsert($project_id, $date, $val, $end_at); | ||
| 75 | + $total_flow += $val; | ||
| 76 | + } | ||
| 77 | + echo 'total project: ' . count($flow) . PHP_EOL; | ||
| 78 | + echo 'total flow: ' . $total_flow . PHP_EOL; | ||
| 79 | + return true; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * @return array | ||
| 84 | + */ | ||
| 85 | + public function getTime() | ||
| 86 | + { | ||
| 87 | + $last_at_log = ProjectFlow::orderBy('last_at', 'desc')->first(); | ||
| 88 | + $today = date('Y-m-d 00:00:00'); | ||
| 89 | + $start_at = $last_at_log ? $last_at_log->last_at : $today; | ||
| 90 | + if (strtotime($start_at) < strtotime($today)) | ||
| 91 | + $start_at = $today; | ||
| 92 | + $end_at = date('Y-m-d H:i:s', time() - 1); | ||
| 93 | + return [$start_at, $end_at]; | ||
| 94 | + } | ||
| 95 | +} |
| @@ -9,6 +9,7 @@ | @@ -9,6 +9,7 @@ | ||
| 9 | 9 | ||
| 10 | namespace App\Console\Commands\Sync; | 10 | namespace App\Console\Commands\Sync; |
| 11 | 11 | ||
| 12 | +use App\Models\Manage\Mobile; | ||
| 12 | use App\Models\User\User; | 13 | use App\Models\User\User; |
| 13 | use Illuminate\Console\Command; | 14 | use Illuminate\Console\Command; |
| 14 | use Illuminate\Support\Facades\DB; | 15 | use Illuminate\Support\Facades\DB; |
| @@ -40,30 +41,42 @@ class SyncMobile extends Command | @@ -40,30 +41,42 @@ class SyncMobile extends Command | ||
| 40 | $url = 'https://www.quanqiusou.cn/extend_api/saas/get_phone.php'; | 41 | $url = 'https://www.quanqiusou.cn/extend_api/saas/get_phone.php'; |
| 41 | // $data = curlGet($url);//TODO::获取号码库 | 42 | // $data = curlGet($url);//TODO::获取号码库 |
| 42 | $client = new \GuzzleHttp\Client(); | 43 | $client = new \GuzzleHttp\Client(); |
| 43 | - $data = $client->request('GET', $url, [ | ||
| 44 | - 'proxy' => env('CURL_PROXY'), // 代理服务器地址和端口号 | ||
| 45 | - ])->getBody()->getContents(); | ||
| 46 | - $data = json_decode($data, true); | ||
| 47 | - DB::table('gl_mobile')->delete(); | ||
| 48 | - $create_time = date('Y-m-d H:i:s'); | ||
| 49 | - foreach ($data as $v){ | ||
| 50 | - $param = [ | ||
| 51 | - 'mobile'=>$v, | ||
| 52 | - 'created_at'=>$create_time | ||
| 53 | - ]; | ||
| 54 | - DB::table('gl_mobile')->insert($param); | 44 | + try { |
| 45 | + $data = $client->request('GET', $url, [ | ||
| 46 | + 'proxy' => env('CURL_PROXY'), // 代理服务器地址和端口号 | ||
| 47 | + ])->getBody()->getContents(); | ||
| 48 | + }catch (\Exception $e){ | ||
| 49 | + echo date('Y-m-d H:i:s').':未拉起到数据'.PHP_EOL; | ||
| 55 | } | 50 | } |
| 56 | if(!empty($data)){ | 51 | if(!empty($data)){ |
| 52 | + $mobileModel = new Mobile(); | ||
| 53 | + $mobileModel->truncate(); | ||
| 54 | + $data = json_decode($data, true); | ||
| 57 | $userModel = new User(); | 55 | $userModel = new User(); |
| 58 | - try { | ||
| 59 | - $data[] = '13083988828'; | ||
| 60 | - $data[] = '6591559603'; | ||
| 61 | - $userModel->edit(['status'=>1],['project_id'=>1,'mobile'=>['not in',$data]]); | ||
| 62 | - $userModel->edit(['status'=>0],['project_id'=>1,'mobile'=>['in',$data]]); | ||
| 63 | - }catch (\Exception $e){ | ||
| 64 | - echo date('Y-m-d H:i:s') . 'error' . PHP_EOL; | 56 | + foreach ($data as $mobile){ |
| 57 | + $param = [ | ||
| 58 | + 'mobile'=>$mobile, | ||
| 59 | + 'created_at'=>date('Y-m-d H:i:s') | ||
| 60 | + ]; | ||
| 61 | + $mobileModel->insert($param); | ||
| 62 | + //查看当前用户是否存在 | ||
| 63 | + $info = $userModel->read(['mobile'=>$mobile,'project_id'=>1]); | ||
| 64 | + if($info === false){ | ||
| 65 | + $data = [ | ||
| 66 | + 'mobile'=>$mobile, | ||
| 67 | + 'password'=>base64_encode(md5('123456')), | ||
| 68 | + 'project_id'=>1, | ||
| 69 | + 'name'=>$mobile, | ||
| 70 | + 'type'=>$userModel::TYPE_ONE | ||
| 71 | + ]; | ||
| 72 | + $userModel->add($data); | ||
| 73 | + } | ||
| 65 | } | 74 | } |
| 75 | + $data[] = '13083988828'; | ||
| 76 | + $userModel->edit(['status'=>1],['project_id'=>1,'mobile'=>['not in',$data]]); | ||
| 77 | + $userModel->edit(['status'=>0],['project_id'=>1,'mobile'=>['in',$data]]); | ||
| 66 | } | 78 | } |
| 79 | + echo 'end.'.PHP_EOL; | ||
| 80 | + return true; | ||
| 67 | } | 81 | } |
| 68 | - | ||
| 69 | } | 82 | } |
| @@ -5,9 +5,11 @@ namespace App\Console\Commands\WorkOrder; | @@ -5,9 +5,11 @@ namespace App\Console\Commands\WorkOrder; | ||
| 5 | use App\Models\Manage\Manage; | 5 | use App\Models\Manage\Manage; |
| 6 | use App\Models\Manage\ManageHr; | 6 | use App\Models\Manage\ManageHr; |
| 7 | use App\Models\Project\Project; | 7 | use App\Models\Project\Project; |
| 8 | +use App\Models\ProjectAssociation\ProjectAssociation; | ||
| 8 | use App\Models\WorkOrder\TicketProject; | 9 | use App\Models\WorkOrder\TicketProject; |
| 9 | use Illuminate\Console\Command; | 10 | use Illuminate\Console\Command; |
| 10 | use Illuminate\Support\Facades\Http; | 11 | use Illuminate\Support\Facades\Http; |
| 12 | +use Illuminate\Support\Str; | ||
| 11 | 13 | ||
| 12 | class FetchTicketProjects extends Command | 14 | class FetchTicketProjects extends Command |
| 13 | { | 15 | { |
| @@ -16,7 +18,7 @@ class FetchTicketProjects extends Command | @@ -16,7 +18,7 @@ class FetchTicketProjects extends Command | ||
| 16 | * | 18 | * |
| 17 | * @var string | 19 | * @var string |
| 18 | */ | 20 | */ |
| 19 | - protected $signature = 'workorder:fetch-ticket-projects {action}}'; | 21 | + protected $signature = 'workorder:fetch-ticket-projects {action}'; |
| 20 | 22 | ||
| 21 | /** | 23 | /** |
| 22 | * The console command description. | 24 | * The console command description. |
| @@ -83,6 +85,7 @@ class FetchTicketProjects extends Command | @@ -83,6 +85,7 @@ class FetchTicketProjects extends Command | ||
| 83 | 'test_website' => $item['test_url'] ?? '', | 85 | 'test_website' => $item['test_url'] ?? '', |
| 84 | 'is_del' => 0, | 86 | 'is_del' => 0, |
| 85 | 'plan' => $item['plan'] ?? '', | 87 | 'plan' => $item['plan'] ?? '', |
| 88 | + 'project_cate' => 1, | ||
| 86 | ]; | 89 | ]; |
| 87 | if (!$project) { | 90 | if (!$project) { |
| 88 | $new = new TicketProject(); | 91 | $new = new TicketProject(); |
| @@ -177,6 +180,11 @@ class FetchTicketProjects extends Command | @@ -177,6 +180,11 @@ class FetchTicketProjects extends Command | ||
| 177 | 'test_website' => $item->deploy_build->test_domain ?? '', | 180 | 'test_website' => $item->deploy_build->test_domain ?? '', |
| 178 | 'version' => empty($item->version) ? 7 : $item->version, // 版本号 | 181 | 'version' => empty($item->version) ? 7 : $item->version, // 版本号 |
| 179 | 'plan' => $item->planMap()[$item->deploy_build->plan] ?? '', | 182 | 'plan' => $item->planMap()[$item->deploy_build->plan] ?? '', |
| 183 | + 'project_cate' => 2, | ||
| 184 | + 'wechat_group_id' => ProjectAssociation::where('project_id', $project->table_id) | ||
| 185 | + ->where('status', ProjectAssociation::STATUS_NORMAL) | ||
| 186 | + ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT) | ||
| 187 | + ->value('friend_id') | ||
| 180 | ]; | 188 | ]; |
| 181 | if (!$project) { | 189 | if (!$project) { |
| 182 | $project = new TicketProject(); | 190 | $project = new TicketProject(); |
| @@ -209,6 +217,98 @@ class FetchTicketProjects extends Command | @@ -209,6 +217,98 @@ class FetchTicketProjects extends Command | ||
| 209 | } | 217 | } |
| 210 | } | 218 | } |
| 211 | 219 | ||
| 220 | + public function fetchAICC() | ||
| 221 | + { | ||
| 222 | + $lastid = 0; | ||
| 223 | + while (true) { | ||
| 224 | + try { | ||
| 225 | + $response = Http::withBasicAuth('bill', 'bill@ai.cc') | ||
| 226 | + ->get('https://fob.ai.cc/api/tickets/projects', [ | ||
| 227 | + 'lastid' => $lastid, | ||
| 228 | + ]); | ||
| 229 | + $items = $response->json(); | ||
| 230 | + if (empty($items)) | ||
| 231 | + { | ||
| 232 | + echo now() . " | INFO | not found items \n"; | ||
| 233 | + break; | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + foreach ($items as $item) { | ||
| 237 | + foreach ($item['plans'] as $plan) | ||
| 238 | + { | ||
| 239 | + // 判断套餐是超迹还是域途, 如果 $item['plans'][0]['name'] 包含 '超迹' 则为超迹,否则为域途 | ||
| 240 | + $project_cate = Str::contains($plan['name'], '超迹') ? 3 : 4; | ||
| 241 | + $uuid = md5("AICC{$item['id']}{$project_cate}"); | ||
| 242 | + $project = TicketProject::where('uuid', $uuid)->first(); | ||
| 243 | + if ($project_cate == 3) | ||
| 244 | + { | ||
| 245 | + // 售后服务经理 | ||
| 246 | + $assm_id = collect([ | ||
| 247 | + ManageHr::where('name', $item['cj_assm']['real_name'] ?? '')->first()->manage_id ?? 0, | ||
| 248 | + 20, //徐莹 | ||
| 249 | + ])->first(fn($v) => $v !== null && $v !== 0, 0); | ||
| 250 | + }else | ||
| 251 | + { | ||
| 252 | + // 域途 | ||
| 253 | + $assm_id = collect([ | ||
| 254 | + ManageHr::where('name', $item['yutu_assm']['real_name'] ?? '')->first()->manage_id ?? 0, | ||
| 255 | + 85, //黄小玉 | ||
| 256 | + ])->first(fn($v) => $v !== null && $v !== 0, 0); | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + // 优化师 | ||
| 260 | + $seom_id = 0; | ||
| 261 | + // 第一负责人 | ||
| 262 | + $engineer_id = $assm_id; | ||
| 263 | + $is_del = 0; | ||
| 264 | + | ||
| 265 | + $fields = [ | ||
| 266 | + 'company_name' => $item['company'], | ||
| 267 | + 'title' => $item['company'] . " - " . $plan['name'], | ||
| 268 | + 'assm_id' => $assm_id, | ||
| 269 | + 'seom_id' => $seom_id, | ||
| 270 | + 'engineer_id' => $engineer_id, | ||
| 271 | + 'is_del' => $is_del, | ||
| 272 | + 'website' => '', | ||
| 273 | + 'test_website' => '', | ||
| 274 | + 'version' => 1, // 版本号 | ||
| 275 | + 'plan' => $plan['name'] ?? '', | ||
| 276 | + 'project_cate' => $project_cate, | ||
| 277 | + 'wechat_group_id' => $item['chatroom_id'], | ||
| 278 | + ]; | ||
| 279 | + | ||
| 280 | + if (!$project) { | ||
| 281 | + $project = new TicketProject(); | ||
| 282 | + $project->uuid = $uuid; | ||
| 283 | + $project->post_id = $item['postid']; | ||
| 284 | + $project->table_id = $item['id']; | ||
| 285 | + foreach ($fields as $k => $v) { | ||
| 286 | + $project->$k = $v; | ||
| 287 | + } | ||
| 288 | + $project->save(); | ||
| 289 | + } else { | ||
| 290 | + $changed = false; | ||
| 291 | + foreach ($fields as $k => $v) { | ||
| 292 | + if ($project->$k != $v) { | ||
| 293 | + $project->$k = $v; | ||
| 294 | + $changed = true; | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | + if ($changed) { | ||
| 298 | + $project->save(); | ||
| 299 | + } | ||
| 300 | + } | ||
| 301 | + $lastid = $item['id']; | ||
| 302 | + echo now() . " | INFO | AICC: {$item['id']} {$item['company']} fetch ok \n"; | ||
| 303 | + } | ||
| 304 | + } | ||
| 305 | + }catch (\Exception $exception){ | ||
| 306 | + echo now() . " | ERROR | " . $exception->getMessage() . "\n" . $exception->getTraceAsString() . "\n"; | ||
| 307 | + break; | ||
| 308 | + } | ||
| 309 | + } | ||
| 310 | + } | ||
| 311 | + | ||
| 212 | public function fetch_uuid() | 312 | public function fetch_uuid() |
| 213 | { | 313 | { |
| 214 | $lastid = 0; | 314 | $lastid = 0; |
| 1 | -<?php | ||
| 2 | - | ||
| 3 | -namespace App\Console\Commands\WorkOrder; | ||
| 4 | - | ||
| 5 | -use App\Models\ProjectAssociation\ProjectAssociation; | ||
| 6 | -use App\Models\Workchat\MessagePush; | ||
| 7 | -use App\Models\WorkOrder\Tickets; | ||
| 8 | -use Illuminate\Console\Command; | ||
| 9 | - | ||
| 10 | -class PushNotify extends Command | ||
| 11 | -{ | ||
| 12 | - /** | ||
| 13 | - * The name and signature of the console command. | ||
| 14 | - * | ||
| 15 | - * @var string | ||
| 16 | - */ | ||
| 17 | - protected $signature = 'workorder:push-notify'; | ||
| 18 | - | ||
| 19 | - /** | ||
| 20 | - * The console command description. | ||
| 21 | - * | ||
| 22 | - * @var string | ||
| 23 | - */ | ||
| 24 | - protected $description = 'tickets push notify'; | ||
| 25 | - | ||
| 26 | - /** | ||
| 27 | - * Create a new command instance. | ||
| 28 | - * | ||
| 29 | - * @return void | ||
| 30 | - */ | ||
| 31 | - public function __construct() | ||
| 32 | - { | ||
| 33 | - parent::__construct(); | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * Execute the console command. | ||
| 38 | - * | ||
| 39 | - * @return int | ||
| 40 | - */ | ||
| 41 | - public function handle() | ||
| 42 | - { | ||
| 43 | - while (true) { | ||
| 44 | - try { | ||
| 45 | - $tick = Tickets::where('ding', 0) | ||
| 46 | - ->where('submit_side', 2) | ||
| 47 | -// ->where('project_id', 1) | ||
| 48 | - ->first(); | ||
| 49 | - if (!$tick) { | ||
| 50 | - echo now() . " WARNING | 没有待推送的工单\n"; | ||
| 51 | - sleep(3); | ||
| 52 | - continue; | ||
| 53 | - } | ||
| 54 | - $project = $tick->project; | ||
| 55 | - if ($project->version != 6 || $project->is_del == 1) { | ||
| 56 | - echo now() . " WARNING | 项目版本或状态异常 \n"; | ||
| 57 | - $tick->ding = 1; | ||
| 58 | - $tick->save(); | ||
| 59 | - continue; | ||
| 60 | - } | ||
| 61 | - $message_push = new MessagePush(); | ||
| 62 | - $message_push->project_id = $project->table_id; | ||
| 63 | - $message_push->friend_id = ProjectAssociation::where('project_id', $project->table_id) | ||
| 64 | - ->where('status', ProjectAssociation::STATUS_NORMAL) | ||
| 65 | - ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT) | ||
| 66 | - ->value('friend_id'); | ||
| 67 | - if (empty($message_push->friend_id)) | ||
| 68 | - { | ||
| 69 | - echo now() . " WARNING | 项目ID:{$project->table_id} 没有绑定企微群\n"; | ||
| 70 | - $tick->ding = 1; | ||
| 71 | - $tick->save(); | ||
| 72 | - continue; | ||
| 73 | - } | ||
| 74 | - $message_push->content_type = 'Link'; | ||
| 75 | - $message_push->content = json_encode([ | ||
| 76 | - 'title' => '工单查看 - ' . $project->company_name, | ||
| 77 | - 'desc' => $tick->title, | ||
| 78 | - 'size' => 0, | ||
| 79 | - 'thumbSize' => 0, | ||
| 80 | - 'thumbUrl' => 'https://oa.quanqiusou.cn/logo.ico', | ||
| 81 | - 'url' => 'https://oa.quanqiusou.cn/tickets?project_id='.$project->uuid | ||
| 82 | - ], JSON_UNESCAPED_UNICODE); | ||
| 83 | - $message_push->send_time = now(); | ||
| 84 | - $message_push->type = MessagePush::TYPE_TICKET; | ||
| 85 | - $message_push->save(); | ||
| 86 | - $tick->ding = 1; | ||
| 87 | - $tick->save(); | ||
| 88 | - echo now() . " INFO | 项目ID:{$project->table_id} 工单ID:{$tick->id} 推送成功\n"; | ||
| 89 | - }catch (\Exception $exception){ | ||
| 90 | - echo date('Y-m-d H:i:s')." ERROR | ".$exception->getMessage()."\n"; | ||
| 91 | - break; | ||
| 92 | - } | ||
| 93 | - } | ||
| 94 | - } | ||
| 95 | -} |
| @@ -2,6 +2,8 @@ | @@ -2,6 +2,8 @@ | ||
| 2 | 2 | ||
| 3 | namespace App\Console\Commands\WorkOrder; | 3 | namespace App\Console\Commands\WorkOrder; |
| 4 | 4 | ||
| 5 | +use App\Models\Manage\Manage; | ||
| 6 | +use App\Models\WorkOrder\TicketChat; | ||
| 5 | use App\Models\WorkOrder\TicketLog; | 7 | use App\Models\WorkOrder\TicketLog; |
| 6 | use App\Services\DingTalkService; | 8 | use App\Services\DingTalkService; |
| 7 | use Illuminate\Console\Command; | 9 | use Illuminate\Console\Command; |
| @@ -14,7 +16,7 @@ class WorkOrderDing extends Command | @@ -14,7 +16,7 @@ class WorkOrderDing extends Command | ||
| 14 | * | 16 | * |
| 15 | * @var string | 17 | * @var string |
| 16 | */ | 18 | */ |
| 17 | - protected $signature = 'workorder:ding'; | 19 | + protected $signature = 'workorder:ding {action}'; |
| 18 | 20 | ||
| 19 | /** | 21 | /** |
| 20 | * The console command description. | 22 | * The console command description. |
| @@ -40,11 +42,17 @@ class WorkOrderDing extends Command | @@ -40,11 +42,17 @@ class WorkOrderDing extends Command | ||
| 40 | */ | 42 | */ |
| 41 | public function handle() | 43 | public function handle() |
| 42 | { | 44 | { |
| 45 | + $action = $this->argument('action'); | ||
| 46 | + $this->$action(); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public function dingLog() | ||
| 50 | + { | ||
| 43 | while (true) { | 51 | while (true) { |
| 44 | try { | 52 | try { |
| 45 | $log = TicketLog::where('ding', 0)->first(); | 53 | $log = TicketLog::where('ding', 0)->first(); |
| 46 | if (!$log) { | 54 | if (!$log) { |
| 47 | - echo now() . " INFO | 没有通知任务\n"; | 55 | + echo now() . " | INFO | 没有通知任务\n"; |
| 48 | sleep(3); | 56 | sleep(3); |
| 49 | continue; | 57 | continue; |
| 50 | } | 58 | } |
| @@ -55,23 +63,82 @@ class WorkOrderDing extends Command | @@ -55,23 +63,82 @@ class WorkOrderDing extends Command | ||
| 55 | )->get('https://oa.cmer.com/api/dingding/user/' . $mobile); | 63 | )->get('https://oa.cmer.com/api/dingding/user/' . $mobile); |
| 56 | if ($response->status() == 200) { | 64 | if ($response->status() == 200) { |
| 57 | $userid = $response->json()['data']['userid']; | 65 | $userid = $response->json()['data']['userid']; |
| 58 | - $text = "**您有新的售后工单**<br>"; | ||
| 59 | - $text .= "工单ID:{$log->work_order_id}<br>"; | ||
| 60 | - $text .= "工单类型:<font color='red'>{$log->workOrder->product}</font><br>"; | ||
| 61 | - $text .= "项目:{$log->workOrder->project->title}<br>"; | ||
| 62 | - $text .= "时间:{$log->created_at}<br>"; | ||
| 63 | $ding = new DingTalkService(); | 66 | $ding = new DingTalkService(); |
| 64 | $resp = $ding->danliao(json_encode([ | 67 | $resp = $ding->danliao(json_encode([ |
| 65 | - 'text' => $text, | ||
| 66 | - 'title' => '售后工单通知', | ||
| 67 | - ]), [$userid]); | 68 | + 'text' => "您有新的工单(ID: {$log->ticket_id}),请及时处理!", |
| 69 | + 'title' => 'AI协同工单 - ' . $log->ticket->project->title, | ||
| 70 | + 'picUrl' => 'https://hub.globalso.com/logocm.png', | ||
| 71 | + 'messageUrl' => 'https://oa.quanqiusou.cn/afterorder?project_id=' . $log->ticket->project->uuid, | ||
| 72 | + ]), [$userid], 'sampleLink'); | ||
| 68 | $log->ding = 1; | 73 | $log->ding = 1; |
| 74 | + echo now() . " | INFO | 工单ID: {$log->ticket_id} 通知成功\n"; | ||
| 69 | }else | 75 | }else |
| 76 | + { | ||
| 70 | $log->ding = 2; | 77 | $log->ding = 2; |
| 78 | + echo now() . " | ERROR | 工单ID: {$log->ticket_id} 通知失败\n"; | ||
| 79 | + } | ||
| 71 | $log->save(); | 80 | $log->save(); |
| 72 | }catch (\Exception $exception){ | 81 | }catch (\Exception $exception){ |
| 73 | - echo now() . " ERROR | ".$exception->getMessage()."\n"; | ||
| 74 | - break; | 82 | + echo now() . " | ERROR | log ID {$log->id} {$exception->getMessage()} {$exception->getTraceAsString()} \n"; |
| 83 | + $log->ding = 2; | ||
| 84 | + $log->save(); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + public function dingChat() | ||
| 90 | + { | ||
| 91 | + while (true) { | ||
| 92 | + $chat = TicketChat::where([ | ||
| 93 | + 'ding' => 0, | ||
| 94 | + 'submit_side' => 2 | ||
| 95 | + ])->first(); | ||
| 96 | + | ||
| 97 | + if (!$chat) { | ||
| 98 | + echo now() . " | INFO | 没有通知任务\n"; | ||
| 99 | + sleep(3); | ||
| 100 | + continue; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + try { | ||
| 104 | + $project = $chat->ticket->project; | ||
| 105 | + | ||
| 106 | + // 通知谁?暂时通知A端最近一次提交的chat记录的人,如果没有,则通第一负责人 | ||
| 107 | + $lastChat = TicketChat::where('ticket_id', $chat->ticket_id) | ||
| 108 | + ->where('submit_side', 1) | ||
| 109 | + ->orderBy('id', 'desc') | ||
| 110 | + ->first(); | ||
| 111 | + if ($lastChat) { | ||
| 112 | + $mobile = Manage::where('id', $lastChat->manage_id)->first()->mobile; | ||
| 113 | + }else | ||
| 114 | + { | ||
| 115 | + $mobile = Manage::where('id', $project->first_engineer)->first()->mobile; | ||
| 116 | + } | ||
| 117 | + $response = Http::withBasicAuth( | ||
| 118 | + env('DINGDING_BASIC_USER'), | ||
| 119 | + env('DINGDING_BASIC_PASS') | ||
| 120 | + )->get('https://oa.cmer.com/api/dingding/user/' . $mobile); | ||
| 121 | + if ($response->status() == 200) { | ||
| 122 | + $userid = $response->json()['data']['userid']; | ||
| 123 | + $ding = new DingTalkService(); | ||
| 124 | + $resp = $ding->danliao(json_encode([ | ||
| 125 | + 'text' => "客户对工单(ID: {$chat->ticket_id})进行了补充,请及时查看处理!", | ||
| 126 | + 'title' => 'AI协同工单 - ' . $project->title, | ||
| 127 | + 'picUrl' => 'https://hub.globalso.com/logocm.png', | ||
| 128 | + 'messageUrl' => 'https://oa.quanqiusou.cn/afterorder?project_id=' . $project->uuid, | ||
| 129 | + ]), [$userid], 'sampleLink'); | ||
| 130 | + $chat->ding = 1; | ||
| 131 | + echo now() . " | INFO | 工单ID: {$chat->ticket_id} 通知成功\n"; | ||
| 132 | + }else | ||
| 133 | + { | ||
| 134 | + $chat->ding = 2; | ||
| 135 | + echo now() . " | ERROR | 工单ID: {$chat->ticket_id} 通知失败\n"; | ||
| 136 | + } | ||
| 137 | + $chat->save(); | ||
| 138 | + }catch (\Exception $exception) { | ||
| 139 | + echo now() . " | ERROR | chat ID {$chat->id} {$exception->getMessage()} {$exception->getTraceAsString()} \n"; | ||
| 140 | + $chat->ding = 2; | ||
| 141 | + $chat->save(); | ||
| 75 | } | 142 | } |
| 76 | } | 143 | } |
| 77 | } | 144 | } |
| @@ -32,6 +32,12 @@ if (!function_exists('generateRoute')) { | @@ -32,6 +32,12 @@ if (!function_exists('generateRoute')) { | ||
| 32 | $string = $string[0]; | 32 | $string = $string[0]; |
| 33 | } | 33 | } |
| 34 | $sign = str_replace(".", "", trim(strtolower(preg_replace('/[^\w.]+/', '-', trim($string))), '-')); | 34 | $sign = str_replace(".", "", trim(strtolower(preg_replace('/[^\w.]+/', '-', trim($string))), '-')); |
| 35 | + if (strpos($sign, 'well-known-') === 0) { | ||
| 36 | + $sign = substr($sign, strlen('well-known-')); | ||
| 37 | + } | ||
| 38 | + if(empty($sign)){ | ||
| 39 | + $sign = 'u'; | ||
| 40 | + } | ||
| 35 | return $sign; | 41 | return $sign; |
| 36 | } | 42 | } |
| 37 | } | 43 | } |
| @@ -659,7 +665,7 @@ if (!function_exists('getImageUrl')) { | @@ -659,7 +665,7 @@ if (!function_exists('getImageUrl')) { | ||
| 659 | * @method :post | 665 | * @method :post |
| 660 | * @time :2023/7/20 16:46 | 666 | * @time :2023/7/20 16:46 |
| 661 | */ | 667 | */ |
| 662 | - function getImageUrl($path,$storage_type = 0,$location = 0){ | 668 | + function getImageUrl($path,$storage_type = 0,$location = 0,$image_cdn = 1){ |
| 663 | if(is_array($path)){ | 669 | if(is_array($path)){ |
| 664 | $url =[]; | 670 | $url =[]; |
| 665 | foreach ($path as $v){ | 671 | foreach ($path as $v){ |
| @@ -677,8 +683,11 @@ if (!function_exists('getImageUrl')) { | @@ -677,8 +683,11 @@ if (!function_exists('getImageUrl')) { | ||
| 677 | } | 683 | } |
| 678 | if($location == 0){ | 684 | if($location == 0){ |
| 679 | $cos = config('filesystems.disks.cos'); | 685 | $cos = config('filesystems.disks.cos'); |
| 680 | - $cosCdn = ($storage_type == 0) ? $cos['cdn'] : $cos['cdn1']; | ||
| 681 | -// $cosCdn = 'https://file.globalso.com';//TODO::暂时使用 | 686 | + if($image_cdn == 0){//v6链接 |
| 687 | + $cosCdn = $cos['cdn2']; | ||
| 688 | + }else{ | ||
| 689 | + $cosCdn = ($storage_type == 0) ? $cos['cdn'] : $cos['cdn1']; | ||
| 690 | + } | ||
| 682 | $url = $cosCdn.$path; | 691 | $url = $cosCdn.$path; |
| 683 | }else{ | 692 | }else{ |
| 684 | $s3 = config('filesystems.disks.s3'); | 693 | $s3 = config('filesystems.disks.s3'); |
| @@ -17,10 +17,10 @@ class TicketChatController extends Controller | @@ -17,10 +17,10 @@ class TicketChatController extends Controller | ||
| 17 | */ | 17 | */ |
| 18 | public function index($project_id, $ticket_id) | 18 | public function index($project_id, $ticket_id) |
| 19 | { | 19 | { |
| 20 | - $ticket = Tickets::find($ticket_id);; | ||
| 21 | - if (!$ticket) return response('工单未找到', 404); | ||
| 22 | - if ($ticket->project->uuid !== $project_id) return response('无权限查看该工单', 403); | ||
| 23 | - if ($ticket->project->is_del) return response('项目状态异常', 400); | 20 | + $ticket = Tickets::find($ticket_id); |
| 21 | + if (!$ticket) return response()->json(['message' => '工单未找到'], 404); | ||
| 22 | + if ($ticket->project->uuid !== $project_id) return response()->json(['message' => '无权限查看该工单'], 403); | ||
| 23 | + if ($ticket->project->is_del) return response()->json(['message' => '项目状态异常'], 400); | ||
| 24 | 24 | ||
| 25 | $chats = TicketChat::where('ticket_id', $ticket->id) | 25 | $chats = TicketChat::where('ticket_id', $ticket->id) |
| 26 | ->get(); | 26 | ->get(); |
| @@ -47,9 +47,11 @@ class TicketChatController extends Controller | @@ -47,9 +47,11 @@ class TicketChatController extends Controller | ||
| 47 | { | 47 | { |
| 48 | $request->validated(); | 48 | $request->validated(); |
| 49 | $ticket = Tickets::with(['project'])->find($ticket_id); | 49 | $ticket = Tickets::with(['project'])->find($ticket_id); |
| 50 | - if (!$ticket) return response('工单未找到', 404); | ||
| 51 | - if ($ticket->project->uuid !== $project_id) return response('无权限查看该工单', 403); | ||
| 52 | - if ($ticket->project->is_del) return response('项目状态异常', 400); | 50 | + if (!$ticket) return response()->json(['message' => '工单未找到'], 404); |
| 51 | + if ($ticket->status >= Tickets::STATUS_COMPLETED) return response()->json(['message' => '工单已完成或已关闭'], 400); | ||
| 52 | + | ||
| 53 | + if ($ticket->project->uuid !== $project_id) return response()->json(['message' => '无权限查看该工单'], 403); | ||
| 54 | + if ($ticket->project->is_del) return response()->json(['message' => '项目状态异常'], 400); | ||
| 53 | 55 | ||
| 54 | $chat = new TicketChat(); | 56 | $chat = new TicketChat(); |
| 55 | $chat->ticket_id = $ticket->id; | 57 | $chat->ticket_id = $ticket->id; |
| @@ -8,8 +8,10 @@ use App\Http\Requests\Api\WorkOrder\TicketStoreRequest; | @@ -8,8 +8,10 @@ use App\Http\Requests\Api\WorkOrder\TicketStoreRequest; | ||
| 8 | use App\Models\WorkOrder\TicketLog; | 8 | use App\Models\WorkOrder\TicketLog; |
| 9 | use App\Models\WorkOrder\TicketProject; | 9 | use App\Models\WorkOrder\TicketProject; |
| 10 | use App\Models\WorkOrder\Tickets; | 10 | use App\Models\WorkOrder\Tickets; |
| 11 | +use Darabonba\GatewaySpi\Models\InterceptorContext\response; | ||
| 11 | use Illuminate\Http\Request; | 12 | use Illuminate\Http\Request; |
| 12 | use Illuminate\Support\Facades\DB; | 13 | use Illuminate\Support\Facades\DB; |
| 14 | +use Illuminate\Support\Facades\Http; | ||
| 13 | 15 | ||
| 14 | class TicketController extends BaseController | 16 | class TicketController extends BaseController |
| 15 | { | 17 | { |
| @@ -86,6 +88,7 @@ class TicketController extends BaseController | @@ -86,6 +88,7 @@ class TicketController extends BaseController | ||
| 86 | $log = new TicketLog(); | 88 | $log = new TicketLog(); |
| 87 | $log->engineer_id = $project->engineer_id; // 默认第一负责人 | 89 | $log->engineer_id = $project->engineer_id; // 默认第一负责人 |
| 88 | $ticket->logs()->save($log); | 90 | $ticket->logs()->save($log); |
| 91 | + $project->pushWechatGroupMsg("客户新增了工单(ID:{$ticket->id}),请及时处理!"); | ||
| 89 | return $ticket; | 92 | return $ticket; |
| 90 | }); | 93 | }); |
| 91 | return response()->json(['data' => $result]); | 94 | return response()->json(['data' => $result]); |
| @@ -149,4 +152,36 @@ class TicketController extends BaseController | @@ -149,4 +152,36 @@ class TicketController extends BaseController | ||
| 149 | if (!$project) return $this->response('未找到项目', 404); | 152 | if (!$project) return $this->response('未找到项目', 404); |
| 150 | return response()->json(['data' => $project]); | 153 | return response()->json(['data' => $project]); |
| 151 | } | 154 | } |
| 155 | + | ||
| 156 | + /** | ||
| 157 | + * @param $friend_id | ||
| 158 | + * @return void | ||
| 159 | + * 企微群里@小超或艾丝,触发推送工单 | ||
| 160 | + * 接收群ID | ||
| 161 | + */ | ||
| 162 | + public function pushTicketByBot($friend_id) | ||
| 163 | + { | ||
| 164 | + $project = TicketProject::where('wechat_group_id', $friend_id)->where('is_del', 0)->first(); | ||
| 165 | + if (!$project) | ||
| 166 | + return response()->json(['message' => '未找到对应的工单项目'], 404); | ||
| 167 | + | ||
| 168 | +// $url = in_array($project->project_cate, [3,4]) ? 'https://hub.ai.cc/api/fob_ai_customer_service/push_message' : 'https://hub.ai.cc/api/globalso_ai_customer_service/send_msg'; | ||
| 169 | +// $response = Http::post($url, [ | ||
| 170 | +// 'type' => 'Link', | ||
| 171 | +// 'friend_id' => $friend_id, | ||
| 172 | +// 'content' => json_encode([ | ||
| 173 | +// 'title' => 'AI协同工单 - ' . $project->company_name, | ||
| 174 | +// 'desc' => "您好,我们同事没有及时回复,你可以查看工单进度!", | ||
| 175 | +// 'size' => 0, | ||
| 176 | +// 'thumbSize' => 0, | ||
| 177 | +// 'thumbUrl' => 'https://hub.globalso.com/logocm.png', | ||
| 178 | +// 'url' => 'https://oa.quanqiusou.cn/afterorder?project_id='.$project->uuid | ||
| 179 | +// ], JSON_UNESCAPED_UNICODE) | ||
| 180 | +// ]); | ||
| 181 | +// // 返回 $response 的相应内容以及网络状态码 | ||
| 182 | +// return response($response->body(), $response->status()); | ||
| 183 | + | ||
| 184 | + $project->pushWechatGroupMsg("您好,我们同事没有及时回复,你可以查看工单进度!"); | ||
| 185 | + return response()->json(['message' => '工单推送成功']); | ||
| 186 | + } | ||
| 152 | } | 187 | } |
| @@ -90,7 +90,7 @@ class GeoQuestionController extends BaseController | @@ -90,7 +90,7 @@ class GeoQuestionController extends BaseController | ||
| 90 | * @param : keywords->提交的关键字 | 90 | * @param : keywords->提交的关键字 |
| 91 | * @param : status->状态(0:可执行 1:禁止执行) | 91 | * @param : status->状态(0:可执行 1:禁止执行) |
| 92 | * @param : project_id->项目id | 92 | * @param : project_id->项目id |
| 93 | - * @param : type->类型(1:品牌 2:营销) | 93 | + * @param : type->类型() |
| 94 | */ | 94 | */ |
| 95 | public function saveGeoQuestion(){ | 95 | public function saveGeoQuestion(){ |
| 96 | $this->request->validate([ | 96 | $this->request->validate([ |
| @@ -13,6 +13,7 @@ use App\Enums\Common\Code; | @@ -13,6 +13,7 @@ use App\Enums\Common\Code; | ||
| 13 | use App\Http\Controllers\Aside\BaseController; | 13 | use App\Http\Controllers\Aside\BaseController; |
| 14 | use App\Models\Domain\DomainInfo; | 14 | use App\Models\Domain\DomainInfo; |
| 15 | use App\Models\Project\CountAllProject; | 15 | use App\Models\Project\CountAllProject; |
| 16 | +use Illuminate\Support\Facades\DB; | ||
| 16 | 17 | ||
| 17 | /** | 18 | /** |
| 18 | * @remark :统计所有项目(4.0,5.0,6.0) | 19 | * @remark :统计所有项目(4.0,5.0,6.0) |
| @@ -46,6 +47,27 @@ class AllProjectController extends BaseController | @@ -46,6 +47,27 @@ class AllProjectController extends BaseController | ||
| 46 | $this->map['company'] = ['like','%'.$this->map['company'].'%']; | 47 | $this->map['company'] = ['like','%'.$this->map['company'].'%']; |
| 47 | } | 48 | } |
| 48 | $data = $allProject->lists($this->map,$this->page,$this->row); | 49 | $data = $allProject->lists($this->map,$this->page,$this->row); |
| 50 | + | ||
| 51 | + if (!empty($data['list'])) { | ||
| 52 | + foreach ($data['list'] as $key => $value) { | ||
| 53 | + $ticketProject = null; | ||
| 54 | + if ($value['version'] == 1) { | ||
| 55 | + // version 为 1:6.0 | ||
| 56 | + $ticketProject = DB::table('gl_ticket_projects') | ||
| 57 | + ->where('table_id', $value['project_id']) | ||
| 58 | + ->where('project_cate', 2) | ||
| 59 | + ->first(); | ||
| 60 | + } else { | ||
| 61 | + // version 不为 1 | ||
| 62 | + $ticketProject = DB::table('gl_ticket_projects') | ||
| 63 | + ->where('post_id', $value['project_id']) | ||
| 64 | + ->where('project_cate', 1) | ||
| 65 | + ->first(); | ||
| 66 | + } | ||
| 67 | + $data['list'][$key]['uuid'] = $ticketProject ? $ticketProject->uuid : null; | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 49 | $this->response('success',Code::SUCCESS,$data); | 71 | $this->response('success',Code::SUCCESS,$data); |
| 50 | } | 72 | } |
| 51 | } | 73 | } |
| @@ -37,6 +37,7 @@ use App\Models\RankData\RankData; | @@ -37,6 +37,7 @@ use App\Models\RankData\RankData; | ||
| 37 | use App\Models\Task\Task; | 37 | use App\Models\Task\Task; |
| 38 | use App\Models\WebSetting\WebLanguage; | 38 | use App\Models\WebSetting\WebLanguage; |
| 39 | use Illuminate\Http\Request; | 39 | use Illuminate\Http\Request; |
| 40 | +use Illuminate\Support\Facades\DB; | ||
| 40 | 41 | ||
| 41 | /** | 42 | /** |
| 42 | * 项目管理 | 43 | * 项目管理 |
| @@ -69,6 +70,16 @@ class ProjectController extends BaseController | @@ -69,6 +70,16 @@ class ProjectController extends BaseController | ||
| 69 | if(!empty($lists) && !empty($lists['list'])){ | 70 | if(!empty($lists) && !empty($lists['list'])){ |
| 70 | foreach ($lists['list'] as $k => $v){ | 71 | foreach ($lists['list'] as $k => $v){ |
| 71 | $v = $this->handleParam($v); | 72 | $v = $this->handleParam($v); |
| 73 | + | ||
| 74 | + // 组装 工单UUID | ||
| 75 | + $ticketProject = null; | ||
| 76 | + $ticketProject = DB::table('gl_ticket_projects') | ||
| 77 | + ->where('table_id', $v['id']) | ||
| 78 | + ->where('project_cate', 2) | ||
| 79 | + ->first(); | ||
| 80 | + $v['uuid'] = $ticketProject ? $ticketProject->uuid : null; | ||
| 81 | + // 组装 工单UUID END | ||
| 82 | + | ||
| 72 | $lists['list'][$k] = $v; | 83 | $lists['list'][$k] = $v; |
| 73 | } | 84 | } |
| 74 | } | 85 | } |
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: zhl | ||
| 5 | + * Date: 2025/7/8 | ||
| 6 | + * Time: 14:11 | ||
| 7 | + */ | ||
| 8 | +namespace App\Http\Controllers\Aside\Project; | ||
| 9 | + | ||
| 10 | +use App\Enums\Common\Code; | ||
| 11 | +use App\Http\Controllers\Aside\BaseController; | ||
| 12 | +use App\Models\Project\Project; | ||
| 13 | +use App\Models\Project\ProjectFlow; | ||
| 14 | +use Illuminate\Http\Request; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * 数据统计结果 | ||
| 18 | + * Class StatisticsController | ||
| 19 | + * @package App\Http\Controllers\Aside\Project | ||
| 20 | + */ | ||
| 21 | +class StatisticsController extends BaseController | ||
| 22 | +{ | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 流量统计 | ||
| 26 | + * @param Request $request | ||
| 27 | + * @return \Illuminate\Http\JsonResponse | ||
| 28 | + */ | ||
| 29 | + public function flow(Request $request) | ||
| 30 | + { | ||
| 31 | + $project_id = intval($request->input('project_id', '0')); | ||
| 32 | + $start_at = $request->input('start_at', ''); | ||
| 33 | + $end_at = $request->input('end_at', ''); | ||
| 34 | + | ||
| 35 | + $result = ProjectFlow::when($project_id, function ($query) use ($project_id) { | ||
| 36 | + return $query->where(['project_id' => $project_id]); | ||
| 37 | + }) | ||
| 38 | + ->when($start_at, function ($query) use ($start_at) { | ||
| 39 | + return $query->where('date', '>=', $start_at); | ||
| 40 | + }) | ||
| 41 | + ->when($end_at, function ($query) use ($end_at) { | ||
| 42 | + return $query->where('date', '<=', $end_at); | ||
| 43 | + }) | ||
| 44 | + ->orderBy('date', 'desc') | ||
| 45 | + ->orderBy('id', 'desc') | ||
| 46 | + ->paginate($this->row); | ||
| 47 | + | ||
| 48 | + if ($result->isEmpty()) | ||
| 49 | + return $this->response('success',Code::SUCCESS, []); | ||
| 50 | + | ||
| 51 | + $result = $result->toArray(); | ||
| 52 | + $project_ids = array_column($result['list'], 'project_id'); | ||
| 53 | + $projects = Project::whereIn('id', $project_ids)->pluck('company', 'id')->toArray(); | ||
| 54 | + $total = 0; | ||
| 55 | + foreach ($result['list'] as &$item) { | ||
| 56 | + $item['company'] = $projects[$item['project_id']]; | ||
| 57 | + $item['use_flow'] = $this->formatBytes($item['cdn_flow']); | ||
| 58 | + $item['use_flow_mb'] = round($item['cdn_flow'] / 1048576, 2); | ||
| 59 | + $total += $item['cdn_flow']; | ||
| 60 | + unset($item['id']); | ||
| 61 | + unset($item['last_at']); | ||
| 62 | + unset($item['updated_at']); | ||
| 63 | + unset($item['created_at']); | ||
| 64 | + } | ||
| 65 | + $result['use_flow'] = $this->formatBytes($total); | ||
| 66 | + return $this->response('success',Code::SUCCESS, $result); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * 字节单位转换 | ||
| 71 | + * @param $bytes | ||
| 72 | + * @param int $precision | ||
| 73 | + * @return string | ||
| 74 | + */ | ||
| 75 | + public function formatBytes($bytes, $precision = 2) { | ||
| 76 | + $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; | ||
| 77 | + | ||
| 78 | + $bytes = max($bytes, 0); | ||
| 79 | + $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); | ||
| 80 | + $pow = min($pow, count($units) - 1); | ||
| 81 | + | ||
| 82 | + $bytes /= pow(1024, $pow); | ||
| 83 | + | ||
| 84 | + return round($bytes, $precision) . ' ' . $units[$pow]; | ||
| 85 | + } | ||
| 86 | +} |
| @@ -8,13 +8,13 @@ use App\Http\Requests\Aside\WorkOrder\AsideTicketStoreRequest; | @@ -8,13 +8,13 @@ use App\Http\Requests\Aside\WorkOrder\AsideTicketStoreRequest; | ||
| 8 | use App\Http\Requests\Aside\WorkOrder\AsideTicketListRequest; | 8 | use App\Http\Requests\Aside\WorkOrder\AsideTicketListRequest; |
| 9 | use App\Http\Requests\Aside\WorkOrder\AsideTicketUpdateRequest; | 9 | use App\Http\Requests\Aside\WorkOrder\AsideTicketUpdateRequest; |
| 10 | use App\Http\Requests\Aside\WorkOrder\TicketProjectListRequest; | 10 | use App\Http\Requests\Aside\WorkOrder\TicketProjectListRequest; |
| 11 | -use App\Models\ProjectAssociation\ProjectAssociation; | ||
| 12 | use App\Models\Workchat\MessagePush; | 11 | use App\Models\Workchat\MessagePush; |
| 13 | use App\Models\WorkOrder\TicketLog; | 12 | use App\Models\WorkOrder\TicketLog; |
| 14 | use App\Models\WorkOrder\TicketProject; | 13 | use App\Models\WorkOrder\TicketProject; |
| 15 | use App\Models\WorkOrder\Tickets; | 14 | use App\Models\WorkOrder\Tickets; |
| 16 | use Illuminate\Support\Facades\DB; | 15 | use Illuminate\Support\Facades\DB; |
| 17 | 16 | ||
| 17 | + | ||
| 18 | class AsideTicketController extends BaseController | 18 | class AsideTicketController extends BaseController |
| 19 | { | 19 | { |
| 20 | /** | 20 | /** |
| @@ -106,6 +106,11 @@ class AsideTicketController extends BaseController | @@ -106,6 +106,11 @@ class AsideTicketController extends BaseController | ||
| 106 | $version = $validated['version']; | 106 | $version = $validated['version']; |
| 107 | return $query->where('version', $version); | 107 | return $query->where('version', $version); |
| 108 | }) | 108 | }) |
| 109 | + ->when(!empty($validated['project_cate']), function ($query) use ($validated) { | ||
| 110 | + // 版本号筛选 | ||
| 111 | + $project_cate = $validated['project_cate']; | ||
| 112 | + return $query->where('project_cate', $project_cate); | ||
| 113 | + }) | ||
| 109 | ->paginate($this->row, ['*'], 'page', $this->page); | 114 | ->paginate($this->row, ['*'], 'page', $this->page); |
| 110 | $this->response('success', Code::SUCCESS, $lists); | 115 | $this->response('success', Code::SUCCESS, $lists); |
| 111 | } | 116 | } |
| @@ -143,6 +148,7 @@ class AsideTicketController extends BaseController | @@ -143,6 +148,7 @@ class AsideTicketController extends BaseController | ||
| 143 | $log->engineer_id = $engineer_id; | 148 | $log->engineer_id = $engineer_id; |
| 144 | $ticket->logs()->save($log); | 149 | $ticket->logs()->save($log); |
| 145 | } | 150 | } |
| 151 | + $project->pushWechatGroupMsg("创贸({$ticket->submit_username})新增了工单(ID:{$ticket->id}),请及时处理!"); | ||
| 146 | return $ticket; | 152 | return $ticket; |
| 147 | }); | 153 | }); |
| 148 | $this->response('success', Code::SUCCESS, $result->toArray()); | 154 | $this->response('success', Code::SUCCESS, $result->toArray()); |
| @@ -232,34 +238,11 @@ class AsideTicketController extends BaseController | @@ -232,34 +238,11 @@ class AsideTicketController extends BaseController | ||
| 232 | if (empty($project)) | 238 | if (empty($project)) |
| 233 | $this->response('工单项目不存在', Code::USER_MODEL_NOTFOUND_ERROE); | 239 | $this->response('工单项目不存在', Code::USER_MODEL_NOTFOUND_ERROE); |
| 234 | 240 | ||
| 235 | - if (empty($project->association)) { | 241 | + if (empty($project->wechat_group_id)) { |
| 236 | $this->response('该工单没有绑定的企微群', Code::USER_MODEL_NOTFOUND_ERROE); | 242 | $this->response('该工单没有绑定的企微群', Code::USER_MODEL_NOTFOUND_ERROE); |
| 237 | } | 243 | } |
| 238 | - | ||
| 239 | - $ticket = Tickets::where('project_id', $project->id) | ||
| 240 | - ->orderBy('id', 'desc') | ||
| 241 | - ->first(); | ||
| 242 | - | ||
| 243 | - $message_push = new MessagePush(); | ||
| 244 | - $message_push->project_id = $project->table_id; | ||
| 245 | - $message_push->friend_id = $project->association->friend_id; | ||
| 246 | - $message_push->content_type = 'Link'; | ||
| 247 | - $message_push->content = json_encode([ | ||
| 248 | - 'title' => '工单查看 - ' . $project->company_name, | ||
| 249 | - 'desc' => $ticket ? $ticket->title : "工单列表", | ||
| 250 | - 'size' => 0, | ||
| 251 | - 'thumbSize' => 0, | ||
| 252 | - 'thumbUrl' => 'https://oa.quanqiusou.cn/logo.ico', | ||
| 253 | - 'url' => 'https://oa.quanqiusou.cn/afterorder?project_id='.$project->uuid | ||
| 254 | - ], JSON_UNESCAPED_UNICODE); | ||
| 255 | - $message_push->send_time = now(); | ||
| 256 | - $message_push->type = MessagePush::TYPE_TICKET; | ||
| 257 | - $message_push->save(); | ||
| 258 | - | ||
| 259 | - if (!empty($ticket)) { | ||
| 260 | - $ticket->ding = 1; // 标记为已推送 | ||
| 261 | - $ticket->save(); | ||
| 262 | - } | 244 | + $project->pushWechatGroupMsg(); |
| 263 | $this->response('success', Code::SUCCESS); | 245 | $this->response('success', Code::SUCCESS); |
| 264 | } | 246 | } |
| 247 | + | ||
| 265 | } | 248 | } |
| @@ -87,6 +87,8 @@ class AsideTicketLogController extends BaseController | @@ -87,6 +87,8 @@ class AsideTicketLogController extends BaseController | ||
| 87 | $ticket->status = Tickets::STATUS_COMPLETED; | 87 | $ticket->status = Tickets::STATUS_COMPLETED; |
| 88 | // 如果所有子任务都完成了,则将工单状态改为已完成 | 88 | // 如果所有子任务都完成了,则将工单状态改为已完成 |
| 89 | $ticket->end_at = now(); | 89 | $ticket->end_at = now(); |
| 90 | + $project = $ticket->project; | ||
| 91 | + $project->pushWechatGroupMsg("工单(ID:{$ticket->id})已全部完成,请访问查看详情!"); | ||
| 90 | } | 92 | } |
| 91 | $ticket->save(); | 93 | $ticket->save(); |
| 92 | return $log; | 94 | return $log; |
| @@ -45,6 +45,7 @@ class TicketChatController extends BaseController | @@ -45,6 +45,7 @@ class TicketChatController extends BaseController | ||
| 45 | $validated = $request->validated(); | 45 | $validated = $request->validated(); |
| 46 | $ticket = Tickets::find($ticket_id); | 46 | $ticket = Tickets::find($ticket_id); |
| 47 | if (!$ticket) return response('工单未找到', 404); | 47 | if (!$ticket) return response('工单未找到', 404); |
| 48 | + if ($ticket->status >= Tickets::STATUS_COMPLETED) return response('工单已完成或已关闭', 400); | ||
| 48 | if ($ticket->project->is_del) return response('项目状态异常', 400); | 49 | if ($ticket->project->is_del) return response('项目状态异常', 400); |
| 49 | 50 | ||
| 50 | $chat = new TicketChat(); | 51 | $chat = new TicketChat(); |
| @@ -62,6 +63,8 @@ class TicketChatController extends BaseController | @@ -62,6 +63,8 @@ class TicketChatController extends BaseController | ||
| 62 | $chat->submit_side = 1; | 63 | $chat->submit_side = 1; |
| 63 | $chat->manage_id = $this->manage['id']; | 64 | $chat->manage_id = $this->manage['id']; |
| 64 | $chat->save(); | 65 | $chat->save(); |
| 66 | + $project = $ticket->project; | ||
| 67 | + $project->pushWechatGroupMsg("{$chat->submit_username}对工单(ID:{$ticket->id})进行了补充,请及时查看处理!"); | ||
| 65 | $this->response('success', Code::SUCCESS, $chat); | 68 | $this->response('success', Code::SUCCESS, $chat); |
| 66 | } | 69 | } |
| 67 | 70 |
| @@ -70,6 +70,9 @@ class ComController extends BaseController | @@ -70,6 +70,9 @@ class ComController extends BaseController | ||
| 70 | if($this->user['login_source'] == User::LOGIN_PASSWORD_SOURCE){ | 70 | if($this->user['login_source'] == User::LOGIN_PASSWORD_SOURCE){ |
| 71 | $data[] = 19; | 71 | $data[] = 19; |
| 72 | } | 72 | } |
| 73 | + if($this->user['login_source'] != User::LOGIN_AUTO_SOURCE){ | ||
| 74 | + $data[] = 76; | ||
| 75 | + } | ||
| 73 | if(!empty($data)){ | 76 | if(!empty($data)){ |
| 74 | $this->map['id'] = ['not in',$data]; | 77 | $this->map['id'] = ['not in',$data]; |
| 75 | } | 78 | } |
| @@ -95,7 +95,7 @@ class OperationHeartbeatController extends BaseController | @@ -95,7 +95,7 @@ class OperationHeartbeatController extends BaseController | ||
| 95 | }else{ | 95 | }else{ |
| 96 | $date_time = strtotime($info['updated_at']) + 60; | 96 | $date_time = strtotime($info['updated_at']) + 60; |
| 97 | if($date_time < time()){ | 97 | if($date_time < time()){ |
| 98 | - $operationHeartbeatModel->edit(['status'=>0,'ip'=>'127.0.0.1'],$condition); | 98 | + $operationHeartbeatModel->edit(['status'=>0,'ip'=>'127.0.0.1'],['id'=>$info['id']]); |
| 99 | $info['status'] = 0; | 99 | $info['status'] = 0; |
| 100 | } | 100 | } |
| 101 | if($info['status'] == 1){ | 101 | if($info['status'] == 1){ |
| @@ -12,6 +12,8 @@ namespace App\Http\Controllers\Bside\Geo; | @@ -12,6 +12,8 @@ namespace App\Http\Controllers\Bside\Geo; | ||
| 12 | use App\Enums\Common\Code; | 12 | use App\Enums\Common\Code; |
| 13 | use App\Http\Controllers\Bside\BaseController; | 13 | use App\Http\Controllers\Bside\BaseController; |
| 14 | use App\Http\Logic\Bside\Geo\GeoQuestionResLogic; | 14 | use App\Http\Logic\Bside\Geo\GeoQuestionResLogic; |
| 15 | +use App\Models\Geo\GeoPlatform; | ||
| 16 | +use App\Models\Geo\GeoQuestion; | ||
| 15 | use Illuminate\Http\Request; | 17 | use Illuminate\Http\Request; |
| 16 | 18 | ||
| 17 | /** | 19 | /** |
| @@ -28,6 +30,32 @@ class GeoQuestionResController extends BaseController | @@ -28,6 +30,32 @@ class GeoQuestionResController extends BaseController | ||
| 28 | parent::__construct($request); | 30 | parent::__construct($request); |
| 29 | $this->logic = new GeoQuestionResLogic(); | 31 | $this->logic = new GeoQuestionResLogic(); |
| 30 | } | 32 | } |
| 33 | + /** | ||
| 34 | + * @remark :获取类型 | ||
| 35 | + * @name :getType | ||
| 36 | + * @author :lyh | ||
| 37 | + * @method :post | ||
| 38 | + * @time :2025/7/3 10:47 | ||
| 39 | + */ | ||
| 40 | + public function getType(){ | ||
| 41 | + $questionModel = new GeoQuestion(); | ||
| 42 | + $data['type'] = $questionModel->brandType(); | ||
| 43 | + $geoPlatformModel = new GeoPlatform(); | ||
| 44 | + $data['platform'] = $geoPlatformModel->getList(); | ||
| 45 | + return $this->response('success',Code::SUCCESS,$data); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * @remark :获取统计数据 | ||
| 50 | + * @name :getCount | ||
| 51 | + * @author :lyh | ||
| 52 | + * @method :post | ||
| 53 | + * @time :2025/7/8 17:18 | ||
| 54 | + */ | ||
| 55 | + public function getCount(){ | ||
| 56 | + $data = $this->logic->getCount(); | ||
| 57 | + $this->response('success',Code::SUCCESS,$data); | ||
| 58 | + } | ||
| 31 | 59 | ||
| 32 | /** | 60 | /** |
| 33 | * @remark :获取列表数据 | 61 | * @remark :获取列表数据 |
| @@ -44,7 +72,7 @@ class GeoQuestionResController extends BaseController | @@ -44,7 +72,7 @@ class GeoQuestionResController extends BaseController | ||
| 44 | 'project_id.required' => 'project_id不能为空', | 72 | 'project_id.required' => 'project_id不能为空', |
| 45 | 'type.required' => '品牌类型不能为空' | 73 | 'type.required' => '品牌类型不能为空' |
| 46 | ]); | 74 | ]); |
| 47 | - $data = $this->logic->getResultList($this->map,$this->page,$this->row,$this->order); | 75 | + $data = $this->logic->getResultList($this->map,$this->page,$this->row); |
| 48 | $this->response('success',Code::SUCCESS,$data); | 76 | $this->response('success',Code::SUCCESS,$data); |
| 49 | } | 77 | } |
| 50 | 78 |
| @@ -27,7 +27,7 @@ class AiCommandLogic extends BaseLogic | @@ -27,7 +27,7 @@ class AiCommandLogic extends BaseLogic | ||
| 27 | */ | 27 | */ |
| 28 | public function getPrompt($is_batch = 0){ | 28 | public function getPrompt($is_batch = 0){ |
| 29 | //是否有项目指令 | 29 | //是否有项目指令 |
| 30 | - $ai_command = $this->model->where('key', $this->param['key'])->where('project_id', $this->project['id'])->first(); | 30 | + $ai_command = $this->model->where('key', $this->param['key'])->where('project_id', $this->user['project_id'] ?? $this->project['id'])->first(); |
| 31 | if(!$ai_command){ | 31 | if(!$ai_command){ |
| 32 | $ai_command = $this->model->where('key', $this->param['key'])->where('project_id', 0)->first(); | 32 | $ai_command = $this->model->where('key', $this->param['key'])->where('project_id', 0)->first(); |
| 33 | } | 33 | } |
| @@ -154,7 +154,7 @@ class CustomModuleContentLogic extends BaseLogic | @@ -154,7 +154,7 @@ class CustomModuleContentLogic extends BaseLogic | ||
| 154 | if($info !== false){ | 154 | if($info !== false){ |
| 155 | $this->fail('当前数据名称已存在'); | 155 | $this->fail('当前数据名称已存在'); |
| 156 | } | 156 | } |
| 157 | - try { | 157 | +// try { |
| 158 | $this->param['sort'] = $this->setNewsSort(); | 158 | $this->param['sort'] = $this->setNewsSort(); |
| 159 | $id = $this->model->addReturnId($this->param); | 159 | $id = $this->model->addReturnId($this->param); |
| 160 | $route = RouteMap::setRoute($this->param['route'], RouteMap::SOURCE_MODULE, | 160 | $route = RouteMap::setRoute($this->param['route'], RouteMap::SOURCE_MODULE, |
| @@ -162,9 +162,9 @@ class CustomModuleContentLogic extends BaseLogic | @@ -162,9 +162,9 @@ class CustomModuleContentLogic extends BaseLogic | ||
| 162 | $this->addUpdateNotify(RouteMap::SOURCE_MODULE,$route); | 162 | $this->addUpdateNotify(RouteMap::SOURCE_MODULE,$route); |
| 163 | $this->curlDelRoute(['new_route'=>$route]); | 163 | $this->curlDelRoute(['new_route'=>$route]); |
| 164 | $this->edit(['route' => $route], ['id' => $id]); | 164 | $this->edit(['route' => $route], ['id' => $id]); |
| 165 | - }catch (\Exception $e){ | ||
| 166 | - $this->fail('系统错误,请联系管理员'); | ||
| 167 | - } | 165 | +// }catch (\Exception $e){ |
| 166 | +// $this->fail('系统错误,请联系管理员'); | ||
| 167 | +// } | ||
| 168 | return $id; | 168 | return $id; |
| 169 | } | 169 | } |
| 170 | 170 | ||
| @@ -248,8 +248,10 @@ class CustomModuleContentLogic extends BaseLogic | @@ -248,8 +248,10 @@ class CustomModuleContentLogic extends BaseLogic | ||
| 248 | { | 248 | { |
| 249 | //生成一条删除路由记录 | 249 | //生成一条删除路由记录 |
| 250 | $info = $this->model->read(['id' => $id], ['id', 'route']); | 250 | $info = $this->model->read(['id' => $id], ['id', 'route']); |
| 251 | - $this->addUpdateNotify(RouteMap::SOURCE_MODULE,$route); | ||
| 252 | - $this->curlDelRoute(['old_route'=>$info['route'],'new_route'=>$route]); | 251 | + if($info !== false){ |
| 252 | + $this->addUpdateNotify(RouteMap::SOURCE_MODULE,$route); | ||
| 253 | + $this->curlDelRoute(['old_route'=>$info['route'],'new_route'=>$route]); | ||
| 254 | + } | ||
| 253 | return true; | 255 | return true; |
| 254 | } | 256 | } |
| 255 | 257 |
| @@ -22,15 +22,34 @@ class GeoQuestionResLogic extends BaseLogic | @@ -22,15 +22,34 @@ class GeoQuestionResLogic extends BaseLogic | ||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| 25 | + * @remark :获取类型统计数据 | ||
| 26 | + * @name :getCount | ||
| 27 | + * @author :lyh | ||
| 28 | + * @method :post | ||
| 29 | + * @time :2025/7/8 17:16 | ||
| 30 | + */ | ||
| 31 | + public function getCount(){ | ||
| 32 | + $total = $this->model->counts(['project_id'=>$this->user['project_id']]); | ||
| 33 | + $type_1 = $this->model->counts(['type'=>$this->model::BRAND_TYPE,'project_id'=>$this->user['project_id']]); | ||
| 34 | + $type_2 = $this->model->counts(['type'=>$this->model::MARKETING_TYPE,'project_id'=>$this->user['project_id']]); | ||
| 35 | + return $this->success(['total'=>$total,'type_1'=>$type_1,'type_2'=>$type_2]); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 25 | * @remark :获取列表页数据 | 39 | * @remark :获取列表页数据 |
| 26 | * @name :getResultList | 40 | * @name :getResultList |
| 27 | * @author :lyh | 41 | * @author :lyh |
| 28 | * @method :post | 42 | * @method :post |
| 29 | * @time :2025/7/4 9:48 | 43 | * @time :2025/7/4 9:48 |
| 30 | */ | 44 | */ |
| 31 | - public function getResultList($map = [],$page = 1,$row = 20,$order = 'id'){ | ||
| 32 | - $filed = ['id','project_id','question_id','platform','question','keywords','url']; | ||
| 33 | - $data = $this->model->lists($map,$page,$row,$order,$filed); | 45 | + public function getResultList($map = [],$page = 1,$row = 20){ |
| 46 | + $filed = ['id','project_id','question_id','platform','question','keywords','url','created_at','updated_at']; | ||
| 47 | + $query = $this->model->formatQuery($map); | ||
| 48 | + $query = $query->where(function ($q) { | ||
| 49 | + $q->whereRaw('JSON_LENGTH(keywords) > 0') | ||
| 50 | + ->orWhereRaw('JSON_LENGTH(url) > 0'); | ||
| 51 | + }); | ||
| 52 | + $data = $query->orderByRaw('CHAR_LENGTH(question) ASC')->paginate($row, $filed, 'page', $page);; | ||
| 34 | return $this->success($data); | 53 | return $this->success($data); |
| 35 | } | 54 | } |
| 36 | 55 |
| @@ -25,7 +25,8 @@ class TicketProjectListRequest extends FormRequest | @@ -25,7 +25,8 @@ class TicketProjectListRequest extends FormRequest | ||
| 25 | { | 25 | { |
| 26 | return [ | 26 | return [ |
| 27 | 'search' => 'nullable|string', // 搜索关键词 | 27 | 'search' => 'nullable|string', // 搜索关键词 |
| 28 | - 'version' => 'nullable|in:5,6,7', // 版本号 | 28 | + 'project_cate' => 'nullable|in:1,2,3,4', // 项目分类:1V5,2V6,3超迹,4域途 |
| 29 | + 'version' => 'nullable|integer', // 版本号 | ||
| 29 | ]; | 30 | ]; |
| 30 | } | 31 | } |
| 31 | } | 32 | } |
| @@ -25,6 +25,12 @@ class GeoQuestion extends Base | @@ -25,6 +25,12 @@ class GeoQuestion extends Base | ||
| 25 | 25 | ||
| 26 | public $frequency = [1,2,3,4,5,6,7,8,9,10];//类型 | 26 | public $frequency = [1,2,3,4,5,6,7,8,9,10];//类型 |
| 27 | 27 | ||
| 28 | + const TYPE_BRAND = 1; | ||
| 29 | + const TYPE_MARKET = 2; | ||
| 30 | + | ||
| 31 | + const STATUS_CLOSE = 0; | ||
| 32 | + const STATUS_OPEN = 1; | ||
| 33 | + | ||
| 28 | /** | 34 | /** |
| 29 | * @remark :geo提交网址获取器 | 35 | * @remark :geo提交网址获取器 |
| 30 | * @name :getUrlAttribute | 36 | * @name :getUrlAttribute |
| @@ -71,16 +77,13 @@ class GeoQuestion extends Base | @@ -71,16 +77,13 @@ class GeoQuestion extends Base | ||
| 71 | } | 77 | } |
| 72 | 78 | ||
| 73 | /** | 79 | /** |
| 74 | - * @remark :品牌类型 | ||
| 75 | - * @name :brandType | ||
| 76 | - * @author :lyh | ||
| 77 | - * @method :post | ||
| 78 | - * @time :2025/7/3 9:43 | 80 | + * 品牌类型 |
| 81 | + * @return array | ||
| 79 | */ | 82 | */ |
| 80 | public function brandType(){ | 83 | public function brandType(){ |
| 81 | return [ | 84 | return [ |
| 82 | - 1=>'品牌数据', | ||
| 83 | - 2=>'营销数据' | 85 | + self::TYPE_BRAND => '品牌数据', |
| 86 | + self::TYPE_MARKET => '营销数据' | ||
| 84 | ]; | 87 | ]; |
| 85 | } | 88 | } |
| 86 | } | 89 | } |
| @@ -22,6 +22,9 @@ use App\Models\Base; | @@ -22,6 +22,9 @@ use App\Models\Base; | ||
| 22 | class GeoQuestionResult extends Base | 22 | class GeoQuestionResult extends Base |
| 23 | { | 23 | { |
| 24 | protected $table = 'gl_geo_question_result'; | 24 | protected $table = 'gl_geo_question_result'; |
| 25 | + | ||
| 26 | + const BRAND_TYPE = 1;//品牌类型 | ||
| 27 | + const MARKETING_TYPE = 2;//营销类型 | ||
| 25 | /** | 28 | /** |
| 26 | * @remark :geo提交关键字获取器 | 29 | * @remark :geo提交关键字获取器 |
| 27 | * @name :getUrlAttribute | 30 | * @name :getUrlAttribute |
| @@ -52,4 +55,18 @@ class GeoQuestionResult extends Base | @@ -52,4 +55,18 @@ class GeoQuestionResult extends Base | ||
| 52 | return $value; | 55 | return $value; |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 58 | + /** | ||
| 59 | + * @remark :geo提交结果获取器 | ||
| 60 | + * @name :getUrlAttribute | ||
| 61 | + * @author :lyh | ||
| 62 | + * @method :post | ||
| 63 | + * @time :2025/7/3 9:52 | ||
| 64 | + */ | ||
| 65 | + public function getTextAttribute($value) | ||
| 66 | + { | ||
| 67 | + if($value){ | ||
| 68 | + $value = Arr::s2a($value); | ||
| 69 | + } | ||
| 70 | + return $value; | ||
| 71 | + } | ||
| 55 | } | 72 | } |
app/Models/Project/ProjectFlow.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: zhl | ||
| 5 | + * Date: 2025/7/4 | ||
| 6 | + * Time: 15:05 | ||
| 7 | + */ | ||
| 8 | +namespace App\Models\Project; | ||
| 9 | + | ||
| 10 | +use App\Models\Base; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 流量统计 | ||
| 14 | + * Class ProjectFlow | ||
| 15 | + * @package App\Models\Project | ||
| 16 | + */ | ||
| 17 | +class ProjectFlow extends Base | ||
| 18 | +{ | ||
| 19 | + /** | ||
| 20 | + * 表名 | ||
| 21 | + * @var string | ||
| 22 | + */ | ||
| 23 | + protected $table = 'gl_project_flow'; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 流量日志记录 | ||
| 27 | + * @param $project_id | ||
| 28 | + * @param $date | ||
| 29 | + * @param $cdn_flow | ||
| 30 | + * @param $last_at | ||
| 31 | + * @return ProjectFlow | ||
| 32 | + */ | ||
| 33 | + public static function flowInsert($project_id, $date, $cdn_flow, $last_at) | ||
| 34 | + { | ||
| 35 | + $flow = self::where(['project_id' => $project_id, 'date' => $date])->first(); | ||
| 36 | + if (empty($flow)) { | ||
| 37 | + $flow = new self(); | ||
| 38 | + $flow->project_id = $project_id; | ||
| 39 | + $flow->date = $date; | ||
| 40 | + $flow->cdn_flow = $cdn_flow; | ||
| 41 | + } else { | ||
| 42 | + $flow->cdn_flow = $flow->cdn_flow + $cdn_flow; | ||
| 43 | + } | ||
| 44 | + $flow->last_at = $last_at; | ||
| 45 | + $flow->save(); | ||
| 46 | + return $flow; | ||
| 47 | + } | ||
| 48 | +} |
| @@ -6,6 +6,7 @@ use App\Models\Base; | @@ -6,6 +6,7 @@ use App\Models\Base; | ||
| 6 | use App\Models\Manage\Manage; | 6 | use App\Models\Manage\Manage; |
| 7 | use App\Models\Project\Project; | 7 | use App\Models\Project\Project; |
| 8 | use App\Models\ProjectAssociation\ProjectAssociation; | 8 | use App\Models\ProjectAssociation\ProjectAssociation; |
| 9 | +use App\Models\Workchat\MessagePush; | ||
| 9 | use Illuminate\Database\Eloquent\Factories\HasFactory; | 10 | use Illuminate\Database\Eloquent\Factories\HasFactory; |
| 10 | 11 | ||
| 11 | class TicketProject extends Base | 12 | class TicketProject extends Base |
| @@ -53,4 +54,31 @@ class TicketProject extends Base | @@ -53,4 +54,31 @@ class TicketProject extends Base | ||
| 53 | ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT) | 54 | ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT) |
| 54 | ->select(['id', 'project_id', 'friend_id', 'binding_app']); | 55 | ->select(['id', 'project_id', 'friend_id', 'binding_app']); |
| 55 | } | 56 | } |
| 57 | + | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * @return void | ||
| 61 | + * 企微群推送工单消息 | ||
| 62 | + */ | ||
| 63 | + public function pushWechatGroupMsg($desc="可提交新的工单、查询工单进度、AI会同步通知售后人员!") | ||
| 64 | + { | ||
| 65 | + if (!empty($this->wechat_group_id)) | ||
| 66 | + { | ||
| 67 | + $message_push = new MessagePush(); | ||
| 68 | + $message_push->project_id = $this->table_id; | ||
| 69 | + $message_push->friend_id = $this->wechat_group_id; | ||
| 70 | + $message_push->content_type = 'Link'; | ||
| 71 | + $message_push->content = json_encode([ | ||
| 72 | + 'title' => "AI协同工单 - " . $this->company_name, | ||
| 73 | + 'desc' => $desc, | ||
| 74 | + 'size' => 0, | ||
| 75 | + 'thumbSize' => 0, | ||
| 76 | + 'thumbUrl' => 'https://hub.globalso.com/logocm.png', | ||
| 77 | + 'url' => 'https://oa.quanqiusou.cn/afterorder?project_id='.$this->uuid | ||
| 78 | + ], JSON_UNESCAPED_UNICODE); | ||
| 79 | + $message_push->send_time = now(); | ||
| 80 | + $message_push->type = MessagePush::TYPE_TICKET; | ||
| 81 | + $message_push->save(); | ||
| 82 | + } | ||
| 83 | + } | ||
| 56 | } | 84 | } |
| @@ -66,7 +66,7 @@ class MessagePush extends Base | @@ -66,7 +66,7 @@ class MessagePush extends Base | ||
| 66 | //9-21 点,每条消息及时通知 | 66 | //9-21 点,每条消息及时通知 |
| 67 | //21-第二天 9 点,整合一起通知 | 67 | //21-第二天 9 点,整合一起通知 |
| 68 | $hour = date('H', strtotime($submit_at)); | 68 | $hour = date('H', strtotime($submit_at)); |
| 69 | - if(($hour >= 9 && $hour < 21) || in_array($project_id, $special_project_ids)) { | 69 | + if(($hour >= 8 && $hour < 21) || in_array($project_id, $special_project_ids)) { |
| 70 | $model = new self(); | 70 | $model = new self(); |
| 71 | $model->project_id = $project_id; | 71 | $model->project_id = $project_id; |
| 72 | $model->friend_id = $friend_id; | 72 | $model->friend_id = $friend_id; |
| @@ -76,7 +76,7 @@ class MessagePush extends Base | @@ -76,7 +76,7 @@ class MessagePush extends Base | ||
| 76 | $model->send_time = $submit_at; | 76 | $model->send_time = $submit_at; |
| 77 | }else{ | 77 | }else{ |
| 78 | //定时发送时间 | 78 | //定时发送时间 |
| 79 | - $send_time = $hour >= 9 ? date('Y-m-d 09:00:00', strtotime($submit_at . '+1 day')) : date('Y-m-d 09:00:00', strtotime($submit_at)); | 79 | + $send_time = $hour >= 8 ? date('Y-m-d 08:00:00', strtotime($submit_at . '+1 day')) : date('Y-m-d 08:00:00', strtotime($submit_at)); |
| 80 | $model = self::where('project_id', $project_id)->where('type', self::TYPE_INQUIRY)->where('send_time', $send_time)->first(); | 80 | $model = self::where('project_id', $project_id)->where('type', self::TYPE_INQUIRY)->where('send_time', $send_time)->first(); |
| 81 | if(!$model){ | 81 | if(!$model){ |
| 82 | $model = new self(); | 82 | $model = new self(); |
| @@ -86,7 +86,7 @@ class MessagePush extends Base | @@ -86,7 +86,7 @@ class MessagePush extends Base | ||
| 86 | $model->ref_ids = $id; | 86 | $model->ref_ids = $id; |
| 87 | $model->countries = $country; | 87 | $model->countries = $country; |
| 88 | $model->send_time = $send_time; | 88 | $model->send_time = $send_time; |
| 89 | - $model->content = '[09:00] 您的全球搜网站收到来自【' . $country . $name . '】的询盘信息,请登录后台或APP进行查看!'; | 89 | + $model->content = '[08:00] 您的全球搜网站收到来自【' . $country . $name . '】的询盘信息,请登录后台或APP进行查看!'; |
| 90 | }else{ | 90 | }else{ |
| 91 | $ref_ids = explode(',', $model->ref_ids); | 91 | $ref_ids = explode(',', $model->ref_ids); |
| 92 | $ref_ids[] = $id; | 92 | $ref_ids[] = $id; |
| @@ -105,7 +105,7 @@ class MessagePush extends Base | @@ -105,7 +105,7 @@ class MessagePush extends Base | ||
| 105 | $country = implode(',', $countries); | 105 | $country = implode(',', $countries); |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
| 108 | - $model->content = '[09:00] 您的全球搜网站收到来自【' . $country . '】'.$count.'条询盘信息,请登录后台或APP进行查看!'; | 108 | + $model->content = '[08:00] 您的全球搜网站收到来自【' . $country . '】'.$count.'条询盘信息,请登录后台或APP进行查看!'; |
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | $model->save(); | 111 | $model->save(); |
| @@ -168,7 +168,7 @@ class ProjectAssociationServices extends BaseService | @@ -168,7 +168,7 @@ class ProjectAssociationServices extends BaseService | ||
| 168 | } | 168 | } |
| 169 | $param['sign'] = $this->getSign($param); | 169 | $param['sign'] = $this->getSign($param); |
| 170 | $url = 'https://hub.ai.cc/api/globalso_ai_customer_service/chatroom_list'; | 170 | $url = 'https://hub.ai.cc/api/globalso_ai_customer_service/chatroom_list'; |
| 171 | - $result = Http::withoutVerifying()->post($url, $param)->json(); | 171 | + $result = Http::withoutVerifying()->withOptions(['proxy' => env('CURL_PROXY')])->post($url, $param)->json(); |
| 172 | if(empty($result) || $result['status'] != 200){ | 172 | if(empty($result) || $result['status'] != 200){ |
| 173 | return []; | 173 | return []; |
| 174 | } | 174 | } |
| @@ -189,7 +189,7 @@ class ProjectAssociationServices extends BaseService | @@ -189,7 +189,7 @@ class ProjectAssociationServices extends BaseService | ||
| 189 | ]; | 189 | ]; |
| 190 | $param['sign'] = $this->getSign($param); | 190 | $param['sign'] = $this->getSign($param); |
| 191 | $url = 'https://hub.ai.cc/api/globalso_ai_customer_service/send_msg'; | 191 | $url = 'https://hub.ai.cc/api/globalso_ai_customer_service/send_msg'; |
| 192 | - $result = Http::withoutVerifying()->timeout(30)->post($url, $param)->json(); | 192 | + $result = Http::withoutVerifying()->withOptions(['proxy' => env('CURL_PROXY')])->timeout(30)->post($url, $param)->json(); |
| 193 | if(empty($result) || $result['status'] != 200){ | 193 | if(empty($result) || $result['status'] != 200){ |
| 194 | throw new \Exception($result['message'] ?? ''); | 194 | throw new \Exception($result['message'] ?? ''); |
| 195 | } | 195 | } |
| @@ -45,7 +45,7 @@ class DingTalkService | @@ -45,7 +45,7 @@ class DingTalkService | ||
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | /** 批量发送私聊消息 */ | 47 | /** 批量发送私聊消息 */ |
| 48 | - public function danliao(string $text, array $user_ids) | 48 | + public function danliao(string $text, array $user_ids, string $msg_key='sampleMarkdown') |
| 49 | { | 49 | { |
| 50 | $endpoint = '/v1/danliao'; | 50 | $endpoint = '/v1/danliao'; |
| 51 | $payload = [ | 51 | $payload = [ |
| @@ -53,7 +53,8 @@ class DingTalkService | @@ -53,7 +53,8 @@ class DingTalkService | ||
| 53 | "appSecret" => $this->appSecret, | 53 | "appSecret" => $this->appSecret, |
| 54 | "robotCode" => $this->robotCode, | 54 | "robotCode" => $this->robotCode, |
| 55 | "msg_param" => $text, | 55 | "msg_param" => $text, |
| 56 | - "user_ids" => $user_ids | 56 | + "user_ids" => $user_ids, |
| 57 | + "msg_key" => $msg_key | ||
| 57 | ]; | 58 | ]; |
| 58 | return $this->send_request('POST', $this->bashUrl . $endpoint, $payload); | 59 | return $this->send_request('POST', $this->bashUrl . $endpoint, $payload); |
| 59 | } | 60 | } |
| @@ -14,16 +14,16 @@ class GeoService | @@ -14,16 +14,16 @@ class GeoService | ||
| 14 | public $api_key = '7yn!We6$&NnVA38bpGy*A@4TQ5iYLJcW'; | 14 | public $api_key = '7yn!We6$&NnVA38bpGy*A@4TQ5iYLJcW'; |
| 15 | 15 | ||
| 16 | public $api_url = 'https://api.cmer.com/'; | 16 | public $api_url = 'https://api.cmer.com/'; |
| 17 | + | ||
| 17 | /** | 18 | /** |
| 18 | - * @remark :请求的方法 | ||
| 19 | - * @name :requestAction | ||
| 20 | - * @author :lyh | ||
| 21 | - * @method :post | ||
| 22 | - * @time :2025/7/3 14:26 | 19 | + * 获取AI平台数据 |
| 20 | + * @param $content | ||
| 21 | + * @param $platform | ||
| 22 | + * @return mixed|string | ||
| 23 | */ | 23 | */ |
| 24 | - public function setWebSearchChatAction($content,$platform){ | ||
| 25 | - $route = 'v1/websearch_chat'; | ||
| 26 | - $url = $this->api_url.$route; | 24 | + public function getAiPlatformResult($content,$platform) |
| 25 | + { | ||
| 26 | + $url = $this->api_url . 'v1/websearch_chat'; | ||
| 27 | $header = [ | 27 | $header = [ |
| 28 | 'accept: application/json', | 28 | 'accept: application/json', |
| 29 | 'X-CmerApi-Host: llm-chat.p.cmer.com', | 29 | 'X-CmerApi-Host: llm-chat.p.cmer.com', |
| @@ -37,10 +37,35 @@ class GeoService | @@ -37,10 +37,35 @@ class GeoService | ||
| 37 | 'role'=>'user' | 37 | 'role'=>'user' |
| 38 | ], | 38 | ], |
| 39 | ], | 39 | ], |
| 40 | - 'platform'=>$platform, | ||
| 41 | - 'security_check'=>true | 40 | + 'platform' => $platform, |
| 41 | + 'security_check' => true | ||
| 42 | ]; | 42 | ]; |
| 43 | $data = http_post($url,json_encode($message,true),$header); | 43 | $data = http_post($url,json_encode($message,true),$header); |
| 44 | return $data; | 44 | return $data; |
| 45 | } | 45 | } |
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 获取Google数据 | ||
| 49 | + * @param $search | ||
| 50 | + * @param int $lum_json 默认1 不只是什么参数 | ||
| 51 | + * @return mixed|string | ||
| 52 | + */ | ||
| 53 | + public function getGooglePlatformResult($search) | ||
| 54 | + { | ||
| 55 | + $url = 'https://api.cmer.com/ai-overviews'; | ||
| 56 | + $header = [ | ||
| 57 | + 'accept: application/json', | ||
| 58 | + 'apikey: UkzZljFv83Z2qBi5YR1o3f2otAVWtug6', | ||
| 59 | + 'Content-Type: application/json', | ||
| 60 | + 'X-CmerApi-Host:ai-overviews.p.cmer.com' | ||
| 61 | + ]; | ||
| 62 | + $param = [ | ||
| 63 | + 'q' => $search, | ||
| 64 | + 'location' => 'New York, United States', | ||
| 65 | + 'gl' => 'us', | ||
| 66 | + 'hl'=>'en' | ||
| 67 | + ]; | ||
| 68 | + $url = $url . '?' . http_build_query($param); | ||
| 69 | + return http_get($url, $header); | ||
| 70 | + } | ||
| 46 | } | 71 | } |
| @@ -67,6 +67,47 @@ class UpyunService | @@ -67,6 +67,47 @@ class UpyunService | ||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | /** | 69 | /** |
| 70 | + * 统计流量 | ||
| 71 | + * @param $start_time | ||
| 72 | + * @param $end_time | ||
| 73 | + * @param string $domain | ||
| 74 | + * @return mixed | ||
| 75 | + */ | ||
| 76 | + public function commonData($start_time, $end_time, $domain = 'ecdn6.globalso.com') | ||
| 77 | + { | ||
| 78 | + $action = '/flow/common_data'; | ||
| 79 | + $param = [ | ||
| 80 | + 'start_time' => $start_time, | ||
| 81 | + 'end_time' => $end_time, | ||
| 82 | + 'domain' => $domain, | ||
| 83 | + ]; | ||
| 84 | +// dd($param); | ||
| 85 | + list($status, $result) = $this->curlRequest($action, $param, 'GET', $this->getHeader()); | ||
| 86 | + return $result; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * 统计流量 | ||
| 91 | + * @param $start_time | ||
| 92 | + * @param $end_time | ||
| 93 | + * @param string $domain | ||
| 94 | + * @return mixed | ||
| 95 | + */ | ||
| 96 | + public function realTimeStatistics($start_time, $end_time, $domain = 'ecdn6.globalso.com') | ||
| 97 | + { | ||
| 98 | + $action = '/flow/real_time_statistics'; | ||
| 99 | + $param = [ | ||
| 100 | + 'start_time' => $start_time, | ||
| 101 | + 'end_time' => $end_time, | ||
| 102 | + 'query_domain' => $domain, | ||
| 103 | + 'query_type' => 'uri_flux' | ||
| 104 | + ]; | ||
| 105 | +// dd($param); | ||
| 106 | + list($status, $result) = $this->curlRequest($action, $param, 'GET', $this->getHeader()); | ||
| 107 | + return $result; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + /** | ||
| 70 | * 头信息需要携带授权token | 111 | * 头信息需要携带授权token |
| 71 | * @return array | 112 | * @return array |
| 72 | */ | 113 | */ |
| @@ -88,6 +129,9 @@ class UpyunService | @@ -88,6 +129,9 @@ class UpyunService | ||
| 88 | public function curlRequest($url, $data, $method = 'POST', $header = [], $time_out = 60) | 129 | public function curlRequest($url, $data, $method = 'POST', $header = [], $time_out = 60) |
| 89 | { | 130 | { |
| 90 | $url = config('custom.upyun.api_url') . $url; | 131 | $url = config('custom.upyun.api_url') . $url; |
| 132 | + if ($method == 'GET') { | ||
| 133 | + $url .= '?' . http_build_query($data); | ||
| 134 | + } | ||
| 91 | $ch = curl_init(); | 135 | $ch = curl_init(); |
| 92 | curl_setopt($ch, CURLOPT_TIMEOUT, $time_out); | 136 | curl_setopt($ch, CURLOPT_TIMEOUT, $time_out); |
| 93 | curl_setopt($ch, CURLOPT_URL, $url); | 137 | curl_setopt($ch, CURLOPT_URL, $url); |
| @@ -86,3 +86,4 @@ Route::prefix('tickets')->group(function () { | @@ -86,3 +86,4 @@ Route::prefix('tickets')->group(function () { | ||
| 86 | Route::get('/chat/{project_id}/{ticket_id}', [\App\Http\Controllers\Api\WorkOrder\TicketChatController::class, 'index'])->summary('B端,渠道-工单聊天记录')->name('tickets.chat.index'); | 86 | Route::get('/chat/{project_id}/{ticket_id}', [\App\Http\Controllers\Api\WorkOrder\TicketChatController::class, 'index'])->summary('B端,渠道-工单聊天记录')->name('tickets.chat.index'); |
| 87 | Route::post('/chat/{project_id}/{ticket_id}', [\App\Http\Controllers\Api\WorkOrder\TicketChatController::class, 'store'])->summary('B端,渠道-工单聊天记录提交')->name('tickets.chat.store'); | 87 | Route::post('/chat/{project_id}/{ticket_id}', [\App\Http\Controllers\Api\WorkOrder\TicketChatController::class, 'store'])->summary('B端,渠道-工单聊天记录提交')->name('tickets.chat.store'); |
| 88 | }); | 88 | }); |
| 89 | +Route::get('/pushTicketByBot/{friend_id}', [\App\Http\Controllers\Api\WorkOrder\TicketController::class, 'pushTicketByBot'])->summary('企微群@机器人触发工单推送')->name('tickets.pushTicketByBot'); |
| @@ -257,7 +257,8 @@ Route::middleware(['aloginauth'])->group(function () { | @@ -257,7 +257,8 @@ Route::middleware(['aloginauth'])->group(function () { | ||
| 257 | Route::post('/{id}', [Aside\WorkOrder\AsideTicketController::class, 'update'])->name('admin.tickets.update')->summary('A端更新工单,审核,邀请同事'); | 257 | Route::post('/{id}', [Aside\WorkOrder\AsideTicketController::class, 'update'])->name('admin.tickets.update')->summary('A端更新工单,审核,邀请同事'); |
| 258 | Route::get('/pushNotify/{id}', [Aside\WorkOrder\AsideTicketController::class, 'pushNotify'])->name('admin.tickets.pushNotify')->summary('A端工单推送企微群'); | 258 | Route::get('/pushNotify/{id}', [Aside\WorkOrder\AsideTicketController::class, 'pushNotify'])->name('admin.tickets.pushNotify')->summary('A端工单推送企微群'); |
| 259 | Route::get('/projects/{search}', [Aside\WorkOrder\AsideTicketController::class, 'getProjects'])->name('admin.tickets.projects')->summary('A端V5V6项目列表'); | 259 | Route::get('/projects/{search}', [Aside\WorkOrder\AsideTicketController::class, 'getProjects'])->name('admin.tickets.projects')->summary('A端V5V6项目列表'); |
| 260 | - Route::get('/v56_projects/list', [Aside\WorkOrder\AsideTicketController::class, 'projectList'])->name('admin.tickets.projectList')->summary('A端V5V6项目列表'); | 260 | + Route::get('/v56_projects/list', [Aside\WorkOrder\AsideTicketController::class, 'projectList'])->name('admin.tickets.projectList')->summary('A端V5V6项目列表') |
| 261 | + ->description("project_cate[项目分类1]: 1 V5, 2 V6, 3 超迹, 4 域途"); | ||
| 261 | Route::post('/log/{id}', [Aside\WorkOrder\AsideTicketLogController::class, 'update'])->name('admin.tickets.log.update')->summary('A端工单操作日志更新,完成工单'); | 262 | Route::post('/log/{id}', [Aside\WorkOrder\AsideTicketLogController::class, 'update'])->name('admin.tickets.log.update')->summary('A端工单操作日志更新,完成工单'); |
| 262 | Route::get('/chat/{ticket_id}', [Aside\WorkOrder\TicketChatController::class, 'index'])->name('admin.tickets.chat.index')->summary('A端工单聊天记录'); | 263 | Route::get('/chat/{ticket_id}', [Aside\WorkOrder\TicketChatController::class, 'index'])->name('admin.tickets.chat.index')->summary('A端工单聊天记录'); |
| 263 | Route::post('/chat/{ticket_id}', [Aside\WorkOrder\TicketChatController::class, 'store'])->name('admin.tickets.chat.store')->summary('A端工单聊天记录创建'); | 264 | Route::post('/chat/{ticket_id}', [Aside\WorkOrder\TicketChatController::class, 'store'])->name('admin.tickets.chat.store')->summary('A端工单聊天记录创建'); |
| @@ -608,6 +609,12 @@ Route::middleware(['aloginauth'])->group(function () { | @@ -608,6 +609,12 @@ Route::middleware(['aloginauth'])->group(function () { | ||
| 608 | Route::any('/save', [Aside\Project\ProjectWhiteHatAffixController::class, 'save'])->name('admin.white_hat_save'); | 609 | Route::any('/save', [Aside\Project\ProjectWhiteHatAffixController::class, 'save'])->name('admin.white_hat_save'); |
| 609 | Route::any('/del', [Aside\Project\ProjectWhiteHatAffixController::class, 'del'])->name('admin.white_hat_del'); | 610 | Route::any('/del', [Aside\Project\ProjectWhiteHatAffixController::class, 'del'])->name('admin.white_hat_del'); |
| 610 | }); | 611 | }); |
| 612 | + // 统计数据 | ||
| 613 | + Route::prefix('statistics')->group(function () { | ||
| 614 | + // 流量统计 | ||
| 615 | + Route::any('/flow', [Aside\Project\StatisticsController::class, 'flow'])->name('admin.statistics_flow'); | ||
| 616 | + }); | ||
| 617 | + | ||
| 611 | }); | 618 | }); |
| 612 | 619 | ||
| 613 | //无需登录验证的路由组 | 620 | //无需登录验证的路由组 |
| @@ -753,6 +753,8 @@ Route::middleware(['bloginauth'])->group(function () { | @@ -753,6 +753,8 @@ Route::middleware(['bloginauth'])->group(function () { | ||
| 753 | Route::prefix('geo_result')->group(function () { | 753 | Route::prefix('geo_result')->group(function () { |
| 754 | Route::any('/getList', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class,'getList'])->name('geo_result_getList'); | 754 | Route::any('/getList', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class,'getList'])->name('geo_result_getList'); |
| 755 | Route::any('/getInfo', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class,'getInfo'])->name('geo_result_getInfo'); | 755 | Route::any('/getInfo', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class,'getInfo'])->name('geo_result_getInfo'); |
| 756 | + Route::any('/getType', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getType'])->name('geo_result_getType');//geo设置类型 | ||
| 757 | + Route::any('/getCount', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getCount'])->name('geo_result_getCount');//geo设置类型统计数量 | ||
| 756 | }); | 758 | }); |
| 757 | }); | 759 | }); |
| 758 | //无需登录验证的路由组 | 760 | //无需登录验证的路由组 |
-
请 注册 或 登录 后发表评论