Merge remote-tracking branch 'origin/master' into akun
正在显示
42 个修改的文件
包含
1357 行增加
和
125 行删除
| @@ -43,7 +43,9 @@ class RemainDay extends Command | @@ -43,7 +43,9 @@ class RemainDay extends Command | ||
| 43 | 1893, | 43 | 1893, |
| 44 | 2066, | 44 | 2066, |
| 45 | 2250, | 45 | 2250, |
| 46 | - 2193 | 46 | + 2193, |
| 47 | + 2399, | ||
| 48 | + 1685 | ||
| 47 | ];//需要单独处理的项目 | 49 | ];//需要单独处理的项目 |
| 48 | /** | 50 | /** |
| 49 | * The console command description. | 51 | * The console command description. |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Console\Commands\Inquiry; | ||
| 4 | + | ||
| 5 | +use App\Models\Domain\DomainInfo; | ||
| 6 | +use App\Models\Inquiry\ReInquiryCount; | ||
| 7 | +use Illuminate\Console\Command; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Class FBInquiryRemainDay | ||
| 11 | + * @package App\Console\Commands\Inquiry | ||
| 12 | + */ | ||
| 13 | +class FBInquiryRemainDay extends Command | ||
| 14 | +{ | ||
| 15 | + /** | ||
| 16 | + * The name and signature of the console command. | ||
| 17 | + * | ||
| 18 | + * @var string | ||
| 19 | + */ | ||
| 20 | + protected $signature = 'fb_inquiry_remain_day'; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * The console command description. | ||
| 24 | + * | ||
| 25 | + * @var string | ||
| 26 | + */ | ||
| 27 | + protected $description = '执行询盘请求'; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * Create a new command instance. | ||
| 31 | + * | ||
| 32 | + * @return void | ||
| 33 | + */ | ||
| 34 | + public function __construct() | ||
| 35 | + { | ||
| 36 | + parent::__construct(); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + public function handle() | ||
| 42 | + { | ||
| 43 | + $list = ReInquiryCount::all(); | ||
| 44 | + foreach ($list as $item){ | ||
| 45 | + $this->output('start:' . $item['id']); | ||
| 46 | + | ||
| 47 | + $tasks = $item->tasks; //调用访问器 | ||
| 48 | + $is_v6 = 0; | ||
| 49 | + foreach ($tasks as $task){ | ||
| 50 | + if($task['is_v6']){ | ||
| 51 | + $is_v6 = 1; | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + if($is_v6){ | ||
| 55 | + $project_id = DomainInfo::where('domain', $item['domain'])->value('project_id') ?: 0; | ||
| 56 | + }else{ | ||
| 57 | + $project_id = 0; | ||
| 58 | + } | ||
| 59 | + //获取剩余天数 | ||
| 60 | + $remaining_days = ReInquiryCount::getRemainingDays($item['domain'], $item['type'], $project_id); | ||
| 61 | + $item->remaining_days = $remaining_days; | ||
| 62 | + $item->save(); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + public function output($message) | ||
| 68 | + { | ||
| 69 | + echo date('Y-m-d H:i:s') . ' | ' . $message . PHP_EOL; | ||
| 70 | + } | ||
| 71 | +} |
| @@ -28,6 +28,7 @@ use App\Models\RouteMap\RouteMap; | @@ -28,6 +28,7 @@ use App\Models\RouteMap\RouteMap; | ||
| 28 | use App\Models\Template\BTemplateMain; | 28 | use App\Models\Template\BTemplateMain; |
| 29 | use App\Models\Template\TemplateTypeMain; | 29 | use App\Models\Template\TemplateTypeMain; |
| 30 | use App\Models\Visit\Visit; | 30 | use App\Models\Visit\Visit; |
| 31 | +use App\Models\WebSetting\TranslateBigProject; | ||
| 31 | use App\Models\WebSetting\WebLanguage; | 32 | use App\Models\WebSetting\WebLanguage; |
| 32 | use App\Models\WebSetting\WebSetting; | 33 | use App\Models\WebSetting\WebSetting; |
| 33 | use App\Models\Workchat\MessagePush; | 34 | use App\Models\Workchat\MessagePush; |
| @@ -56,40 +57,26 @@ class lyhDemo extends Command | @@ -56,40 +57,26 @@ class lyhDemo extends Command | ||
| 56 | protected $description = '更新路由'; | 57 | protected $description = '更新路由'; |
| 57 | 58 | ||
| 58 | public function handle(){ | 59 | public function handle(){ |
| 59 | - $projectModel = new Project(); | ||
| 60 | - $lists = $projectModel->list(['delete_status' => 0,'project_type'=>0,'extend_type'=>0,'type'=>['in',[2,3,4,6]]], 'id', ['id']); | ||
| 61 | - foreach ($lists as $item){ | ||
| 62 | - echo date('Y-m-d H:i:s') . '开始--项目的id:'. $item['id'] . PHP_EOL; | ||
| 63 | - ProjectServer::useProject($item['id']); | ||
| 64 | - $authorModel = new AiBlogAuthor(); | ||
| 65 | - $author_list = $authorModel->list(['id'=>['>',0]]); | ||
| 66 | - if(empty($author_list)){ | ||
| 67 | - echo '跳过的项目id:'.$item['id'].PHP_EOL; | ||
| 68 | - DB::disconnect('custom_mysql'); | ||
| 69 | - continue; | ||
| 70 | - } | ||
| 71 | - $projectAiSettingModel = new ProjectAiSetting(); | ||
| 72 | - $aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$item['id']]); | ||
| 73 | - if($aiSettingInfo === false){ | ||
| 74 | - echo '跳过的项目id:'.$item['id'].PHP_EOL; | ||
| 75 | - DB::disconnect('custom_mysql'); | ||
| 76 | - continue; | ||
| 77 | - } | ||
| 78 | - $aiBlogService = new AiBlogService($item['id']); | ||
| 79 | - foreach ($author_list as $val){ | ||
| 80 | - $aiBlogService->author_id = $val['author_id']; | ||
| 81 | - $result = $aiBlogService->getAuthorDetail(); | ||
| 82 | - if(isset($result['status']) && $result['status'] == 200){ | ||
| 83 | - //当前作者的页面 | ||
| 84 | - $aiBlogAuthorModel = new AiBlogAuthor(); | ||
| 85 | - $authorInfo = $aiBlogAuthorModel->read(['author_id'=>$val['author_id']],['id','route']); | ||
| 86 | - if($authorInfo !== false && !empty($result['data']['section'])){ | ||
| 87 | - $aiBlogAuthorModel->edit(['text'=>$result['data']['section']],['author_id'=>$val['author_id']]); | ||
| 88 | - } | ||
| 89 | - } | ||
| 90 | - } | ||
| 91 | - DB::disconnect('custom_mysql'); | 60 | + $str = '3671,955,752,1270,439,2674,3588,2388,1271,1543,738,624,552,1417,1237,651,1143,817,1556,1234,1350,650,538,491,631,2059,1845,866,1194,1699,546,684,905,1805,1728,2811,952,2972,2827,983,812,3081,554,741,1349,980'; |
| 61 | + $arr = explode(',',$str); | ||
| 62 | + $model = new TranslateBigProject(); | ||
| 63 | + foreach ($arr as $val){ | ||
| 64 | + $model->addReturnId(['project_id'=>$val]); | ||
| 92 | } | 65 | } |
| 66 | + return true; | ||
| 67 | +// $projectModel = new Project(); | ||
| 68 | +// $lists = $projectModel->list(['delete_status' => 0,'project_type'=>0,'extend_type'=>0,'type'=>['in',[1,2,3,4,6]]], 'id', ['id']); | ||
| 69 | +// foreach ($lists as $item){ | ||
| 70 | +//// echo date('Y-m-d H:i:s') . '开始--项目的id:'. $item['id'] . PHP_EOL; | ||
| 71 | +// ProjectServer::useProject($item['id']); | ||
| 72 | +// $webSettingModel = new WebSetting(); | ||
| 73 | +// $info = $webSettingModel->read(['project_id'=>$item['id']]); | ||
| 74 | +// if($info === false){ | ||
| 75 | +// $webSettingModel->addReturnId(['project_id'=>$item['id']]); | ||
| 76 | +// echo '当前数据为空:'.$item['id'].PHP_EOL; | ||
| 77 | +// } | ||
| 78 | +// DB::disconnect('custom_mysql'); | ||
| 79 | +// } | ||
| 93 | } | 80 | } |
| 94 | 81 | ||
| 95 | public function _actionTemplateMain(){ | 82 | public function _actionTemplateMain(){ |
| 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 InitKeywordComment extends Command | ||
| 21 | +{ | ||
| 22 | + /** | ||
| 23 | + * The name and signature of the console command. | ||
| 24 | + * | ||
| 25 | + * @var string | ||
| 26 | + */ | ||
| 27 | + protected $signature = 'init_keyword_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 | + return $this->_action(467); | ||
| 40 | + while (true){ | ||
| 41 | + $list = NoticeLog::where('type', NoticeLog::TYPE_INIT_KEYWORD_COMMON)->where('status', NoticeLog::STATUS_PENDING)->get(); | ||
| 42 | + if(empty($list)){ | ||
| 43 | + sleep(200); | ||
| 44 | + continue; | ||
| 45 | + } | ||
| 46 | + foreach ($list as $item){ | ||
| 47 | + echo date('Y-m-d H:i:s').'start:' . $item['id'] . PHP_EOL; | ||
| 48 | + $project_id = $item['data']['project_id']; | ||
| 49 | + echo date('Y-m-d H:i:s').'执行的项目id:' . $project_id . PHP_EOL; | ||
| 50 | + try { | ||
| 51 | + $this->_action($project_id); | ||
| 52 | + $count = $keywordCommonModel->counts(['project_id'=>$project_id]); | ||
| 53 | + if($count > 100){ | ||
| 54 | + $item->status = NoticeLog::STATUS_SUCCESS; | ||
| 55 | + $item->save(); | ||
| 56 | + } | ||
| 57 | + }catch (\Exception $e){ | ||
| 58 | + echo date('Y-m-d H:i:s').'错误信息:'.$e->getMessage().PHP_EOL; | ||
| 59 | + continue; | ||
| 60 | + } | ||
| 61 | + echo date('Y-m-d H:i:s').'end:' . $item['id'] . PHP_EOL; | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + return true; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * @remark :执行的方法 | ||
| 69 | + * @name :_action | ||
| 70 | + * @author :lyh | ||
| 71 | + * @method :post | ||
| 72 | + * @time :2025/6/3 15:42 | ||
| 73 | + */ | ||
| 74 | + public function _action($project_id){ | ||
| 75 | + $aiCommonModel = new AiCommand(); | ||
| 76 | + $info = $aiCommonModel->read(['key'=>'tag_comment']); | ||
| 77 | + $text = Gpt::instance()->openai_chat_qqs($info['ai']); | ||
| 78 | + $text = Common::deal_keywords($text); | ||
| 79 | + preg_match_all('/\{[^{}]*\}/', $text, $matches); | ||
| 80 | + if(!empty($text)){ | ||
| 81 | + $data = []; | ||
| 82 | + foreach ($matches[0] as $item){ | ||
| 83 | + $item = str_replace("'", '"', $item); | ||
| 84 | + // 解码成 PHP 关联数组 | ||
| 85 | + $item = json_decode($item, true); | ||
| 86 | + if(!isset($item['name']) || !isset($item['comment'])){ | ||
| 87 | + continue; | ||
| 88 | + } | ||
| 89 | + $data[] = [ | ||
| 90 | + 'nickname'=>$item['name'], | ||
| 91 | + 'text'=>$item['comment'], | ||
| 92 | + 'project_id'=>$project_id, | ||
| 93 | + 'type'=>1, | ||
| 94 | + 'uid'=>0, | ||
| 95 | + 'created_at'=>date('Y-m-d H:i:s'), | ||
| 96 | + 'updated_at'=>date('Y-m-d H:i:s') | ||
| 97 | + ]; | ||
| 98 | + } | ||
| 99 | + $keywordCommonModel = new AggregateKeywordComment(); | ||
| 100 | + $keywordCommonModel->insertAll($data); | ||
| 101 | + } | ||
| 102 | + return true; | ||
| 103 | + } | ||
| 104 | +} |
app/Console/Commands/WorkOrderDing.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Console\Commands; | ||
| 4 | + | ||
| 5 | +use App\Models\WorkOrder\WorkOrderLog; | ||
| 6 | +use App\Services\DingTalkService; | ||
| 7 | +use Illuminate\Console\Command; | ||
| 8 | +use Illuminate\Support\Facades\Http; | ||
| 9 | + | ||
| 10 | +class WorkOrderDing extends Command | ||
| 11 | +{ | ||
| 12 | + /** | ||
| 13 | + * The name and signature of the console command. | ||
| 14 | + * | ||
| 15 | + * @var string | ||
| 16 | + */ | ||
| 17 | + protected $signature = 'workorder:ding'; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * The console command description. | ||
| 21 | + * | ||
| 22 | + * @var string | ||
| 23 | + */ | ||
| 24 | + protected $description = '售后工单钉钉通知'; | ||
| 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 | + $log = WorkOrderLog::where('ding', 0)->first(); | ||
| 46 | + if (!$log) { | ||
| 47 | + sleep(3); | ||
| 48 | + continue; | ||
| 49 | + } | ||
| 50 | + $mobile = $log->manager->mobile; | ||
| 51 | + $response = Http::withBasicAuth( | ||
| 52 | + env('DINGDING_BASIC_USER'), | ||
| 53 | + env('DINGDING_BASIC_PASS') | ||
| 54 | + )->get('https://oa.cmer.com/api/dingding/user/' . $mobile); | ||
| 55 | + if ($response->status() == 200) { | ||
| 56 | + $userid = $response->json()['data']['userid']; | ||
| 57 | + $text = "**您有新的售后工单**<br>"; | ||
| 58 | + $text .= "工单ID:{$log->work_order_id}<br>"; | ||
| 59 | + $text .= "工单类型:<font color='red'>{$log->workOrder->product}</font><br>"; | ||
| 60 | + $text .= "项目:{$log->workOrder->project->title}<br>"; | ||
| 61 | + $text .= "时间:{$log->created_at}<br>"; | ||
| 62 | + $ding = new DingTalkService(); | ||
| 63 | + $resp = $ding->danliao(json_encode([ | ||
| 64 | + 'text' => $text, | ||
| 65 | + 'title' => '售后工单通知', | ||
| 66 | + ]), [$userid]); | ||
| 67 | + $log->ding = 1; | ||
| 68 | + }else | ||
| 69 | + $log->ding = 2; | ||
| 70 | + $log->save(); | ||
| 71 | + }catch (\Exception $exception){ | ||
| 72 | + echo date('Y-m-d H:i:s')." ".$exception->getMessage()."\n"; | ||
| 73 | + break; | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | +} |
| @@ -39,6 +39,8 @@ class Kernel extends ConsoleKernel | @@ -39,6 +39,8 @@ class Kernel extends ConsoleKernel | ||
| 39 | $schedule->command('sync_ad_cost')->everyThirtyMinutes()->withoutOverlapping(1); | 39 | $schedule->command('sync_ad_cost')->everyThirtyMinutes()->withoutOverlapping(1); |
| 40 | // 优化预设关键词 同步 20点会开始TDK生成 | 40 | // 优化预设关键词 同步 20点会开始TDK生成 |
| 41 | $schedule->command('optimize_set_keyword_sync')->dailyAt('20:00')->withoutOverlapping(1); | 41 | $schedule->command('optimize_set_keyword_sync')->dailyAt('20:00')->withoutOverlapping(1); |
| 42 | + //FB询盘剩余时间 | ||
| 43 | + $schedule->command('fb_inquiry_remain_day')->dailyAt('02:00')->withoutOverlapping(1); | ||
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | /** | 46 | /** |
| @@ -310,4 +310,25 @@ class QuanqiusouApi | @@ -310,4 +310,25 @@ class QuanqiusouApi | ||
| 310 | } | 310 | } |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | + /** | ||
| 314 | + * 获取代理信息 | ||
| 315 | + * @param $domain | ||
| 316 | + * @return array|mixed | ||
| 317 | + * @author zbj | ||
| 318 | + * @date 2024/10/26 | ||
| 319 | + */ | ||
| 320 | + public function getV5RemainDay($domain){ | ||
| 321 | + $token = md5($domain.'qqs'); | ||
| 322 | + try { | ||
| 323 | + $client = new \GuzzleHttp\Client(); | ||
| 324 | + $res = $client->request('GET', 'https://quanqiusou.cn/extend_api/api/get_remain_day_by_domain.php?'.http_build_query(['token' => $token, 'domain' => $domain]), [ | ||
| 325 | + 'proxy' => env('CURL_PROXY'), // 代理服务器地址和端口号 | ||
| 326 | + ])->getBody()->getContents(); | ||
| 327 | + return Arr::s2a($res); | ||
| 328 | + } catch (\Exception | GuzzleException $e) { | ||
| 329 | + errorLog('获取代理失败', [$domain], $e); | ||
| 330 | + return []; | ||
| 331 | + } | ||
| 332 | + } | ||
| 333 | + | ||
| 313 | } | 334 | } |
| @@ -879,7 +879,7 @@ function getRouteMap($source,$source_id,$is_upgrade = 0, $returnModel = false){ | @@ -879,7 +879,7 @@ function getRouteMap($source,$source_id,$is_upgrade = 0, $returnModel = false){ | ||
| 879 | $route = $info['route']; | 879 | $route = $info['route']; |
| 880 | } | 880 | } |
| 881 | } | 881 | } |
| 882 | - if($returnModel){ | 882 | + if($returnModel && ($info !== false)){ |
| 883 | return $info; | 883 | return $info; |
| 884 | } | 884 | } |
| 885 | return $route; | 885 | return $route; |
| @@ -35,6 +35,18 @@ class DomainApplicantLogController extends BaseController | @@ -35,6 +35,18 @@ class DomainApplicantLogController extends BaseController | ||
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | + * @remark :获取详情 | ||
| 39 | + * @name :info | ||
| 40 | + * @author :lyh | ||
| 41 | + * @method :post | ||
| 42 | + * @time :2025/5/30 14:35 | ||
| 43 | + */ | ||
| 44 | + public function info(){ | ||
| 45 | + $lists = $this->logic->info(); | ||
| 46 | + $this->response('success',Code::SUCCESS,$lists); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + /** | ||
| 38 | * @remark :保存数据 | 50 | * @remark :保存数据 |
| 39 | * @name :save | 51 | * @name :save |
| 40 | * @author :lyh | 52 | * @author :lyh |
| @@ -400,7 +400,6 @@ class AdsController extends BaseController | @@ -400,7 +400,6 @@ class AdsController extends BaseController | ||
| 400 | }else{ | 400 | }else{ |
| 401 | $item['project_id'] = 0; | 401 | $item['project_id'] = 0; |
| 402 | } | 402 | } |
| 403 | - | ||
| 404 | } | 403 | } |
| 405 | 404 | ||
| 406 | return $this->response('success', Code::SUCCESS, $result); | 405 | return $this->response('success', Code::SUCCESS, $result); |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Controllers\Aside\WorkOrder; | ||
| 4 | + | ||
| 5 | +use App\Enums\Common\Code; | ||
| 6 | +use App\Http\Controllers\Aside\BaseController; | ||
| 7 | +use App\Http\Requests\Aside\WorkOrder\WorkOrderListRequest; | ||
| 8 | +use App\Http\Requests\Aside\WorkOrder\WorkOrderUpdateRequest; | ||
| 9 | +use App\Models\WorkOrder\WorkOrder; | ||
| 10 | +use App\Models\WorkOrder\WorkOrderLog; | ||
| 11 | +use Illuminate\Support\Facades\DB; | ||
| 12 | + | ||
| 13 | +class WorkOrderController extends BaseController | ||
| 14 | +{ | ||
| 15 | + /** | ||
| 16 | + * A端工单列表 | ||
| 17 | + * 显示有我参与的工单列表 | ||
| 18 | + */ | ||
| 19 | + public function index(WorkOrderListRequest $request) | ||
| 20 | + { | ||
| 21 | + /* | ||
| 22 | + * A端工程师工单列表, 查询我的工单 | ||
| 23 | + */ | ||
| 24 | + $request->validated(); | ||
| 25 | + # manage_id 或 engineer_id 是我 | ||
| 26 | + $lists = WorkOrderLog::with([ | ||
| 27 | + 'workOrder.logs.manager:id,name', | ||
| 28 | + 'workOrder.project:id,company,title', | ||
| 29 | + ]) | ||
| 30 | + ->where('manage_id', $this->manage['id']) | ||
| 31 | + ->when($request->input('project_id') !== null, function ($query) use ($request) { | ||
| 32 | + // project_id 查 workOrder | ||
| 33 | + return $query->whereHas('workOrder', function ($q) use ($request) { | ||
| 34 | + $q->where('project_id', $request->input('project_id')); | ||
| 35 | + }); | ||
| 36 | + }) | ||
| 37 | + ->when($request->input('status') !== null, function ($query) use ($request) { | ||
| 38 | + // status 查 workOrder | ||
| 39 | + return $query->whereHas('workOrder', function ($q) use ($request) { | ||
| 40 | + $q->where('status', $request->input('status')); | ||
| 41 | + }); | ||
| 42 | + }) | ||
| 43 | + ->when($request->input('search'), function ($query) use ($request) { | ||
| 44 | + // search 查 workOrder | ||
| 45 | + return $query->whereHas('workOrder', function ($q) use ($request) { | ||
| 46 | + $q->where('product', 'like', '%' . $request->input('search') . '%') | ||
| 47 | + ->orWhere('content', 'like', '%' . $request->input('search') . '%'); | ||
| 48 | + }); | ||
| 49 | + }) | ||
| 50 | + ->orderBy('id', 'desc') | ||
| 51 | + ->paginate($this->row, ['*'], 'page', $this->page); | ||
| 52 | + $this->response('success', Code::SUCCESS, $lists); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * @param WorkOrderListRequest $request | ||
| 58 | + * @return void | ||
| 59 | + * A端管理员的工单列表 | ||
| 60 | + */ | ||
| 61 | + public function manager(WorkOrderListRequest $request) | ||
| 62 | + { | ||
| 63 | + $request->validated(); | ||
| 64 | + // 管理员查看所有工单 | ||
| 65 | + $lists = WorkOrder::with([ | ||
| 66 | + 'user:id,name', | ||
| 67 | + 'manager:id,name', | ||
| 68 | + 'engineer:id,name', | ||
| 69 | + 'logs.manager:id,name', | ||
| 70 | + 'project:id,company:title', | ||
| 71 | + ]) | ||
| 72 | + ->when($request->input('project_id') !== null, function ($query) use ($request) { | ||
| 73 | + return $query->where('project_id', $request->input('project_id')); | ||
| 74 | + }) | ||
| 75 | + ->when($request->input('status') !== null, function ($query) use ($request) { | ||
| 76 | + return $query->where('status', $request->input('status')); | ||
| 77 | + }) | ||
| 78 | + ->when($request->input('search'), function ($query) use ($request) { | ||
| 79 | + return $query->where('product', 'like', '%' . $request->input('search') . '%') | ||
| 80 | + ->orWhere('content', 'like', '%' . $request->input('search') . '%'); | ||
| 81 | + }) | ||
| 82 | + ->orderBy('id', 'desc') | ||
| 83 | + ->paginate($this->row, ['*'], 'page', $this->page); | ||
| 84 | + $this->response('success', Code::SUCCESS, $lists); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * A端工单详情 | ||
| 89 | + * | ||
| 90 | + * @param int $id | ||
| 91 | + * @return \Illuminate\Http\Response | ||
| 92 | + */ | ||
| 93 | + public function show($id) | ||
| 94 | + { | ||
| 95 | + $workOrder = WorkOrder::with([ | ||
| 96 | + 'logs.manager:id,name', | ||
| 97 | + 'user:id,name', | ||
| 98 | + 'manager:id,name', | ||
| 99 | + 'engineer:id,name', | ||
| 100 | + 'project:id,company:title', | ||
| 101 | + ])->find($id); | ||
| 102 | + | ||
| 103 | + if (!$workOrder) | ||
| 104 | + $this->response('工单不存在', Code::USER_MODEL_NOTFOUND_ERROE); | ||
| 105 | + | ||
| 106 | + // TODO 判断是否有查看工单详情权限,待添加 | ||
| 107 | + $this->response('success', Code::SUCCESS, $workOrder->toArray()); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * A端操作工单,工程师操作的是工单日志 | ||
| 112 | + * - 工程师:回复工单,自动��拆分给自己的子任务改为完成 | ||
| 113 | + * - 工单第一对接人: | ||
| 114 | + * - 邀请工程师处理工单 | ||
| 115 | + * - 修改工单状态 | ||
| 116 | + * 若全部子任务完成,则将工单状态改为完成 | ||
| 117 | + */ | ||
| 118 | + public function update(WorkOrderUpdateRequest $request, $id) | ||
| 119 | + { | ||
| 120 | + $request->validated(); | ||
| 121 | + $log = WorkOrderLog::find($id); // 拆分的子工单 | ||
| 122 | + if (!$log) { | ||
| 123 | + $this->response('工单不存在', Code::USER_MODEL_NOTFOUND_ERROE); | ||
| 124 | + } | ||
| 125 | + if ($log->manage_id != $this->manage['id']) { | ||
| 126 | + // 只能操作自己的工单 | ||
| 127 | + $this->response('没有权限操作该工单', Code::USER_PERMISSION_ERROE); | ||
| 128 | + } | ||
| 129 | + $workOrder = $log->workOrder; | ||
| 130 | + $result = DB::transaction(function () use ($request, $workOrder, $log) { | ||
| 131 | + if ($request->input('engineer_ids')) | ||
| 132 | + { | ||
| 133 | + // 有邀请工程师协同处理 | ||
| 134 | + foreach ($request->input('engineer_ids') as $engineer_id) | ||
| 135 | + { | ||
| 136 | + try { | ||
| 137 | + // 利用唯一索引去重 | ||
| 138 | + $new_log = new WorkOrderLog(); | ||
| 139 | + $new_log->manage_id = $engineer_id; | ||
| 140 | + $workOrder->logs()->save($new_log); | ||
| 141 | + $workOrder->engineer_id = $engineer_id; | ||
| 142 | + $workOrder->save(); | ||
| 143 | + }catch (\Exception $exception){} | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + if ($request->input('content')) | ||
| 147 | + $log->content = $request->input('content'); | ||
| 148 | + if ($request->input('files')) | ||
| 149 | + $log->files = $request->input('files'); | ||
| 150 | + if ($request->input('status') !== null) | ||
| 151 | + { | ||
| 152 | + $log->status = $request->input('status'); | ||
| 153 | + if ($log->status == WorkOrder::STATUS_COMPLETED) | ||
| 154 | + { | ||
| 155 | + // 我的工单标记为已完成 | ||
| 156 | + $log->status = WorkOrderLog::STATUS_COMPLETED; | ||
| 157 | + $log->end_at = now(); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + $log->save(); | ||
| 161 | + // 是否有未完成的子任务 | ||
| 162 | + $pending = $workOrder->logs() | ||
| 163 | + ->where('status', '<', WorkOrderLog::STATUS_COMPLETED) | ||
| 164 | + ->count(); | ||
| 165 | + $workOrder->status = $pending == 0 ? WorkOrderLog::STATUS_COMPLETED : WorkOrderLog::STATUS_PROCESSING; | ||
| 166 | + $workOrder->save(); | ||
| 167 | + return $log; | ||
| 168 | + }); | ||
| 169 | + $this->response('success', Code::SUCCESS, $result->toArray()); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | +} |
| @@ -143,9 +143,15 @@ class AyrShareController extends BaseController | @@ -143,9 +143,15 @@ class AyrShareController extends BaseController | ||
| 143 | $data = [ | 143 | $data = [ |
| 144 | 'profileKey'=>$info['profile_key'] | 144 | 'profileKey'=>$info['profile_key'] |
| 145 | ]; | 145 | ]; |
| 146 | - $res = $ayrShareHelper->post_generate_jwt($data); | ||
| 147 | - if($res['status'] == 'fail'){ | ||
| 148 | - $this->response($res['message'],Code::USER_ERROR); | 146 | + try { |
| 147 | + $res = $ayrShareHelper->post_generate_jwt($data); | ||
| 148 | + if($res['status'] == 'fail'){ | ||
| 149 | + $ayrShareLogic->ayr_share_edit(['profile_key'=>null,'bind_platforms'=>null,'ref_id'=>null],$info['id']); | ||
| 150 | + $this->response('当前key值已过期,请刷新重新绑定',Code::USER_ERROR); | ||
| 151 | + } | ||
| 152 | + }catch (\Exception $e){ | ||
| 153 | + $ayrShareLogic->ayr_share_edit(['profile_key'=>null,'bind_platforms'=>null,'ref_id'=>null],$info['id']); | ||
| 154 | + $this->response('当前key值已过期,请刷新重新绑定',Code::USER_ERROR); | ||
| 149 | } | 155 | } |
| 150 | $this->response('success',Code::SUCCESS,$res); | 156 | $this->response('success',Code::SUCCESS,$res); |
| 151 | } | 157 | } |
| @@ -34,6 +34,7 @@ use App\Models\Project\Country as CountryModel; | @@ -34,6 +34,7 @@ use App\Models\Project\Country as CountryModel; | ||
| 34 | use App\Models\Project\Project; | 34 | use App\Models\Project\Project; |
| 35 | use App\Models\RouteMap\RouteMap; | 35 | use App\Models\RouteMap\RouteMap; |
| 36 | use App\Models\WebSetting\SettingNum; | 36 | use App\Models\WebSetting\SettingNum; |
| 37 | +use App\Models\WebSetting\TranslateBigProject; | ||
| 37 | use App\Models\WebSetting\WebLanguage; | 38 | use App\Models\WebSetting\WebLanguage; |
| 38 | use Illuminate\Http\Request; | 39 | use Illuminate\Http\Request; |
| 39 | use Illuminate\Support\Facades\DB; | 40 | use Illuminate\Support\Facades\DB; |
| @@ -61,7 +62,8 @@ class CNoticeController extends BaseController | @@ -61,7 +62,8 @@ class CNoticeController extends BaseController | ||
| 61 | ],[ | 62 | ],[ |
| 62 | 'language.required' => 'language不能为空', | 63 | 'language.required' => 'language不能为空', |
| 63 | ]); | 64 | ]); |
| 64 | - $project_id_arr = explode(',',env('PROJECT_ID')) ?? []; | 65 | + $bigProjectModel = new TranslateBigProject(); |
| 66 | + $project_id_arr = $bigProjectModel->selectField(['status'=>1],'project_id') ?? []; | ||
| 65 | if(in_array($this->user['project_id'],$project_id_arr)){ | 67 | if(in_array($this->user['project_id'],$project_id_arr)){ |
| 66 | $this->response('success'); | 68 | $this->response('success'); |
| 67 | } | 69 | } |
| @@ -62,8 +62,8 @@ class ProductController extends BaseController | @@ -62,8 +62,8 @@ class ProductController extends BaseController | ||
| 62 | $userModel = new User(); | 62 | $userModel = new User(); |
| 63 | foreach ($lists['list'] as $k=>$v){ | 63 | foreach ($lists['list'] as $k=>$v){ |
| 64 | $route = getRouteMap(RouteMap::SOURCE_PRODUCT,$v['id'], 0, true); | 64 | $route = getRouteMap(RouteMap::SOURCE_PRODUCT,$v['id'], 0, true); |
| 65 | - $v['url'] = $this->user['domain'] . $route['route']; | ||
| 66 | - $v['pv'] = $route['pv']; | 65 | + $v['url'] = $this->user['domain'] . ($route['route'] ?? ''); |
| 66 | + $v['pv'] = $route['pv'] ?? ''; | ||
| 67 | $v['category_id_text'] = $this->categoryName($v['id'],$cate_data); | 67 | $v['category_id_text'] = $this->categoryName($v['id'],$cate_data); |
| 68 | $v['keyword_id_text'] = $this->keywordName($v['keyword_id'],$key_data); | 68 | $v['keyword_id_text'] = $this->keywordName($v['keyword_id'],$key_data); |
| 69 | $v['created_uid_text'] = $userModel->getName($v['created_uid']); | 69 | $v['created_uid_text'] = $userModel->getName($v['created_uid']); |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Controllers\Bside\WorkOrder; | ||
| 4 | + | ||
| 5 | +use App\Enums\Common\Code; | ||
| 6 | +use App\Http\Controllers\Bside\BaseController; | ||
| 7 | +use App\Http\Requests\Aside\WorkOrder\WorkOrderListRequest; | ||
| 8 | +use App\Http\Requests\Bside\WorkOrder\WorkOrderCreateRequest; | ||
| 9 | +use App\Http\Requests\Bside\WorkOrder\WorkOrderUpdateRequest; | ||
| 10 | +use App\Models\Project\Project; | ||
| 11 | +use App\Models\WorkOrder\WorkOrder; | ||
| 12 | +use App\Models\WorkOrder\WorkOrderLog; | ||
| 13 | +use Illuminate\Support\Facades\DB; | ||
| 14 | + | ||
| 15 | +class WorkOrderController extends BaseController | ||
| 16 | +{ | ||
| 17 | + /** | ||
| 18 | + * B端售后工单列表 | ||
| 19 | + * | ||
| 20 | + * @return \Illuminate\Http\Response | ||
| 21 | + */ | ||
| 22 | + public function index(WorkOrderListRequest $request) | ||
| 23 | + { | ||
| 24 | + $request->validated(); | ||
| 25 | + $where = [ | ||
| 26 | + 'project_id' => $this->user['project_id'], | ||
| 27 | + ]; | ||
| 28 | + // 分页查询 | ||
| 29 | + $lists = WorkOrder::with([ | ||
| 30 | + 'manager:id,name', | ||
| 31 | + ]) | ||
| 32 | + ->where($where) | ||
| 33 | + ->when($request->input('status'), function ($query) use ($request) { | ||
| 34 | + return $query->where('status', $request->input('status')); | ||
| 35 | + }) | ||
| 36 | + ->when($request->input('search'), function ($query) use ($request) { | ||
| 37 | + return $query->where('product', 'like', '%' . $request->input('search') . '%') | ||
| 38 | + ->orWhere('content', 'like', '%' . $request->input('search') . '%'); | ||
| 39 | + }) | ||
| 40 | + ->orderBy('id', 'desc')->paginate($this->row, ['*'], 'page', $this->page); | ||
| 41 | + $this->response('success', Code::SUCCESS, $lists); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * B端用户提交工单 | ||
| 46 | + * | ||
| 47 | + * @return \Illuminate\Http\Response | ||
| 48 | + */ | ||
| 49 | + public function store(WorkOrderCreateRequest $request) | ||
| 50 | + { | ||
| 51 | + $request->validated(); | ||
| 52 | + $result = DB::transaction(function () use ($request) { | ||
| 53 | + $workOrder = new WorkOrder; | ||
| 54 | + $workOrder->product = $request->input('product'); | ||
| 55 | + $workOrder->content = $request->input('content'); | ||
| 56 | + $workOrder->files = json_encode($request->input('files')); | ||
| 57 | + $workOrder->project_user_id = $this->user['id']; | ||
| 58 | + $workOrder->project_id = $this->user['project_id']; | ||
| 59 | + $workOrder->engineer_id = 0; | ||
| 60 | + if ($this->project['type'] == 3){ | ||
| 61 | + // 项目类型是优化推广,项目负责人找优化 | ||
| 62 | + $seo = Project::find($this->user['project_id'])->deploy_optimize; | ||
| 63 | + $workOrder->manage_id = $seo->manager_mid ?? $seo->optimist_mid ?? 0; | ||
| 64 | + }else{ | ||
| 65 | + // 非优化推广项目,项目负责人找技术组长 | ||
| 66 | + $build = Project::find($this->user['project_id'])->deploy_build; | ||
| 67 | + $workOrder->manage_id = $build->leader_mid ?? 0; | ||
| 68 | + } | ||
| 69 | + $workOrder->save(); | ||
| 70 | + // 添加工单日志 | ||
| 71 | + $log = new WorkOrderLog(); | ||
| 72 | + $log->manage_id = $workOrder->manage_id; | ||
| 73 | + $workOrder->logs()->save($log); | ||
| 74 | + return $workOrder; | ||
| 75 | + }); | ||
| 76 | + $this->response('success', Code::SUCCESS, $result->toArray()); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * Display the specified resource. | ||
| 81 | + * | ||
| 82 | + * @param int $id | ||
| 83 | + * @return \Illuminate\Http\Response | ||
| 84 | + */ | ||
| 85 | + public function show($id) | ||
| 86 | + { | ||
| 87 | + $workOrder = WorkOrder::with([ | ||
| 88 | + 'logs.manager:id,name', | ||
| 89 | + 'user:id,name', | ||
| 90 | + 'manager:id,name', | ||
| 91 | + 'engineer:id,name', | ||
| 92 | + ])->find($id); | ||
| 93 | + if (!$workOrder) { | ||
| 94 | + $this->response('工单未找到', 404); | ||
| 95 | + } | ||
| 96 | + if ($workOrder->project_id != $this->user['project_id'] && $workOrder->engineer_id != $this->user['id']) { | ||
| 97 | + $this->response('无权限查看该工单', 403); | ||
| 98 | + } | ||
| 99 | + $this->response('success', Code::SUCCESS, $workOrder->toArray()); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * B端用户修改工单,只能是修改工单状态 | ||
| 104 | + * | ||
| 105 | + * @param \Illuminate\Http\Request $request | ||
| 106 | + * @param int $id | ||
| 107 | + * @return \Illuminate\Http\Response | ||
| 108 | + */ | ||
| 109 | + public function update(WorkOrderUpdateRequest $request, $id) | ||
| 110 | + { | ||
| 111 | + $request->validated(); | ||
| 112 | + $workOrder = WorkOrder::find($id); | ||
| 113 | + if (!$workOrder) { | ||
| 114 | + $this->response('工单未找到', 404); | ||
| 115 | + } | ||
| 116 | + // b端只有自己项目下的账号可以更新工单 | ||
| 117 | + if ($workOrder->project_id != $this->user['project_id']) { | ||
| 118 | + $this->response('无权限更新该工单', 403); | ||
| 119 | + } | ||
| 120 | + // 更新工单状态 | ||
| 121 | + $workOrder->status = WorkOrder::STATUS_COMPLETED; | ||
| 122 | + $workOrder->save(); | ||
| 123 | + // B端完成工单,将所有子任务标记为完成 | ||
| 124 | + $workOrder->logs()->update(['status' => WorkOrderLog::STATUS_COMPLETED]); | ||
| 125 | + $this->response('success', Code::SUCCESS); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + public function destroy($id) | ||
| 129 | + { | ||
| 130 | + $workOrder = WorkOrder::find($id); | ||
| 131 | + if (!$workOrder) { | ||
| 132 | + $this->response('工单未找到', 404); | ||
| 133 | + } | ||
| 134 | + if ($workOrder->status >= WorkOrder::STATUS_COMPLETED) | ||
| 135 | + $this->response('已完结的工单不能删除', 403); | ||
| 136 | + | ||
| 137 | + if ($this->user['type'] != 1 && $workOrder->project_user_id != $this->user['id']) { | ||
| 138 | + // 只有项目负责人可以删除工单 | ||
| 139 | + $this->response('无权限删除该工单', 403); | ||
| 140 | + } | ||
| 141 | + # 删除工单 | ||
| 142 | + $workOrder->delete(); | ||
| 143 | + $this->response('工单已删除', Code::SUCCESS); | ||
| 144 | + | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | +} |
| @@ -514,22 +514,22 @@ class ImageController extends Controller | @@ -514,22 +514,22 @@ class ImageController extends Controller | ||
| 514 | foreach ($files as $file){ | 514 | foreach ($files as $file){ |
| 515 | if(isset($this->cache['image_max']) && ($this->cache['image_max'] != 0)){ | 515 | if(isset($this->cache['image_max']) && ($this->cache['image_max'] != 0)){ |
| 516 | if ($file->getSize() > $this->cache['image_max'] * 1024) { | 516 | if ($file->getSize() > $this->cache['image_max'] * 1024) { |
| 517 | - $this->response('图片最大为'.$this->cache['image_max'],Code::SYSTEM_ERROR); | 517 | + $this->response('图片最大为'.$this->cache['image_max'].'k',Code::SYSTEM_ERROR); |
| 518 | } | 518 | } |
| 519 | }else{ | 519 | }else{ |
| 520 | if ($file->getSize() > $max) { | 520 | if ($file->getSize() > $max) { |
| 521 | - $this->response('图片最大为1024K',Code::SYSTEM_ERROR); | 521 | + $this->response('图片最大为2m',Code::SYSTEM_ERROR); |
| 522 | } | 522 | } |
| 523 | } | 523 | } |
| 524 | } | 524 | } |
| 525 | }else{ | 525 | }else{ |
| 526 | if(isset($this->cache['image_max']) && ($this->cache['image_max'] != 0)){ | 526 | if(isset($this->cache['image_max']) && ($this->cache['image_max'] != 0)){ |
| 527 | if ($files->getSize() > $this->cache['image_max'] * 1024) { | 527 | if ($files->getSize() > $this->cache['image_max'] * 1024) { |
| 528 | - $this->response('图片最大为'.$this->cache['image_max'],Code::SYSTEM_ERROR); | 528 | + $this->response('图片最大为'.$this->cache['image_max'].'k',Code::SYSTEM_ERROR); |
| 529 | } | 529 | } |
| 530 | }else{ | 530 | }else{ |
| 531 | if ($files->getSize() > $max) { | 531 | if ($files->getSize() > $max) { |
| 532 | - $this->response('图片最大为1024K',Code::SYSTEM_ERROR); | 532 | + $this->response('图片最大为2m',Code::SYSTEM_ERROR); |
| 533 | } | 533 | } |
| 534 | } | 534 | } |
| 535 | } | 535 | } |
| @@ -29,11 +29,32 @@ class DomainApplicantLogLogic extends BaseLogic | @@ -29,11 +29,32 @@ class DomainApplicantLogLogic extends BaseLogic | ||
| 29 | * @time :2025/5/29 14:34 | 29 | * @time :2025/5/29 14:34 |
| 30 | */ | 30 | */ |
| 31 | public function lists($map,$page,$row){ | 31 | public function lists($map,$page,$row){ |
| 32 | + if(isset($map['domain']) && !empty($map['domain'])){ | ||
| 33 | + $map['domain'] = ['like','%'.$map['domain'].'%']; | ||
| 34 | + } | ||
| 35 | + if(isset($map['applicant_name']) && !empty($map['applicant_name'])){ | ||
| 36 | + $map['applicant_name'] = ['like','%'.$map['applicant_name'].'%']; | ||
| 37 | + } | ||
| 38 | + if(isset($map['operator_name']) && !empty($map['operator_name'])){ | ||
| 39 | + $map['operator_name'] = ['like','%'.$map['operator_name'].'%']; | ||
| 40 | + } | ||
| 32 | $lists = $this->model->lists($map,$page,$row,'id',['*']); | 41 | $lists = $this->model->lists($map,$page,$row,'id',['*']); |
| 33 | return $this->success($lists); | 42 | return $this->success($lists); |
| 34 | } | 43 | } |
| 35 | 44 | ||
| 36 | /** | 45 | /** |
| 46 | + * @remark :获取详情 | ||
| 47 | + * @name :info | ||
| 48 | + * @author :lyh | ||
| 49 | + * @method :post | ||
| 50 | + * @time :2025/5/30 14:35 | ||
| 51 | + */ | ||
| 52 | + public function info(){ | ||
| 53 | + $lists = $this->model->read($this->param); | ||
| 54 | + return $this->success($lists); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 37 | * @remark :保存域名申请记录 | 58 | * @remark :保存域名申请记录 |
| 38 | * @name :saveDomainLog | 59 | * @name :saveDomainLog |
| 39 | * @author :lyh | 60 | * @author :lyh |
| @@ -553,7 +553,7 @@ class RankDataLogic extends BaseLogic | @@ -553,7 +553,7 @@ class RankDataLogic extends BaseLogic | ||
| 553 | $without_extension_project_ids = [658]; //是否达标只统计主词的 | 553 | $without_extension_project_ids = [658]; //是否达标只统计主词的 |
| 554 | $extension_project_ids = [354]; //扩展词也到达标的 | 554 | $extension_project_ids = [354]; //扩展词也到达标的 |
| 555 | $compliance_project_ids = [2163,257,823,1750,497]; //直接达标处理的 | 555 | $compliance_project_ids = [2163,257,823,1750,497]; //直接达标处理的 |
| 556 | - $ceaseProjectId = [354, 378, 649, 1226, 1283, 1703, 1893, 2066, 2250,2193];//暂停的项目 | 556 | + $ceaseProjectId = [354, 378, 649, 1226, 1283, 1703, 1893, 2066, 2250,2193,2399,1685];//暂停的项目 |
| 557 | $uptimeProjectId = [1434,1812,276,2414,2974];//按上线时间统计的项目 | 557 | $uptimeProjectId = [1434,1812,276,2414,2974];//按上线时间统计的项目 |
| 558 | //一个项目多个api_no | 558 | //一个项目多个api_no |
| 559 | $multiple_api_no_project_ids = [ | 559 | $multiple_api_no_project_ids = [ |
| @@ -24,7 +24,8 @@ class WebSettingLogic extends BaseLogic | @@ -24,7 +24,8 @@ class WebSettingLogic extends BaseLogic | ||
| 24 | public function setting_read(){ | 24 | public function setting_read(){ |
| 25 | $info = $this->model->read(['project_id'=>$this->user['project_id']]); | 25 | $info = $this->model->read(['project_id'=>$this->user['project_id']]); |
| 26 | if($info === false){ | 26 | if($info === false){ |
| 27 | - $info = []; | 27 | + $this->model->addReturnId(['project_id'=>$this->user['project_id']]); |
| 28 | + $info =$this->model->read(['project_id'=>$this->user['project_id']]); | ||
| 28 | } | 29 | } |
| 29 | return $this->success($info); | 30 | return $this->success($info); |
| 30 | } | 31 | } |
| @@ -7,6 +7,7 @@ use App\Exceptions\AsideGlobalException; | @@ -7,6 +7,7 @@ use App\Exceptions\AsideGlobalException; | ||
| 7 | use App\Exceptions\BsideGlobalException; | 7 | use App\Exceptions\BsideGlobalException; |
| 8 | use App\Helper\Common; | 8 | use App\Helper\Common; |
| 9 | use App\Models\Domain\DomainInfo; | 9 | use App\Models\Domain\DomainInfo; |
| 10 | +use App\Models\Manage\ManageHr; | ||
| 10 | use App\Models\Project\Project; | 11 | use App\Models\Project\Project; |
| 11 | use App\Models\Scoring\ScoringSystem; | 12 | use App\Models\Scoring\ScoringSystem; |
| 12 | use App\Models\Sms\SmsLog; | 13 | use App\Models\Sms\SmsLog; |
| @@ -292,6 +293,9 @@ class UserLoginLogic | @@ -292,6 +293,9 @@ class UserLoginLogic | ||
| 292 | $info['service_duration'] = $project['deploy_build']['service_duration'] ?? 0; | 293 | $info['service_duration'] = $project['deploy_build']['service_duration'] ?? 0; |
| 293 | $info['is_comment'] = $project['deploy_build']['is_comment'] ?? 0; | 294 | $info['is_comment'] = $project['deploy_build']['is_comment'] ?? 0; |
| 294 | $info['is_ai_blog_send'] = $project['deploy_optimize']['is_ai_blog_send'] ?? 0; | 295 | $info['is_ai_blog_send'] = $project['deploy_optimize']['is_ai_blog_send'] ?? 0; |
| 296 | + $info['tech_leader'] = $project['deploy_optimize']['tech_leader'] ?? 0; | ||
| 297 | + $manageModel = new ManageHr(); | ||
| 298 | + $info['tech_leader_name'] = $manageModel->getName($project['deploy_optimize']['tech_leader'] ?? 0); | ||
| 295 | $info['remain_day'] = $project['remain_day'] ?? 0; | 299 | $info['remain_day'] = $project['remain_day'] ?? 0; |
| 296 | $info['project_created_at'] = $project['created_at']; | 300 | $info['project_created_at'] = $project['created_at']; |
| 297 | $info['type'] = $project['type'] ?? 1; | 301 | $info['type'] = $project['type'] ?? 1; |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Requests\Aside\WorkOrder; | ||
| 4 | + | ||
| 5 | +use Illuminate\Foundation\Http\FormRequest; | ||
| 6 | + | ||
| 7 | +class WorkOrderListRequest extends FormRequest | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Determine if the user is authorized to make this request. | ||
| 11 | + * | ||
| 12 | + * @return bool | ||
| 13 | + */ | ||
| 14 | + public function authorize() | ||
| 15 | + { | ||
| 16 | + return true; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * Get the validation rules that apply to the request. | ||
| 21 | + * | ||
| 22 | + * @return array | ||
| 23 | + */ | ||
| 24 | + public function rules() | ||
| 25 | + { | ||
| 26 | + return [ | ||
| 27 | + 'page' => 'nullable|integer', | ||
| 28 | + 'size' => 'nullable|integer', | ||
| 29 | + 'project_id' => 'nullable|integer', // 产品ID | ||
| 30 | + 'status' => 'nullable|in:0,1,2,3|integer', | ||
| 31 | + 'search' => 'nullable|string', // 搜索关键词 | ||
| 32 | + ]; | ||
| 33 | + } | ||
| 34 | +} |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Requests\Aside\WorkOrder; | ||
| 4 | + | ||
| 5 | +use Illuminate\Foundation\Http\FormRequest; | ||
| 6 | + | ||
| 7 | +class WorkOrderUpdateRequest extends FormRequest | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Determine if the user is authorized to make this request. | ||
| 11 | + * | ||
| 12 | + * @return bool | ||
| 13 | + */ | ||
| 14 | + public function authorize() | ||
| 15 | + { | ||
| 16 | + return true; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * Get the validation rules that apply to the request. | ||
| 21 | + * | ||
| 22 | + * @return array | ||
| 23 | + * A端更新售后工单 | ||
| 24 | + */ | ||
| 25 | + public function rules() | ||
| 26 | + { | ||
| 27 | + return [ | ||
| 28 | + 'status' => 'nullable|in:0,1,2,3|integer', | ||
| 29 | + 'engineer_ids' => 'nullable|array', | ||
| 30 | + 'content' => 'nullable|string', | ||
| 31 | + 'files' => 'nullable|array', | ||
| 32 | + ]; | ||
| 33 | + } | ||
| 34 | +} |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Requests\Bside\WorkOrder; | ||
| 4 | + | ||
| 5 | +use Illuminate\Foundation\Http\FormRequest; | ||
| 6 | + | ||
| 7 | +class WorkOrderCreateRequest extends FormRequest | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Determine if the user is authorized to make this request. | ||
| 11 | + * | ||
| 12 | + * @return bool | ||
| 13 | + */ | ||
| 14 | + public function authorize() | ||
| 15 | + { | ||
| 16 | + return true; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * Get the validation rules that apply to the request. | ||
| 21 | + * | ||
| 22 | + * @return array | ||
| 23 | + */ | ||
| 24 | + public function rules() | ||
| 25 | + { | ||
| 26 | + return [ | ||
| 27 | + 'product' => 'required|string', | ||
| 28 | + 'content' => 'required|string', | ||
| 29 | + 'files' => 'nullable|array', | ||
| 30 | + ]; | ||
| 31 | + } | ||
| 32 | +} |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Requests\Bside\WorkOrder; | ||
| 4 | + | ||
| 5 | +use Illuminate\Foundation\Http\FormRequest; | ||
| 6 | + | ||
| 7 | +class WorkOrderUpdateRequest extends FormRequest | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Determine if the user is authorized to make this request. | ||
| 11 | + * | ||
| 12 | + * @return bool | ||
| 13 | + */ | ||
| 14 | + public function authorize() | ||
| 15 | + { | ||
| 16 | + return true; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * Get the validation rules that apply to the request. | ||
| 21 | + * | ||
| 22 | + * @return array | ||
| 23 | + */ | ||
| 24 | + public function rules() | ||
| 25 | + { | ||
| 26 | + return [ | ||
| 27 | + 'status' => 'nullable|in:0,1,2,3|integer', | ||
| 28 | + 'engineer_ids' => 'nullable|array', | ||
| 29 | + 'content' => 'nullable|string', | ||
| 30 | + 'files' => 'nullable|array', | ||
| 31 | + ]; | ||
| 32 | + } | ||
| 33 | +} |
| @@ -13,6 +13,7 @@ class NoticeLog extends Base | @@ -13,6 +13,7 @@ class NoticeLog extends Base | ||
| 13 | const TYPE_PROJECT = 'project'; | 13 | const TYPE_PROJECT = 'project'; |
| 14 | const TYPE_RANK_DATA = 'rank_data'; | 14 | const TYPE_RANK_DATA = 'rank_data'; |
| 15 | const TYPE_INIT_PROJECT = 'init_project'; | 15 | const TYPE_INIT_PROJECT = 'init_project'; |
| 16 | + const TYPE_INIT_KEYWORD_COMMON = 'init_keyword_common';//聚合页关键词评论 | ||
| 16 | const TYPE_COPY_PROJECT = 'copy_project'; | 17 | const TYPE_COPY_PROJECT = 'copy_project'; |
| 17 | const TYPE_INIT_KEYWORD = 'init_keyword'; | 18 | const TYPE_INIT_KEYWORD = 'init_keyword'; |
| 18 | const DELETE_PRODUCT_CATEGORY = 'delete_product_category'; | 19 | const DELETE_PRODUCT_CATEGORY = 'delete_product_category'; |
| @@ -103,4 +103,22 @@ class ReInquiryCount extends Base | @@ -103,4 +103,22 @@ class ReInquiryCount extends Base | ||
| 103 | } | 103 | } |
| 104 | return $res; | 104 | return $res; |
| 105 | } | 105 | } |
| 106 | + | ||
| 107 | + public static function getRemainingDays($domain, $type, $project_id) | ||
| 108 | + { | ||
| 109 | + $cache_key = 're_inquiry_count_' . $domain . '_' . date('Ymd'); | ||
| 110 | + $data = Cache::get($cache_key); | ||
| 111 | + if($data === null){ | ||
| 112 | + if($project_id){ | ||
| 113 | + $data = Project::where('id', $project_id)->value('remain_day'); | ||
| 114 | + }else if($type == 3){ | ||
| 115 | + $data = '-'; | ||
| 116 | + }else{ | ||
| 117 | + $res = (new QuanqiusouApi())->getV5RemainDay($domain); | ||
| 118 | + $data = $res['data']['remain_day'] ??'-'; | ||
| 119 | + } | ||
| 120 | + Cache::put($cache_key, $data, 24 * 3600); | ||
| 121 | + } | ||
| 122 | + return $data; | ||
| 123 | + } | ||
| 106 | } | 124 | } |
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * @remark : | ||
| 4 | + * @name :AggregateKeywordComment.php | ||
| 5 | + * @author :lyh | ||
| 6 | + * @method :post | ||
| 7 | + * @time :2025/6/3 17:42 | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | +namespace App\Models\Project; | ||
| 11 | + | ||
| 12 | +use App\Models\Base; | ||
| 13 | + | ||
| 14 | +class AggregateKeywordComment extends Base | ||
| 15 | +{ | ||
| 16 | + protected $table = 'gl_aggregate_keyword_comment'; | ||
| 17 | +} |
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * @remark : | ||
| 4 | + * @name :TranslateBigProject.php | ||
| 5 | + * @author :lyh | ||
| 6 | + * @method :post | ||
| 7 | + * @time :2025/6/4 14:40 | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | +namespace App\Models\WebSetting; | ||
| 11 | + | ||
| 12 | +use App\Models\Base; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * @remark :需要翻译的大网站 | ||
| 16 | + * @name :TranslateBigProject | ||
| 17 | + * @author :lyh | ||
| 18 | + * @method :post | ||
| 19 | + * @time :2025/6/4 14:41 | ||
| 20 | + */ | ||
| 21 | +class TranslateBigProject extends Base | ||
| 22 | +{ | ||
| 23 | + protected $table = 'gl_translate_big_project'; | ||
| 24 | +} |
app/Models/WorkOrder/WorkOrder.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Models\WorkOrder; | ||
| 4 | + | ||
| 5 | +use App\Models\Base; | ||
| 6 | +use App\Models\Manage\Manage; | ||
| 7 | +use App\Models\Project\Project; | ||
| 8 | +use App\Models\User\User; | ||
| 9 | + | ||
| 10 | +class WorkOrder extends Base | ||
| 11 | +{ | ||
| 12 | + protected $table = 'gl_work_orders'; | ||
| 13 | + | ||
| 14 | + const STATUS_PEDDING = 0; // 待处理 | ||
| 15 | + const STATUS_PROCESSING = 1; // 处理中 | ||
| 16 | + const STATUS_COMPLETED = 2; // 已完成 | ||
| 17 | + const STATUS_CLOSED = 3; // 已关闭 | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 工单操作日志 | ||
| 22 | + */ | ||
| 23 | + public function logs() | ||
| 24 | + { | ||
| 25 | + return $this->hasMany(WorkOrderLog::class, 'work_order_id', 'id'); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 提交工单的用户 | ||
| 30 | + */ | ||
| 31 | + public function user() | ||
| 32 | + { | ||
| 33 | + return $this->belongsTo(User::class, 'project_user_id', 'id'); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 工单分配的管理员 | ||
| 38 | + */ | ||
| 39 | + public function manager() | ||
| 40 | + { | ||
| 41 | + return $this->belongsTo(Manage::class, 'manage_id', 'id'); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * 工单分配的工程师 | ||
| 46 | + */ | ||
| 47 | + public function engineer() | ||
| 48 | + { | ||
| 49 | + return $this->belongsTo(Manage::class, 'engineer_id', 'id'); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** 工单所属项目 */ | ||
| 53 | + public function project() | ||
| 54 | + { | ||
| 55 | + return $this->belongsTo(Project::class, 'project_id', 'id'); | ||
| 56 | + } | ||
| 57 | +} |
app/Models/WorkOrder/WorkOrderLog.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Models\WorkOrder; | ||
| 4 | + | ||
| 5 | +use App\Models\Base; | ||
| 6 | +use App\Models\Manage\Manage; | ||
| 7 | + | ||
| 8 | +class WorkOrderLog extends Base | ||
| 9 | +{ | ||
| 10 | + protected $table = 'gl_work_order_logs'; | ||
| 11 | + | ||
| 12 | + const STATUS_PEDDING = 0; // 待处理 | ||
| 13 | + const STATUS_PROCESSING = 1; // 处理中 | ||
| 14 | + const STATUS_COMPLETED = 2; // 已完成 | ||
| 15 | + const STATUS_CLOSED = 3; // 已关闭 | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 所属工单 | ||
| 19 | + */ | ||
| 20 | + public function workOrder() | ||
| 21 | + { | ||
| 22 | + return $this->belongsTo(WorkOrder::class, 'work_order_id'); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 分配的工单负责人,工程师等 | ||
| 27 | + */ | ||
| 28 | + public function manager() | ||
| 29 | + { | ||
| 30 | + return $this->belongsTo(Manage::class, 'manage_id', 'id'); | ||
| 31 | + } | ||
| 32 | +} |
| 1 | <?php | 1 | <?php |
| 2 | -/** | ||
| 3 | - * @remark : | ||
| 4 | - * @name :AiCommandService.php | ||
| 5 | - * @author :lyh | ||
| 6 | - * @method :post | ||
| 7 | - * @time :2025/5/26 17:01 | ||
| 8 | - */ | ||
| 9 | - | ||
| 10 | namespace App\Services; | 2 | namespace App\Services; |
| 11 | 3 | ||
| 12 | /** | 4 | /** |
| 13 | - * @remark :AI指令返回数据 | ||
| 14 | - * @name :AiCommandService | ||
| 15 | - * @author :lyh | ||
| 16 | - * @method :post | ||
| 17 | - * @time :2025/5/26 17:01 | 5 | + * Class AiCommandService |
| 6 | + * @package App\Services | ||
| 18 | */ | 7 | */ |
| 19 | class AiCommandService | 8 | class AiCommandService |
| 20 | { | 9 | { |
| @@ -22,16 +11,22 @@ class AiCommandService | @@ -22,16 +11,22 @@ class AiCommandService | ||
| 22 | 11 | ||
| 23 | public $api_key = 'nnLsyr3IhPNsJt5OvTtD9SVCLEixMntg'; | 12 | public $api_key = 'nnLsyr3IhPNsJt5OvTtD9SVCLEixMntg'; |
| 24 | 13 | ||
| 14 | + /** | ||
| 15 | + * @var string gemini 模型 | ||
| 16 | + * https://gemini.google.com/app | ||
| 17 | + * gemini-2.0-flash-lite | ||
| 18 | + * gemini-2.5-pro-preview-05-06 | ||
| 19 | + * gemini-2.5-flash-preview-05-20 | ||
| 20 | + * gemini-2.5-flash-preview-04-17 | ||
| 21 | + */ | ||
| 25 | public $model = 'gemini-2.0-flash-lite'; | 22 | public $model = 'gemini-2.0-flash-lite'; |
| 26 | 23 | ||
| 27 | public $supplier = 'google'; | 24 | public $supplier = 'google'; |
| 28 | 25 | ||
| 29 | /** | 26 | /** |
| 30 | - * @remark :Ai一键排版 | ||
| 31 | - * @name :ai_click_layout | ||
| 32 | - * @author :lyh | ||
| 33 | - * @method :post | ||
| 34 | - * @time :2025/5/26 17:03 | 27 | + * AI排版 |
| 28 | + * @param $content | ||
| 29 | + * @return array | ||
| 35 | */ | 30 | */ |
| 36 | public function send_layout_design($content){ | 31 | public function send_layout_design($content){ |
| 37 | $param = [ | 32 | $param = [ |
app/Services/DingTalkService.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Services; | ||
| 4 | + | ||
| 5 | +use App\DingDepartment; | ||
| 6 | +use App\DingUser; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 文档 https://apihub.cmer.com/docs/cmerdingtalk.html | ||
| 10 | + */ | ||
| 11 | +class DingTalkService | ||
| 12 | +{ | ||
| 13 | + protected $appKey; | ||
| 14 | + protected $appSecret; | ||
| 15 | + protected $robotCode; | ||
| 16 | + | ||
| 17 | + protected $headers = []; | ||
| 18 | + protected $bashUrl = 'https://api.cmer.com'; | ||
| 19 | + | ||
| 20 | + public function __construct() | ||
| 21 | + { | ||
| 22 | + $this->appKey = env('DING_TALK_APP_KEY'); | ||
| 23 | + $this->appSecret = env('DING_TALK_APP_SECRET'); | ||
| 24 | + $this->robotCode = env('DING_TALK_APP_KEY'); | ||
| 25 | + $this->headers = [ | ||
| 26 | + "Content-Type" => "application/json", | ||
| 27 | + "apikey" => "UkzZljFv83Z2qBi5YR1o3f2otAVWtug6", | ||
| 28 | + "X-CmerApi-Host" => "cmerdingtalk.p.cmer.com", | ||
| 29 | + ]; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** 发起请求 */ | ||
| 33 | + public function send_request(string $method, string $url, array $payload = [], array $params = []) | ||
| 34 | + { | ||
| 35 | + $client = new \GuzzleHttp\Client(); | ||
| 36 | + $options = [ | ||
| 37 | + 'headers' => $this->headers, | ||
| 38 | + 'json' => $payload | ||
| 39 | + ]; | ||
| 40 | + if (!empty($params)) | ||
| 41 | + $options['query'] = $params; | ||
| 42 | + | ||
| 43 | + $response = $client->request($method, $url, $options); | ||
| 44 | + return $response; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** 批量发送私聊消息 */ | ||
| 48 | + public function danliao(string $text, array $user_ids) | ||
| 49 | + { | ||
| 50 | + $endpoint = '/v1/danliao'; | ||
| 51 | + $payload = [ | ||
| 52 | + "appKey" => $this->appKey, | ||
| 53 | + "appSecret" => $this->appSecret, | ||
| 54 | + "robotCode" => $this->robotCode, | ||
| 55 | + "msg_param" => $text, | ||
| 56 | + "user_ids" => $user_ids | ||
| 57 | + ]; | ||
| 58 | + return $this->send_request('POST', $this->bashUrl . $endpoint, $payload); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + /** 批量发送Ding */ | ||
| 62 | + public function danliao_ding(string $text, array $user_ids) | ||
| 63 | + { | ||
| 64 | + $endpoint = '/v1/danliao_ding'; | ||
| 65 | + $payload = [ | ||
| 66 | + "appKey" => $this->appKey, | ||
| 67 | + "appSecret" => $this->appSecret, | ||
| 68 | + "robotCode" => $this->robotCode, | ||
| 69 | + "content" => $text, | ||
| 70 | + "receiver_user_id_list" => $user_ids | ||
| 71 | + ]; | ||
| 72 | + return $this->send_request('POST', $this->bashUrl . $endpoint, $payload); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | +} |
| @@ -12,6 +12,7 @@ | @@ -12,6 +12,7 @@ | ||
| 12 | "beyondcode/laravel-websockets": "^1.14", | 12 | "beyondcode/laravel-websockets": "^1.14", |
| 13 | "doctrine/dbal": "^3.6", | 13 | "doctrine/dbal": "^3.6", |
| 14 | "fruitcake/laravel-cors": "^2.0", | 14 | "fruitcake/laravel-cors": "^2.0", |
| 15 | + "g4t/swagger": "^4.0", | ||
| 15 | "guzzlehttp/guzzle": "^7.0.1", | 16 | "guzzlehttp/guzzle": "^7.0.1", |
| 16 | "hashids/hashids": "^4.1", | 17 | "hashids/hashids": "^4.1", |
| 17 | "intervention/image": "^2.7", | 18 | "intervention/image": "^2.7", |
config/swagger.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + /* | ||
| 5 | + |-------------------------------------------------------------------------- | ||
| 6 | + | API Title | ||
| 7 | + |-------------------------------------------------------------------------- | ||
| 8 | + | | ||
| 9 | + | The title of your API documentation. | ||
| 10 | + | | ||
| 11 | + */ | ||
| 12 | + "title" => env("SWAGGER_TITLE", "Globalso V6 Api Documentation"), | ||
| 13 | + | ||
| 14 | + /* | ||
| 15 | + |-------------------------------------------------------------------------- | ||
| 16 | + | API Description | ||
| 17 | + |-------------------------------------------------------------------------- | ||
| 18 | + | | ||
| 19 | + | The description of your API. | ||
| 20 | + | | ||
| 21 | + */ | ||
| 22 | + "description" => env("SWAGGER_DESCRIPTION", "Laravel autogenerate swagger"), | ||
| 23 | + | ||
| 24 | + /* | ||
| 25 | + |-------------------------------------------------------------------------- | ||
| 26 | + | API Email | ||
| 27 | + |-------------------------------------------------------------------------- | ||
| 28 | + | | ||
| 29 | + | The email associated with your API documentation. | ||
| 30 | + | | ||
| 31 | + */ | ||
| 32 | + "email" => env("SWAGGER_EMAIL", "bill@ai.cc"), | ||
| 33 | + | ||
| 34 | + /* | ||
| 35 | + |-------------------------------------------------------------------------- | ||
| 36 | + | API Version | ||
| 37 | + |-------------------------------------------------------------------------- | ||
| 38 | + | | ||
| 39 | + | The version of your API. | ||
| 40 | + | | ||
| 41 | + */ | ||
| 42 | + "version" => env("SWAGGER_VERSION", "3.0.7"), | ||
| 43 | + | ||
| 44 | + /* | ||
| 45 | + |-------------------------------------------------------------------------- | ||
| 46 | + | Documentation Auth | ||
| 47 | + |-------------------------------------------------------------------------- | ||
| 48 | + | | ||
| 49 | + | This options to enable documentation auth | ||
| 50 | + | | ||
| 51 | + */ | ||
| 52 | + "enable_auth" => false, | ||
| 53 | + "username" => "admin", | ||
| 54 | + "password" => "pass", | ||
| 55 | + "sesson_ttl" => 100000, | ||
| 56 | + | ||
| 57 | + /* | ||
| 58 | + |-------------------------------------------------------------------------- | ||
| 59 | + | Enable Response Schema | ||
| 60 | + |-------------------------------------------------------------------------- | ||
| 61 | + | | ||
| 62 | + | Whether to enable response schema or not. | ||
| 63 | + | | ||
| 64 | + */ | ||
| 65 | + "enable_response_schema" => true, | ||
| 66 | + | ||
| 67 | + "suggestions_select_input" => false, | ||
| 68 | + | ||
| 69 | + "load_from_json" => false, | ||
| 70 | + | ||
| 71 | + /* | ||
| 72 | + |-------------------------------------------------------------------------- | ||
| 73 | + | Authentication Middlewares | ||
| 74 | + |-------------------------------------------------------------------------- | ||
| 75 | + | | ||
| 76 | + | List of middleware names used for authentication. | ||
| 77 | + | | ||
| 78 | + */ | ||
| 79 | + "auth_middlewares" => [ | ||
| 80 | + "auth", | ||
| 81 | + "auth:api", | ||
| 82 | + "aloginauth", | ||
| 83 | + "bloginauth", | ||
| 84 | + ], | ||
| 85 | + | ||
| 86 | + /* | ||
| 87 | + |-------------------------------------------------------------------------- | ||
| 88 | + | API URL | ||
| 89 | + |-------------------------------------------------------------------------- | ||
| 90 | + | | ||
| 91 | + | The URL path for accessing your API documentation. | ||
| 92 | + | | ||
| 93 | + */ | ||
| 94 | + "url" => env("SWAGGER_URL", "swagger/documentation"), | ||
| 95 | + | ||
| 96 | + /* | ||
| 97 | + |-------------------------------------------------------------------------- | ||
| 98 | + | Issues URL | ||
| 99 | + |-------------------------------------------------------------------------- | ||
| 100 | + | | ||
| 101 | + | The URL path for accessing issues related to your API documentation. | ||
| 102 | + | | ||
| 103 | + */ | ||
| 104 | + "issues_url" => env("SWAGGER_ISSUE_URL", "swagger/issues"), | ||
| 105 | + | ||
| 106 | + /* | ||
| 107 | + |-------------------------------------------------------------------------- | ||
| 108 | + | Enable Swagger | ||
| 109 | + |-------------------------------------------------------------------------- | ||
| 110 | + | | ||
| 111 | + | Whether Swagger is enabled or not. | ||
| 112 | + | | ||
| 113 | + */ | ||
| 114 | + "enable" => env('SWAGGER_ENABLED', true), | ||
| 115 | + | ||
| 116 | + /* | ||
| 117 | + |-------------------------------------------------------------------------- | ||
| 118 | + | Show Prefix | ||
| 119 | + |-------------------------------------------------------------------------- | ||
| 120 | + | | ||
| 121 | + | List of prefixes to show in Swagger. | ||
| 122 | + | | ||
| 123 | + */ | ||
| 124 | + "show_prefix" => [], | ||
| 125 | + | ||
| 126 | + /* | ||
| 127 | + |-------------------------------------------------------------------------- | ||
| 128 | + | Include Web Routes | ||
| 129 | + |-------------------------------------------------------------------------- | ||
| 130 | + | | ||
| 131 | + | If you want to includes web.php routes, then enable this | ||
| 132 | + | | ||
| 133 | + */ | ||
| 134 | + "include_web_routes" => env('SWAGGER_INCLUDE_WEB_ROUTES', true), | ||
| 135 | + | ||
| 136 | + | ||
| 137 | + /* | ||
| 138 | + |-------------------------------------------------------------------------- | ||
| 139 | + | API Versions | ||
| 140 | + |-------------------------------------------------------------------------- | ||
| 141 | + | | ||
| 142 | + | List of versions to show in Swagger. | ||
| 143 | + | | ||
| 144 | + */ | ||
| 145 | + "versions" => [ | ||
| 146 | + "all", | ||
| 147 | + // "v1" | ||
| 148 | + ], | ||
| 149 | + | ||
| 150 | + "default" => "all", | ||
| 151 | + | ||
| 152 | + | ||
| 153 | + /* | ||
| 154 | + |-------------------------------------------------------------------------- | ||
| 155 | + | Servers | ||
| 156 | + |-------------------------------------------------------------------------- | ||
| 157 | + | | ||
| 158 | + | List of servers associated with your API. | ||
| 159 | + | | ||
| 160 | + */ | ||
| 161 | + "servers" => [ | ||
| 162 | + [ | ||
| 163 | + "url" => env("APP_URL"), | ||
| 164 | + "description" => "localhost" | ||
| 165 | + ] | ||
| 166 | + ], | ||
| 167 | + | ||
| 168 | + | ||
| 169 | + /* | ||
| 170 | + |-------------------------------------------------------------------------- | ||
| 171 | + | Security Schemes | ||
| 172 | + |-------------------------------------------------------------------------- | ||
| 173 | + | | ||
| 174 | + | Security schemes used in your API. | ||
| 175 | + | | ||
| 176 | + */ | ||
| 177 | + "security_schemes" => [ | ||
| 178 | + "APIKeyHeader" => [ | ||
| 179 | + "type" => "apiKey", | ||
| 180 | + "name" => "token", | ||
| 181 | + "in" => "header" | ||
| 182 | + ], | ||
| 183 | + ], | ||
| 184 | + | ||
| 185 | + /* | ||
| 186 | + |-------------------------------------------------------------------------- | ||
| 187 | + | Spatie Query Builder | ||
| 188 | + |-------------------------------------------------------------------------- | ||
| 189 | + | | ||
| 190 | + | Enable it if you using Spatie query builder package to add spatie filters in all GET routes. | ||
| 191 | + | | ||
| 192 | + */ | ||
| 193 | + "spatie_query_builder" => false, | ||
| 194 | + | ||
| 195 | + | ||
| 196 | + /* | ||
| 197 | + |-------------------------------------------------------------------------- | ||
| 198 | + | Status | ||
| 199 | + |-------------------------------------------------------------------------- | ||
| 200 | + | | ||
| 201 | + | HTTP response statuses for various methods. | ||
| 202 | + | | ||
| 203 | + */ | ||
| 204 | + "status" => [ | ||
| 205 | + "GET" => [ | ||
| 206 | + "200" => [ | ||
| 207 | + "description" => "Successful Operation", | ||
| 208 | + ], | ||
| 209 | + "404" => [ | ||
| 210 | + "description" => "Not Found" | ||
| 211 | + ] | ||
| 212 | + ], | ||
| 213 | + "POST" => [ | ||
| 214 | + "200" => [ | ||
| 215 | + "description" => "Successful Operation", | ||
| 216 | + ], | ||
| 217 | + "422" => [ | ||
| 218 | + "description" => "Validation Issues" | ||
| 219 | + ] | ||
| 220 | + ], | ||
| 221 | + "PUT" => [ | ||
| 222 | + "200" => [ | ||
| 223 | + "description" => "Successful Operation", | ||
| 224 | + ], | ||
| 225 | + "404" => [ | ||
| 226 | + "description" => "Not Found" | ||
| 227 | + ], | ||
| 228 | + "405" => [ | ||
| 229 | + "description" => "Validation exception" | ||
| 230 | + ] | ||
| 231 | + ], | ||
| 232 | + "PATCH" => [ | ||
| 233 | + "200" => [ | ||
| 234 | + "description" => "Successful Operation", | ||
| 235 | + ], | ||
| 236 | + "404" => [ | ||
| 237 | + "description" => "Not Found" | ||
| 238 | + ], | ||
| 239 | + "405" => [ | ||
| 240 | + "description" => "Validation exception" | ||
| 241 | + ] | ||
| 242 | + ], | ||
| 243 | + "DELETE" => [ | ||
| 244 | + "200" => [ | ||
| 245 | + "description" => "successful Operation", | ||
| 246 | + ], | ||
| 247 | + "404" => [ | ||
| 248 | + "description" => "page Not Found" | ||
| 249 | + ] | ||
| 250 | + ], | ||
| 251 | + ], | ||
| 252 | + | ||
| 253 | +]; |
| 1 | -<?php | ||
| 2 | - | ||
| 3 | -use Illuminate\Database\Migrations\Migration; | ||
| 4 | -use Illuminate\Database\Schema\Blueprint; | ||
| 5 | -use Illuminate\Support\Facades\Schema; | ||
| 6 | - | ||
| 7 | -class CreateFailedJobsTable extends Migration | ||
| 8 | -{ | ||
| 9 | - /** | ||
| 10 | - * Run the migrations. | ||
| 11 | - * | ||
| 12 | - * @return void | ||
| 13 | - */ | ||
| 14 | - public function up() | ||
| 15 | - { | ||
| 16 | - Schema::create('failed_jobs', function (Blueprint $table) { | ||
| 17 | - $table->id(); | ||
| 18 | - $table->string('uuid')->unique(); | ||
| 19 | - $table->text('connection'); | ||
| 20 | - $table->text('queue'); | ||
| 21 | - $table->longText('payload'); | ||
| 22 | - $table->longText('exception'); | ||
| 23 | - $table->timestamp('failed_at')->useCurrent(); | ||
| 24 | - }); | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - /** | ||
| 28 | - * Reverse the migrations. | ||
| 29 | - * | ||
| 30 | - * @return void | ||
| 31 | - */ | ||
| 32 | - public function down() | ||
| 33 | - { | ||
| 34 | - Schema::dropIfExists('failed_jobs'); | ||
| 35 | - } | ||
| 36 | -} |
| @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; | @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; | ||
| 4 | use Illuminate\Database\Schema\Blueprint; | 4 | use Illuminate\Database\Schema\Blueprint; |
| 5 | use Illuminate\Support\Facades\Schema; | 5 | use Illuminate\Support\Facades\Schema; |
| 6 | 6 | ||
| 7 | -class CreatePersonalAccessTokensTable extends Migration | 7 | +class CreateWorkOrdersTable extends Migration |
| 8 | { | 8 | { |
| 9 | /** | 9 | /** |
| 10 | * Run the migrations. | 10 | * Run the migrations. |
| @@ -13,15 +13,21 @@ class CreatePersonalAccessTokensTable extends Migration | @@ -13,15 +13,21 @@ class CreatePersonalAccessTokensTable extends Migration | ||
| 13 | */ | 13 | */ |
| 14 | public function up() | 14 | public function up() |
| 15 | { | 15 | { |
| 16 | - Schema::create('personal_access_tokens', function (Blueprint $table) { | 16 | + Schema::create('gl_work_orders', function (Blueprint $table) { |
| 17 | $table->id(); | 17 | $table->id(); |
| 18 | - $table->morphs('tokenable'); | ||
| 19 | - $table->string('name'); | ||
| 20 | - $table->string('token', 64)->unique(); | ||
| 21 | - $table->text('abilities')->nullable(); | ||
| 22 | - $table->timestamp('last_used_at')->nullable(); | ||
| 23 | $table->timestamps(); | 18 | $table->timestamps(); |
| 19 | + $table->string('product')->nullable()->comment('相关产品,工单类型'); | ||
| 20 | + $table->longText('content')->comment('工单图文描述'); | ||
| 21 | + $table->json('files')->nullable()->comment('附件'); | ||
| 22 | + $table->integer('status')->index()->default(0)->comment('工单状态,0:待处理, 1:处理中,2:已完成, 3:已关闭'); | ||
| 23 | + $table->integer('project_user_id')->index()->comment('客户ID'); | ||
| 24 | + $table->integer('project_id')->index()->comment('项目ID'); | ||
| 25 | + $table->integer('manage_id')->index()->comment('A端项目负责人ID, gl_manage 表ID'); | ||
| 26 | + $table->integer('engineer_id')->index()->comment('处理技术,工程师id, gl_manage 表ID'); | ||
| 27 | + $table->timestamp('end_at')->nullable()->comment('完成时间'); | ||
| 24 | }); | 28 | }); |
| 29 | + # 添加表注释 | ||
| 30 | + \Illuminate\Support\Facades\DB::statement("ALTER TABLE gl_work_orders comment '工单表'"); | ||
| 25 | } | 31 | } |
| 26 | 32 | ||
| 27 | /** | 33 | /** |
| @@ -31,6 +37,6 @@ class CreatePersonalAccessTokensTable extends Migration | @@ -31,6 +37,6 @@ class CreatePersonalAccessTokensTable extends Migration | ||
| 31 | */ | 37 | */ |
| 32 | public function down() | 38 | public function down() |
| 33 | { | 39 | { |
| 34 | - Schema::dropIfExists('personal_access_tokens'); | 40 | + Schema::dropIfExists('gl_work_orders'); |
| 35 | } | 41 | } |
| 36 | } | 42 | } |
| @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; | @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; | ||
| 4 | use Illuminate\Database\Schema\Blueprint; | 4 | use Illuminate\Database\Schema\Blueprint; |
| 5 | use Illuminate\Support\Facades\Schema; | 5 | use Illuminate\Support\Facades\Schema; |
| 6 | 6 | ||
| 7 | -class CreateUsersTable extends Migration | 7 | +class CreateWorkOrderLogsTable extends Migration |
| 8 | { | 8 | { |
| 9 | /** | 9 | /** |
| 10 | * Run the migrations. | 10 | * Run the migrations. |
| @@ -13,15 +13,19 @@ class CreateUsersTable extends Migration | @@ -13,15 +13,19 @@ class CreateUsersTable extends Migration | ||
| 13 | */ | 13 | */ |
| 14 | public function up() | 14 | public function up() |
| 15 | { | 15 | { |
| 16 | - Schema::create('users', function (Blueprint $table) { | 16 | + Schema::create('gl_work_order_logs', function (Blueprint $table) { |
| 17 | $table->id(); | 17 | $table->id(); |
| 18 | - $table->string('name'); | ||
| 19 | - $table->string('email')->unique(); | ||
| 20 | - $table->timestamp('email_verified_at')->nullable(); | ||
| 21 | - $table->string('password'); | ||
| 22 | - $table->rememberToken(); | ||
| 23 | $table->timestamps(); | 18 | $table->timestamps(); |
| 19 | + $table->integer('work_order_id')->index(); | ||
| 20 | + $table->integer('manage_id')->comment('gl_manage 表ID,操作人ID'); | ||
| 21 | + $table->boolean('ding')->default(false)->comment('是否钉钉通知'); | ||
| 22 | + $table->longText('content')->nullable()->comment('处理结果,图文描述'); | ||
| 23 | + $table->json('files')->nullable()->comment('附件'); | ||
| 24 | + $table->integer('status')->index()->default(0)->comment('工单状态,0:待处理, 1:处理中, 2:已完成'); | ||
| 25 | + $table->timestamp('end_at')->nullable()->comment('完成时间'); | ||
| 26 | + $table->unique(['work_order_id', 'manage_id'], 'work_order_manage_unique'); # 唯一索引,防止同一工单被同一人多次操作,同一工单,可以多人协作 | ||
| 24 | }); | 27 | }); |
| 28 | + \Illuminate\Support\Facades\DB::statement('ALTER TABLE gl_work_order_logs comment "工单操作日志表,分配工程师时创建,工程师完成时修改状态"'); | ||
| 25 | } | 29 | } |
| 26 | 30 | ||
| 27 | /** | 31 | /** |
| @@ -31,6 +35,6 @@ class CreateUsersTable extends Migration | @@ -31,6 +35,6 @@ class CreateUsersTable extends Migration | ||
| 31 | */ | 35 | */ |
| 32 | public function down() | 36 | public function down() |
| 33 | { | 37 | { |
| 34 | - Schema::dropIfExists('users'); | 38 | + Schema::dropIfExists('gl_work_order_logs'); |
| 35 | } | 39 | } |
| 36 | } | 40 | } |
| @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; | @@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration; | ||
| 4 | use Illuminate\Database\Schema\Blueprint; | 4 | use Illuminate\Database\Schema\Blueprint; |
| 5 | use Illuminate\Support\Facades\Schema; | 5 | use Illuminate\Support\Facades\Schema; |
| 6 | 6 | ||
| 7 | -class CreatePasswordResetsTable extends Migration | 7 | +class WorkOrderLogsAddForeignId extends Migration |
| 8 | { | 8 | { |
| 9 | /** | 9 | /** |
| 10 | * Run the migrations. | 10 | * Run the migrations. |
| @@ -13,11 +13,12 @@ class CreatePasswordResetsTable extends Migration | @@ -13,11 +13,12 @@ class CreatePasswordResetsTable extends Migration | ||
| 13 | */ | 13 | */ |
| 14 | public function up() | 14 | public function up() |
| 15 | { | 15 | { |
| 16 | - Schema::create('password_resets', function (Blueprint $table) { | ||
| 17 | - $table->string('email')->index(); | ||
| 18 | - $table->string('token'); | ||
| 19 | - $table->timestamp('created_at')->nullable(); | ||
| 20 | - }); | 16 | + Schema::table('gl_work_order_logs', function (Blueprint $table) { |
| 17 | + // 字段已存在,给字段添加外键约束 | ||
| 18 | + $table->foreign('work_order_id') | ||
| 19 | + ->references('id')->on('gl_work_orders') | ||
| 20 | + ->onDelete('cascade'); // 设置级联删除 | ||
| 21 | + }); | ||
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| @@ -27,6 +28,9 @@ class CreatePasswordResetsTable extends Migration | @@ -27,6 +28,9 @@ class CreatePasswordResetsTable extends Migration | ||
| 27 | */ | 28 | */ |
| 28 | public function down() | 29 | public function down() |
| 29 | { | 30 | { |
| 30 | - Schema::dropIfExists('password_resets'); | 31 | + Schema::table('gl_work_order_logs', function (Blueprint $table) { |
| 32 | + // 删除外键约束 | ||
| 33 | + $table->dropForeign(['work_order_id']); | ||
| 34 | + }); | ||
| 31 | } | 35 | } |
| 32 | } | 36 | } |
docs/售后工单设计图.drawio.pdf
0 → 100644
不能预览此文件类型
| @@ -246,6 +246,13 @@ Route::middleware(['aloginauth'])->group(function () { | @@ -246,6 +246,13 @@ Route::middleware(['aloginauth'])->group(function () { | ||
| 246 | Route::post('/save_follow', [Aside\Task\TaskController::class, 'save_follow'])->name('admin.task_save_follow'); | 246 | Route::post('/save_follow', [Aside\Task\TaskController::class, 'save_follow'])->name('admin.task_save_follow'); |
| 247 | Route::any('/getUserTaskList', [Aside\Task\TaskController::class, 'getUserTaskList'])->name('admin.task_getUserTaskList'); | 247 | Route::any('/getUserTaskList', [Aside\Task\TaskController::class, 'getUserTaskList'])->name('admin.task_getUserTaskList'); |
| 248 | }); | 248 | }); |
| 249 | + // 售后工单 | ||
| 250 | + Route::prefix('workorder')->group(function () { | ||
| 251 | + Route::get('/', [Aside\WorkOrder\WorkOrderController::class, 'index'])->name('admin.workorder.index')->summary('A端工程师的工单列表'); | ||
| 252 | + Route::get('/manager', [Aside\WorkOrder\WorkOrderController::class, 'manager'])->name('admin.workorder.manager')->summary('A端管理员的工单列表'); | ||
| 253 | + Route::get('/{id}', [Aside\WorkOrder\WorkOrderController::class, 'show'])->name('admin.workorder.show')->summary('A端工单详情'); | ||
| 254 | + Route::post('/{id}', [Aside\WorkOrder\WorkOrderController::class, 'update'])->name('admin.workorder.update')->summary('A端更新工单'); | ||
| 255 | + }); | ||
| 249 | //服务器配置 | 256 | //服务器配置 |
| 250 | Route::prefix('devops')->group(function () { | 257 | Route::prefix('devops')->group(function () { |
| 251 | Route::any('/', [Aside\Devops\ServerConfigController::class, 'lists'])->name('admin.devops.lists'); | 258 | Route::any('/', [Aside\Devops\ServerConfigController::class, 'lists'])->name('admin.devops.lists'); |
| @@ -271,6 +278,7 @@ Route::middleware(['aloginauth'])->group(function () { | @@ -271,6 +278,7 @@ Route::middleware(['aloginauth'])->group(function () { | ||
| 271 | }); | 278 | }); |
| 272 | Route::prefix('domain_log')->group(function () { | 279 | Route::prefix('domain_log')->group(function () { |
| 273 | Route::any('/', [Aside\Domain\DomainApplicantLogController::class, 'lists'])->name('admin.domain_log_lists'); | 280 | Route::any('/', [Aside\Domain\DomainApplicantLogController::class, 'lists'])->name('admin.domain_log_lists'); |
| 281 | + Route::any('/info', [Aside\Domain\DomainApplicantLogController::class, 'info'])->name('admin.domain_log_info'); | ||
| 274 | Route::any('/save', [Aside\Domain\DomainApplicantLogController::class, 'save'])->name('admin.domain_log_save'); | 282 | Route::any('/save', [Aside\Domain\DomainApplicantLogController::class, 'save'])->name('admin.domain_log_save'); |
| 275 | Route::any('/del', [Aside\Domain\DomainApplicantLogController::class, 'del'])->name('admin.domain_log_del'); | 283 | Route::any('/del', [Aside\Domain\DomainApplicantLogController::class, 'del'])->name('admin.domain_log_del'); |
| 276 | }); | 284 | }); |
| @@ -269,6 +269,16 @@ Route::middleware(['bloginauth'])->group(function () { | @@ -269,6 +269,16 @@ Route::middleware(['bloginauth'])->group(function () { | ||
| 269 | Route::any('/save',[\App\Http\Controllers\Bside\Setting\WebSettingAmpController::class, 'save'])->name('amp_save'); | 269 | Route::any('/save',[\App\Http\Controllers\Bside\Setting\WebSettingAmpController::class, 'save'])->name('amp_save'); |
| 270 | }); | 270 | }); |
| 271 | }); | 271 | }); |
| 272 | + | ||
| 273 | + // 售后工单 | ||
| 274 | + Route::prefix('workorder')->group(function () { | ||
| 275 | + Route::get('/', [\App\Http\Controllers\Bside\WorkOrder\WorkOrderController::class, 'index'])->name('workorder.index')->summary('B端售后工单列表'); | ||
| 276 | + Route::post('/', [\App\Http\Controllers\Bside\WorkOrder\WorkOrderController::class, 'store'])->name('workorder.store')->summary('B端创建工单'); | ||
| 277 | + Route::get('/{id}', [\App\Http\Controllers\Bside\WorkOrder\WorkOrderController::class, 'show'])->name('workorder.show')->summary('B端查看工单'); | ||
| 278 | + Route::post('/{id}', [\App\Http\Controllers\Bside\WorkOrder\WorkOrderController::class, 'update'])->name('workorder.update')->summary('B端完结工单'); | ||
| 279 | + Route::delete('/{id}', [\App\Http\Controllers\Bside\WorkOrder\WorkOrderController::class, 'destroy'])->name('workorder.destroy')->summary('B端删除工单,已完结的工单无法删除'); | ||
| 280 | + }); | ||
| 281 | + | ||
| 272 | //产品 | 282 | //产品 |
| 273 | Route::prefix('product')->group(function () { | 283 | Route::prefix('product')->group(function () { |
| 274 | //产品 | 284 | //产品 |
-
请 注册 或 登录 后发表评论