cqp 6 days ago
parent
commit
aa3f38270a

+ 13 - 0
app/Http/Controllers/Api/BIController.php

@@ -19,4 +19,17 @@ class BIController extends BaseController
             return $this->json_return(201,$data);
         }
     }
+
+    public function cockpit(Request $request)
+    {
+        $service = new BIService();
+        $user = $request->userData;
+        list($status,$data) = $service->cockpit($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
 }

+ 13 - 0
app/Http/Controllers/Api/WorkFlowController.php

@@ -87,6 +87,19 @@ class WorkFlowController extends BaseController
         }
     }
 
+    public function getMyPendingApprovalsDetail(Request $request)
+    {
+        $service = new WorkFlowService();
+        $user = $request->userData;
+        list($status,$data) = $service->getMyPendingApprovalsDetail($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
     public function getMyHandledApprovals(Request $request)
     {
         $service = new WorkFlowService();

+ 157 - 0
app/Service/BIService.php

@@ -2,6 +2,8 @@
 
 namespace App\Service;
 
+use App\Model\DailyDwOrder;
+use App\Model\DailyDwOrderDetails;
 use App\Model\DailyPwOrder;
 use App\Model\DailyPwOrderDetails;
 use App\Model\ExpenseClaims;
@@ -376,4 +378,159 @@ class BIService extends Service
 
         return $return;
     }
+
+    public function cockpit($data, $user)
+    {
+        // 1. 声明时区对象
+        $utcZone   = new \DateTimeZone('UTC');
+        $localZone = new \DateTimeZone('Asia/Shanghai'); // 你的数据库/服务器本地时区(北京时间)
+
+        if (!empty($data['time'][0]) && !empty($data['time'][1])) {
+            // 【A. 满足 employeeSalarySummary 的 UTC 干净时间】
+            // 提取前端 ISO 串中的纯日期,强制转为 UTC 视角的开始和结束
+            $rawStartUtc = new \DateTime($data['time'][0], $utcZone);
+            $rawEndUtc   = new \DateTime($data['time'][1], $utcZone);
+
+            $startDateTimeUtc = new \DateTime($rawStartUtc->format('Y-m-d') . ' 00:00:00', $utcZone);
+            $endDateTimeUtc   = new \DateTime($rawEndUtc->format('Y-m-d') . ' 23:59:59', $utcZone);
+
+            // 【B. 满足 getManWork 的本地 00点和23点 时间戳】
+            $startTimestampLocal = (new \DateTime($rawStartUtc->format('Y-m-d') . ' 00:00:00', $localZone))->getTimestamp();
+            $endTimestampLocal   = (new \DateTime($rawEndUtc->format('Y-m-d') . ' 23:59:59', $localZone))->getTimestamp();
+
+        } else {
+            // 【没传参时的默认兜底逻辑】
+            // UTC 视角的当月起止
+            $startDateTimeUtc = new \DateTime('first day of this month 00:00:00', $utcZone);
+            $endDateTimeUtc   = new \DateTime('last day of this month 23:59:59', $utcZone);
+
+            // 本地视角的当月起止时间戳
+            $startTimestampLocal = (new \DateTime('first day of this month 00:00:00', $localZone))->getTimestamp();
+            $endTimestampLocal   = (new \DateTime('last day of this month 23:59:59', $localZone))->getTimestamp();
+        }
+
+        $data['start_time'] = $startTimestampLocal;
+        $data['end_time']   = $endTimestampLocal;
+
+        $array = $this->getManWork($data, $user);
+        // 当月设备工时信息
+        $array2 = $this->getDeviceWork($data, $user);
+        $array = array_merge_recursive($array, $array2);
+        $array3 = $this->getDeviceOldWork($data, $user);
+        $array = array_merge_recursive($array, $array3);
+        $array3 = $this->getFeeOrder($data, $user);
+        $array = array_merge_recursive($array, $array3);
+
+        $passTime = [
+            $startDateTimeUtc->format('Y-m-d'),
+            $endDateTimeUtc->format('Y-m-d')
+        ];
+
+        list($status, $return) = (new StatisticService())->employeeSalarySummary(['time' => $passTime], $user);
+        if(! $status) return [false, $return];
+        $total = array_sum(array_column($return,'money'));
+        $array['rd_total_money'] = $total;
+
+        return [true, $array];
+    }
+
+    private function getManWork($data, $user){
+        $model = DailyPwOrder::Clear($user, $data);
+        $id = $model->where('del_time', 0)
+            ->where('order_time', '>=', $data['start_time'])
+            ->where('order_time', '<=', $data['end_time'])
+            ->pluck('id')
+            ->toArray();
+
+        $details = DailyPwOrderDetails::where('del_time', 0)
+            ->whereIn('main_id', $id) // 💡 避坑提示:原代码如果是数组 $id,这里建议用 whereIn
+            ->select('employee_id', 'total_work_min')
+            ->get()->toArray();
+        // 1. 计算当月总工时(将二维数组中所有 'total_work_min' 字段求和)
+        $totalWorkMin = array_sum(array_column($details, 'total_work_min'));
+
+        // 2. 如果你需要把分钟数转换为“小时”,可以除以 60(保留两位小数,根据业务需要决定是否转换)
+        $totalWorkHours = round($totalWorkMin / 60, 2);
+
+        // 3. 计算参与人员总数(先提取所有员工ID,再通过 array_unique 去重,最后 count 计算数量)
+        $employeeIds = array_column($details, 'employee_id');
+        $uniqueEmployeeIds = array_unique($employeeIds);
+        $totalEmployees = count($uniqueEmployeeIds);
+
+
+        return [
+            'man_total_work_hours' => $totalWorkHours, // 当月总工时
+            'man_total_employees'  => $totalEmployees,  // 参与人员总数
+        ];
+    }
+
+    private function getDeviceWork($data, $user){
+        $model = DailyDwOrder::Clear($user, $data);
+        $id = $model->where('del_time', 0)
+            ->where('order_time', '>=', $data['start_time'])
+            ->where('order_time', '<=', $data['end_time'])
+            ->pluck('id')
+            ->toArray();
+
+        $details = DailyDwOrderDetails::where('del_time', 0)
+            ->whereIn('main_id', $id) // 💡 避坑提示:原代码如果是数组 $id,这里建议用 whereIn
+            ->select('device_id', 'total_work_min')
+            ->get()->toArray();
+        // 1. 计算当月总工时(将二维数组中所有 'total_work_min' 字段求和)
+        $totalWorkMin = array_sum(array_column($details, 'total_work_min'));
+
+        // 2. 如果你需要把分钟数转换为“小时”,可以除以 60(保留两位小数,根据业务需要决定是否转换)
+        $totalWorkHours = round($totalWorkMin / 60, 2);
+
+        $employeeIds = array_column($details, 'device_id');
+        $uniqueEmployeeIds = array_unique($employeeIds);
+        $totalEmployees = count($uniqueEmployeeIds);
+
+        return [
+            'device_total_work_hours' => $totalWorkHours, // 当月总工时
+            'device_total_num'  => $totalEmployees,  // 参与人员总数
+        ];
+    }
+
+    private function getDeviceOldWork($data, $user){
+        $model = MonthlyDdOrder::Clear($user, $data);
+        $id = $model->where('del_time', 0)
+            ->where('month', '>=', $data['start_time'])
+            ->where('month', '<=', $data['end_time'])
+            ->pluck('id')
+            ->toArray();
+
+        $details = MonthlyDdOrderDetails::where('del_time', 0)
+            ->whereIn('main_id', $id)
+            ->select('device_id', 'depreciation_amount')
+            ->get()->toArray();
+        $totalWorkMin = array_sum(array_column($details, 'depreciation_amount'));
+
+        return [
+            'device_total_money' => $totalWorkMin,
+        ];
+    }
+
+    private function getFeeOrder($data, $user){
+        $model = ExpenseClaims::Clear($user, $data);
+        $id = $model->where('del_time', 0)
+            ->where('month', '>=', $data['start_time'])
+            ->where('month', '<=', $data['end_time'])
+            ->pluck('id')
+            ->toArray();
+
+        $details = ExpenseClaimsDetails::where('del_time', 0)
+            ->whereIn('expense_claims_id', $id)
+            ->select('item_id', 'amount')
+            ->get()->toArray();
+        $totalWorkMin = array_sum(array_column($details, 'amount'));
+
+        $employeeIds = array_column($details, 'item_id');
+        $uniqueEmployeeIds = array_unique($employeeIds);
+        $totalEmployees = count($uniqueEmployeeIds);
+        return [
+            'fee_total_money' => $totalWorkMin,
+            'fee_total_num' => $totalEmployees,
+        ];
+    }
 }

+ 63 - 0
app/Service/StatisticService.php

@@ -1223,4 +1223,67 @@ class StatisticService extends StatisticCommonService
 
         return $data;
     }
