智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

212 lines
6.8 KiB

<?php
namespace app\job\contract;
use core\base\BaseJob;
use app\model\contract\ContractSign;
use app\model\document\DocumentGenerateLog;
/**
* 文档生成队列任务
*/
class DocumentGenerateJobBasic extends BaseJob
{
/**
* 执行任务
* @param array $data 任务数据
* @return bool
*/
public function doJob(array $data): bool
{
$contractSignId = $data['contract_sign_id'];
try {
// 1. 获取合同签署信息
$contractSign = (new ContractSign())->find($contractSignId);
if (!$contractSign) {
throw new \Exception('合同签署记录不存在');
}
// 2. 获取填充数据
$fillData = json_decode($contractSign['fill_data'], true);
if (!$fillData) {
throw new \Exception('填充数据格式错误');
}
// 3. 生成Word文档
$generatedFile = $this->generateWordDocument($contractSign, $fillData);
// 4. 更新生成记录
$this->updateGenerateLog($contractSignId, 'completed', $generatedFile);
return true;
} catch (\Exception $e) {
$this->updateGenerateLog($contractSignId, 'failed', null, $e->getMessage());
return false;
}
}
/**
* 生成Word文档
* @param ContractSign $contractSign 合同签署记录
* @param array $fillData 填充数据
* @return string 生成的文件路径
* @throws \Exception
*/
private function generateWordDocument(ContractSign $contractSign, array $fillData): string
{
// 1. 获取合同模板
$contract = \app\model\contract\Contract::find($contractSign['contract_id']);
if (!$contract) {
throw new \Exception('合同模板不存在');
}
$templatePath = public_path() . '/' . $contract['file_path'];
if (!file_exists($templatePath)) {
throw new \Exception('模板文件不存在:' . $templatePath);
}
// 2. 获取数据源配置
$configs = \app\model\document\DocumentDataSourceConfig::where('contract_id', $contractSign['contract_id'])
->select()
->toArray();
// 3. 构建替换数据
$replacements = [];
foreach ($configs as $config) {
$placeholder = '{{' . $config['placeholder'] . '}}';
$value = $fillData[$config['field_name']] ?? $config['default_value'] ?? '';
$replacements[$placeholder] = $this->formatValue($value, $config['field_type']);
}
// 4. 创建输出目录
$outputDir = 'generated/' . date('Y/m/d/');
$fullOutputDir = public_path() . '/' . $outputDir;
if (!is_dir($fullOutputDir)) {
mkdir($fullOutputDir, 0755, true);
}
// 5. 生成文件名
$fileName = time() . '_' . $contractSign['personnel_id'] . '_contract.docx';
$outputPath = $outputDir . $fileName;
$fullOutputPath = public_path() . '/' . $outputPath;
// 6. 使用PhpWord处理文档
try {
$phpWord = \PhpOffice\PhpWord\IOFactory::load($templatePath);
// 7. 替换占位符
$this->replaceDocumentPlaceholders($phpWord, $replacements);
// 8. 保存文档
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$writer->save($fullOutputPath);
// 9. 验证文件是否生成成功
if (!file_exists($fullOutputPath)) {
throw new \Exception('文档生成失败');
}
return $outputPath;
} catch (\Exception $e) {
throw new \Exception('文档处理失败:' . $e->getMessage());
}
}
/**
* 替换文档中的占位符
* @param \PhpOffice\PhpWord\PhpWord $phpWord
* @param array $replacements
*/
private function replaceDocumentPlaceholders(\PhpOffice\PhpWord\PhpWord $phpWord, array $replacements): void
{
foreach ($phpWord->getSections() as $section) {
foreach ($section->getElements() as $element) {
$this->replaceElementPlaceholders($element, $replacements);
}
}
}
/**
* 递归替换元素中的占位符
* @param mixed $element
* @param array $replacements
*/
private function replaceElementPlaceholders($element, array $replacements): void
{
if (method_exists($element, 'getElements')) {
foreach ($element->getElements() as $subElement) {
$this->replaceElementPlaceholders($subElement, $replacements);
}
}
if (method_exists($element, 'getText')) {
$text = $element->getText();
if (is_string($text)) {
$newText = str_replace(array_keys($replacements), array_values($replacements), $text);
if (method_exists($element, 'setText')) {
$element->setText($newText);
}
}
}
}
/**
* 格式化值
* @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 int $contractSignId 合同签署ID
* @param string $status 状态
* @param string|null $generatedFile 生成的文件路径
* @param string|null $errorMsg 错误信息
*/
private function updateGenerateLog(int $contractSignId, string $status, ?string $generatedFile = null, ?string $errorMsg = null): void
{
$updateData = [
'status' => $status,
'completed_at' => time()
];
if ($generatedFile) {
$updateData['generated_file'] = $generatedFile;
}
if ($errorMsg) {
$updateData['error_msg'] = $errorMsg;
}
(new DocumentGenerateLog())->where('id', $contractSignId)->update($updateData);
}
}