Browse Source

糊盒工资计算

unknown 1 day ago
parent
commit
2a2aedf0f1

+ 8 - 7
application/api/controller/GluChronographSheet.php

@@ -216,12 +216,12 @@ class GluChronographSheet extends Api
         $rows = db('糊盒报工机时')
             ->alias('a')
             ->field('LEFT(a.wgjs_rq, 10) as wgjs_rq, a.UniqId, 
-            wgjs_bh1,  wgjs_js1, rtrim(wgjs_yy1) as wgjs_yy1, 
-            wgjs_bh2,  wgjs_js2, rtrim(wgjs_yy2) as wgjs_yy2, 
-            wgjs_bh3,  wgjs_js3, rtrim(wgjs_yy3) as wgjs_yy3, 
-            wgjs_bh4,  wgjs_js4, rtrim(wgjs_yy4) as wgjs_yy4, 
-            wgjs_bh5,  wgjs_js5, rtrim(wgjs_yy5) as wgjs_yy5, 
-            wgjs_bh6,  wgjs_js6, rtrim(wgjs_yy6) as wgjs_yy6,
+            wgjs_bh1,  wgjs_js1, rtrim(wgjs_yy1) as wgjs_yy1, wgjs_je1,
+            wgjs_bh2,  wgjs_js2, rtrim(wgjs_yy2) as wgjs_yy2, wgjs_je2,
+            wgjs_bh3,  wgjs_js3, rtrim(wgjs_yy3) as wgjs_yy3, wgjs_je3,
+            wgjs_bh4,  wgjs_js4, rtrim(wgjs_yy4) as wgjs_yy4, wgjs_je4,
+            wgjs_bh5,  wgjs_js5, rtrim(wgjs_yy5) as wgjs_yy5, wgjs_je5,
+            wgjs_bh6,  wgjs_js6, rtrim(wgjs_yy6) as wgjs_yy6, wgjs_je6,
             rtrim(rs1.员工姓名) as name1,rtrim(rs2.员工姓名) as name2,rtrim(rs3.员工姓名)
             as name3,rtrim(rs4.员工姓名) as name4,rtrim(rs5.员工姓名) as name5,rtrim(rs6.员工姓名)
             as name6')
@@ -258,7 +258,8 @@ class GluChronographSheet extends Api
             'wgjs_rq',
             'wgjs_bh1', 'wgjs_bh2', 'wgjs_bh3', 'wgjs_bh4', 'wgjs_bh5', 'wgjs_bh6',
             'wgjs_js1', 'wgjs_js2', 'wgjs_js3', 'wgjs_js4', 'wgjs_js5', 'wgjs_js6',
-            'wgjs_yy1', 'wgjs_yy2', 'wgjs_yy3', 'wgjs_yy4', 'wgjs_yy5', 'wgjs_yy6'
+            'wgjs_yy1', 'wgjs_yy2', 'wgjs_yy3', 'wgjs_yy4', 'wgjs_yy5', 'wgjs_yy6',
+            'wgjs_je1', 'wgjs_je2', 'wgjs_je3', 'wgjs_je4', 'wgjs_je5', 'wgjs_je6'
         ];
         $data = [];
         foreach ($arr as $key => $value){

+ 90 - 74
application/api/controller/GluSalaryCalculation.php

@@ -3,6 +3,8 @@
 namespace app\api\controller;
 
 use app\common\controller\Api;
+use think\Db;
+use think\Queue;
 
 /**
  * 糊盒工资计算
@@ -12,96 +14,110 @@ class GluSalaryCalculation extends Api
     protected $noNeedLogin = ['*'];
     protected $noNeedRight = ['*'];
 
-
+    /**
+     * 提交糊盒工资计算任务到队列
+     */
     public function salaryCalculation()
     {
-        if(!$this->request->isGet()){
+        if (!$this->request->isGet()) {
             $this->error('请求错误');
         }
+
         $params = $this->request->param();
-        if (!isset($params['month']) || empty($params['month'])) {
+        if (empty($params['month']) || empty($params['startDay']) || empty($params['endDay'])) {
             $this->error('参数错误');
         }
-        db('糊盒工资汇总')->where('sczl_rq','like',$params['month'].'%')->delete();
-        $where = ['a.sczl_rq' => ['between', [$params['startDay'].' 00:00:00', $params['endDay'].' 23:59:59']]];
-        //糊盒计件产量
-        $filds = "a.sczl_gdbh as 工单编号,a.sczl_gxmc as 工序名称,a.sczl_cl as 产量,a.sczl_rq as 日期,
-        a.sczl_dedh as 定额代号,a.工价系数,a.保养工时,a.装版工时,a.异常工时,a.设备运行工时,a.role,a.sczl_jtbh,b.Gd_cpdh,b.Gd_cpmc,a.price";
-        $list = db('设备_糊盒报工资料')
-            ->alias('a')
-            ->join('工单_基本资料 b', 'a.sczl_gdbh = b.Gd_gdbh ','left')
-            ->field($filds)
-            ->where($where)
-            ->group('a.Uid')
-            ->select();
-        $data = [];
-        foreach ($list as $k=>$v){
-            $result = $this->salaryCalculationClass($v['role']);
-            $salary = $v['产量'] * $v['price'];
-            for ($i = 1; $i <= 30; $i++) {
-                $bh = $result['bh'.$i];
-                $name = $result['员工姓名'.$i];
-                $rate = $result['rate'.$i];
-                if (!empty($bh) && $bh !== '') {
-                    $wage = $salary * $rate;
-                    $data[] = [
-                        'sczl_gdbh' => $v['工单编号'],
-                        'sczl_gxmc' => $v['工序名称'],
-                        'sczl_rq' => $v['日期'],
-                        'sczl_cl' => $v['产量'],
-                        'sczl_dedh' => $v['定额代号'],
-                        '工价系数' => $v['工价系数'],
-                        '保养工时' => $v['保养工时'],
-                        '装版工时' => $v['装版工时'],
-                        '异常工时' => $v['异常工时'],
-                        '设备运行工时' => $v['设备运行工时'],
-                        'sczl_jtbh' => $v['sczl_jtbh'],
-                        'cpdh' => $v['Gd_cpdh'],
-                        'cpmc' => $v['Gd_cpmc'],
-                        'bh' => $bh,
-                        'rate' => $rate,
-                        'name' => $name,
-                        'salary' => $wage,
-                        'price' => $v['price'],
-                        'sys_id' => $params['sys_id'],
-                        'sys_rq' => date('Y-m-d H:i:s',time())
-                    ];
-                }
-            }
+
+        $month = trim($params['month']);
+        $runningTask = Db::name('queue_tasks')
+            ->where('task_type', 'glu_salary_calculation')
+            ->where('task_data', 'like', '%"month":"' . $month . '"%')
+            ->where('status', 'in', ['pending', 'processing'])
+            ->find();
+
+        if ($runningTask) {
+            $this->success('该月份的糊盒工资计算任务正在执行中,请稍后查看结果', null, [
+                'task_id' => $runningTask['id'],
+                'month' => $month,
+                'status' => $runningTask['status'],
+            ]);
         }
-        $sql = db('糊盒工资汇总')->fetchSql(true)->insertAll($data);
-        $res = db()->query($sql);
-        if ($res !== false){
-            $this->success('成功');
-        }else{
-            $this->error('失败');
+
+        $taskData = [
+            'month' => $month,
+            'startDay' => $params['startDay'],
+            'endDay' => $params['endDay'],
+            'sys_id' => $params['sys_id'] ?? '',
+            'request_time' => date('Y-m-d H:i:s'),
+        ];
+
+        $taskId = Db::name('queue_tasks')->insertGetId([
+            'task_type' => 'glu_salary_calculation',
+            'task_data' => json_encode($taskData, JSON_UNESCAPED_UNICODE),
+            'status' => 'pending',
+            'queue_name' => 'salary_calculation',
+            'create_time' => date('Y-m-d H:i:s'),
+        ]);
+
+        $taskData['task_id'] = $taskId;
+        $jobId = Queue::push('app\job\GluSalaryCalculationJob', $taskData, 'salary_calculation');
+
+        if ($jobId) {
+            Db::name('queue_tasks')
+                ->where('id', $taskId)
+                ->update([
+                    'job_id' => $jobId,
+                    'update_time' => date('Y-m-d H:i:s'),
+                ]);
+
+            $this->success('糊盒工资计算任务已提交到队列,请稍后查看结果', null, [
+                'task_id' => $taskId,
+                'job_id' => $jobId,
+                'month' => $month,
+                'queue_name' => 'salary_calculation',
+            ]);
         }
+
+        Db::name('queue_tasks')
+            ->where('id', $taskId)
+            ->update([
+                'status' => 'failed',
+                'error' => '任务提交到队列失败',
+                'update_time' => date('Y-m-d H:i:s'),
+            ]);
+        $this->error('糊盒工资计算任务提交失败');
     }
 
-    protected function salaryCalculationClass($role)
+    /**
+     * 查询糊盒工资计算任务状态
+     */
+    public function status()
     {
-        // 构建查询对象
-        $query = db('糊盒报工班组')->alias('a')->where('a.id', $role);
-
-        // 构建字段列表
-        $fieldParts = [];
+        if (!$this->request->isGet()) {
+            $this->error('请求错误');
+        }
 
-        // 添加 bh 和 rate 字段
-        for ($i = 1; $i <= 30; $i++) {
-            $fieldParts[] = "a.bh{$i}";
-            $fieldParts[] = "a.rate{$i}";
+        $params = $this->request->param();
+        if (empty($params['month'])) {
+            $this->error('参数错误');
         }
 
-        // 添加 JOIN 和员工姓名字段
-        for ($i = 1; $i <= 30; $i++) {
-            $table = 'b' . $i;
-            $fieldParts[] = "{$table}.员工姓名 as 员工姓名{$i}";
-            $query->join("人事_基本资料 {$table}", "a.bh{$i} = {$table}.员工编号", 'left');
+        $month = trim($params['month']);
+        $task = Db::name('queue_tasks')
+            ->where('task_type', 'glu_salary_calculation')
+            ->where('task_data', 'like', '%"month":"' . $month . '"%')
+            ->order('id desc')
+            ->find();
+
+        if (empty($task)) {
+            $this->error('未找到任务记录');
         }
 
-        // 设置字段
-        $query->field(implode(',', $fieldParts));
+        $task['task_data'] = json_decode($task['task_data'], true);
+        if (!empty($task['result'])) {
+            $task['result'] = json_decode($task['result'], true);
+        }
 
-        return $query->find();
+        $this->success('成功', $task);
     }
-}
+}

+ 92 - 0
application/job/GluSalaryCalculationJob.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace app\job;
+
+use app\service\GluSalaryCalculationService;
+use think\Db;
+use think\Log;
+
+/**
+ * 糊盒工资计算队列任务
+ */
+class GluSalaryCalculationJob
+{
+    /**
+     * @param \think\queue\Job $job
+     * @param array $data
+     */
+    public function fire($job, $data)
+    {
+        $taskId = $data['task_id'] ?? 0;
+
+        try {
+            Log::info('开始执行糊盒工资计算队列任务', $data);
+            $this->updateTaskStatus($taskId, 'processing', [
+                'start_time' => date('Y-m-d H:i:s'),
+                'retry_count' => $job->attempts(),
+            ]);
+
+            $service = new GluSalaryCalculationService();
+            $result = $service->execute($data);
+
+            if (!empty($result['success'])) {
+                $job->delete();
+                $this->updateTaskStatus($taskId, 'success', [
+                    'end_time' => date('Y-m-d H:i:s'),
+                    'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
+                ]);
+                Log::info('糊盒工资计算任务执行成功', $result);
+                return;
+            }
+
+            $message = $result['message'] ?? '糊盒工资计算失败';
+            $maxRetry = config('queue.queues.salary_calculation.retry') ?? 2;
+            if ($job->attempts() >= $maxRetry) {
+                $job->delete();
+                $this->updateTaskStatus($taskId, 'failed', [
+                    'end_time' => date('Y-m-d H:i:s'),
+                    'error' => $message,
+                    'retry_count' => $job->attempts(),
+                ]);
+                Log::error('糊盒工资计算任务失败', ['data' => $data, 'error' => $message]);
+                return;
+            }
+
+            $job->release($this->getRetryDelay($job->attempts()));
+            Log::warning('糊盒工资计算任务重试', ['attempts' => $job->attempts(), 'error' => $message]);
+        } catch (\Exception $e) {
+            Log::error('糊盒工资计算队列任务异常: ' . $e->getMessage());
+            $maxRetry = config('queue.queues.salary_calculation.retry') ?? 2;
+            if ($job->attempts() >= $maxRetry) {
+                $job->delete();
+                $this->updateTaskStatus($taskId, 'error', [
+                    'end_time' => date('Y-m-d H:i:s'),
+                    'error' => $e->getMessage(),
+                    'retry_count' => $job->attempts(),
+                ]);
+                return;
+            }
+            $job->release(60);
+        }
+    }
+
+    protected function updateTaskStatus($taskId, $status, array $data = [])
+    {
+        if (empty($taskId)) {
+            return;
+        }
+
+        Db::name('queue_tasks')
+            ->where('id', $taskId)
+            ->update(array_merge([
+                'status' => $status,
+                'update_time' => date('Y-m-d H:i:s'),
+            ], $data));
+    }
+
+    protected function getRetryDelay($attempts)
+    {
+        $delays = [10, 30, 60];
+        return $delays[min($attempts - 1, count($delays) - 1)] ?? 60;
+    }
+}

+ 564 - 0
application/service/GluSalaryCalculationService.php

@@ -0,0 +1,564 @@
+<?php
+
+namespace app\service;
+
+/**
+ * 糊盒工资计算服务
+ */
+class GluSalaryCalculationService
+{
+    /**
+     * 执行糊盒工资计算
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params)
+    {
+        try {
+            if (empty($params['month']) || empty($params['startDay']) || empty($params['endDay'])) {
+                return ['success' => false, 'message' => '参数错误'];
+            }
+
+            $where = ['a.sczl_rq' => ['between', [$params['startDay'] . ' 00:00:00', $params['endDay'] . ' 23:59:59']]];
+            $filds = "a.sczl_gdbh as 工单编号,a.sczl_gxmc as 工序名称,a.sczl_cl as 产量,a.sczl_rq as 日期,
+            a.sczl_dedh as 定额代号,d.日定额 as 日定额,a.工价系数,a.保养工时,a.装版工时,a.异常工时,a.设备运行工时,a.role,a.sczl_jtbh,b.Gd_cpdh,b.Gd_cpmc,a.price";
+            $list = db('设备_糊盒报工资料')
+                ->alias('a')
+                ->join('工单_基本资料 b', 'a.sczl_gdbh = b.Gd_gdbh ', 'left')
+                ->join('dic_lzde d', 'a.sczl_dedh = d.sys_bh', 'left')
+                ->field($filds)
+                ->where($where)
+                ->group('a.Uid')
+                ->select();
+
+            $pieceData = [];
+            foreach ($list as $v) {
+                $result = $this->salaryCalculationClass($v['role']);
+                if ($this->isManualMachine($v['sczl_jtbh'])) {
+                    $wageList = $this->calculateManualPieceWages($v, $result);
+                } else {
+                    $wageList = $this->calculateRegularPieceWages($v, $result);
+                }
+
+                foreach ($wageList as $wageItem) {
+                    $pieceData[] = $this->buildSalarySummaryRow([
+                        'sczl_gdbh' => $v['工单编号'],
+                        'sczl_gxmc' => $v['工序名称'],
+                        'sczl_rq' => $v['日期'],
+                        'sczl_cl' => $v['产量'],
+                        'sczl_dedh' => $v['定额代号'],
+                        '工价系数' => $v['工价系数'],
+                        '保养工时' => $v['保养工时'],
+                        '装版工时' => $v['装版工时'],
+                        '异常工时' => $v['异常工时'],
+                        '设备运行工时' => $v['设备运行工时'],
+                        'sczl_jtbh' => $v['sczl_jtbh'],
+                        'cpdh' => $v['Gd_cpdh'],
+                        'cpmc' => $v['Gd_cpmc'],
+                        'bh' => $wageItem['bh'],
+                        'rate' => $wageItem['rate'],
+                        'name' => $wageItem['name'],
+                        'salary' => $wageItem['wage'],
+                        'price' => $v['price'],
+                        'sys_id' => $params['sys_id'] ?? '',
+                    ]);
+                }
+            }
+
+            $teamres = $this->teamTimekeepCalculation($params['month']);
+            $timekeepres = $this->calculateTimekeepSalary($params['month']);
+            $timekeepData = $this->mergeTimekeepSalaryData($teamres, $timekeepres);
+
+            $timekeepInsert = [];
+            foreach ($timekeepData as $item) {
+                $remark = $item['remark'] ?? '';
+                if (!empty($item['type'])) {
+                    $remark = $remark !== '' ? $item['type'] . ',' . $remark : $item['type'];
+                }
+                $timekeepInsert[] = $this->buildSalarySummaryRow([
+                    'sczl_rq' => $item['sczl_rq'] . ' 00:00:00',
+                    'bh' => $item['bh'],
+                    'name' => $item['姓名'],
+                    'time_salary' => $item['salary'],
+                    'time_price' => $item['price'],
+                    'time_duration' => $item['duration'],
+                    'remark' => $remark,
+                    'sys_id' => $params['sys_id'] ?? '',
+                ]);
+            }
+
+            $insertData = array_merge($pieceData, $timekeepInsert);
+            if (empty($insertData)) {
+                return ['success' => false, 'message' => '无可保存的工资数据'];
+            }
+
+            db('糊盒工资汇总')->where('sczl_rq', 'like', $params['month'] . '%')->delete();
+            $sql = db('糊盒工资汇总')->fetchSql(true)->insertAll($insertData);
+            $res = db()->query($sql);
+            if ($res === false) {
+                return ['success' => false, 'message' => '工资数据保存失败'];
+            }
+
+            return [
+                'success' => true,
+                'message' => '成功',
+                'piece_count' => count($pieceData),
+                'timekeep_count' => count($timekeepInsert),
+                'total_count' => count($insertData),
+            ];
+        } catch (\Exception $e) {
+            return ['success' => false, 'message' => '糊盒工资计算失败: ' . $e->getMessage()];
+        }
+    }
+
+    protected function salaryCalculationClass($role)
+    {
+        // 构建查询对象
+        $query = db('糊盒报工班组')->alias('a')->where('a.id', $role);
+
+        // 构建字段列表
+        $fieldParts = [];
+
+        // 添加 bh 和 rate 字段
+        for ($i = 1; $i <= 30; $i++) {
+            $fieldParts[] = "a.bh{$i}";
+            $fieldParts[] = "a.rate{$i}";
+        }
+
+        // 添加 JOIN 和员工姓名字段
+        for ($i = 1; $i <= 30; $i++) {
+            $table = 'b' . $i;
+            $fieldParts[] = "{$table}.员工姓名 as 员工姓名{$i}";
+            $query->join("人事_基本资料 {$table}", "a.bh{$i} = {$table}.员工编号", 'left');
+        }
+
+        // 设置字段
+        $query->field(implode(',', $fieldParts));
+
+        return $query->find();
+    }
+
+    /**
+     * 判断是否手工机台
+     * @param string $jtbh
+     * @return bool
+     */
+    protected function isManualMachine($jtbh)
+    {
+        return stripos((string)$jtbh, 'SG') !== false;
+    }
+
+    /**
+     * 普通机台计件工资
+     * @param array $report
+     * @param array $classResult
+     * @return array
+     */
+    protected function calculateRegularPieceWages(array $report, array $classResult)
+    {
+        $wageList = [];
+        $salary = (float)$report['产量'] * (float)$report['price'];
+
+        for ($i = 1; $i <= 30; $i++) {
+            $bh = trim($classResult['bh' . $i] ?? '');
+            if ($bh === '' || $bh === '0000') {
+                continue;
+            }
+
+            $wageList[] = [
+                'bh' => $bh,
+                'name' => $classResult['员工姓名' . $i] ?? '',
+                'rate' => $classResult['rate' . $i] ?? '',
+                'wage' => floatval(number_format($salary * (float)$classResult['rate' . $i], 2, '.', '')),
+            ];
+        }
+
+        return $wageList;
+    }
+
+    /**
+     * 手工机台计件超产工资
+     * @param array $report
+     * @param array $classResult
+     * @return array
+     */
+    protected function calculateManualPieceWages(array $report, array $classResult)
+    {
+        $employees = [];
+        for ($i = 1; $i <= 30; $i++) {
+            $bh = trim($classResult['bh' . $i] ?? '');
+            if ($bh === '' || $bh === '0000') {
+                continue;
+            }
+            $employees[] = [
+                'bh' => $bh,
+                'name' => $classResult['员工姓名' . $i] ?? '',
+                'rate' => $classResult['rate' . $i] ?? '',
+            ];
+        }
+
+        if (empty($employees)) {
+            return [];
+        }
+
+        $hireDates = db('人事_基本资料')
+            ->whereIn('员工编号', array_column($employees, 'bh'))
+            ->column('聘用日期', '员工编号');
+
+        $totalOutput = (float)$report['产量'];
+        $dailyQuota = (float)$report['日定额'];
+        if ($dailyQuota <= 0) {
+            $dailyQuota = (float)$report['定额代号'];
+        }
+        $unitPrice = (float)$report['price'];
+        $reportDate = $report['日期'];
+        $totalCount = count($employees);
+
+        $countGt3 = 0;
+        $count8to15 = 0;
+        $countGt15 = 0;
+        $allPiece = true;
+
+        foreach ($employees as &$employee) {
+            $workDays = $this->getEmployeeTenureDays($employee['bh'], $reportDate, $hireDates);
+            $employee['work_days'] = $workDays;
+
+            if ($workDays > 3) {
+                $countGt3++;
+            }
+            if ($workDays >= 8 && $workDays <= 15) {
+                $count8to15++;
+            }
+            if ($workDays > 15) {
+                $countGt15++;
+            }
+            if ($workDays <= 7) {
+                $allPiece = false;
+            }
+        }
+        unset($employee);
+
+        $wageList = [];
+        if ($allPiece) {
+            $overPerPerson = $totalCount > 0
+                ? max(0, ($totalOutput - $dailyQuota * $totalCount) * $unitPrice / $totalCount)
+                : 0;
+            foreach ($employees as $employee) {
+                $wageList[] = [
+                    'bh' => $employee['bh'],
+                    'name' => $employee['name'],
+                    'rate' => $employee['rate'],
+                    'wage' => floatval(number_format($overPerPerson, 2, '.', '')),
+                ];
+            }
+            return $wageList;
+        }
+
+        $value1 = $countGt3 > 0
+            ? max(0, ($totalOutput - $dailyQuota * $countGt3) * $unitPrice)
+            : 0;
+        $halfShare = $countGt3 > 0 ? $value1 / $countGt3 / 2 : 0;
+        $value2 = max(0, $value1 - $halfShare * $count8to15);
+        $gt15Share = $countGt15 > 0 ? $value2 / $countGt15 : 0;
+
+        foreach ($employees as $employee) {
+            $workDays = $employee['work_days'];
+            if ($workDays <= 7) {
+                $wage = 0;
+            } elseif ($workDays >= 8 && $workDays <= 15) {
+                $wage = $halfShare;
+            } elseif ($workDays > 15) {
+                $wage = $gt15Share;
+            } else {
+                $wage = 0;
+            }
+
+            $wageList[] = [
+                'bh' => $employee['bh'],
+                'name' => $employee['name'],
+                'rate' => $employee['rate'],
+                'wage' => floatval(number_format($wage, 2, '.', '')),
+            ];
+        }
+
+        return $wageList;
+    }
+
+    /**
+     * 计算员工上班天数
+     * @param string $bh
+     * @param string $reportDate
+     * @param array $hireDates
+     * @return int
+     */
+    protected function getEmployeeTenureDays($bh, $reportDate, array $hireDates)
+    {
+        if (empty($hireDates[$bh])) {
+            return 0;
+        }
+
+        $hireTime = strtotime(date('Y-m-d', strtotime($hireDates[$bh])));
+        $reportTime = strtotime(date('Y-m-d', strtotime($reportDate)));
+        if ($hireTime === false || $reportTime === false || $reportTime < $hireTime) {
+            return 0;
+        }
+
+        return (int)floor(($reportTime - $hireTime) / 86400) + 1;
+    }
+
+
+
+    /**
+     * 班组计时工资计算
+     * @param string $month 月份
+     * @return array 班组计时工资数据
+     */
+    protected function teamTimekeepCalculation($month)
+    {
+        $bhFields = [];
+        for ($i = 1; $i <= 30; $i++) {
+            $bhFields[] = 'bh' . $i;
+        }
+
+        $list = db('糊盒班组计时')
+            ->field(array_merge(['sczl_rq', 'type', 'duration', 'price', 'remark'], $bhFields))
+            ->where('sczl_rq', 'like', $month . '%')
+            ->select();
+       
+        if (empty($list)) {
+            return [];
+        }
+
+        $employeeIds = [];
+        foreach ($list as $row) {
+            for ($i = 1; $i <= 30; $i++) {
+                $bh = isset($row['bh' . $i]) ? trim($row['bh' . $i]) : '';
+                if ($bh !== '' && $bh !== '0000') {
+                    $employeeIds[$bh] = true;
+                }
+            }
+        }
+
+        $employeeNames = [];
+        if (!empty($employeeIds)) {
+            $employees = db('人事_基本资料')
+                ->whereIn('员工编号', array_keys($employeeIds))
+                ->field('员工编号, rtrim(员工姓名) as 姓名')
+                ->select();
+            foreach ($employees as $employee) {
+                $employeeNames[$employee['员工编号']] = $employee['姓名'];
+            }
+        }
+
+        $data = [];
+        foreach ($list as $row) {
+            $employees = [];
+            for ($i = 1; $i <= 30; $i++) {
+                $bh = isset($row['bh' . $i]) ? trim($row['bh' . $i]) : '';
+                if ($bh !== '' && $bh !== '0000') {
+                    $employees[] = $bh;
+                }
+            }
+            if (empty($employees)) {
+                continue;
+            }
+
+            $employeeCount = count($employees);
+            $salaryPerEmployee = ((float)$row['duration'] * (float)$row['price']) / $employeeCount;
+            $ymd = date('Ymd', strtotime($row['sczl_rq']));
+
+            foreach ($employees as $bh) {
+                $name = $employeeNames[$bh] ?? '';
+                $key = $ymd . '-' . $bh . '-' . $name . '-' . $row['price'];
+                $durationPerEmployee = (float)$row['duration'] / $employeeCount;
+
+                if (isset($data[$key])) {
+                    $data[$key]['duration'] = floatval(number_format((float)$data[$key]['duration'] + $durationPerEmployee, 2, '.', ''));
+                    $data[$key]['salary'] = floatval(number_format($data[$key]['salary'] + $salaryPerEmployee, 2, '.', ''));
+                    if ($row['type'] !== '' && strpos($data[$key]['type'], $row['type']) === false) {
+                        $data[$key]['type'] = trim($data[$key]['type'] . ',' . $row['type'], ',');
+                    }
+                    if ($row['remark'] !== '' && strpos($data[$key]['remark'], $row['remark']) === false) {
+                        $data[$key]['remark'] = trim($data[$key]['remark'] . ',' . $row['remark'], ',');
+                    }
+                    continue;
+                }
+
+                $data[$key] = [
+                    'sczl_rq'  => date('Y-m-d', strtotime($row['sczl_rq'])),
+                    'type'     => $row['type'],
+                    'duration' => floatval(number_format($durationPerEmployee, 2, '.', '')),
+                    'price'    => $row['price'],
+                    'remark'   => $row['remark'],
+                    'bh'       => $bh,
+                    '姓名'     => $name,
+                    'salary'   => floatval(number_format($salaryPerEmployee, 2, '.', '')),
+                ];
+            }
+        }
+
+        return $data;
+    }
+
+
+    /**
+     * 计算糊盒计时工资
+     * @param string $month 月份
+     * @return array 糊盒计时工资数据
+     */
+    protected function calculateTimekeepSalary($month)
+    {
+        $list = db('糊盒报工机时')
+            ->field(['wgjs_rq', 'wgjs_bh1', 'wgjs_js1', 'wgjs_yy1', 'wgjs_je1',
+            'wgjs_bh2', 'wgjs_js2', 'wgjs_yy2', 'wgjs_je2',
+            'wgjs_bh3', 'wgjs_js3', 'wgjs_yy3', 'wgjs_je3',
+            'wgjs_bh4', 'wgjs_js4', 'wgjs_yy4', 'wgjs_je4',
+            'wgjs_bh5', 'wgjs_js5', 'wgjs_yy5', 'wgjs_je5',
+            'wgjs_bh6', 'wgjs_js6', 'wgjs_yy6', 'wgjs_je6'])
+            ->where('wgjs_rq', 'like', $month . '%')
+            ->select();
+
+        if (empty($list)) {
+            return [];
+        }
+
+        $employeeIds = [];
+        foreach ($list as $row) {
+            for ($i = 1; $i <= 6; $i++) {
+                $bh = isset($row['wgjs_bh' . $i]) ? trim($row['wgjs_bh' . $i]) : '';
+                if ($bh !== '') {
+                    $employeeIds[$bh] = true;
+                }
+            }
+        }
+
+        $employeeNames = [];
+        if (!empty($employeeIds)) {
+            $employees = db('人事_基本资料')
+                ->whereIn('员工编号', array_keys($employeeIds))
+                ->field('员工编号, rtrim(员工姓名) as 姓名')
+                ->select();
+            foreach ($employees as $employee) {
+                $employeeNames[$employee['员工编号']] = $employee['姓名'];
+            }
+        }
+
+        $data = [];
+        foreach ($list as $row) {
+            $ymd = date('Ymd', strtotime($row['wgjs_rq']));
+            $sczl_rq = date('Y-m-d', strtotime($row['wgjs_rq']));
+
+            for ($i = 1; $i <= 6; $i++) {
+                $bh = isset($row['wgjs_bh' . $i]) ? trim($row['wgjs_bh' . $i]) : '';
+                if ($bh === '') {
+                    continue;
+                }
+
+                $duration = isset($row['wgjs_js' . $i]) ? (float)$row['wgjs_js' . $i] : 0;
+                $type = isset($row['wgjs_yy' . $i]) ? trim($row['wgjs_yy' . $i]) : '';
+                $salary = isset($row['wgjs_je' . $i]) ? (float)$row['wgjs_je' . $i] : 0;
+                $price = '';
+                $name = $employeeNames[$bh] ?? '';
+                $key = $ymd . '-' . $bh . '-' . $name . '-' . $price;
+
+                if (isset($data[$key])) {
+                    $data[$key]['duration'] = floatval(number_format((float)$data[$key]['duration'] + $duration, 2, '.', ''));
+                    $data[$key]['salary'] = floatval(number_format((float)$data[$key]['salary'] + $salary, 2, '.', ''));
+                    if ($type !== '' && strpos($data[$key]['type'], $type) === false) {
+                        $data[$key]['type'] = trim($data[$key]['type'] . ',' . $type, ',');
+                    }
+                    continue;
+                }
+
+                $data[$key] = [
+                    'sczl_rq'  => $sczl_rq,
+                    'type'     => $type,
+                    'duration' => floatval(number_format($duration, 2, '.', '')),
+                    'price'    => '',
+                    'remark'   => '',
+                    'bh'       => $bh,
+                    '姓名'     => $name,
+                    'salary'   => floatval(number_format($salary, 2, '.', '')),
+                ];
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * 合并计时工资数据
+     * @param array $data1
+     * @param array $data2
+     * @return array
+     */
+    protected function mergeTimekeepSalaryData(array $data1, array $data2)
+    {
+        $data = $data1;
+        foreach ($data2 as $key => $item) {
+            if (!isset($data[$key])) {
+                $data[$key] = $item;
+                continue;
+            }
+
+            $data[$key]['duration'] = floatval(number_format((float)$data[$key]['duration'] + (float)$item['duration'], 2, '.', ''));
+            $data[$key]['salary'] = floatval(number_format((float)$data[$key]['salary'] + (float)$item['salary'], 2, '.', ''));
+            if (!empty($item['type']) && strpos($data[$key]['type'], $item['type']) === false) {
+                $data[$key]['type'] = trim($data[$key]['type'] . ',' . $item['type'], ',');
+            }
+            if (!empty($item['remark']) && strpos($data[$key]['remark'], $item['remark']) === false) {
+                $data[$key]['remark'] = trim($data[$key]['remark'] . ',' . $item['remark'], ',');
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * 构建工资汇总统一字段结构
+     * @param array $fields
+     * @return array
+     */
+    protected function buildSalarySummaryRow(array $fields = [])
+    {
+        $defaults = [
+            'sczl_gdbh' => '',
+            'sczl_gxmc' => '',
+            'sczl_rq' => '',
+            'sczl_dedh' => '',
+            'sczl_cl' => 0,
+            '工价系数' => '',
+            '保养工时' => '',
+            '装版工时' => '',
+            '异常工时' => '',
+            '设备运行工时' => '',
+            'sczl_jtbh' => '',
+            'cpdh' => '',
+            'cpmc' => '',
+            'bh' => '',
+            'rate' => '',
+            'name' => '',
+            'salary' => 0,
+            'time_salary' => 0,
+            'price' => 0,
+            'time_price' => 0,
+            'time_duration' => 0,
+            'remark' => '',
+            'sys_id' => '',
+            'sys_rq' => date('Y-m-d H:i:s'),
+        ];
+
+        $row = array_merge($defaults, $fields);
+
+        $decimalFields = ['sczl_cl', 'salary', 'time_salary', 'price', 'time_price', 'time_duration'];
+        foreach ($decimalFields as $field) {
+            if (!isset($row[$field]) || $row[$field] === '' || $row[$field] === null) {
+                $row[$field] = 0;
+            } else {
+                $row[$field] = is_numeric($row[$field]) ? (float)$row[$field] : 0;
+            }
+        }
+
+        return $row;
+    }
+}