cqp 1 mese fa
parent
commit
119fb2495a

+ 39 - 0
app/Http/Controllers/Api/ItemController.php

@@ -324,4 +324,43 @@ class ItemController extends BaseController
             return $this->json_return(201,$data);
         }
     }
+
+    public function itemNodeMissionDetailBoard(Request $request)
+    {
+        $service = new ItemService();
+        $user = $request->userData;
+        list($status,$data) = $service->itemNodeMissionDetailBoard($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function itemNodeMissionUpdateProgress(Request $request)
+    {
+        $service = new ItemService();
+        $user = $request->userData;
+        list($status,$data) = $service->itemNodeMissionUpdateProgress($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
+    public function itemNodeMissionUpdateProgressContent(Request $request)
+    {
+        $service = new ItemService();
+        $user = $request->userData;
+        list($status,$data) = $service->itemNodeMissionUpdateProgressContent($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
 }

+ 12 - 0
app/Model/ItemNodeMissionContent.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace App\Model;
+
+class ItemNodeMissionContent extends DataScopeBaseModel
+{
+    protected $guarded = [];
+    protected $table = "item_node_mission_content"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+}

+ 207 - 3
app/Service/ItemService.php

@@ -14,6 +14,7 @@ use App\Model\ItemNode;
 use App\Model\ItemNodeDetails;
 use App\Model\ItemNodeEmployee;
 use App\Model\ItemNodeMission;
+use App\Model\ItemNodeMissionContent;
 use App\Model\ItemNodeMissionDetails;
 use App\Model\ItemNodeMissionEmployee;
 use App\Model\SysOssTasks;
@@ -1379,6 +1380,8 @@ class ItemService extends Service
 
             $model = new ItemNodeMission();
             $model->item_id = $data['item_id'] ?? 0;
+            $model->item_node_id = $data['item_node_id'] ?? 0;
+            $model->parent_item_node_mission_id = $data['parent_item_node_mission_id'] ?? 0;
             $tableName = $model->getTable();
             $model->code = $this->generateBillNo([
                 'top_depart_id' => $user['top_depart_id'],
@@ -1570,12 +1573,200 @@ class ItemService extends Service
         $customer['mission_title'] = $node_tmp['title'] ?? '';
         $customer['mission_code'] = $node_tmp['code'] ?? '';
 
+        $item_node_map = $this->getItemNodeMap($customer['id']);
+        $customer['item_node_title'] = $item_node_map[$customer['id']];
+
         $details = $this->getNodeMissionDetail($data['id']);
         $customer = array_merge($customer, $details);
 
         return [true, $customer];
     }
 
+    public function itemNodeMissionUpdateProgressContent($data, $user){
+        if(empty($data['id'])) return [false, '任务ID不能为空'];
+        $customer = ItemNodeMission::where('del_time',0)
+            ->where('id',$data['id'])
+            ->first();
+        if(empty($customer)) return [false,'项目节点任务不存在或已被删除'];
+        $customer = $customer->toArray();
+        if(empty($data['data'])) return [false, '任务进展明细不能为空'];
+
+        $empDisplayMap = Employee::whereIn('id', array_unique(array_column($data['data'],'data_id')))
+            ->get(['id', 'code', 'title'])
+            ->mapWithKeys(function($item){
+                return [$item->id => "[{$item->code}]{$item->title}"];
+            })->toArray();
+
+        foreach ($data['data'] as $key => $value){
+            $line = $key + 1;
+            $t = "第" . $line . "行";
+            if(empty($value['data_id'])) return [false, '人员ID不能为空'];
+            $empId = $value['data_id'] ?? 0;
+            $empName = $empDisplayMap[$empId] ?? "ID:{$empId}";
+            if(empty($data['order_time'])) return [false, '提交日期不能为空'];
+            $order_time = $this->changeDateToDate($data['order_time']);
+            if($order_time > $customer['end_time'] || $order_time < $customer['start_time']) return [false, $t . "提交日期必须在任务周期内"];
+            $data['data'][$key]['order_time'] = $order_time;
+
+            // 校验数字有效性
+            $res = $this->checkNumber($value['start_time_hour'], 0, 'non-negative');
+            if(!$res['valid']) return [false, $t . "人员{$empName}开始点:" . $res['error']];
+            if($value['start_time_hour'] > 23) return [false, false, $t . "人员{$empName}开始点不合法"];
+            $res = $this->checkNumber($value['start_time_min'], 0, 'non-negative');
+            if(!$res['valid']) return [false, $t ."人员{$empName}开始分:" . $res['error']];
+            if($value['start_time_min'] > 60) return [false, false, $t . "人员{$empName}开始点不合法"];
+            $res = $this->checkNumber($value['end_time_hour'], 0, 'non-negative');
+            if(!$res['valid']) return [false, $t ."人员{$empName}结束点:" . $res['error']];
+            if($value['end_time_hour'] > 24) return [false, false, $t . "人员{$empName}结束点不合法"];
+            $res = $this->checkNumber($value['end_time_min'], 0, 'non-negative');
+            if(!$res['valid']) return [false, $t ."人员{$empName}结束分:" . $res['error']];
+            if($value['end_time_min'] > 60) return [false, false, $t . "人员{$empName}结束分不合法"];
+
+            $currentStart = $value['start_time_hour'] * 60 + $value['start_time_min'];
+            $currentEnd   = $value['end_time_hour'] * 60 + $value['end_time_min'];
+
+            if ($currentStart >= $currentEnd) {
+                return [false, $t . "人员{$empName}:开始时间必须早于结束时间"];
+            }
+
+            // --- 新增:总分钟数校验 ---
+            $calculatedTotal = $currentEnd - $currentStart;
+            if (!isset($value['total_work_min']) || intval($value['total_work_min']) !== $calculatedTotal) {
+                return [false, $t . "人员{$empName}:工时计算有误,应为 {$calculatedTotal} 分钟"];
+            }
+
+            // --- 3. 内部重叠校验(防止一次提交多行重复) ---
+            if (isset($internalOverlap[$empId])) {
+                foreach ($internalOverlap[$empId] as $period) {
+                    if ($currentStart < $period['e'] && $period['s'] < $currentEnd) {
+                        return [false, "人员{$empName}在本次提交的多行明细中时间段重叠"];
+                    }
+                }
+            }
+            $internalOverlap[$empId][] = ['s' => $currentStart, 'e' => $currentEnd];
+
+            if(!isset($value['content'])) return [false, '工作内容字段不存在'];
+
+            $data['data'][$key]['item_id'] = $customer['item_id'];
+            $data['data'][$key]['item_node_id'] = $customer['item_node_id'];
+            $data['data'][$key]['item_node_mission_id'] = $customer['id'];
+            $data['data'][$key]['top_depart_id'] = $user['top_depart_id'];
+            $data['data'][$key]['crt_id'] = $user['id'];
+        }
+
+        try {
+            DB::beginTransaction();
+            $time = time();
+
+            ItemNodeMissionContent::where('item_node_mission_id', $data['id'])->where('del_time',0)->update(['del_time' => $time]);
+
+            ItemNodeMissionContent::insert($data['data']);
+
+            DB::commit();
+        }catch (\Exception $exception){
+            DB::rollBack();
+            return [false,$exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    public function itemNodeMissionUpdateProgress($data, $user){
+        if(empty($data['id'])) return [false, 'ID不能为空'];
+        if(empty($data['progress'])) return [false, '任务进展不能为空'];
+        $res = $this->checkNumber($data['progress'],0,'positive');
+        if (! $res['valid']) return [false, "任务进展:" . $res['error']];
+        if($data['progress'] > 100) return [false, '任务进展不能超过100'];
+
+        ItemNodeMission::where('id', $data['id'])->update(['progress' => $data['progress']]);
+
+        return [true, ''];
+    }
+
+    public function itemNodeMissionDetailBoard($data, $user){
+        list($status, $msg) = $this->itemNodeMissionDetail($data, $user);
+        if(! $status) return [false, $msg];
+        $customer = $msg;
+
+        //任务进展信息
+        $customer['mission_progress'] = $this->itemMissionProgressBoard($data, $user);
+
+        //文件归档
+        $customer['file_list'] = $this->getMissionProgressFile($data, $user, $customer);
+
+        return [true, $customer];
+    }
+
+    public function itemMissionProgressBoard($data,$user){
+        $list = ItemNodeMissionContent::where('del_time',0)
+            ->where('item_node_mission_id', $data['id'])
+            ->select('*')
+            ->get()->toArray();
+
+        $emp = (new EmployeeService())->getEmployeeMap(array_unique(array_merge_recursive(array_column($list,'data_id'), array_column($list,'crt_id'))));
+        foreach ($list as $key => $value){
+            $list[$key]['order_time'] = $value['order_time'] ? date('Y-m-d',$value['order_time']) : '';
+            $list[$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
+            $list[$key]['crt_name'] = $emp[$value['crt_id']] ?? '';
+            $list[$key]['data_name'] = $emp[$value['data_id']] ?? '';
+        }
+
+        return $list;
+    }
+
+    public function getMissionProgressFile($data, $user, $item){
+        $file = ItemFile::where('del_time',0)
+            ->where('item_node_mission_id', $data['id'])
+            ->get()->toArray();
+
+        $employee_id = array_unique(array_merge_recursive(array_column($file,'crt_id'), array_column($item['custom_fields'],'crt_id')));
+        $map = (new EmployeeService())->getEmployeeMap($employee_id);
+
+        $return = [];
+        if(! empty($item['custom_fields'])){
+            foreach ($item['custom_fields'] as $value){
+                if($value['field_type'] == CustomFieldValue::type_two){
+                    $return[] = [
+                        'id' => $value['id'],
+                        'url' => $value['field_value'],
+                        'name' => $value['field_name'],
+                        'show_url' => $value['field_value_show'],
+                        'type_name' => '任务',
+                        'type_name_2' => CustomFieldValue::type[CustomFieldValue::type_two],
+                        'type' => 'custom_fields',
+                        'from' => ItemFile::type_two,
+                        'crt_name' => $map[$value['crt_id']],
+                        'crt_time' => date("Y-m-d", $value['crt_time']),
+                        'crt_id' => $value['crt_id'],
+                        'is_delivery' => $value['is_delivery'],
+                    ];
+                }
+            }
+        }
+
+        if(! empty($file)){
+            $fileUploadService = new FileUploadService();
+            foreach ($file as $value){
+                $return[] = [
+                    'id' => $value['id'],
+                    'url' => $value['url'],
+                    'name' => $value['name'],
+                    'show_url' => $fileUploadService->getFileShow($value['url']),
+                    'type_name' => ItemFile::from[$value['from']],
+                    'type_name_2' => ItemFile::type[$value['type']],
+                    'type' => 'item_file',
+                    'from' => $value['from'],
+                    'crt_name' => $map[$value['crt_id']],
+                    'crt_time' => date("Y-m-d", $value['crt_time']),
+                    'crt_id' => $value['crt_id'],
+                    'is_delivery' => $value['is_delivery'],
+                ];
+            }
+        }
+
+        return $return;
+    }
+
     public function itemNodeMissionCommon($data,$user, $field = []){
         if(empty($field)) $field = ItemNodeMission::$field;
 
@@ -1644,11 +1835,16 @@ class ItemService extends Service
 
     public function itemNodeMissionRule(&$data, $user, $is_add = true){
         $data['top_depart_id'] = $user['top_depart_id'];
+        if(empty($data['item_node_id']) && empty($data['parent_item_node_mission_id'])) return [false, '节点与父级任务不能同时为空'];
         if(empty($data['item_node_id'])) return [false, '项目节点ID不能为空'];
         $item = ItemNode::where('id', $data['item_node_id'])->where('del_time',0)->first();
         if(empty($item)) return [false, '项目节点不存在或已被删除'];
         $item = $item->toArray();
         $data['item_id'] = $item['item_id'];
+        if(! empty($data['parent_item_node_mission_id'])) {
+            $bool = ItemNodeMission::where('id', $data['parent_item_node_mission_id'])->where('del_time',0)->exists();
+            if(! $bool) return [false, '父任务不存在或已被删除'];
+        }
         if(empty($data['title'])) return [false, '任务名称不能为空'];
         if(! empty($data['start_time'])) $data['start_time'] = $this->changeDateToDate($data['start_time']);
         if(! empty($data['end_time'])) $data['end_time'] = $this->changeDateToDate($data['end_time'],true);
@@ -1657,7 +1853,6 @@ class ItemService extends Service
         $itemEndTime = $item['end_time'];
         if (!empty($data['start_time'])) {
             $inputStartTime = $data['start_time'];
-
             if ($itemStartTime > 0 && $inputStartTime < $itemStartTime) {
                 return [false, '任务开始时间不能早于项目节点开始时间:' . date('Y-m-d', $itemStartTime)];
             }
@@ -1668,7 +1863,6 @@ class ItemService extends Service
                 return [false, '任务结束时间不能晚于项目节点结束时间:' . date('Y-m-d', $itemEndTime)];
             }
         }
-
         if(! empty($data['man_list'])) {
             foreach ($data['man_list'] as $key => $value){
                 if(empty($value['type'])) return [false, '类型不能为空'];
@@ -1678,7 +1872,6 @@ class ItemService extends Service
             list($status, $msg) = $this->checkArrayRepeat($data['man_list'],'data_id','人员');
             if(! $status) return [false, $msg];
         }
-
         if(! empty($data['device_list'])) {
             foreach ($data['device_list'] as $key => $value){
                 if(empty($value['type'])) return [false, '类型不能为空'];
@@ -1714,6 +1907,7 @@ class ItemService extends Service
 
         $emp = (new EmployeeService())->getEmployeeMap(array_unique(array_merge_recursive(array_column($data['data'],'charge_id'), array_column($data['data'],'crt_id'))));
         $tag = (new TagService())->getTagMap(array_unique(array_merge_recursive(array_column($data['data'],'priority_id'),array_column($data['data'],'mission_id'))));
+        $item_node_map = $this->getItemNodeMap(array_column($data['data'],'id'));
         foreach ($data['data'] as $key => $value){
             $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : '';
             $data['data'][$key]['start_time'] = $value['start_time'] ? date('Y-m-d',$value['start_time']) : '';
@@ -1727,8 +1921,18 @@ class ItemService extends Service
             $node_tmp = $tag[$value['mission_id']] ?? [];
             $data['data'][$key]['mission_title'] = $node_tmp['title'] ?? '';
             $data['data'][$key]['mission_code'] = $node_tmp['code'] ?? '';
+            $data['data'][$key]['item_node_title'] = $item_node_map[$value['id']] ?? '';
         }
 
         return $data;
     }
+
+    public function getItemNodeMap($item_node_mission_id){
+        if(! is_array($item_node_mission_id)) $item_node_mission_id = [$item_node_mission_id];
+        return ItemNodeMission::from('item_node_mission as a')
+            ->leftJoin('item_node as b','b.id','a.item_node_id')
+            ->whereIn('a.id', $item_node_mission_id)
+            ->pluck('b.title','a.id')
+            ->toArray();
+    }
 }

+ 4 - 1
routes/api.php

@@ -114,11 +114,14 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
 
     //项目节点任务
     $route->any('itemNodeMissionListBySearch', 'Api\ItemController@itemNodeMissionListBySearch'); //不分页 带 项目 节点查询
+    $route->any('itemNodeMissionDetailBoard', 'Api\ItemController@itemNodeMissionDetailBoard');
     $route->any('itemNodeMissionEdit', 'Api\ItemController@itemNodeMissionEdit');
     $route->any('itemNodeMissionAdd', 'Api\ItemController@itemNodeMissionAdd');
     $route->any('itemNodeMissionDel', 'Api\ItemController@itemNodeMissionDel');
     $route->any('itemNodeMissionDetail', 'Api\ItemController@itemNodeMissionDetail');
-    $route->any('itemNodeMissionFinish', 'Api\ItemController@itemNodeMissionFinish');
+    $route->any('itemNodeMissionFinish', 'Api\ItemController@itemNodeMissionFinish'); // 完结
+    $route->any('itemNodeMissionUpdateProgress', 'Api\ItemController@itemNodeMissionUpdateProgress'); // 更新任务进展
+    $route->any('itemNodeMissionUpdateProgressContent', 'Api\ItemController@itemNodeMissionUpdateProgressContent'); // 更新任务进展人员日报
     $route->any('itemNodeMissionList', 'Api\ItemController@itemNodeMissionList');
 
     //标签管理