cqp 7 ماه پیش
والد
کامیت
634183b016

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

@@ -7,6 +7,19 @@ use Illuminate\Http\Request;
 
 class RDController extends BaseController
 {
+    public function rdCreate(Request $request)
+    {
+        $service = new RDService();
+        $user = $request->userData;
+        list($status,$data) = $service->rdCreate($request->all(),$user);
+
+        if($status){
+            return $this->json_return(200,'',$data);
+        }else{
+            return $this->json_return(201,$data);
+        }
+    }
+
     public function rdEdit(Request $request)
     {
         $service = new RDService();

+ 3 - 0
app/Service/EmployeeService.php

@@ -1368,6 +1368,9 @@ class EmployeeService extends Service
         $funcName = $menuItem ? $menuItem->title : "";
 
         $header_default = config("header." . $menu_id) ?? [];
+        $header_f = "extra_" . $menu_id;
+        $service = new TableHeadService();
+        if(method_exists($service,$header_f)) $service->$header_f($header_default);
         $user['e_header_default'] = $header_default;
 
         return [$func, $funcName];

+ 11 - 0
app/Service/RDService.php

@@ -11,6 +11,11 @@ use Illuminate\Support\Facades\DB;
 
 class RDService extends Service
 {
+    public function rdCreate($data, $user){
+        list($status, $msg) = (new RdGenerateService())->generate($data);
+        return [$status, $msg];
+    }
+
     public function rdEdit($data,$user){
         list($status,$msg) = $this->rdRule($data, $user, false);
         if(!$status) return [$status,$msg];
@@ -315,6 +320,12 @@ class RDService extends Service
 
     public function generateOrderNumber()
     {
+        $dayPrefix = date('Ymd', time()); // 例如 20251216
+        // 随机后缀 + uniqid 保证唯一
+        $orderNumber = 'RD' . $dayPrefix . mt_rand(1000, 9999) . substr(uniqid(), -3);
+
+        return $orderNumber;
+
         $yyyymm = date('Ym');
 
         // 数据库事务(防止并发)

+ 203 - 0
app/Service/RdGenerateService.php

@@ -0,0 +1,203 @@
+<?php
+
+namespace App\Service;
+
+use Carbon\Carbon;
+use Illuminate\Support\Facades\DB;
+
+class RdGenerateService extends Service
+{
+    public function generate(array $data)
+    {
+        if (empty($data['month'])) {
+            return [false, '请选择生成研发人员工时单年月'];
+        }
+
+        try {
+            DB::transaction(function () use ($data) {
+                $this->doGenerate($data['month']);
+            });
+        } catch (\Throwable $e) {
+            return [false, $e->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    protected function doGenerate(string $month)
+    {
+        $monthStart = Carbon::createFromFormat('Y-m', $month)->startOfMonth()->timestamp;
+        $monthEnd   = Carbon::createFromFormat('Y-m', $month)->endOfMonth()->timestamp;
+
+        // 日历
+        $calendar = DB::table('calendar')
+            ->where('time', $monthStart)
+            ->first();
+
+        if (!$calendar) {
+            throw new \Exception('当月日历未配置');
+        }
+
+        // 工作日
+        $workDays = DB::table('calendar_details')
+            ->where('calendar_id', $calendar->id)
+            ->where('is_work', 1)
+            ->orderBy('time')
+            ->pluck('time')
+            ->toArray();
+
+        if (empty($workDays)) {
+            throw new \Exception('当月无工作日');
+        }
+
+        // 启用项目
+        $items = DB::table('item')
+            ->where('is_use', 1)
+            ->where('start_time', '<=', $monthEnd)
+            ->where('end_time', '>=', $monthStart)
+            ->get();
+
+        // 删除当月所有项目的老数据
+        $itemIds = $items->pluck('id')->toArray();
+        if (!empty($itemIds)) {
+            $rds = DB::table('rd')
+                ->whereIn('item_id', $itemIds)
+                ->whereBetween('order_time', [$monthStart, $monthEnd])
+                ->pluck('id')
+                ->toArray();
+
+            if (!empty($rds)) {
+                DB::table('rd_details')->whereIn('rd_id', $rds)->delete();
+                DB::table('rd')->whereIn('id', $rds)->delete();
+            }
+        }
+
+        // 获取所有员工id
+        $employeeIds = DB::table('item_details')
+            ->whereIn('item_id', $itemIds)
+            ->where('type', 1)
+            ->pluck('data_id')
+            ->unique()
+            ->toArray();
+
+        // 按员工生成当月工时单
+        foreach ($employeeIds as $employeeId) {
+            $this->generateEmployeeMonth($employeeId, $items, $workDays, $calendar);
+        }
+    }
+
+    /**
+     * 按员工生成当月工时单,严格保证总工时匹配
+     */
+    protected function generateEmployeeMonth(int $employeeId, $items, array $workDays, $calendar)
+    {
+        $employeeMonth = DB::table('employee_details')
+            ->where('employee_id', $employeeId)
+            ->where('time', $calendar->time)
+            ->first();
+
+        if (!$employeeMonth || $employeeMonth->total_hours_2 <= 0) {
+            return;
+        }
+
+        $totalMinutes = (int)round($employeeMonth->total_hours_2 * 60); // 员工总分钟数
+        $dayMaxMinutes = 510; // 每天最大分钟数 (含午休)
+
+        // 员工参与的项目
+        $employeeItems = [];
+        foreach ($items as $item) {
+            $exists = DB::table('item_details')
+                ->where('item_id', $item->id)
+                ->where('type', 1)
+                ->where('data_id', $employeeId)
+                ->exists();
+            if ($exists) {
+                $employeeItems[] = $item;
+            }
+        }
+
+        if (empty($employeeItems)) return;
+
+        // 生成所有槽位:项目 × 工作日(有效周期内)
+        $slots = [];
+        foreach ($employeeItems as $item) {
+            foreach ($workDays as $day) {
+                if ($day >= $item->start_time && $day <= $item->end_time) {
+                    $slots[] = [
+                        'item_id' => $item->id,
+                        'day' => $day
+                    ];
+                }
+            }
+        }
+
+        if (empty($slots)) return;
+
+        // 均分总分钟数
+        $numSlots = count($slots);
+        $baseMinutes = floor($totalMinutes / $numSlots);
+        $remainder = $totalMinutes - $baseMinutes * $numSlots;
+
+        foreach ($slots as $i => $slot) {
+            $minutes = $baseMinutes;
+            if ($i === $numSlots - 1) {
+                // 最后 slot 补齐余数
+                $minutes += $remainder;
+            }
+
+            // 确保单日不超过最大分钟数
+            $minutes = min($minutes, $dayMaxMinutes - 30); // 扣掉午休
+
+            $this->createRd($slot['item_id'], $slot['day'], $minutes, $employeeId);
+        }
+    }
+
+    /**
+     * 创建单条研发工时单
+     */
+    protected function createRd(int $itemId, int $dayTime, int $minutes, int $employeeId)
+    {
+        $startHour = 8;
+        $startMin  = 0;
+        $maxMinutes = 510; // 每天最大分钟数 (含午休)
+
+        // 加午休 30 分钟
+        $workMinutes = min($minutes + 30, $maxMinutes);
+        $realMinutes = $workMinutes - 30; // 实际研发工时分钟数
+
+        // 随机结束时间 08:00~16:30
+        $endTime = Carbon::createFromTimestamp($dayTime)
+            ->setTime($startHour, $startMin)
+            ->addMinutes($workMinutes);
+
+        // 随机 crt_time 16:30 ~ 17:00
+        $crtTime = Carbon::createFromTimestamp($dayTime)
+            ->setTime(16, 30)
+            ->addSeconds(mt_rand(0, 30*60))
+            ->timestamp;
+
+        $dayPrefix = date('Ymd', $dayTime);
+        $orderNumber = 'RD' . $dayPrefix . mt_rand(1000, 9999) . substr(uniqid(), -3);
+
+        $rdId = DB::table('rd')->insertGetId([
+            'crt_time' => $crtTime,
+            'order_time' => $dayTime,
+            'item_id' => $itemId,
+            'start_time_hour' => $startHour,
+            'start_time_min' => $startMin,
+            'end_time_hour' => $endTime->hour,
+            'end_time_min' => $endTime->minute,
+            'total_hours' => $realMinutes,
+            'order_number' => $orderNumber,
+            'type' => 1
+        ]);
+
+        DB::table('rd_details')->insert([
+            'rd_id' => $rdId,
+            'data_id' => $employeeId,
+            'type' => 1,
+            'crt_time' => $crtTime,
+            'upd_time' => $crtTime,
+        ]);
+    }
+}

+ 8 - 0
app/Service/StatisticsService.php

@@ -6,6 +6,7 @@ use App\Model\Device;
 use App\Model\DeviceDetails;
 use App\Model\Employee;
 use App\Model\EmployeeDetails;
+use App\Model\EmployeeRole;
 use App\Model\Item;
 use App\Model\RdDetails;
 use Illuminate\Support\Facades\DB;
@@ -75,13 +76,20 @@ class StatisticsService extends Service
     }
 
     public function statisticsEmployeeFillData($data, $ergs){
+        $employee_id = EmployeeRole::where('del_time',0)
+            ->where('role_id', 87)
+            ->pluck('employee_id')
+            ->toArray();
+
         $employee_hours_map = EmployeeDetails::where('del_time', 0)
             ->whereIn('time', $ergs)
+            ->whereIn('employee_id',$employee_id)
             ->selectRaw('employee_id, SUM(total_hours) as total_hours')
             ->groupBy('employee_id')
             ->pluck('total_hours', 'employee_id')
             ->toArray();
         $employee = Employee::where('del_time',0)
+            ->whereIn('id',$employee_id)
             ->where('id','<>',Employee::SPECIAL_ADMIN)
             ->select('id','emp_name as name')
             ->get()->toArray();

+ 2 - 2
app/Service/TableHeadService.php

@@ -102,7 +102,7 @@ class TableHeadService extends Service
         return [true, ['column' => $header_default, 'common' => $header_common]];
     }
 
-    private function extra_73(&$data){
+    public function extra_73(&$data){
         $item_total = Item::where('del_time',0)->pluck('code','id')->toArray();
 
         foreach ($item_total as $key => $value){
@@ -113,7 +113,7 @@ class TableHeadService extends Service
         }
     }
 
-    private function extra_74(&$data){
+    public function extra_74(&$data){
         $item_total = Item::where('del_time',0)->pluck('code','id')->toArray();
 
         foreach ($item_total as $key => $value){

+ 2 - 0
routes/api.php

@@ -118,6 +118,8 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
     $route->any('rdDel', 'Api\RDController@rdDel');
     $route->any('rdDetail', 'Api\RDController@rdDetail');
 
+    $route->any('rdCreate', 'Api\RDController@rdCreate');
+
     //统计
     $route->any('statisticsEmployee', 'Api\StatisticsController@statisticsEmployee');
     $route->any('statisticsDevice', 'Api\StatisticsController@statisticsDevice');