unknown hace 1 mes
padre
commit
879a7fc997
Se han modificado 1 ficheros con 158 adiciones y 99 borrados
  1. 158 99
      application/service/UnifiedCostCalculationService.php

+ 158 - 99
application/service/UnifiedCostCalculationService.php

@@ -93,10 +93,10 @@ class UnifiedCostCalculationService
      */
     public function calculateAndSaveAll(array $param): array
     {
-        Log::info("开始成本计算,参数: " . json_encode($param));
-
         Db::startTrans();
         try {
+            Log::info("开始成本计算", ['param' => $param, 'timestamp' => date('Y-m-d H:i:s')]);
+
             if (!isset($param['month'])) {
                 throw new Exception("缺少必要参数: month");
             }
@@ -104,26 +104,23 @@ class UnifiedCostCalculationService
             $month = $param['month'];
             $sysId = $param['sys_id'] ?? uniqid();
 
-            Log::info("开始清空旧数据");
+            // 重置数据数组,确保是空数组
+            $this->monthlyCostDetails = [];
+            $this->allocationFactors = [];
+
+            // 1. 清空旧数据
             $this->clearOldData($month);
 
-            Log::info("开始计算直接人工");
+            // 2. 执行五项计算
             $this->calculateDirectLabor($param);
-            Log::info("直接人工计算完成,记录数: " . count($this->monthlyCostDetails));
+            Log::info("直接人工计算完成", ['记录数' => is_countable($this->monthlyCostDetails) ? count($this->monthlyCostDetails) : 0]);
 
-            Log::info("开始计算直接水电");
             $this->calculateDirectUtilities($param);
-
-            Log::info("开始计算间接材料");
             $this->calculateIndirectMaterials($month);
-
-            Log::info("开始计算间接人工");
             $this->calculateIndirectLabor($month);
-
-            Log::info("开始计算分摊水电");
             $this->calculateApportionedUtilities($param);
 
-            Log::info("开始保存数据");
+            // 3. 统一插入数据
             $this->saveAllData($month, $sysId);
 
             Db::commit();
@@ -132,37 +129,48 @@ class UnifiedCostCalculationService
 
             return $this->buildSuccessResponse($month);
 
-        } catch (\Throwable $t) {  // 使用 Throwable 而不是 Exception
+        } catch (\Throwable $t) {
             Db::rollback();
 
-            // 记录详细的错误信息
-            $errorInfo = [
-                'message' => $t->getMessage(),
-                'code' => $t->getCode(),
-                'file' => $t->getFile(),
-                'line' => $t->getLine(),
-                'trace' => $t->getTraceAsString(),
-                'param' => $param
-            ];
-
-            Log::error("统一成本核算失败: " . json_encode($errorInfo, JSON_UNESCAPED_UNICODE));
+            // 直接记录错误,不通过 logError 方法
+            try {
+                error_log("成本核算失败: " . $t->getMessage() . " at " . $t->getFile() . ":" . $t->getLine());
+                error_log("堆栈跟踪: " . $t->getTraceAsString());
+
+                // 尝试记录到系统日志
+                if (class_exists('think\Log')) {
+                    Log::error("成本核算失败(直接记录)", [
+                        'message' => $t->getMessage(),
+                        'file' => $t->getFile(),
+                        'line' => $t->getLine()
+                    ]);
+                }
+            } catch (\Throwable $logError) {
+                // 忽略日志记录错误
+            }
 
             return [
                 'success' => false,
                 'message' => '成本核算失败: ' . $t->getMessage(),
                 'error' => $t->getMessage(),
-                'error_details' => $errorInfo
+                'file' => $t->getFile(),
+                'line' => $t->getLine()
             ];
         }
     }
 