+
+    /**
+     * 获取人员维度的研发工资及工时汇总报表
+     * * @param array $data 包含时间范围或年份的请求数据
+     * @param object $user 当前用户上下文
+     * @return array
+     */
+    public function employeeSalarySummary($data, $user)
+    {
+        // 1. 复用时间解析和校验规则
+        list($status, $month_start, $month_end) = $this->commonRule($data);
+        if (!$status) return [false, $month_start];
+
+        // 2. 复用原始数据拉取:项目人员工时、人员全额原始工资
+        $month_employee_list = $this->getItemEmployeeMonthWorkList($user, $data, $month_start, $month_end);
+        $salary_map = $this->getEmployeeSalary($user, $data, $month_start, $month_end);
+
+        // 3. 计算每个员工的月总工时(作为分母)
+        $keys = ["employee_id", "order_month"];
+        $employee_monthly_total_min = $this->calculateSum($month_employee_list, $keys, "total_work");
+
+        // 4. 调用核心分摊算法(拿到每一项明细的 allocated_salary)
+        list($item_month_list, ) = $this->calculateRatioForMonth(
+            $month_employee_list,
+            $employee_monthly_total_min,
+            $salary_map,
+            ["employee_id", "order_month"],
+            ["order_month", "item_id", "employee_id"]
+        );
+
+        // 5. 将分摊数据转化为集合,纯粹根据【员工ID + 月份】进行分组汇总
+        $collect = collect($item_month_list);
+
+        $employee_ids = $collect->pluck('employee_id')->unique()->values()->all();
+
+        // 6. 仅拉取人员档案名称,不再拉取项目档案(省去不必要的查询,提升性能)
+        $employeeModel = Employee::TopClear($user, $data);
+        $employee_title_map = $employeeModel->wherein('id', $employee_ids)->pluck("title", "id")->toArray();
+
+        // 7. 开始聚合
+        $result = $collect->groupBy(function ($item) {
+            // 根据 员工ID_月份 分组,支持跨月查询时的正确归类
+            return $item['employee_id'] . '_' . $item['month'];
+        })->map(function ($group) use ($employee_title_map) {
+            $first = $group->first();
+
+            // 汇总这个人当月在所有项目里的研发工资(分),然后除以 100 变成元
+            $total_allocated_salary = round($group->sum('allocated_salary') / 100, 2);
+
+            // 汇总这个人当月的研发总工时(分钟转小时)
+            $total_work_hours = round($group->sum('work_minutes') / 60, 2);
+
+            return [
+                'month'          => $first['month'],
+                'employee_id'    => $first['employee_id'],
+                'employee_title' => $employee_title_map[$first['employee_id']] ?? "未知人员({$first['employee_id']})",
+//                '研发总工时(小时)' => $total_work_hours,
+                'money'    => $total_allocated_salary // 这里就是您要的纯人员维度的研发工资总额
+            ];
+        })->values()->all();
+
+        return [true, $result];
+    }
 }

