作者 ZhengBing He

Merge branch 'hbb' into workorder

@@ -56,65 +56,99 @@ class FetchTicketProjects extends Command @@ -56,65 +56,99 @@ class FetchTicketProjects extends Command
56 */ 56 */
57 public function fetchV5() 57 public function fetchV5()
58 { 58 {
59 - # pm 项目经理 assm 售后服务经理  
60 - $response = Http::get('https://www.quanqiusou.cn/extend_api/webs/globalso_all.php');  
61 - if ($response->status() == 200) {  
62 - $items = $response->json();  
63 - foreach ($items as $item) {  
64 - # V5: 版本号+postid  
65 - $uuid = md5("V5{$item['postid']}");  
66 - $project = TicketProject::where('uuid', $uuid)->first();  
67 - $assm_id = Manage::where('name', $item['assm'])->value('id') ?? Manage::where('name', '张鸿飞')->value('id') ?? 0; //售后服务经理  
68 - $seom_id = Manage::where('name', $item['yhs'])->value('id') ?? Manage::where('name', '陶婵')->value('id') ?? 0; //优化师  
69 - // 如果 $item['cate'] 包含”推广“字符,则 $engineer_name = $item['assm']  
70 - /**  
71 - * 第一负责人逻即说明:  
72 - * 优化推广项目:找售后服务经理??鸿飞  
73 - * 建站类项目: 找杨长远  
74 - */  
75 - $engineer_id = (strpos($item['cate'], '推广') !== false) ? $assm_id : Manage::where('name', '杨长远')->value('id') ?? 0; 59 + $page = 1;
  60 + $postids = [];
76 61
77 - $fields = [  
78 - 'post_id' => $item['postid'],  
79 - 'company_name' => $item['company'],  
80 - 'title' => $item['title'],  
81 - 'engineer_id' => $engineer_id, // 第一负责人  
82 - 'assm_id' => $assm_id,  
83 - 'seom_id' => $seom_id,  
84 - 'website' => $item['main_url'] ?? '',  
85 - 'test_website' => $item['test_url'] ?? '',  
86 - 'is_del' => 0,  
87 - 'plan' => $item['plan'] ?? '',  
88 - 'project_cate' => 1,  
89 - ];  
90 - if (!$project) {  
91 - $new = new TicketProject();  
92 - $new->uuid = $uuid;  
93 - $new->version = 5;  
94 - $new->table_id = 0;  
95 - foreach ($fields as $k => $v) {  
96 - $new->$k = $v;  
97 - }  
98 - $new->save();  
99 - } else {  
100 - $changed = false;  
101 - foreach ($fields as $k => $v) {  
102 - if ($project->$k != $v) {  
103 - $project->$k = $v;  
104 - $changed = true; 62 + while (true) {
  63 + $response = Http::get('https://www.quanqiusou.cn/extend_api/webs/globalso_all.php?page=' . $page);
  64 + if ($response->status() == 200) {
  65 + $resp_json = $response->json();
  66 + $items = $resp_json['data'] ?? [];
  67 + if (empty($items))
  68 + {
  69 + echo now() . " | INFO | V5: not found items on page $page \n";
  70 + break;
  71 + }
  72 + foreach ($items as $item) {
  73 + # V5: 版本号+postid
  74 + $uuid = md5("V5{$item['postid']}");
  75 + $project = TicketProject::where('uuid', $uuid)->first();
  76 +
  77 + // 项目状态, 根据 $item['cate'] 判断,建站中,建站客户,推广
  78 + if (strpos($item['cate'], '推广') !== false)
  79 + $status=3; // 推广
  80 + elseif ($item['cate'] == "建站客户")
  81 + $status=2; // 建站客户
  82 + elseif ($item['cate'] == "建站中")
  83 + $status=1; // 建站中
  84 +
  85 + $assm_id = Manage::where('name', $item['assm'])->value('id') ?? Manage::where('name', '张鸿飞')->value('id') ?? 0; //售后服务经理
  86 + $seom_id = Manage::where('name', $item['yhs'])->value('id') ?? Manage::where('name', '陶婵')->value('id') ?? 0; //优化师
  87 + $pm_id = Manage::where('name', $item['pm'])->value('id') ?? Manage::where('name', '李洁玉')->value('id') ?? 0; // 项目经理
  88 +
  89 + /**
  90 + * 第一负责人逻即说明:
  91 + * 优化推广项目:找售后服务经理??鸿飞
  92 + * 建站中:项目经理
  93 + * 建站完成:杨长远
  94 + */
  95 +
  96 + if ($status == 3)
  97 + $engineer_id = $assm_id; // 推广类项目找售后服务经理
  98 + elseif ($status == 2)
  99 + $engineer_id = Manage::where('name', '杨长远')->value('id') ?? 0; //建站完成
  100 + elseif ($status == 1)
  101 + $engineer_id = $pm_id; // 建站中找项目经理
  102 +
  103 + $fields = [
  104 + 'post_id' => $item['postid'],
  105 + 'company_name' => $item['company'],
  106 + 'title' => $item['title'] . " - V5",
  107 + 'engineer_id' => $engineer_id, // 第一负责人
  108 + 'assm_id' => $assm_id,
  109 + 'seom_id' => $seom_id,
  110 + 'website' => $item['main_url'] ?? '',
  111 + 'test_website' => $item['test_url'] ?? '',
  112 + 'is_del' => 0,
  113 + 'plan' => $item['plan'] ?? '',
  114 + 'project_cate' => 1,
  115 + 'pm_id' => $pm_id,
  116 + 'status' => $status, // 项目状态
  117 + 'wechat_group_id' => $item['wx_id']
  118 + ];
  119 + if (!$project) {
  120 + $new = new TicketProject();
  121 + $new->uuid = $uuid;
  122 + $new->version = 5;
  123 + $new->table_id = 0;
  124 + foreach ($fields as $k => $v) {
  125 + $new->$k = $v;
  126 + }
  127 + $new->save();
  128 + } else {
  129 + $changed = false;
  130 + foreach ($fields as $k => $v) {
  131 + if ($project->$k != $v) {
  132 + $project->$k = $v;
  133 + $changed = true;
  134 + }
  135 + }
  136 + if ($changed) {
  137 + $project->save();
105 } 138 }
106 } 139 }
107 - if ($changed) {  
108 - $project->save();  
109 - } 140 + echo now() . " | INFO | V5: {$item['postid']} {$item['company']} fetch ok \n";
110 } 141 }
  142 + $page++;
  143 + $postids = array_merge($postids, collect($items)->pluck('postid')->toArray());
111 } 144 }
112 - $postids = collect($items)->pluck('postid')->toArray(); 145 + }
  146 + if ($postids)
  147 + {
113 // 软删除 gl_ticket_projects 中不存在的项目 148 // 软删除 gl_ticket_projects 中不存在的项目
114 TicketProject::where('version', 5) 149 TicketProject::where('version', 5)
115 ->whereNotIn('post_id', $postids) 150 ->whereNotIn('post_id', $postids)
116 ->update(['is_del' => 1]); 151 ->update(['is_del' => 1]);
117 - echo date("Y-m-d H:i:s") . " V5: fetch completed, total " . count($items) . " items\n";  
118 } 152 }
119 } 153 }
120 154
@@ -142,26 +176,35 @@ class FetchTicketProjects extends Command @@ -142,26 +176,35 @@ class FetchTicketProjects extends Command
142 foreach ($items as $item) { 176 foreach ($items as $item) {
143 $uuid = md5("V6{$item->id}"); 177 $uuid = md5("V6{$item->id}");
144 $project = TicketProject::where('uuid', $uuid)->first(); 178 $project = TicketProject::where('uuid', $uuid)->first();
  179 + // 项目状态
  180 + if ($item->type == Project::TYPE_ONE)
  181 + $status = 1; // 建站中
  182 + elseif ($item->type == Project::TYPE_THREE)
  183 + $status = 2; // 建站完成
  184 + else
  185 + $status = 3; // 推广找售后服务经理
  186 +
145 // 售后服务经理 187 // 售后服务经理
146 $assm_id = collect([ 188 $assm_id = collect([
147 ManageHr::find($item->deploy_optimize->manager_mid)->manage_id ?? 0, 189 ManageHr::find($item->deploy_optimize->manager_mid)->manage_id ?? 0,
148 ManageHr::find($item->deploy_optimize->tech_leader)->manage_id ?? 0, 190 ManageHr::find($item->deploy_optimize->tech_leader)->manage_id ?? 0,
149 8, //张鸿飞 191 8, //张鸿飞
150 ])->first(fn($v) => $v !== null && $v !== 0, 0); 192 ])->first(fn($v) => $v !== null && $v !== 0, 0);
  193 +
151 // 优化师 194 // 优化师
152 - $optimist_mid = ManageHr::find($item->deploy_optimize->optimist_mid) ? ManageHr::find($item->deploy_optimize->optimist_mid)->manage_id : 0;  
153 - $seom_id = $optimist_mid ? $optimist_mid : $assm_id;  
154 - /**  
155 - * 第一负责人逻辑  
156 - * 建站类项目:找杨长远  
157 - * 推广类:找售后  
158 - */  
159 - if ($item->type == Project::TYPE_THREE) {  
160 - $engineer_id = Manage::where('name', '杨长远')->value('id') ?? 0; // 建站类项目找杨长远  
161 - }else {  
162 - // 其他找售后服务经理  
163 - $engineer_id = $assm_id;  
164 - } 195 + $seom_id = ManageHr::find($item->deploy_optimize->optimist_mid) ? ManageHr::find($item->deploy_optimize->optimist_mid)->manage_id : 0;
  196 +
  197 + // 项目经理
  198 + $pm_id = ManageHr::find($item->deploy_build->manager_mid)->manage_id ?? ManageHr::where('name', '李洁玉')->value('manage_id') ?? 0;
  199 +
  200 + // 第一负责人
  201 + if ($status == 1)
  202 + $engineer_id = $pm_id; // 建站中找项目经理
  203 + elseif ($status == 2)
  204 + $engineer_id = Manage::where('name', '杨长远')->value('id') ?? 0; // 建站完成找杨长远
  205 + else
  206 + $engineer_id = $assm_id; // 推广找售后服务经理
  207 +
165 $is_del = ( 208 $is_del = (
166 $item->extend_type == 5 209 $item->extend_type == 5
167 || $item->type == 8 210 || $item->type == 8
@@ -171,7 +214,7 @@ class FetchTicketProjects extends Command @@ -171,7 +214,7 @@ class FetchTicketProjects extends Command
171 214
172 $fields = [ 215 $fields = [
173 'company_name' => $item->company, 216 'company_name' => $item->company,
174 - 'title' => $item->title, 217 + 'title' => $item->title . " - V6",
175 'assm_id' => $assm_id, 218 'assm_id' => $assm_id,
176 'seom_id' => $seom_id, 219 'seom_id' => $seom_id,
177 'engineer_id' => $engineer_id, 220 'engineer_id' => $engineer_id,
@@ -181,10 +224,12 @@ class FetchTicketProjects extends Command @@ -181,10 +224,12 @@ class FetchTicketProjects extends Command
181 'version' => empty($item->version) ? 7 : $item->version, // 版本号 224 'version' => empty($item->version) ? 7 : $item->version, // 版本号
182 'plan' => $item->planMap()[$item->deploy_build->plan] ?? '', 225 'plan' => $item->planMap()[$item->deploy_build->plan] ?? '',
183 'project_cate' => 2, 226 'project_cate' => 2,
184 - 'wechat_group_id' => ProjectAssociation::where('project_id', $project->table_id) 227 + 'wechat_group_id' => ProjectAssociation::where('project_id', $item->id)
185 ->where('status', ProjectAssociation::STATUS_NORMAL) 228 ->where('status', ProjectAssociation::STATUS_NORMAL)
186 ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT) 229 ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT)
187 - ->value('friend_id') 230 + ->value('friend_id'),
  231 + 'pm_id' => $pm_id,
  232 + 'status' => $status, // 项目状态
188 ]; 233 ];
189 if (!$project) { 234 if (!$project) {
190 $project = new TicketProject(); 235 $project = new TicketProject();
@@ -8,10 +8,8 @@ use App\Http\Requests\Api\WorkOrder\TicketStoreRequest; @@ -8,10 +8,8 @@ use App\Http\Requests\Api\WorkOrder\TicketStoreRequest;
8 use App\Models\WorkOrder\TicketLog; 8 use App\Models\WorkOrder\TicketLog;
9 use App\Models\WorkOrder\TicketProject; 9 use App\Models\WorkOrder\TicketProject;
10 use App\Models\WorkOrder\Tickets; 10 use App\Models\WorkOrder\Tickets;
11 -use Darabonba\GatewaySpi\Models\InterceptorContext\response;  
12 use Illuminate\Http\Request; 11 use Illuminate\Http\Request;
13 use Illuminate\Support\Facades\DB; 12 use Illuminate\Support\Facades\DB;
14 -use Illuminate\Support\Facades\Http;  
15 13
16 class TicketController extends BaseController 14 class TicketController extends BaseController
17 { 15 {
@@ -29,8 +27,11 @@ class TicketController extends BaseController @@ -29,8 +27,11 @@ class TicketController extends BaseController
29 $size = (int)$request->input('size', 10); 27 $size = (int)$request->input('size', 10);
30 28
31 $tickets = Tickets::with([ 29 $tickets = Tickets::with([
32 - 'project:*',  
33 - 'logs.engineer:id,name', 30 + 'project.pm',
  31 + 'project.assm',
  32 + 'project.seom',
  33 + 'project.first_engineer',
  34 + 'logs.engineer',
34 ]) 35 ])
35 ->where('project_id', $project->id) 36 ->where('project_id', $project->id)
36 // ->where('submit_side', 2) 37 // ->where('submit_side', 2)
@@ -85,9 +86,7 @@ class TicketController extends BaseController @@ -85,9 +86,7 @@ class TicketController extends BaseController
85 $ticket->submit_side = 2; // 2 for B-side submission 86 $ticket->submit_side = 2; // 2 for B-side submission
86 $ticket->submit_username = $request->input('submit_username'); 87 $ticket->submit_username = $request->input('submit_username');
87 $ticket->save(); 88 $ticket->save();
88 - $log = new TicketLog();  
89 - $log->engineer_id = $project->engineer_id; // 默认第一负责人  
90 - $ticket->logs()->save($log); 89 + $ticket->saveEngineers([$project->engineer_id]);
91 $project->pushWechatGroupMsg("客户新增了工单(ID:{$ticket->id}),请及时处理!"); 90 $project->pushWechatGroupMsg("客户新增了工单(ID:{$ticket->id}),请及时处理!");
92 return $ticket; 91 return $ticket;
93 }); 92 });
@@ -143,10 +142,10 @@ class TicketController extends BaseController @@ -143,10 +142,10 @@ class TicketController extends BaseController
143 public function projectInfo($project_id) 142 public function projectInfo($project_id)
144 { 143 {
145 $project = TicketProject::with([ 144 $project = TicketProject::with([
146 - 'projectV6:id,company',  
147 - 'assm:id,name',  
148 - 'seom:id,name',  
149 - 'first_engineer:id,name', 145 + 'pm',
  146 + 'assm',
  147 + 'seom',
  148 + 'first_engineer',
150 ]) 149 ])
151 ->where('uuid', $project_id)->first(); 150 ->where('uuid', $project_id)->first();
152 if (!$project) return $this->response('未找到项目', 404); 151 if (!$project) return $this->response('未找到项目', 404);
@@ -8,7 +8,7 @@ use App\Http\Requests\Aside\WorkOrder\AsideTicketStoreRequest; @@ -8,7 +8,7 @@ use App\Http\Requests\Aside\WorkOrder\AsideTicketStoreRequest;
8 use App\Http\Requests\Aside\WorkOrder\AsideTicketListRequest; 8 use App\Http\Requests\Aside\WorkOrder\AsideTicketListRequest;
9 use App\Http\Requests\Aside\WorkOrder\AsideTicketUpdateRequest; 9 use App\Http\Requests\Aside\WorkOrder\AsideTicketUpdateRequest;
10 use App\Http\Requests\Aside\WorkOrder\TicketProjectListRequest; 10 use App\Http\Requests\Aside\WorkOrder\TicketProjectListRequest;
11 -use App\Models\Workchat\MessagePush; 11 +use App\Models\Manage\ManageHr;
12 use App\Models\WorkOrder\TicketLog; 12 use App\Models\WorkOrder\TicketLog;
13 use App\Models\WorkOrder\TicketProject; 13 use App\Models\WorkOrder\TicketProject;
14 use App\Models\WorkOrder\Tickets; 14 use App\Models\WorkOrder\Tickets;
@@ -26,8 +26,8 @@ class AsideTicketController extends BaseController @@ -26,8 +26,8 @@ class AsideTicketController extends BaseController
26 { 26 {
27 $validated = $request->validated(); 27 $validated = $request->validated();
28 $lists = Tickets::with([ 28 $lists = Tickets::with([
29 - 'logs.engineer:id,name',  
30 - 'project', 29 + 'logs.engineer',
  30 + 'project.pm',
31 ]) 31 ])
32 ->when(!empty($validated['engineer_id']), function ($query) use ($validated) { 32 ->when(!empty($validated['engineer_id']), function ($query) use ($validated) {
33 // 查 gl_tickets 表 submit_user_id 或 gl_ticket_logs 表 engineer_id 33 // 查 gl_tickets 表 submit_user_id 或 gl_ticket_logs 表 engineer_id
@@ -51,6 +51,10 @@ class AsideTicketController extends BaseController @@ -51,6 +51,10 @@ class AsideTicketController extends BaseController
51 $status = $request->input('status'); 51 $status = $request->input('status');
52 return $query->where('status', $status); 52 return $query->where('status', $status);
53 }) 53 })
  54 + ->when($request->input('star') !== null, function ($query) use ($request) {
  55 + $star = $request->input('star');
  56 + return $query->where('star', $star);
  57 + })
54 ->when($request->input('search'), function ($query) use ($request) { 58 ->when($request->input('search'), function ($query) use ($request) {
55 // search 查 gl_tickets.title 或 gl_ticket_projects.title 或 gl_ticket_projects.company_name 59 // search 查 gl_tickets.title 或 gl_ticket_projects.title 或 gl_ticket_projects.company_name
56 $search = $request->input('search'); 60 $search = $request->input('search');
@@ -92,7 +96,31 @@ class AsideTicketController extends BaseController @@ -92,7 +96,31 @@ class AsideTicketController extends BaseController
92 public function projectList(TicketProjectListRequest $request) 96 public function projectList(TicketProjectListRequest $request)
93 { 97 {
94 $validated = $request->validated(); 98 $validated = $request->validated();
  99 + $dept_id = ManageHr::where('manage_id', $this->manage['id'])
  100 + ->value('dept_id');
  101 +
95 $lists = TicketProject::where('is_del', 0) 102 $lists = TicketProject::where('is_del', 0)
  103 + ->when(($this->manage['role'] != 1 && $dept_id != 5), function ($query) use ($dept_id) {
  104 + /**
  105 + * 超管看所有项目 $this->manage['role']=1
  106 + * 全球搜: 技术部ID 1、售后部ID 2
  107 + * 超迹AI: AICC技术部 ID 4
  108 + * 域途:域途运营部 ID 17
  109 + */
  110 + if (in_array($dept_id, [1, 2])) {
  111 + // V5 V6
  112 + return $query->whereIn('project_cate', [1, 2]);
  113 + }elseif ($dept_id == 4) {
  114 + // 超迹AI
  115 + return $query->where('project_cate', 3);
  116 + }elseif ($dept_id == 17){
  117 + // 域途
  118 + return $query->where('project_cate', 4);
  119 + }else{
  120 + // 其他部门,不允许看数据
  121 + return $query->where('id', 0); // 返回空结果
  122 + }
  123 + })
96 ->when(!empty($validated['search']), function ($query) use ($validated) { 124 ->when(!empty($validated['search']), function ($query) use ($validated) {
97 // 查找项目名称或公司名称 125 // 查找项目名称或公司名称
98 $search = $validated['search']; 126 $search = $validated['search'];
@@ -141,13 +169,12 @@ class AsideTicketController extends BaseController @@ -141,13 +169,12 @@ class AsideTicketController extends BaseController
141 $ticket->submit_side = 1; // 1 for A-side submission 169 $ticket->submit_side = 1; // 1 for A-side submission
142 $ticket->submit_user_id = $this->manage['id']; 170 $ticket->submit_user_id = $this->manage['id'];
143 $ticket->submit_username = $this->manage['name']; 171 $ticket->submit_username = $this->manage['name'];
  172 + $ticket->star = $request->input('star', 3);
  173 + $ticket->plan_end_at = $request->input('plan_end_at', null);
144 $ticket->save(); 174 $ticket->save();
145 - // A 端提工单,都是针对客户提的需求等开发任务;比如翻译,修改页面等。。。  
146 - foreach ($request->input('engineer_ids', []) as $engineer_id) {  
147 - $log = new TicketLog();  
148 - $log->engineer_id = $engineer_id;  
149 - $ticket->logs()->save($log);  
150 - } 175 +
  176 + // 分配工单参与人
  177 + $ticket->saveEngineers($request->input('engineer_ids', []));
151 $project->pushWechatGroupMsg("创贸({$ticket->submit_username})新增了工单(ID:{$ticket->id}),请及时处理!"); 178 $project->pushWechatGroupMsg("创贸({$ticket->submit_username})新增了工单(ID:{$ticket->id}),请及时处理!");
152 return $ticket; 179 return $ticket;
153 }); 180 });
@@ -186,19 +213,11 @@ class AsideTicketController extends BaseController @@ -186,19 +213,11 @@ class AsideTicketController extends BaseController
186 // 开始修改 213 // 开始修改
187 $result = DB::transaction(function () use ($request, $ticket) { 214 $result = DB::transaction(function () use ($request, $ticket) {
188 if ($request->input('engineer_ids')) 215 if ($request->input('engineer_ids'))
189 - {  
190 - // 有邀请工程师协同处理  
191 - foreach ($request->input('engineer_ids') as $engineer_id)  
192 - {  
193 - try {  
194 - // 利用唯一索引去重  
195 - $new_log = new TicketLog();  
196 - $new_log->engineer_id = $engineer_id;  
197 - $ticket->logs()->save($new_log);  
198 - }catch (\Exception $exception){}  
199 - }  
200 - } 216 + $ticket->saveEngineers($request->input('engineer_ids'));
201 217
  218 + // 其他字段有提交数据才修改,比如star plan_end_at
  219 + $ticket->star = $request->input('star', $ticket->star);
  220 + $ticket->plan_end_at = $request->input('plan_end_at', $ticket->plan_end_at);
202 $ticket->reply = $request->input('reply', null); 221 $ticket->reply = $request->input('reply', null);
203 $ticket->status = $request->input('status', $ticket->status); 222 $ticket->status = $request->input('status', $ticket->status);
204 if ($ticket->status == Tickets::STATUS_COMPLETED) 223 if ($ticket->status == Tickets::STATUS_COMPLETED)
@@ -78,6 +78,7 @@ class AsideTicketLogController extends BaseController @@ -78,6 +78,7 @@ class AsideTicketLogController extends BaseController
78 // 是否有未完成的子任务 78 // 是否有未完成的子任务
79 $pending = $ticket->logs() 79 $pending = $ticket->logs()
80 ->where('status', '<', TicketLog::STATUS_COMPLETED) 80 ->where('status', '<', TicketLog::STATUS_COMPLETED)
  81 + ->where('is_engineer', 1)
81 ->count(); 82 ->count();
82 if ($pending) 83 if ($pending)
83 { 84 {
@@ -89,6 +90,7 @@ class AsideTicketLogController extends BaseController @@ -89,6 +90,7 @@ class AsideTicketLogController extends BaseController
89 $ticket->end_at = now(); 90 $ticket->end_at = now();
90 $project = $ticket->project; 91 $project = $ticket->project;
91 $project->pushWechatGroupMsg("工单(ID:{$ticket->id})已全部完成,请访问查看详情!"); 92 $project->pushWechatGroupMsg("工单(ID:{$ticket->id})已全部完成,请访问查看详情!");
  93 + $ticket->pushDing('finish');
92 } 94 }
93 $ticket->save(); 95 $ticket->save();
94 return $log; 96 return $log;
@@ -26,6 +26,7 @@ class AsideTicketListRequest extends FormRequest @@ -26,6 +26,7 @@ class AsideTicketListRequest extends FormRequest
26 return [ 26 return [
27 'project_id' => 'nullable|string', 27 'project_id' => 'nullable|string',
28 'status' => 'nullable|in:0,1,2,3|integer', 28 'status' => 'nullable|in:0,1,2,3|integer',
  29 + 'star' => 'nullable|in:1,2,3|integer',
29 'search' => 'nullable|string', // 搜索关键词 30 'search' => 'nullable|string', // 搜索关键词
30 'engineer_id' => 'nullable|integer', // 工程师ID 31 'engineer_id' => 'nullable|integer', // 工程师ID
31 'page' => 'nullable|integer', 32 'page' => 'nullable|integer',
@@ -29,6 +29,8 @@ class AsideTicketStoreRequest extends FormRequest @@ -29,6 +29,8 @@ class AsideTicketStoreRequest extends FormRequest
29 'content' => 'required|string', 29 'content' => 'required|string',
30 'files' => 'nullable|array', 30 'files' => 'nullable|array',
31 'engineer_ids' => 'array', 31 'engineer_ids' => 'array',
  32 + 'star' => 'nullable|in:1,2,3|integer',
  33 + 'plan_end_at' => 'nullable|date',
32 ]; 34 ];
33 } 35 }
34 } 36 }
@@ -27,6 +27,8 @@ class AsideTicketUpdateRequest extends FormRequest @@ -27,6 +27,8 @@ class AsideTicketUpdateRequest extends FormRequest
27 'status' => 'nullable|in:0,1,2,3|integer', 27 'status' => 'nullable|in:0,1,2,3|integer',
28 'reply' => 'nullable|string', 28 'reply' => 'nullable|string',
29 'engineer_ids' => 'nullable|array', 29 'engineer_ids' => 'nullable|array',
  30 + 'star' => 'nullable|in:1,2,3|integer',
  31 + 'plan_end_at' => 'nullable|date',
30 ]; 32 ];
31 } 33 }
32 } 34 }
  1 +<?php
  2 +
  3 +namespace App\Models\WorkOrder;
  4 +
  5 +use Illuminate\Database\Eloquent\Factories\HasFactory;
  6 +use Illuminate\Database\Eloquent\Model;
  7 +
  8 +class TicketDing extends Model
  9 +{
  10 + use HasFactory;
  11 +
  12 + protected $table = 'gl_ticket_dings';
  13 +}
@@ -4,6 +4,7 @@ namespace App\Models\WorkOrder; @@ -4,6 +4,7 @@ namespace App\Models\WorkOrder;
4 4
5 use App\Models\Base; 5 use App\Models\Base;
6 use App\Models\Manage\Manage; 6 use App\Models\Manage\Manage;
  7 +use App\Models\Manage\ManageHr;
7 use Illuminate\Database\Eloquent\Factories\HasFactory; 8 use Illuminate\Database\Eloquent\Factories\HasFactory;
8 9
9 class TicketLog extends Base 10 class TicketLog extends Base
@@ -19,8 +20,8 @@ class TicketLog extends Base @@ -19,8 +20,8 @@ class TicketLog extends Base
19 20
20 public function engineer() 21 public function engineer()
21 { 22 {
22 - return $this->belongsTo(Manage::class, 'engineer_id', 'id')  
23 - ->select(['id', 'name', 'mobile']); 23 + return $this->belongsTo(ManageHr::class, 'engineer_id', 'manage_id')
  24 + ->select(['manage_id', 'name', 'nickname']);
24 } 25 }
25 26
26 public function ticket() 27 public function ticket()
@@ -4,6 +4,7 @@ namespace App\Models\WorkOrder; @@ -4,6 +4,7 @@ namespace App\Models\WorkOrder;
4 4
5 use App\Models\Base; 5 use App\Models\Base;
6 use App\Models\Manage\Manage; 6 use App\Models\Manage\Manage;
  7 +use App\Models\Manage\ManageHr;
7 use App\Models\Project\Project; 8 use App\Models\Project\Project;
8 use App\Models\ProjectAssociation\ProjectAssociation; 9 use App\Models\ProjectAssociation\ProjectAssociation;
9 use App\Models\Workchat\MessagePush; 10 use App\Models\Workchat\MessagePush;
@@ -21,18 +22,24 @@ class TicketProject extends Base @@ -21,18 +22,24 @@ class TicketProject extends Base
21 ->where('version', 6); 22 ->where('version', 6);
22 } 23 }
23 24
  25 + // 项目经理
  26 + public function pm()
  27 + {
  28 + return $this->hasOne(ManageHr::class, 'manage_id', 'pm_id')->select(['manage_id', 'name', 'nickname']);
  29 + }
  30 +
24 //售后服务经理 31 //售后服务经理
25 public function assm() 32 public function assm()
26 { 33 {
27 - return $this->hasOne(Manage::class, 'id', 'assm_id')  
28 - ->select(['id', 'name']); 34 + return $this->hasOne(ManageHr::class, 'manage_id', 'assm_id')
  35 + ->select(['manage_id', 'name', 'nickname']);
29 } 36 }
30 37
31 // 优化师 38 // 优化师
32 public function seom() 39 public function seom()
33 { 40 {
34 - return $this->hasOne(Manage::class, 'id', 'seom_id')  
35 - ->select(['id', 'name']); 41 + return $this->hasOne(ManageHr::class, 'manage_id', 'seom_id')
  42 + ->select(['manage_id', 'name', 'nickname']);
36 } 43 }
37 44
38 /** 45 /**
@@ -40,8 +47,8 @@ class TicketProject extends Base @@ -40,8 +47,8 @@ class TicketProject extends Base
40 */ 47 */
41 public function first_engineer() 48 public function first_engineer()
42 { 49 {
43 - return $this->hasOne(Manage::class, 'id', 'engineer_id')  
44 - ->select(['id', 'name']); 50 + return $this->hasOne(ManageHr::class, 'manage_id', 'engineer_id')
  51 + ->select(['manage_id', 'name', 'nickname']);
45 } 52 }
46 53
47 /** 54 /**
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 namespace App\Models\WorkOrder; 3 namespace App\Models\WorkOrder;
4 4
5 use App\Models\Base; 5 use App\Models\Base;
  6 +use App\Models\Manage\ManageHr;
6 use Illuminate\Database\Eloquent\Factories\HasFactory; 7 use Illuminate\Database\Eloquent\Factories\HasFactory;
  8 +use Illuminate\Support\Facades\Log;
7 9
8 class Tickets extends Base 10 class Tickets extends Base
9 { 11 {
@@ -32,4 +34,90 @@ class Tickets extends Base @@ -32,4 +34,90 @@ class Tickets extends Base
32 { 34 {
33 return $this->belongsTo(TicketProject::class, 'project_id', 'id'); 35 return $this->belongsTo(TicketProject::class, 'project_id', 'id');
34 } 36 }
  37 +
  38 + /**
  39 + * 当前工单,保存参与的人员到 gl_ticket_logs 表
  40 + * 逻辑说明:
  41 + * 1. 如果当前项目是超迹,要把徐莹和第一负责人加进去,为参与人
  42 + * 2. 若是域途项目,把黄小玉和第一负责人加进去,为参与人
  43 + */
  44 + public function saveEngineers($engineer_ids = [])
  45 + {
  46 + $canyu = [
  47 + $this->project->engineer_id, // 第一负责人
  48 + ];
  49 +
  50 + if ($this->project->project_cate == 3)
  51 + $canyu[] = 20; // 徐莹
  52 + elseif ($this->project->project_cate == 4)
  53 + $canyu[] = 85; // 黄小玉
  54 +
  55 + $all_engineer_ids = array_unique(array_merge($canyu, $engineer_ids));
  56 +
  57 + foreach ($all_engineer_ids as $engineer_id)
  58 + {
  59 + try {
  60 + $log = $this->logs()->where('engineer_id', $engineer_id)->first();
  61 + if ($log && $log->is_engineer != in_array($engineer_id, $engineer_ids))
  62 + {
  63 + $log->is_engineer = in_array($engineer_id, $engineer_ids);
  64 + $log->save();
  65 + }else
  66 + {
  67 + // 利用唯一索引去重
  68 + $log = new TicketLog();
  69 + $log->engineer_id = $engineer_id;
  70 + $log->is_engineer = in_array($engineer_id, $engineer_ids);
  71 + $this->logs()->save($log);
  72 + }
  73 + }catch (\Exception $exception){
  74 + Log::error(" | ERRPR | Ticket saveEngineers {$exception->getMessage()} \n {$exception->getTraceAsString()}");
  75 + }
  76 + }
  77 +
  78 + // 删除没有参与当前工单的人员(若之前已有)
  79 + $this->logs()->whereNotIn('engineer_id', $all_engineer_ids)->delete();
  80 + }
  81 +
  82 + /**
  83 + * TODO 这个是一个补充功能
  84 + * 那些情况需要推送钉钉内部通知?
  85 + * 1. 客户提交了工单
  86 + * - 通知第一负责人 (gl_ticket_logs 表做了标记)
  87 + * 2. 客户补充了工单
  88 + * - 通知最近的聊天技术(gl_ticket_chats 表做了标记)
  89 + * 3. 技术完成了工单
  90 + * - 通知第一负责人 (暂无,所以这里做补充,如果以后要把上面的逻辑也加进来也可以,只是我为了偷懒,暂时只考虑完成工单请款)
  91 + */
  92 + public function pushDing($type = 'finish')
  93 + {
  94 + try {
  95 + $ding = new TicketDing();
  96 + $ding->msgKey = 'sampleLink';
  97 + $ding->table_name = 'gl_tickets';
  98 + $ding->table_id = $this->id;
  99 +
  100 + if ($type == 'finish')
  101 + {
  102 + // 所以技术完成了工单,通知第一负责人 和 工单的提交人
  103 + $ding->userIds = [$this->project->engineer_id];
  104 + if ($this->submit_side == 1) {
  105 + // A 端提的,还要通知提交人
  106 + $ding->userIds[] = $this->submit_user_id;
  107 + // 去重
  108 + $ding->userIds = array_unique($ding->userIds);
  109 + }
  110 + $ding->msgParam = json_encode([
  111 + 'text' => "工单(ID: {$this->id}),已经全部完成,请访问查看详情!",
  112 + 'title' => 'AI协同工单 - ' . $this->project->title,
  113 + 'picUrl' => 'https://hub.globalso.com/logocm.png',
  114 + 'messageUrl' => 'https://oa.quanqiusou.cn/afterorder?project_id=' . $this->project->uuid,
  115 + ], JSON_UNESCAPED_UNICODE);
  116 + $ding->save();
  117 + }
  118 + }catch (\Exception $exception){
  119 + Log::error(" | ERRPR | Ticket {$exception->getMessage()} \n {$exception->getTraceAsString()}");
  120 + }
  121 + }
  122 +
35 } 123 }
  1 +<?php
  2 +
  3 +use Illuminate\Database\Migrations\Migration;
  4 +use Illuminate\Database\Schema\Blueprint;
  5 +use Illuminate\Support\Facades\Schema;
  6 +
  7 +class CreateTicketDingsTable extends Migration
  8 +{
  9 + /**
  10 + * Run the migrations.
  11 + *
  12 + * @return void
  13 + */
  14 + public function up()
  15 + {
  16 + Schema::create('gl_ticket_dings', function (Blueprint $table) {
  17 + $table->id();
  18 + $table->json('userIds')->comment('接收人ID列表');
  19 + $table->string('msgKey')->default('sampleMarkdown')->comment('消息模板标识');
  20 + $table->json('msgParam')->comment('消息内容参数,JSON格式');
  21 + $table->smallInteger('status')->default(0)->index()->comment('发送状态:0-未发送,1-已发送,2-发送失败');
  22 + $table->string('errorMsg')->nullable()->comment('错误信息,发送失败时记录');
  23 + $table->string('table_name', 50)->nullable()->comment('关联表名称');
  24 + $table->string('table_id', 50)->nullable()->comment('关联表ID');
  25 + $table->timestamps();
  26 + });
  27 + }
  28 +
  29 + /**
  30 + * Reverse the migrations.
  31 + *
  32 + * @return void
  33 + */
  34 + public function down()
  35 + {
  36 + Schema::dropIfExists('gl_ticket_dings');
  37 + }
  38 +}