0, 'msg' => '获取合同列表失败', 'data' => [] ]; try { $page = $where['page'] ?? 1; $limit = $where['limit'] ?? 10; $personnel_id = $where['personnel_id'] ?? 0; if (empty($personnel_id)) { $res['msg'] = '员工ID不能为空'; return $res; } // 查询合同签订记录,关联合同表 // type=1是给员工签的合同,关联的是school_personnel表 $contractSignModel = new ContractSign(); $list = $contractSignModel->alias('cs') ->join('school_contract c', 'cs.contract_id = c.id') ->where('cs.personnel_id', $personnel_id) ->where('cs.type', 1) // 添加type=1条件,确保查询员工合同 ->where('cs.deleted_at', 0) ->where('c.deleted_at', 0) ->field([ 'cs.id', 'cs.contract_id', 'cs.personnel_id', 'cs.sign_file', 'cs.status', 'cs.created_at', 'cs.sign_time', 'c.contract_name', 'c.contract_template', 'c.contract_status', 'c.contract_type', 'c.remarks' ]) ->order('cs.created_at', 'desc') ->paginate([ 'list_rows' => $limit, 'page' => $page ]) ->toArray(); $res = [ 'code' => 1, 'msg' => '获取成功', 'data' => $list ]; } catch (\Exception $e) { $res['msg'] = '获取合同列表异常:' . $e->getMessage(); } return $res; } /** * 获取合同详情 * @param array $where * @return array */ public function getContractDetail(array $where) { $res = [ 'code' => 0, 'msg' => '获取合同详情失败', 'data' => [] ]; try { $id = $where['id'] ?? 0; if (empty($id)) { $res['msg'] = '参数错误'; return $res; } // 查询合同签订记录,关联合同表 $contractSign = ContractSign::alias('cs') ->join('school_contract c', 'cs.contract_id = c.id') ->where('cs.id', $id) ->where('cs.type', 1) // 添加type=1条件,确保查询员工合同 ->where('cs.deleted_at', 0) ->where('c.deleted_at', 0) ->field([ 'cs.id', 'cs.contract_id', 'cs.personnel_id', 'cs.sign_file', 'cs.status', 'cs.created_at', 'cs.sign_time', 'cs.updated_at', 'c.contract_name', 'c.contract_template', 'c.contract_status', 'c.contract_type', 'c.remarks' ]) ->find(); if (empty($contractSign)) { $res['msg'] = '合同不存在或无权限访问'; return $res; } $contractData = $contractSign->toArray(); $res = [ 'code' => 1, 'msg' => '获取成功', 'data' => $contractData ]; } catch (\Exception $e) { $res['msg'] = '获取合同详情异常:' . $e->getMessage(); } return $res; } /** * 签订合同 * @param array $data * @return array */ public function signContract(array $data) { $res = [ 'code' => 0, 'msg' => '签订合同失败', 'data' => [] ]; try { $contract_id = $data['contract_id'] ?? 0; $personnel_id = $data['personnel_id'] ?? 0; $form_data = $data['form_data'] ?? []; $signature_image = $data['signature_image'] ?? ''; $sign_file = $data['sign_file'] ?? ''; // 兼容旧版本 if (empty($contract_id) || empty($personnel_id)) { $res['msg'] = '参数错误'; return $res; } // 开启事务 Db::startTrans(); // 查询合同签订记录 $contractSign = ContractSign::where('contract_id', $contract_id) ->where('personnel_id', $personnel_id) ->where('type', 1) // 添加type=1条件,确保查询员工合同 ->where('deleted_at', 0) ->find(); if (empty($contractSign)) { Db::rollback(); $res['msg'] = '合同签订记录不存在'; return $res; } // 检查合同状态 if ($contractSign['status'] != 1) { Db::rollback(); $res['msg'] = '合同状态不允许签订'; return $res; } // 检查是否已经签订 if (!empty($contractSign['sign_file'])) { Db::rollback(); $res['msg'] = '合同已经签订,无需重复签订'; return $res; } // 验证必填字段(如果有表单数据) if ($form_data) { $this->validateStaffFormData($contract_id, $form_data); } // 生成签署后的合同文档 $generatedFile = null; $useSignatureImage = $signature_image ?: $sign_file; // 优先使用新的signature_image字段 if ($useSignatureImage || $form_data) { $generatedFile = $this->generateStaffSignedContract($contract_id, $personnel_id, $form_data, $useSignatureImage); } // 更新签订信息 $updateData = [ 'status' => 2, // 已签署 'sign_file' => $generatedFile ?: $useSignatureImage, 'sign_time' => date('Y-m-d H:i:s'), 'fill_data' => $form_data ? json_encode($form_data, JSON_UNESCAPED_UNICODE) : null, 'updated_at' => date('Y-m-d H:i:s') ]; if ($useSignatureImage) { $updateData['signature_image'] = $useSignatureImage; } $updateResult = ContractSign::where('id', $contractSign['id'])->update($updateData); if (!$updateResult) { Db::rollback(); $res['msg'] = '更新签订信息失败'; return $res; } // 提交事务 Db::commit(); $res = [ 'code' => 1, 'msg' => '签订成功', 'data' => [ 'sign_id' => $contractSign['id'], 'contract_id' => $contract_id, 'sign_time' => $updateData['sign_time'], 'generated_file' => $generatedFile ] ]; } catch (\Exception $e) { Db::rollback(); $res['msg'] = '签订合同异常:' . $e->getMessage(); } return $res; } /** * 获取合同签订状态 * @param array $where * @return array */ public function getSignStatus(array $where) { $res = [ 'code' => 0, 'msg' => '获取签订状态失败', 'data' => [] ]; try { $contract_id = $where['contract_id'] ?? 0; $personnel_id = $where['personnel_id'] ?? 0; if (empty($contract_id) || empty($personnel_id)) { $res['msg'] = '参数错误'; return $res; } $contractSign = ContractSign::where('contract_id', $contract_id) ->where('personnel_id', $personnel_id) ->where('type', 1) // 添加type=1条件,确保查询员工合同 ->where('deleted_at', 0) ->field('id,sign_file,status,sign_time') ->find(); if (empty($contractSign)) { $res['msg'] = '合同签订记录不存在'; return $res; } $signData = $contractSign->toArray(); // 判断签订状态 $signData['is_signed'] = !empty($signData['sign_file']); $signData['can_sign'] = $signData['status'] == 1 && empty($signData['sign_file']); $res = [ 'code' => 1, 'msg' => '获取成功', 'data' => $signData ]; } catch (\Exception $e) { $res['msg'] = '获取签订状态异常:' . $e->getMessage(); } return $res; } /** * 获取员工合同签署表单配置 * @param array $where * @return array */ public function getStaffContractSignForm(array $where) { $res = [ 'code' => 0, 'msg' => '获取签署表单失败', 'data' => [] ]; try { $contract_id = $where['contract_id'] ?? 0; $personnel_id = $where['personnel_id'] ?? 0; if (empty($contract_id) || empty($personnel_id)) { $res['msg'] = '参数错误'; return $res; } // 查询合同签署记录 $contractSign = ContractSign::alias('cs') ->join('school_contract c', 'cs.contract_id = c.id') ->where('cs.id', $contract_id) ->where('cs.deleted_at', 0) ->where('c.deleted_at', 0) ->field([ 'cs.id as sign_id', 'cs.contract_id', 'cs.status', 'cs.fill_data', 'c.contract_name', 'c.contract_type', 'c.contract_content', 'c.contract_template' ]) ->find(); if (!$contractSign) { $res['msg'] = '合同不存在或无权限访问'; return $res; } $contractData = $contractSign->toArray(); // 获取表单字段配置 $formFields = Db::table('school_document_data_source_config') ->where('contract_sign_id', $contract_id) ->order('id', 'asc') ->select() ->toArray(); if(!empty($contractSign['contract_content'])){ $contractData['contract_content'] = replace_placeholders_with_underlines($contractSign['contract_content']); } // 处理表单字段 $processedFields = []; foreach ($formFields as $field) { $processedFields[] = [ 'name' => str_replace(['{{', '}}'], '', $field['placeholder']), 'placeholder' => str_replace(['{{', '}}'], '', $field['placeholder']), 'field_type' => $field['field_type'] ?: 'text', 'data_type' => $field['data_type'], 'is_required' => $field['is_required'] ? true : false, 'default_value' => $field['default_value'] ?: '', 'sign_party' => $field['sign_party'] ?: null ]; } $res = [ 'code' => 1, 'msg' => '获取成功', 'data' => [ 'sign_id' => $contractData['sign_id'], 'contract_id' => $contractData['contract_id'], 'contract_name' => $contractData['contract_name'], 'contract_type' => $contractData['contract_type'], 'contract_content' => $contractData['contract_content'] ?: '', 'form_fields' => $processedFields, 'contract_template_url' => $contractData['contract_template'] ? '/upload/' . $contractData['contract_template'] : '', 'status' => $contractData['status'], 'existing_data' => $contractData['fill_data'] ? json_decode($contractData['fill_data'], true) : [] ] ]; } catch (\Exception $e) { $res['msg'] = '获取签署表单异常:' . $e->getMessage(); } return $res; } /** * 下载合同文件 * @param array $where * @return array */ public function downloadContract(array $where) { $res = [ 'code' => 0, 'msg' => '下载合同失败', 'data' => [] ]; try { $contract_id = $where['contract_id'] ?? 0; $personnel_id = $where['personnel_id'] ?? 0; if (empty($contract_id) || empty($personnel_id)) { $res['msg'] = '参数错误'; return $res; } // 查询合同信息 $contractSign = ContractSign::alias('cs') ->join('school_contract c', 'cs.contract_id = c.id') ->where('cs.contract_id', $contract_id) ->where('cs.personnel_id', $personnel_id) ->where('cs.type', 1) // 添加type=1条件,确保查询员工合同 ->where('cs.deleted_at', 0) ->where('c.deleted_at', 0) ->field([ 'cs.sign_file', 'c.contract_template', 'c.contract_name' ]) ->find(); if (empty($contractSign)) { $res['msg'] = '合同不存在或无权限访问'; return $res; } $contractData = $contractSign->toArray(); // 返回下载信息 $downloadData = [ 'contract_name' => $contractData['contract_name'], 'sign_file' => $contractData['sign_file'], 'contract_template' => $contractData['contract_template'], 'download_url' => !empty($contractData['sign_file']) ? $contractData['sign_file'] : $contractData['contract_template'] ]; $res = [ 'code' => 1, 'msg' => '获取下载信息成功', 'data' => $downloadData ]; } catch (\Exception $e) { $res['msg'] = '获取下载信息异常:' . $e->getMessage(); } return $res; } /** * 验证员工表单数据 * @param int $contractId * @param array $formData * @throws \Exception */ private function validateStaffFormData($contractId, $formData) { // 获取数据源配置 $configs = Db::table('school_document_data_source_config') ->where('contract_id', $contractId) ->where('is_required', 1) ->select() ->toArray(); foreach ($configs as $config) { $placeholder = str_replace(['{{', '}}'], '', $config['placeholder']); $value = $formData[$placeholder] ?? ''; if (empty($value)) { throw new \Exception("必填字段 {$placeholder} 不能为空"); } } } /** * 生成员工签署后的合同文档 * @param int $contractId * @param int $personnelId * @param array $formData * @param string $signatureImage * @return string|null */ private function generateStaffSignedContract($contractId, $personnelId, $formData = [], $signatureImage = '') { try { // 获取合同模板信息 $contract = Contract::find($contractId); if (!$contract || !$contract['contract_template']) { return null; } // 构建模板路径 $templatePath = public_path() . '/upload/' . $contract['contract_template']; if (!file_exists($templatePath)) { return null; } // 生成输出文件名和路径 $outputFileName = 'staff_signed_contract_' . $personnelId . '_' . $contractId . '_' . date('YmdHis') . '.docx'; $outputRelPath = 'contracts/staff_signed/' . date('Y/m/') . $outputFileName; $outputFullPath = public_path() . '/upload/' . $outputRelPath; // 确保目录存在 $outputDir = dirname($outputFullPath); if (!is_dir($outputDir)) { mkdir($outputDir, 0755, true); } // 获取员工信息并准备填充数据 $fillData = $this->prepareStaffFillData($contractId, $personnelId, $formData); // 使用PhpWord处理模板 $templateProcessor = new TemplateProcessor($templatePath); // 填充文本数据 foreach ($fillData as $placeholder => $value) { $templateProcessor->setValue($placeholder, $value); } // 处理签名图片 if ($signatureImage) { // 处理签名图片 $signImagePath = $this->processStaffSignatureImage($signatureImage); // 使用ContractSign服务插入签名 $contractSignService = new ContractSignService(); $contractSignService->setSign($templatePath, $outputFullPath, $signImagePath, '员工签名'); // 清理临时文件 if (file_exists($signImagePath)) { unlink($signImagePath); } } else { // 没有签名时直接保存 $templateProcessor->saveAs($outputFullPath); } return $outputRelPath; } catch (\Exception $e) { return null; } } /** * 准备员工填充数据 * @param int $contractId * @param int $personnelId * @param array $formData * @return array */ private function prepareStaffFillData($contractId, $personnelId, $formData = []) { $fillData = []; try { // 获取数据源配置 $configs = Db::table('school_document_data_source_config') ->where('contract_id', $contractId) ->select() ->toArray(); foreach ($configs as $config) { $placeholder = str_replace(['{{', '}}'], '', $config['placeholder']); $value = ''; switch ($config['data_type']) { case 'database': $value = $this->getStaffDataFromDatabase($config['table_name'], $config['field_name'], $personnelId); break; case 'system': $value = $this->getSystemValue($config['system_function']); break; case 'user_input': case 'signature': case 'sign_img': default: $value = $formData[$placeholder] ?? $config['default_value'] ?? ''; break; } $fillData[$placeholder] = $value; } // 如果没有配置,使用默认填充逻辑 if (empty($fillData)) { // 获取员工信息 $personnel = Db::table('school_personnel')->where('id', $personnelId)->find(); if ($personnel) { $fillData['员工姓名'] = $personnel['name'] ?? ''; $fillData['员工编号'] = $personnel['employee_number'] ?? ''; $fillData['员工电话'] = $personnel['phone'] ?? ''; $fillData['员工邮箱'] = $personnel['email'] ?? ''; $fillData['入职时间'] = $personnel['join_time'] ?? ''; } // 添加系统信息 $fillData['签署日期'] = date('Y-m-d'); $fillData['签署时间'] = date('Y-m-d H:i:s'); $fillData['合同编号'] = $contractId . date('Ymd') . $personnelId; // 合并表单数据 if ($formData) { $fillData = array_merge($fillData, $formData); } } } catch (\Exception $e) { // 记录错误日志但不中断流程 } return $fillData; } /** * 从数据库获取员工数据 * @param string $tableName * @param string $fieldName * @param int $personnelId * @return string */ private function getStaffDataFromDatabase($tableName, $fieldName, $personnelId) { try { switch ($tableName) { case 'school_personnel': $data = Db::table('school_personnel')->where('id', $personnelId)->find(); return $data[$fieldName] ?? ''; default: return ''; } } catch (\Exception $e) { return ''; } } /** * 获取系统值 * @param string $systemFunction * @return string */ private function getSystemValue($systemFunction) { switch ($systemFunction) { case 'current_date': return date('Y-m-d'); case 'current_time': return date('Y-m-d H:i:s'); case 'current_year': return date('Y'); case 'current_month': return date('m'); case 'current_day': return date('d'); default: return ''; } } /** * 处理员工签名图片 * @param string $signatureImage * @return string */ private function processStaffSignatureImage($signatureImage) { $tempImagePath = public_path() . '/upload/temp_staff_sign_' . date('YmdHis') . '_' . mt_rand(1000, 9999) . '.png'; if (strpos($signatureImage, 'data:image') === 0) { // Base64图片 $imageData = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $signatureImage)); if ($imageData !== false) { file_put_contents($tempImagePath, $imageData); } } elseif (filter_var($signatureImage, FILTER_VALIDATE_URL)) { // URL图片 $imageContent = file_get_contents($signatureImage); if ($imageContent !== false) { file_put_contents($tempImagePath, $imageContent); } } else { // 本地路径 $localPath = public_path() . '/upload/' . ltrim($signatureImage, '/'); if (file_exists($localPath)) { copy($localPath, $tempImagePath); } } return $tempImagePath; } }