+
     /**
      * 清空旧数据
      */
     protected function clearOldData(string $month): void
     {
+        // 确保数据数组是有效的数组
         $this->monthlyCostDetails = [];
         $this->allocationFactors = [];
+
+        // 记录清空操作
+        Log::info("清空旧数据", ['month' => $month]);
     }
 
     /**
@@ -1317,69 +1325,66 @@ class UnifiedCostCalculationService
      */
     protected function validateDataStructure(): void
     {
-        if (empty($this->monthlyCostDetails)) {
-            Log::warning("月度成本明细数据为空");
-            return;
-        }
+        try {
+            if (!is_array($this->monthlyCostDetails)) {
+                Log::error("monthlyCostDetails 不是数组: " . gettype($this->monthlyCostDetails));
+                $this->monthlyCostDetails = [];
+                return;
+            }
 
-        $tableName = '成本v23_月度成本明细';
+            if (empty($this->monthlyCostDetails)) {
+                Log::warning("月度成本明细数据为空");
+                return;
+            }
+
+            $tableName = '成本v23_月度成本明细';
 
-        try {
-            // 获取数据库表结构
             $columns = Db::query("DESCRIBE `{$tableName}`");
-            $columnNames = array_column($columns, 'Field');
+            if (empty($columns)) {
+                Log::error("无法获取表结构: {$tableName}");
+                return;
+            }
 
+            $columnNames = array_column($columns, 'Field');
             Log::info("表{$tableName}结构字段数: " . count($columnNames));
-            Log::debug("表字段列表: " . implode(', ', $columnNames));
 
-            // 检查并修正每行数据
+            // 验证并修复每条记录
             foreach ($this->monthlyCostDetails as $index => &$row) {
                 // 确保行是数组
-                $rowArray = is_object($row) ? (array)$row : $row;
-
-                // 1. 移除表中不存在的字段
-                foreach ($rowArray as $key => $value) {
-                    if (!in_array($key, $columnNames)) {
-                        Log::warning("移除无效字段 (行 {$index}): {$key}");
-                        unset($rowArray[$key]);
-                    }
+                if (!is_array($row)) {
+                    Log::warning("第{$index}行不是数组: " . gettype($row));
+                    $row = [];
+                    continue;
                 }
 
-                // 2. 确保所有表字段都存在
-                foreach ($columnNames as $column) {
-                    if (!array_key_exists($column, $rowArray)) {
-                        // 设置默认值
-                        if (in_array($column, ['直接水电', '分摊材料', '车间人工', '部门人工附加', '分摊水电',
-                            '废气处理', '锅炉', '空压机', '热水锅炉', '真空鼓风机', '中央空调', '分摊其他'])) {
-                            $rowArray[$column] = 0;
-                        } else {
-                            $rowArray[$column] = null;
-                        }
-                        Log::debug("添加缺失字段 (行 {$index}): {$column}");
-                    }
-                }
+                // 检查字段数是否匹配
+                $rowCount = count($row);
+                $columnCount = count($columnNames);
 
-                // 3. 确保字段顺序与表一致
-                $orderedRow = [];
-                foreach ($columnNames as $column) {
-                    $orderedRow[$column] = $rowArray[$column] ?? null;
+                if ($rowCount !== $columnCount) {
+                    Log::warning("第" . ($index + 1) . "行字段数不匹配: 数据{$rowCount}个,表{$columnCount}个");
+                    $this->fixRowData($row, $columnNames, $index);
                 }
 
-                // 4. 修复字段名中的特殊字符
-                $this->sanitizeFieldNames($orderedRow);
-
-                $row = $orderedRow;
-
-                // 记录第一行的字段信息用于调试
-                if ($index === 0) {
-                    Log::debug("第一行字段数: " . count($orderedRow) . ", 字段: " . implode(', ', array_keys($orderedRow)));
+                // 确保所有键名都是字符串
+                foreach ($row as $key => $value) {
+                    if (!is_string($key) && !is_int($key)) {
+                        Log::warning("发现非法键名类型 (行 {$index}): " . gettype($key));
+                        // 移除非法键名
+                        unset($row[$key]);
+                        // 如果有值,尝试保存
+                        if ($value !== null) {
+                            $row['invalid_key_' . $index] = $value;
+                        }
+                    }
                 }
             }
 
             Log::info("数据结构验证完成,总记录数: " . count($this->monthlyCostDetails));
 
-        } catch (\Exception $e) {
-            Log::error("验证数据结构时出错: " . $e->getMessage());
+        } catch (\Throwable $t) {
+            Log::error("验证数据结构时出错: " . $t->getMessage());
+            // 不抛出异常,继续执行
         }
     }
 
@@ -1390,14 +1395,32 @@ class UnifiedCostCalculationService
     protected function fixRowData(array &$row, array $columnNames, int $index): void
     {
         $fixedRow = [];
+
         foreach ($columnNames as $column) {
-            $fixedRow[$column] = $row[$column] ?? 0;
+            // 确保列名是字符串
+            $column = (string)$column;
+
+            // 获取值,如果不存在则设置默认值
+            if (array_key_exists($column, $row)) {
+                $value = $row[$column];
+            } else {
+                // 根据列名设置默认值
+                if (in_array($column, ['直接水电', '分摊材料', '车间人工', '部门人工附加', '分摊水电',
+                    '废气处理', '锅炉', '空压机', '热水锅炉', '真空鼓风机', '中央空调', '分摊其他'])) {
+                    $value = 0;
+                } else {
+                    $value = null;
+                }
+            }
+
+            $fixedRow[$column] = $value;
         }
 
         $this->monthlyCostDetails[$index] = $fixedRow;
         Log::info("已修复第" . ($index + 1) . "行数据");
     }
 
+
     /**
      * 插入所有数据
      */
@@ -1505,11 +1528,31 @@ class UnifiedCostCalculationService
      */
     protected function logSuccess(string $month): void
     {
-        Log::info("成本核算完成", [
-            'month' => $month,
-            '月度成本明细记录数' => count($this->monthlyCostDetails),
-            '分摊系数记录数' => count($this->allocationFactors)
-        ]);
+        try {
+            // 确保记录数为整数
+            $monthlyCostDetailsCount = is_countable($this->monthlyCostDetails) ? count($this->monthlyCostDetails) : 0;
+            $allocationFactorsCount = is_countable($this->allocationFactors) ? count($this->allocationFactors) : 0;
+
+            $logData = [
+                'month' => $month,
+                '月度成本明细记录数' => $monthlyCostDetailsCount,
+                '分摊系数记录数' => $allocationFactorsCount,
+                'timestamp' => date('Y-m-d H:i:s')
+            ];
+
+            // 记录每个字段的数据类型,用于调试
+            if (!empty($this->monthlyCostDetails)) {
+                $firstRecord = reset($this->monthlyCostDetails);
+                $logData['first_record_keys'] = is_array($firstRecord) ? array_keys($firstRecord) : 'invalid';
+                $logData['first_record_type'] = gettype($firstRecord);
+            }
+
+            Log::info("成本核算完成", $logData);
+
+        } catch (\Throwable $t) {
+            // 如果日志记录失败,至少输出到标准错误
+            error_log("成本核算完成(日志记录失败): " . $t->getMessage());
+        }
     }
 
     /**
@@ -1517,15 +1560,26 @@ class UnifiedCostCalculationService
      */
     protected function buildSuccessResponse(string $month): array
     {
-        return [
-            'success' => true,
-            'message' => '成本核算完成',
-            'month' => $month,
-            'stats' => [
-                'monthly_cost_details' => count($this->monthlyCostDetails),
-                'allocation_factors' => count($this->allocationFactors)
-            ]
-        ];
+        try {
+            return [
+                'success' => true,
+                'message' => '成本核算完成',
+                'month' => $month,
+                'stats' => [
+                    'monthly_cost_details' => is_countable($this->monthlyCostDetails) ? count($this->monthlyCostDetails) : 0,
+                    'allocation_factors' => is_countable($this->allocationFactors) ? count($this->allocationFactors) : 0
+                ],
+                'timestamp' => date('Y-m-d H:i:s')
+            ];
+        } catch (\Throwable $t) {
+            // 即使构建响应失败,也返回基本成功信息
+            return [
+                'success' => true,
+                'message' => '成本核算完成(统计信息获取失败)',
+                'month' => $month,
+                'error' => $t->getMessage()
+            ];
+        }
     }
 
     /**
@@ -1533,22 +1587,27 @@ class UnifiedCostCalculationService
      */
     protected function logError(\Throwable $t): void
     {
-        $errorDetails = [
-            '时间' => date('Y-m-d H:i:s'),
-            '错误类型' => get_class($t),
-            '错误信息' => $t->getMessage(),
-            '错误代码' => $t->getCode(),
-            '文件' => $t->getFile(),
-            '行号' => $t->getLine(),
-            '堆栈跟踪' => $t->getTraceAsString(),
-            '月度成本明细数' => count($this->monthlyCostDetails),
-            '分摊系数数' => count($this->allocationFactors),
-        ];
+        try {
+            $errorDetails = [
+                '时间' => date('Y-m-d H:i:s'),
+                '错误类型' => get_class($t),
+                '错误信息' => $t->getMessage(),
+                '错误代码' => $t->getCode(),
+                '文件' => $t->getFile(),
+                '行号' => $t->getLine(),
+                '堆栈跟踪' => $t->getTraceAsString(),
+                '月度成本明细数' => is_countable($this->monthlyCostDetails) ? count($this->monthlyCostDetails) : 'N/A',
+                '分摊系数数' => is_countable($this->allocationFactors) ? count($this->allocationFactors) : 'N/A',
+            ];
 
-        Log::error("统一成本核算失败详情: " . json_encode($errorDetails, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+            Log::error("统一成本核算失败详情", $errorDetails);
+        } catch (\Throwable $logError) {
+            // 如果日志记录也失败,至少输出到标准错误
+            error_log("无法记录错误日志: " . $logError->getMessage());
+            error_log("原始错误: " . $t->getMessage());
+        }
     }
 
-
     /**
      * 构建错误响应
      */