find($logId); if (!$log) { Log::error('DocumentGenerateJob: Generate log not found', ['log_id' => $logId]); return false; } // 更新状态为处理中 $log->save(['status' => 'processing']); // 执行文档生成 $result = $this->generateDocument($log); if ($result['success']) { // 生成成功 $log->save([ 'status' => 'completed', 'generated_file' => $result['file_path'], 'completed_at' => time(), 'error_msg' => null ]); Log::info('DocumentGenerateJob: Document generated successfully', [ 'log_id' => $logId, 'file_path' => $result['file_path'] ]); } else { // 生成失败 $log->save([ 'status' => 'failed', 'error_msg' => $result['error'], 'completed_at' => time() ]); Log::error('DocumentGenerateJob: Document generation failed', [ 'log_id' => $logId, 'error' => $result['error'] ]); } return $result['success']; } catch (\Exception $e) { // 异常处理 if (isset($log)) { $log->save([ 'status' => 'failed', 'error_msg' => $e->getMessage(), 'completed_at' => time() ]); } Log::error('DocumentGenerateJob: Exception occurred', [ 'log_id' => $logId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return false; } } /** * 生成文档 * @param DocumentGenerateLog $log 生成记录 * @return array */ private function generateDocument(DocumentGenerateLog $log): array { try { // 获取合同模板信息 $contract = (new Contract())->find($log['template_id']); if (!$contract) { return ['success' => false, 'error' => '合同模板不存在']; } if (empty($contract['file_path'])) { return ['success' => false, 'error' => '合同模板文件不存在']; } // 解析填充数据 $fillData = json_decode($log['fill_data'], true); if (!$fillData) { return ['success' => false, 'error' => '填充数据格式错误']; } // 获取数据源配置 $dataSourceConfigs = (new DocumentDataSourceConfig()) ->where('contract_id', $log['template_id']) ->select() ->toArray(); // 构建占位符替换数据 $replacements = $this->buildReplacements($dataSourceConfigs, $fillData); // 使用DocumentTemplateService生成文档 $service = new DocumentTemplateService(); $result = $service->generateDocument([ 'template_path' => $contract['file_path'], 'replacements' => $replacements, 'output_name' => $this->generateFileName($contract, $log) ]); if ($result['success']) { return [ 'success' => true, 'file_path' => $result['file_path'] ]; } else { return [ 'success' => false, 'error' => $result['error'] ?? '文档生成失败' ]; } } catch (\Exception $e) { return [ 'success' => false, 'error' => '文档生成异常:' . $e->getMessage() ]; } } /** * 构建占位符替换数据 * @param array $dataSourceConfigs 数据源配置 * @param array $fillData 填充数据 * @return array */ private function buildReplacements(array $dataSourceConfigs, array $fillData): array { $replacements = []; foreach ($dataSourceConfigs as $config) { $placeholder = $config['field_alias'] ?? $config['placeholder'] ?? ''; $fieldName = $config['field_name'] ?? ''; if (empty($placeholder)) { continue; } // 从填充数据中获取值 $value = $fillData[$fieldName] ?? $config['default_value'] ?? ''; // 格式化值 $value = $this->formatValue($value, $config['field_type'] ?? 'string'); // 添加到替换数组 $replacements['{{' . $placeholder . '}}'] = $value; } return $replacements; } /** * 格式化值 * @param mixed $value 原始值 * @param string $type 字段类型 * @return string */ private function formatValue($value, string $type): string { switch ($type) { case 'datetime': if (is_numeric($value)) { return date('Y-m-d H:i:s', $value); } elseif (strtotime($value)) { return date('Y-m-d H:i:s', strtotime($value)); } break; case 'date': if (is_numeric($value)) { return date('Y-m-d', $value); } elseif (strtotime($value)) { return date('Y-m-d', strtotime($value)); } break; case 'decimal': return number_format((float)$value, 2); case 'integer': return (string)(int)$value; default: return (string)$value; } return (string)$value; } /** * 生成文件名 * @param Contract $contract 合同模板 * @param DocumentGenerateLog $log 生成记录 * @return string */ private function generateFileName(Contract $contract, DocumentGenerateLog $log): string { $timestamp = date('YmdHis'); $contractName = preg_replace('/[^\w\-_\.]/', '_', $contract['name']); $userId = $log['user_id']; return "{$contractName}_{$userId}_{$timestamp}.docx"; } }