From 8e28ee51815dda683087588f4b15c3c800095782 Mon Sep 17 00:00:00 2001 From: zeyan <258785420@qq.com> Date: Tue, 19 Aug 2025 09:44:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/apiController/Contract.php | 17 +- .../model/document/DocumentGenerateLog.php | 8 + .../document/DocumentDataSourceService.php | 4 +- .../document/DocumentGenerateService.php | 2 +- .../document/DocumentTemplateService.php | 278 ++++++++++++++++-- .../document/DocumentTemplateServiceBasic.php | 4 +- uniapp/pages-student/contracts/sign.vue | 4 +- 7 files changed, 273 insertions(+), 44 deletions(-) diff --git a/niucloud/app/api/controller/apiController/Contract.php b/niucloud/app/api/controller/apiController/Contract.php index 7fe38da7..846c0112 100644 --- a/niucloud/app/api/controller/apiController/Contract.php +++ b/niucloud/app/api/controller/apiController/Contract.php @@ -469,12 +469,17 @@ class Contract extends BaseApiService // 使用ContractSignFormService的公共方法获取完整的表单数据(包括处理后的default_value) $contractSignFormService = new ContractSignFormService(); - $signFormData = $contractSignFormService->getStudentContractSignFormBySignId($contract_sign_id, $contractSign['student_id']); + $signFormResult = $contractSignFormService->getStudentContractSignFormBySignId([ + 'contract_sign_id' => $contract_sign_id, + 'student_id' => $contractSign['student_id'] + ]); - if (empty($signFormData) || empty($signFormData['form_fields'])) { - return fail('未找到合同字段配置数据'); + if (!$signFormResult['code'] || empty($signFormResult['data']) || empty($signFormResult['data']['form_fields'])) { + return fail($signFormResult['msg'] ?? '未找到合同字段配置数据'); } + $signFormData = $signFormResult['data']; + // 准备填充数据 - 使用处理后的default_value $fillData = []; foreach ($signFormData['form_fields'] as $field) { @@ -492,14 +497,14 @@ class Contract extends BaseApiService ]; $result = $documentService->generateDocument($generateData); - + // 更新school_contract_sign表的sign_file字段和status字段 $updateResult = Db::table('school_contract_sign') ->where('id', $contract_sign_id) ->update([ - 'sign_file' => $result['file_path'], + 'sign_file' => '/upload/'.$result['file_path'], 'status' => 3, - 'updated_at' => time() + 'updated_at' => date('Y-m-d H:i:s') ]); if (!$updateResult) { diff --git a/niucloud/app/model/document/DocumentGenerateLog.php b/niucloud/app/model/document/DocumentGenerateLog.php index 75a49570..c7437237 100644 --- a/niucloud/app/model/document/DocumentGenerateLog.php +++ b/niucloud/app/model/document/DocumentGenerateLog.php @@ -12,6 +12,14 @@ class DocumentGenerateLog extends BaseModel { protected $pk = 'id'; protected $name = 'document_generate_log'; + + // 字段类型定义 + protected $type = [ + 'created_at' => 'timestamp', + 'updated_at' => 'timestamp', + 'process_start_time' => 'datetime', + 'process_end_time' => 'datetime' + ]; /** * 关联合同表 diff --git a/niucloud/app/service/admin/document/DocumentDataSourceService.php b/niucloud/app/service/admin/document/DocumentDataSourceService.php index 0a3d80a7..3c3e44c2 100644 --- a/niucloud/app/service/admin/document/DocumentDataSourceService.php +++ b/niucloud/app/service/admin/document/DocumentDataSourceService.php @@ -104,7 +104,7 @@ class DocumentDataSourceService extends BaseAdminService throw new \Exception('PLACEHOLDER_EXISTS'); } - $data['created_at'] = time(); + $data['created_at'] = date('Y-m-d H:i:s'); $res = $this->model->save($data); if (!$res) { throw new \Exception('ADD_FAIL'); @@ -194,7 +194,7 @@ class DocumentDataSourceService extends BaseAdminService 'field_type' => $config['field_type'] ?? 'string', 'is_required' => $config['is_required'] ?? 0, 'default_value' => $config['default_value'] ?? '', - 'created_at' => time() + 'created_at' => date('Y-m-d H:i:s') ]; } diff --git a/niucloud/app/service/admin/document/DocumentGenerateService.php b/niucloud/app/service/admin/document/DocumentGenerateService.php index fba8f259..5d8bfffc 100644 --- a/niucloud/app/service/admin/document/DocumentGenerateService.php +++ b/niucloud/app/service/admin/document/DocumentGenerateService.php @@ -111,7 +111,7 @@ class DocumentGenerateService extends BaseAdminService 'user_id' => $data['user_id'], 'fill_data' => json_encode($data['fill_data']), 'status' => 'pending', - 'created_at' => time() + 'created_at' => date('Y-m-d H:i:s') ]; $log = $this->model->create($logData); diff --git a/niucloud/app/service/admin/document/DocumentTemplateService.php b/niucloud/app/service/admin/document/DocumentTemplateService.php index 1cff81c2..1b73c87e 100644 --- a/niucloud/app/service/admin/document/DocumentTemplateService.php +++ b/niucloud/app/service/admin/document/DocumentTemplateService.php @@ -32,6 +32,7 @@ class DocumentTemplateService extends BaseAdminService protected $contractModel; protected $logModel; protected $dataSourceModel; + protected $site_id; public function __construct() { @@ -39,6 +40,7 @@ class DocumentTemplateService extends BaseAdminService $this->contractModel = new Contract(); $this->logModel = new DocumentGenerateLog(); $this->dataSourceModel = new DocumentDataSourceConfig(); + $this->site_id = 1; // 默认站点ID } /** @@ -349,7 +351,18 @@ class DocumentTemplateService extends BaseAdminService foreach ($phpWord->getSections() as $section) { foreach ($section->getElements() as $element) { if (method_exists($element, 'getText')) { - $content .= $element->getText() . "\n"; + // 使用反射获取文本内容 + $text = ''; + if($element instanceof \PhpOffice\PhpWord\Element\Text) { + $text = $element->getText(); + } else if($element instanceof \PhpOffice\PhpWord\Element\TextRun) { + foreach($element->getElements() as $item) { + if($item instanceof \PhpOffice\PhpWord\Element\Text) { + $text .= $item->getText(); + } + } + } + $content .= $text . "\n"; } } } @@ -623,11 +636,10 @@ class DocumentTemplateService extends BaseAdminService 'site_id' => $this->site_id, 'template_id' => $data['template_id'], 'user_id' => $this->uid, - 'user_type' => 'admin', + 'user_type' => 1, 'fill_data' => json_encode($data['fill_data']), 'status' => 'pending', - 'created_at' => time(), - 'updated_at' => time() + 'completed_at' => date('Y-m-d H:i:s') ]; $log = $this->logModel->create($logData); @@ -645,13 +657,42 @@ class DocumentTemplateService extends BaseAdminService // 生成文档 $templatePath = public_path() . '/upload/' . $template['contract_template']; $outputFileName = $data['output_filename'] ?: ($template['contract_name'] . '_' . date('YmdHis') . '.docx'); + + // 使用系统临时目录,避免权限问题 + $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'niucloud_documents'; $outputPath = 'generated_documents/' . date('Y/m/') . $outputFileName; - $fullOutputPath = public_path() . '/upload/' . $outputPath; - - // 确保目录存在 - $outputDir = dirname($fullOutputPath); - if (!is_dir($outputDir)) { - mkdir($outputDir, 0755, true); + + // 尝试创建临时目录 + $fullOutputPath = ''; + $useTemp = false; + + if (!is_dir($tempDir)) { + if (@mkdir($tempDir, 0755, true) || is_dir($tempDir)) { + $fullOutputPath = $tempDir . DIRECTORY_SEPARATOR . $outputFileName; + $useTemp = true; + } + } else { + $fullOutputPath = $tempDir . DIRECTORY_SEPARATOR . $outputFileName; + $useTemp = true; + } + + // 如果临时目录创建失败,尝试使用项目根目录下的temp目录 + if (!$useTemp) { + $projectTempDir = dirname(app()->getRootPath()) . DIRECTORY_SEPARATOR . 'temp'; + if (!is_dir($projectTempDir)) { + if (@mkdir($projectTempDir, 0755, true) || is_dir($projectTempDir)) { + $fullOutputPath = $projectTempDir . DIRECTORY_SEPARATOR . $outputFileName; + $useTemp = true; + } + } else { + $fullOutputPath = $projectTempDir . DIRECTORY_SEPARATOR . $outputFileName; + $useTemp = true; + } + } + + // 如果所有目录创建都失败,抛出异常 + if (!$useTemp || empty($fullOutputPath)) { + throw new \Exception('无法创建临时文档存储目录,请检查系统权限'); } // 使用 PhpWord 模板处理器 @@ -663,19 +704,68 @@ class DocumentTemplateService extends BaseAdminService $templateProcessor->saveAs($fullOutputPath); - // 更新生成记录 - $log->status = 'completed'; - $log->generated_file_path = $outputPath; - $log->generated_file_name = $outputFileName; - $log->process_end_time = date('Y-m-d H:i:s'); - $log->save(); - - return [ - 'log_id' => $log->id, - 'file_path' => $outputPath, - 'file_name' => $outputFileName, - 'download_url' => url('/upload/' . $outputPath) - ]; + // 生成文档后,尝试复制到public目录供下载 + $publicOutputPath = public_path() . '/upload/' . $outputPath; + $publicOutputDir = dirname($publicOutputPath); + $copySuccess = false; + + // 尝试创建public目录并复制文件 + if (@mkdir($publicOutputDir, 0755, true) || is_dir($publicOutputDir)) { + if (@copy($fullOutputPath, $publicOutputPath)) { + $copySuccess = true; + } + } + + if ($copySuccess) { + // 复制成功,删除临时文件 + @unlink($fullOutputPath); + + // 更新生成记录 + $log->status = 'completed'; + $log->generated_file_path = $outputPath; + $log->generated_file_name = $outputFileName; + $log->process_end_time = date('Y-m-d H:i:s'); + $log->save(); + + return [ + 'log_id' => $log->id, + 'file_path' => $outputPath, + 'file_name' => $outputFileName, + 'download_url' => url('/upload/' . $outputPath) + ]; + } else { + // 复制失败,使用runtime目录作为替代方案 + $runtimeDir = runtime_path() . 'generated_documents' . DIRECTORY_SEPARATOR; + if (!is_dir($runtimeDir)) { + @mkdir($runtimeDir, 0755, true); + } + + $runtimePath = $runtimeDir . $outputFileName; + $runtimeCopySuccess = false; + + // 尝试复制到runtime目录 + if (@copy($fullOutputPath, $runtimePath)) { + $runtimeCopySuccess = true; + @unlink($fullOutputPath); // 删除临时文件 + } + + // 更新生成记录 + $log->status = 'completed'; + $log->generated_file_path = $runtimeCopySuccess ? 'runtime/generated_documents/' . $outputFileName : 'temp/' . $outputFileName; + $log->generated_file_name = $outputFileName; + $log->temp_file_path = $runtimeCopySuccess ? $runtimePath : $fullOutputPath; + $log->process_end_time = date('Y-m-d H:i:s'); + $log->save(); + + return [ + 'log_id' => $log->id, + 'file_path' => $runtimeCopySuccess ? 'runtime/generated_documents/' . $outputFileName : 'temp/' . $outputFileName, + 'file_name' => $outputFileName, + 'download_url' => url('/adminapi/document/download/' . $log->id), + 'temp_file_path' => $runtimeCopySuccess ? $runtimePath : $fullOutputPath, + 'message' => $runtimeCopySuccess ? '文档已生成,使用临时下载链接' : '文档已生成,但无法复制到公共目录,请联系管理员处理权限问题' + ]; + } } catch (\Exception $e) { // 更新记录为失败状态 @@ -701,12 +791,39 @@ class DocumentTemplateService extends BaseAdminService foreach ($placeholderConfig as $placeholder => $config) { $value = ''; - if ($config['data_source'] === 'manual') { - // 手动填写的数据 - $value = $userFillData[$placeholder] ?? $config['default_value'] ?? ''; - } else if ($config['data_source'] === 'database') { - // 从数据库获取数据 - $value = $this->getDataFromDatabase($config, $userFillData); + // 检查data_type字段是否存在,如果不存在则默认为user_input + $dataType = $config['data_type'] ?? 'user_input'; + + switch ($dataType) { + case 'user_input': + // 用户输入的数据 + $value = $userFillData[$placeholder] ?? $config['default_value'] ?? ''; + break; + + case 'database': + // 从数据库获取数据 + $value = $this->getDataFromDatabase($config, $userFillData); + break; + + case 'system': + // 系统函数获取数据 + $value = $this->getSystemData($config); + break; + + case 'sign_img': + // 签名图片 + $value = $this->getSignatureImage($config, $userFillData); + break; + + case 'signature': + // 电子签名 + $value = $this->getElectronicSignature($config, $userFillData); + break; + + default: + // 默认使用用户输入 + $value = $userFillData[$placeholder] ?? $config['default_value'] ?? ''; + break; } // 应用处理函数 @@ -733,7 +850,7 @@ class DocumentTemplateService extends BaseAdminService $fieldName = $config['field_name']; // 简单的数据库查询(实际应用中需要更完善的查询逻辑) - $model = Db::connect(); + $model = \think\facade\Db::connect(); $result = $model->table($tableName)->field($fieldName)->find(); return $result[$fieldName] ?? $config['default_value'] ?? ''; @@ -743,6 +860,90 @@ class DocumentTemplateService extends BaseAdminService } } + /** + * 获取系统数据 + * @param array $config + * @return string + */ + private function getSystemData(array $config) + { + try { + $systemFunction = $config['system_function'] ?? ''; + + switch ($systemFunction) { + case 'current_date': + return date('Y-m-d'); + case 'current_datetime': + return date('Y-m-d H:i:s'); + case 'current_time': + return date('H:i:s'); + case 'current_year': + return date('Y'); + case 'current_month': + return date('m'); + case 'current_day': + return date('d'); + case 'timestamp': + return time(); + default: + return $config['default_value'] ?? ''; + } + } catch (\Exception $e) { + Log::error('系统函数调用失败:' . $e->getMessage()); + return $config['default_value'] ?? ''; + } + } + + /** + * 获取签名图片 + * @param array $config + * @param array $userFillData + * @return string + */ + private function getSignatureImage(array $config, array $userFillData) + { + try { + $placeholder = $config['placeholder'] ?? ''; + $signatureImagePath = $userFillData[$placeholder] ?? $config['default_value'] ?? ''; + + // 如果是相对路径,转换为绝对路径 + if ($signatureImagePath && !str_starts_with($signatureImagePath, 'http')) { + $signatureImagePath = public_path() . '/uploads/' . ltrim($signatureImagePath, '/'); + } + + return $signatureImagePath; + } catch (\Exception $e) { + Log::error('签名图片获取失败:' . $e->getMessage()); + return $config['default_value'] ?? ''; + } + } + + /** + * 获取电子签名 + * @param array $config + * @param array $userFillData + * @return string + */ + private function getElectronicSignature(array $config, array $userFillData) + { + try { + $placeholder = $config['placeholder'] ?? ''; + $signatureData = $userFillData[$placeholder] ?? $config['default_value'] ?? ''; + + // 如果是base64编码的签名数据,可以直接返回或进行处理 + if ($signatureData && str_starts_with($signatureData, 'data:image/')) { + // 处理base64图片数据 + return $signatureData; + } + + // 如果是签名文本或其他格式 + return $signatureData; + } catch (\Exception $e) { + Log::error('电子签名获取失败:' . $e->getMessage()); + return $config['default_value'] ?? ''; + } + } + /** * 应用处理函数 * @param mixed $value @@ -784,9 +985,24 @@ class DocumentTemplateService extends BaseAdminService throw new \Exception('文档尚未生成完成'); } + // 优先尝试从public目录下载 $filePath = public_path() . '/upload/' . $log['generated_file_path']; + + // 如果public目录文件不存在,尝试从临时文件路径下载 + if (!file_exists($filePath) && !empty($log['temp_file_path'])) { + $filePath = $log['temp_file_path']; + } + + // 如果还是不存在,尝试从runtime目录 + if (!file_exists($filePath)) { + $runtimePath = runtime_path() . 'generated_documents' . DIRECTORY_SEPARATOR . $log['generated_file_name']; + if (file_exists($runtimePath)) { + $filePath = $runtimePath; + } + } + if (!file_exists($filePath)) { - throw new \Exception('文件不存在'); + throw new \Exception('文件不存在或已被删除'); } // 更新下载统计 diff --git a/niucloud/app/service/admin/document/DocumentTemplateServiceBasic.php b/niucloud/app/service/admin/document/DocumentTemplateServiceBasic.php index 49c5c229..a9e44d49 100644 --- a/niucloud/app/service/admin/document/DocumentTemplateServiceBasic.php +++ b/niucloud/app/service/admin/document/DocumentTemplateServiceBasic.php @@ -74,8 +74,8 @@ class DocumentTemplateServiceBasic extends BaseAdminService 'file_path' => $fullPath, 'status' => 1, // 启用状态 'type' => $data['contract_type'] ?? 'general', - 'created_at' => time(), - 'updated_at' => time() + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s') ]; $contractId = $contract->insertGetId($contractData); diff --git a/uniapp/pages-student/contracts/sign.vue b/uniapp/pages-student/contracts/sign.vue index 423f1ff2..e05ba8fb 100644 --- a/uniapp/pages-student/contracts/sign.vue +++ b/uniapp/pages-student/contracts/sign.vue @@ -190,7 +190,7 @@