+ 34 - 0
app/Service/WorkFlowService.php

@@ -412,6 +412,40 @@ class WorkFlowService extends Service
         return [true, $pageData];
     }
 
+    public function getMyPendingApprovalsDetail($data, $user)
+    {
+        if(empty($data['instance_id'])) return [false, 'instanceId不能为空'];
+        if(empty($data['document_id'])) return [false, 'ID不能为空'];
+        if(empty($data['document_type'])) return [false, '类型不能为空'];
+
+        $instances = WorkFlowInstances::where('id', $data['instance_id'])->first();
+        if(! empty($instances)){
+            $instances->crt_name = Employee::where('id', $instances->crt_id)->value('title');
+            $instances->crt_time_show = date('Y-m-d H:i:s', $instances->crt_time->timestamp);
+        }
+        $return['instance'] = $instances ? $instances->toArray() : [];
+
+        //获取草稿
+        $draft = Draft::where('del_time', 0)
+            ->where('document_type', $data['document_type'])
+            ->where('document_id', $data['document_id'])
+            ->latest()
+            ->first();
+        $return['after'] = $draft->content ?? [];
+
+        $config = [
+            'item' => "itemDetail",
+            'item_node' => "itemNodeDetail",
+            'item_node_mission' => "itemNodeMissionDetail",
+        ];
+        $func = $config[$data['document_type']];
+        list($status, $msg) = (new ItemService())->$func(['id' => $data['document_id']], $user);
+        if(! $status) return [false, $msg];
+        $return['before'] = $msg;
+
+        return [true, $return];
+    }
+
     public function approval($data, $user)
     {
         DB::beginTransaction(); // 开启最外层事务

+ 4 - 0
routes/api.php

@@ -150,6 +150,8 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
 
     //待我审核
     $route->any('getMyPendingApprovals', 'Api\WorkFlowController@getMyPendingApprovals');
+    //待我审核时查看详情
+    $route->any('getMyPendingApprovalsDetail', 'Api\WorkFlowController@getMyPendingApprovalsDetail');
     //已完成
     $route->any('getMyHandledApprovals', 'Api\WorkFlowController@getMyHandledApprovals');
     //审核接口
@@ -286,5 +288,7 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
 
     //首页BI数据
     $route->any('homePageData', 'Api\BIController@homePageData');
+    //驾驶舱
+    $route->any('cockpit', 'Api\BIController@cockpit');
 });