作者 刘锟

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 +}
  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 +}
@@ -60,6 +60,8 @@ class Project extends Base @@ -60,6 +60,8 @@ class Project extends Base
60 5 => 'Q告知书二', 60 5 => 'Q告知书二',
61 6 => 'KA', 61 6 => 'KA',
62 7 => 'CKA', 62 7 => 'CKA',
  63 + 18 => '白帽V1(AI视频)',
  64 + 19 => '白帽V2(保证排名)',
63 ]; 65 ];
64 } 66 }
65 67
  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 +}
  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 +}
  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 = [
  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",
  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 }
不能预览此文件类型
@@ -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 //产品