|
|
@ -32,6 +32,7 @@ class DocumentTemplateService extends BaseAdminService |
|
|
protected $contractModel; |
|
|
protected $contractModel; |
|
|
protected $logModel; |
|
|
protected $logModel; |
|
|
protected $dataSourceModel; |
|
|
protected $dataSourceModel; |
|
|
|
|
|
protected $site_id; |
|
|
|
|
|
|
|
|
public function __construct() |
|
|
public function __construct() |
|
|
{ |
|
|
{ |
|
|
@ -39,6 +40,7 @@ class DocumentTemplateService extends BaseAdminService |
|
|
$this->contractModel = new Contract(); |
|
|
$this->contractModel = new Contract(); |
|
|
$this->logModel = new DocumentGenerateLog(); |
|
|
$this->logModel = new DocumentGenerateLog(); |
|
|
$this->dataSourceModel = new DocumentDataSourceConfig(); |
|
|
$this->dataSourceModel = new DocumentDataSourceConfig(); |
|
|
|
|
|
$this->site_id = 1; // 默认站点ID |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -349,7 +351,18 @@ class DocumentTemplateService extends BaseAdminService |
|
|
foreach ($phpWord->getSections() as $section) { |
|
|
foreach ($phpWord->getSections() as $section) { |
|
|
foreach ($section->getElements() as $element) { |
|
|
foreach ($section->getElements() as $element) { |
|
|
if (method_exists($element, 'getText')) { |
|
|
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, |
|
|
'site_id' => $this->site_id, |
|
|
'template_id' => $data['template_id'], |
|
|
'template_id' => $data['template_id'], |
|
|
'user_id' => $this->uid, |
|
|
'user_id' => $this->uid, |
|
|
'user_type' => 'admin', |
|
|
'user_type' => 1, |
|
|
'fill_data' => json_encode($data['fill_data']), |
|
|
'fill_data' => json_encode($data['fill_data']), |
|
|
'status' => 'pending', |
|
|
'status' => 'pending', |
|
|
'created_at' => time(), |
|
|
'completed_at' => date('Y-m-d H:i:s') |
|
|
'updated_at' => time() |
|
|
|
|
|
]; |
|
|
]; |
|
|
|
|
|
|
|
|
$log = $this->logModel->create($logData); |
|
|
$log = $this->logModel->create($logData); |
|
|
@ -645,13 +657,42 @@ class DocumentTemplateService extends BaseAdminService |
|
|
// 生成文档 |
|
|
// 生成文档 |
|
|
$templatePath = public_path() . '/upload/' . $template['contract_template']; |
|
|
$templatePath = public_path() . '/upload/' . $template['contract_template']; |
|
|
$outputFileName = $data['output_filename'] ?: ($template['contract_name'] . '_' . date('YmdHis') . '.docx'); |
|
|
$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; |
|
|
$outputPath = 'generated_documents/' . date('Y/m/') . $outputFileName; |
|
|
$fullOutputPath = public_path() . '/upload/' . $outputPath; |
|
|
|
|
|
|
|
|
|
|
|
// 确保目录存在 |
|
|
// 尝试创建临时目录 |
|
|
$outputDir = dirname($fullOutputPath); |
|
|
$fullOutputPath = ''; |
|
|
if (!is_dir($outputDir)) { |
|
|
$useTemp = false; |
|
|
mkdir($outputDir, 0755, true); |
|
|
|
|
|
|
|
|
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 模板处理器 |
|
|
// 使用 PhpWord 模板处理器 |
|
|
@ -663,19 +704,68 @@ class DocumentTemplateService extends BaseAdminService |
|
|
|
|
|
|
|
|
$templateProcessor->saveAs($fullOutputPath); |
|
|
$templateProcessor->saveAs($fullOutputPath); |
|
|
|
|
|
|
|
|
// 更新生成记录 |
|
|
// 生成文档后,尝试复制到public目录供下载 |
|
|
$log->status = 'completed'; |
|
|
$publicOutputPath = public_path() . '/upload/' . $outputPath; |
|
|
$log->generated_file_path = $outputPath; |
|
|
$publicOutputDir = dirname($publicOutputPath); |
|
|
$log->generated_file_name = $outputFileName; |
|
|
$copySuccess = false; |
|
|
$log->process_end_time = date('Y-m-d H:i:s'); |
|
|
|
|
|
$log->save(); |
|
|
|
|
|
|
|
|
|
|
|
return [ |
|
|
// 尝试创建public目录并复制文件 |
|
|
'log_id' => $log->id, |
|
|
if (@mkdir($publicOutputDir, 0755, true) || is_dir($publicOutputDir)) { |
|
|
'file_path' => $outputPath, |
|
|
if (@copy($fullOutputPath, $publicOutputPath)) { |
|
|
'file_name' => $outputFileName, |
|
|
$copySuccess = true; |
|
|
'download_url' => url('/upload/' . $outputPath) |
|
|
} |
|
|
]; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
} catch (\Exception $e) { |
|
|
// 更新记录为失败状态 |
|
|
// 更新记录为失败状态 |
|
|
@ -701,12 +791,39 @@ class DocumentTemplateService extends BaseAdminService |
|
|
foreach ($placeholderConfig as $placeholder => $config) { |
|
|
foreach ($placeholderConfig as $placeholder => $config) { |
|
|
$value = ''; |
|
|
$value = ''; |
|
|
|
|
|
|
|
|
if ($config['data_source'] === 'manual') { |
|
|
// 检查data_type字段是否存在,如果不存在则默认为user_input |
|
|
// 手动填写的数据 |
|
|
$dataType = $config['data_type'] ?? 'user_input'; |
|
|
$value = $userFillData[$placeholder] ?? $config['default_value'] ?? ''; |
|
|
|
|
|
} else if ($config['data_source'] === 'database') { |
|
|
switch ($dataType) { |
|
|
// 从数据库获取数据 |
|
|
case 'user_input': |
|
|
$value = $this->getDataFromDatabase($config, $userFillData); |
|
|
// 用户输入的数据 |
|
|
|
|
|
$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']; |
|
|
$fieldName = $config['field_name']; |
|
|
|
|
|
|
|
|
// 简单的数据库查询(实际应用中需要更完善的查询逻辑) |
|
|
// 简单的数据库查询(实际应用中需要更完善的查询逻辑) |
|
|
$model = Db::connect(); |
|
|
$model = \think\facade\Db::connect(); |
|
|
$result = $model->table($tableName)->field($fieldName)->find(); |
|
|
$result = $model->table($tableName)->field($fieldName)->find(); |
|
|
|
|
|
|
|
|
return $result[$fieldName] ?? $config['default_value'] ?? ''; |
|
|
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 |
|
|
* @param mixed $value |
|
|
@ -784,9 +985,24 @@ class DocumentTemplateService extends BaseAdminService |
|
|
throw new \Exception('文档尚未生成完成'); |
|
|
throw new \Exception('文档尚未生成完成'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 优先尝试从public目录下载 |
|
|
$filePath = public_path() . '/upload/' . $log['generated_file_path']; |
|
|
$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)) { |
|
|
if (!file_exists($filePath)) { |
|
|
throw new \Exception('文件不存在'); |
|
|
throw new \Exception('文件不存在或已被删除'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 更新下载统计 |
|
|
// 更新下载统计 |
|
|
|