$contract_sign_id, 'student_id' => $student_id ]); // 1. 从签署记录获取合同ID $sign_record = Db::table('school_contract_sign') ->where('id', $contract_sign_id) ->where('student_id', $student_id) ->find(); if (!$sign_record) { throw new \Exception('合同签署记录不存在'); } $contract_id = $sign_record['contract_id']; // 2. 获取合同模板基本信息 $contract = $this->getContractInfo($contract_id); if (!$contract) { throw new \Exception('合同模板不存在或已删除'); } // 3. 获取学员基本信息 $student = $this->getStudentInfo($student_id); if (!$student) { throw new \Exception('学员信息不存在'); } // 4. 从document_data_source_config表获取该签署关系专属的字段配置 $form_fields = $this->getSignSpecificFormFields($contract_sign_id, $student); // 5. 组装返回数据 $result = [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'contract_name' => $contract['contract_name'], 'contract_type' => $contract['contract_type'], 'contract_content' => $contract['contract_content'] ?? '', 'status' => $sign_record['status'], 'sign_file' => $sign_record['sign_file'], 'form_fields' => $form_fields, 'student_info' => [ 'id' => $student['id'], 'name' => $student['name'], 'phone' => $student['contact_phone'] ?? '', 'user_id' => $student['user_id'] ] ]; Log::info('根据签署记录ID获取表单成功', [ 'contract_sign_id' => $contract_sign_id, 'student_id' => $student_id, 'form_fields_count' => count($form_fields) ]); return [ 'code' => 1, 'msg' => '获取成功', 'data' => $result ]; } catch (\Exception $e) { Log::error('根据签署记录ID获取表单失败', [ 'contract_sign_id' => $params['contract_sign_id'] ?? 0, 'student_id' => $params['student_id'] ?? 0, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'code' => 0, 'msg' => $e->getMessage(), 'data' => [] ]; } } /** * 获取学员合同签署表单配置 * 该方法为移动端提供合同签署表单的完整配置信息 * 包括合同基本信息、占位符字段配置、预填充数据等 * * @param array $params 请求参数 * - contract_id: 合同模板ID (必填) * - student_id: 学员ID (必填) * @return array 返回格式化的表单配置数据 * @throws \Exception 当参数验证失败或数据获取异常时抛出异常 */ public function getStudentContractSignForm(array $params) { try { // 1. 验证必要参数 if (empty($params['contract_id']) || empty($params['student_id'])) { throw new \Exception('缺少必要参数:contract_id 和 student_id'); } $contract_id = (int)$params['contract_id']; $student_id = (int)$params['student_id']; Log::info('开始获取学员合同签署表单', [ 'contract_id' => $contract_id, 'student_id' => $student_id ]); // 2. 获取合同模板基本信息 $contract = $this->getContractInfo($contract_id); if (!$contract) { throw new \Exception('合同模板不存在或已删除'); } // 3. 获取学员基本信息 $student = $this->getStudentInfo($student_id); if (!$student) { throw new \Exception('学员信息不存在'); } // 4. 获取占位符配置信息 $placeholder_config = $this->getPlaceholderConfig($contract_id); // 5. 处理占位符配置,生成表单字段 $form_fields = $this->processFormFields($placeholder_config, $student); // 6. 组装返回数据 $result = [ 'contract_id' => $contract_id, 'contract_name' => $contract['contract_name'], 'contract_type' => $contract['contract_type'], 'contract_content' => $contract['contract_content'] ?? '', 'form_fields' => $form_fields, 'student_info' => [ 'id' => $student['id'], 'name' => $student['name'], 'phone' => $student['contact_phone'] ?? '', 'user_id' => $student['user_id'] ] ]; Log::info('学员合同签署表单获取成功', [ 'contract_id' => $contract_id, 'student_id' => $student_id, 'form_fields_count' => count($form_fields) ]); return [ 'code' => 1, 'msg' => '获取成功', 'data' => $result ]; } catch (\Exception $e) { Log::error('获取学员合同签署表单失败', [ 'contract_id' => $params['contract_id'] ?? 0, 'student_id' => $params['student_id'] ?? 0, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'code' => 0, 'msg' => $e->getMessage(), 'data' => [] ]; } } /** * 获取合同模板基本信息 * 从数据库中获取合同模板的基础信息 * * @param int $contract_id 合同模板ID * @return array|null 合同信息数组,失败返回null */ private function getContractInfo($contract_id) { try { $contract = Db::table('school_contract') ->where([ ['id', '=', $contract_id], ['contract_status', '=', 'active'], // 只获取启用状态的合同 ['deleted_at', '=', 0] ]) ->field([ 'id', 'contract_name', 'contract_type', 'contract_content', 'placeholder_config', 'created_at', 'updated_at' ]) ->find(); return $contract ? $contract : null; } catch (\Exception $e) { Log::error('获取合同信息失败', [ 'contract_id' => $contract_id, 'error' => $e->getMessage() ]); return null; } } /** * 获取学员基本信息 * 从数据库中获取学员的详细信息,用于表单预填充 * * @param int $student_id 学员ID * @return array|null 学员信息数组,失败返回null */ private function getStudentInfo($student_id) { try { $student = Db::table('school_student') ->where([ ['id', '=', $student_id], ['status', '=', 1] // 只获取有效学员 ]) ->field([ 'id', 'name', 'gender', 'age', 'birthday', 'emergency_contact', 'contact_phone', 'member_label', 'user_id', 'campus_id', 'created_at' ]) ->find(); return $student ? $student : null; } catch (\Exception $e) { Log::error('获取学员信息失败', [ 'student_id' => $student_id, 'error' => $e->getMessage() ]); return null; } } /** * 获取合同占位符配置 * 从合同模板中解析占位符配置信息 * 支持从 placeholder_config JSON字段获取配置 * * @param int $contract_id 合同模板ID * @return array 占位符配置数组 */ private function getPlaceholderConfig($contract_id) { try { // 从合同表获取占位符配置 $placeholder_config_json = Db::table('school_contract') ->where('id', $contract_id) ->value('placeholder_config'); if (empty($placeholder_config_json)) { Log::warning('合同占位符配置为空', ['contract_id' => $contract_id]); return []; } $config = json_decode($placeholder_config_json, true); if (!is_array($config)) { Log::warning('合同占位符配置格式错误', [ 'contract_id' => $contract_id, 'config' => $placeholder_config_json ]); return []; } Log::info('获取占位符配置成功', [ 'contract_id' => $contract_id, 'config_count' => count($config), 'raw_config_length' => strlen($placeholder_config_json), 'config_keys' => array_keys($config) ]); return $config; } catch (\Exception $e) { Log::error('获取占位符配置失败', [ 'contract_id' => $contract_id, 'error' => $e->getMessage() ]); return []; } } /** * 处理表单字段配置 * 根据占位符配置生成移动端可用的表单字段数据 * 对不同数据类型进行差异化处理,预填充相应的默认值 * * @param array $placeholder_config 占位符配置数组 * @param array $student 学员信息 * @return array 处理后的表单字段数组 */ private function processFormFields($placeholder_config, $student) { $form_fields = []; Log::info('开始处理表单字段配置', [ 'config_type' => gettype($placeholder_config), 'config_count' => is_array($placeholder_config) ? count($placeholder_config) : 0, 'config_keys' => is_array($placeholder_config) ? array_keys($placeholder_config) : [] ]); // 检查配置数据格式 if (!is_array($placeholder_config) || empty($placeholder_config)) { Log::warning('占位符配置为空或格式错误'); return []; } // 处理JSON对象格式的配置:{"字段名": {配置}} foreach ($placeholder_config as $placeholder_name => $config) { // 确保$config是数组 if (!is_array($config)) { Log::warning('跳过无效配置项', ['placeholder' => $placeholder_name, 'config' => $config]); continue; } // 基础字段信息 - 使用键名作为占位符名称 $field = [ 'name' => $placeholder_name, 'placeholder' => $placeholder_name, 'data_type' => $config['data_type'] ?? 'user_input', 'field_type' => $config['field_type'] ?? 'text', 'is_required' => (int)($config['is_required'] ?? 0), 'default_value' => '', 'validation_rule' => $config['validation_rule'] ?? '', 'sign_party' => $config['sign_party'] ?? '', ]; // 根据数据类型处理默认值 switch ($config['data_type'] ?? 'user_input') { case 'database': // 数据库类型:从相关表获取数据 $field['default_value'] = $this->getDatabaseFieldValue($config, $student); break; case 'system': // 系统函数类型:调用系统函数获取值 $field['default_value'] = $this->getSystemFunctionValue($config); break; case 'user_input': // 用户输入类型:使用配置的默认值 $field['default_value'] = $config['default_value'] ?? ''; break; case 'signature': // 电子签名类型:无默认值,需要用户手写签名 $field['signature_type'] = $config['signature_type'] ?? 'handwrite'; $field['default_value'] = ''; break; case 'sign_img': // 签名图片类型:无默认值,需要用户上传或选择 $field['sign_image_source'] = $config['sign_image_source'] ?? 'upload'; $field['default_value'] = ''; break; default: $field['default_value'] = $config['default_value'] ?? ''; break; } $form_fields[] = $field; } Log::info('表单字段处理完成', [ 'total_fields' => count($form_fields), 'database_fields' => count(array_filter($form_fields, fn($f) => $f['data_type'] === 'database')), 'system_fields' => count(array_filter($form_fields, fn($f) => $f['data_type'] === 'system')), 'user_input_fields' => count(array_filter($form_fields, fn($f) => $f['data_type'] === 'user_input')), 'signature_fields' => count(array_filter($form_fields, fn($f) => $f['data_type'] === 'signature')), 'sign_img_fields' => count(array_filter($form_fields, fn($f) => $f['data_type'] === 'sign_img')), 'field_names' => array_column($form_fields, 'name') ]); return $form_fields; } /** * 获取数据库字段值 * 根据配置的表名和字段名从数据库获取对应的值 * 支持学员表、订单表、用户表、员工表等多种数据源 * * @param array $config 字段配置 * @param array $student 学员信息(用于关联查询) * @return string 字段值 */ private function getDatabaseFieldValue($config, $student) { try { $table_name = $config['table_name'] ?? ''; $field_name = $config['field_name'] ?? ''; if (empty($table_name) || empty($field_name)) { return ''; } $value = ''; switch ($table_name) { case 'school_student': // 学员表:直接从学员信息获取 $value = $student[$field_name] ?? ''; break; case 'school_customer_resources': // 用户表:通过学员的user_id关联查询 if (!empty($student['user_id'])) { $value = Db::table('school_customer_resources') ->where('id', $student['user_id']) ->value($field_name) ?? ''; } break; case 'school_order_table': // 订单表:查询该学员最新的订单信息 $value = Db::table('school_order_table') ->where('student_id', $student['id']) ->order('created_at', 'desc') ->value($field_name) ?? ''; break; case 'school_personnel': // 员工表:这里可能需要根据业务逻辑确定关联的员工 // 暂时返回空值,具体业务逻辑需要根据实际需求调整 $value = ''; break; default: Log::warning('不支持的数据库表', [ 'table_name' => $table_name, 'field_name' => $field_name ]); break; } // 对特殊字段进行格式化处理 $value = $this->formatFieldValue($field_name, $value); return (string)$value; } catch (\Exception $e) { Log::error('获取数据库字段值失败', [ 'config' => $config, 'student_id' => $student['id'], 'error' => $e->getMessage() ]); return ''; } } /** * 获取系统函数值 * 调用预定义的系统函数获取动态值 * 支持日期时间、业务信息、系统信息等多种函数 * * @param array $config 字段配置 * @return string 函数返回值 */ private function getSystemFunctionValue($config) { try { $system_function = $config['system_function'] ?? ''; if (empty($system_function)) { return ''; } // 检查函数是否存在 if (!function_exists($system_function)) { Log::warning('系统函数不存在', [ 'function_name' => $system_function ]); return ''; } // 调用系统函数 $value = call_user_func($system_function); Log::info('系统函数调用成功', [ 'function_name' => $system_function, 'result' => $value ]); return (string)$value; } catch (\Exception $e) { Log::error('获取系统函数值失败', [ 'config' => $config, 'error' => $e->getMessage() ]); return ''; } } /** * 格式化字段值 * 对特定类型的字段值进行格式化处理 * 例如日期格式化、金额格式化等 * * @param string $field_name 字段名 * @param mixed $value 原始值 * @return string 格式化后的值 */ private function formatFieldValue($field_name, $value) { if (empty($value)) { return ''; } // 根据字段名进行特殊处理 switch (true) { case str_contains($field_name, 'date') || str_contains($field_name, 'time'): // 日期时间字段格式化 if (is_numeric($value)) { return date('Y-m-d', $value); } elseif (strtotime($value)) { return date('Y-m-d', strtotime($value)); } break; case str_contains($field_name, 'amount') || str_contains($field_name, 'price'): // 金额字段格式化 return number_format((float)$value, 2); case str_contains($field_name, 'phone'): // 手机号格式化(可以添加脱敏处理) return (string)$value; default: // 默认返回字符串 return (string)$value; } return (string)$value; } /** * 保存合同签署记录 * 将签署数据保存到数据库中 * * @param int $contract_id 合同ID * @param int $student_id 学员ID * @param array $form_data 表单数据 * @return int|false 签署记录ID,失败返回false */ private function saveContractSignRecord($contract_id, $student_id, $form_data) { try { $now = date('Y-m-d H:i:s'); // 准备签署记录数据 $sign_data = [ 'contract_id' => $contract_id, 'student_id' => $student_id, 'form_data' => json_encode($form_data, JSON_UNESCAPED_UNICODE), 'sign_status' => 1, // 已签署 'sign_time' => $now, 'created_at' => $now, 'updated_at' => $now, 'deleted_at' => 0 ]; // 插入签署记录 $sign_id = Db::table('school_contract_sign')->insertGetId($sign_data); return $sign_id; } catch (\Exception $e) { Log::error('保存合同签署记录失败', [ 'contract_id' => $contract_id, 'student_id' => $student_id, 'error' => $e->getMessage() ]); return false; } } /** * 获取签署关系专属的表单字段 * @param int $contract_sign_id 合同签署记录ID * @param array $student 学员信息 * @return array */ private function getSignSpecificFormFields($contract_sign_id, $student) { try { // 先获取签署记录以得到合同ID $sign_record = Db::table('school_contract_sign') ->where('id', $contract_sign_id) ->find(); if (!$sign_record) { Log::error('签署记录不存在', ['contract_sign_id' => $contract_sign_id]); return []; } $contract_id = $sign_record['contract_id']; // 优先获取该签署关系专属的字段配置 $configs = Db::table('school_document_data_source_config') ->where('contract_sign_id', $contract_sign_id) ->select() ->toArray(); // 如果该签署记录没有专属配置,则获取合同模板的基础配置 if (empty($configs)) { Log::info('该签署记录无专属配置,使用合同模板基础配置', [ 'contract_sign_id' => $contract_sign_id, 'contract_id' => $contract_id ]); $configs = Db::table('school_document_data_source_config') ->where('contract_id', $contract_id) ->whereNull('contract_sign_id') ->select() ->toArray(); } if (empty($configs)) { Log::warning('该合同无字段配置', [ 'contract_sign_id' => $contract_sign_id, 'contract_id' => $contract_id ]); return []; } $form_fields = []; foreach ($configs as $config) { // 基础字段信息 $field = [ 'name' => $config['placeholder'] ?? '', 'placeholder' => $config['placeholder'] ?? '', 'data_type' => $config['data_type'] ?? 'user_input', 'field_type' => $config['field_type'] ?? 'text', 'is_required' => (int)($config['is_required'] ?? 0), 'default_value' => $config['default_value'], 'validation_rule' => $config['validation_rule'] ?? '', 'sign_party' => $config['sign_party'] ?? '', ]; // 根据数据类型处理默认值 switch ($config['data_type'] ?? 'user_input') { case 'database': // 数据库类型:从相关表获取数据 $field['default_value'] = $this->getDatabaseFieldValueFromConfig($config, $student); break; case 'system': // 系统函数类型:调用系统函数获取值 $field['default_value'] = $this->getSystemFunctionValueFromConfig($config); break; case 'user_input': // 用户输入类型:使用配置的默认值 $field['default_value'] = $config['default_value'] ?? ''; break; case 'signature': // 电子签名类型:无默认值,需要用户手写签名 $field['signature_type'] = 'handwrite'; $field['default_value'] = $config['default_value'] ?? ''; break; case 'sign_img': // 签名图片类型:无默认值,需要用户上传或选择 $field['sign_image_source'] = 'upload'; $field['default_value'] = $config['default_value'] ?? ''; break; default: $field['default_value'] = $config['default_value'] ?? ''; break; } $form_fields[] = $field; } Log::info('获取签署关系专属字段完成', [ 'contract_sign_id' => $contract_sign_id, 'fields_count' => count($form_fields) ]); return $form_fields; } catch (\Exception $e) { Log::error('获取签署关系专属字段失败', [ 'contract_sign_id' => $contract_sign_id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return []; } } /** * 从配置中获取数据库字段值 * @param array $config 字段配置 * @param array $student 学员信息 * @return string */ private function getDatabaseFieldValueFromConfig($config, $student) { try { $table_name = $config['table_name'] ?? ''; $field_name = $config['field_name'] ?? ''; if (empty($table_name) || empty($field_name)) { return ''; } $value = ''; switch ($table_name) { case 'school_student': case 'students': // 兼容配置中的简化表名 // 学员表:使用CoreFieldMappingService进行字段映射和转义 $service = new CoreFieldMappingService('school_student', ['id' => $student['id']]); // 配置枚举映射 $service->setFieldEnums([ 'gender' => [0 => '未知', 1 => '男', 2 => '女'], 'status' => [0 => '无效', 1 => '有效', 2 => '过期', 3 => '结业'] ]); // 配置关联字段映射 $service->setFieldRelations([ 'user_id' => [ 'table' => 'school_customer_resources', 'display_field' => 'name', 'key_field' => 'id' ], 'campus_id' => [ 'table' => 'school_campus', 'display_field' => 'campus_name', 'key_field' => 'id' ], 'class_id' => [ 'table' => 'school_class', 'display_field' => 'class_name', 'key_field' => 'id' ], 'consultant_id' => [ 'table' => 'school_personnel', 'display_field' => 'name', 'key_field' => 'id' ], 'coach_id' => [ 'table' => 'school_personnel', 'display_field' => 'name', 'key_field' => 'id' ] ]); // 检查是否为关联字段,使用链式调用获取关联值 if (in_array($field_name, ['user_id', 'campus_id', 'class_id', 'consultant_id', 'coach_id'])) { $relation_config = $service->getRelationMapping()[$field_name]; $value = $service->getValueWithChain($field_name) ->withRelation( $relation_config['table'], $relation_config['display_field'], $relation_config['key_field'] ); } else { // 普通字段或枚举字段,自动转义枚举值 $value = $service->getValue($field_name); } break; case 'school_customer_resources': // 客户资源表:通过学员的user_id关联查询 if (!empty($student['user_id'])) { $service = new CoreFieldMappingService($config['table_name'], ['id' => $student['user_id']]); // 配置枚举映射 $service->setFieldEnums([ 'gender' => ['male' => '男性', 'female' => '女性', 'other' => '其他'], 'initial_intent' => ['high' => '高', 'medium' => '中', 'low' => '低'], 'rf_type' => ['market' => '市场人员新增', 'sale' => '销售人员新增', 'teacher' => '教练新增'], 'blacklist' => [1 => '可追单', 0 => '黑名单'] ]); $value = $service->getValue($field_name); } break; case 'school_order_table': // 订单表:使用CoreFieldMappingService进行字段映射和转义 $service = new CoreFieldMappingService($config['table_name'], ['contract_sign_id' => $config['contract_sign_id']]); // 配置枚举映射 $service->setFieldEnums([ 'order_type' => [1 => '新订单', 2 => '续费订单', 3 => '内部员工订单', 4 => '转校', 5 => '客户内转课订单'], 'order_status' => ['pending' => '待支付', 'paid' => '已支付', 'signed' => '待签约', 'completed' => '已完成', 'transfer' => '转学'], 'payment_type' => ['cash' => '现金支付', 'scan_code' => '扫码支付', 'subscription' => '订阅支付', 'wxpay_online' => '微信在线代付'], 'gift_type' => [1 => '减现', 2 => '赠课'] ]); // 配置关联字段映射 $service->setFieldRelations([ 'course_id' => [ 'table' => 'school_course', 'display_field' => 'course_name', 'key_field' => 'id' ], 'class_id' => [ 'table' => 'school_class', 'display_field' => 'class_name', 'key_field' => 'id' ], 'staff_id' => [ 'table' => 'school_personnel', 'display_field' => 'name', 'key_field' => 'id' ], 'resource_id' => [ 'table' => 'school_customer_resources', 'display_field' => 'name', 'key_field' => 'id' ], 'campus_id' => [ 'table' => 'school_campus', 'display_field' => 'CONCAT(campus_name, campus_address)', 'key_field' => 'id' ], 'gift_id' => [ 'table' => 'shcool_resources_gift', 'display_field' => 'gift_name', 'key_field' => 'id' ], 'course_plan_id' => [ 'table' => 'school_student_courses', 'display_field' => 'CONCAT("正式课时数量:", total_hours, ",赠送课时", gift_hours, ",课程有效期为", start_date, "至", end_date)', 'key_field' => 'id' ] ]); // 检查是否为关联字段,使用链式调用获取关联值 if (in_array($field_name, ['course_id', 'class_id', 'staff_id', 'resource_id', 'campus_id', 'gift_id', 'course_plan_id'])) { $relation_config = $service->getRelationMapping()[$field_name]; $value = $service->getValueWithChain($field_name) ->withRelation( $relation_config['table'], $relation_config['display_field'], $relation_config['key_field'] ); } else { // 普通字段或枚举字段,自动转义枚举值 $value = $service->getValue($field_name); } break; case 'school_personnel': // 员工表:这里可能需要根据业务逻辑确定关联的员工 // 暂时返回空值,具体业务逻辑需要根据实际需求调整 $value = ''; break; default: Log::warning('不支持的数据库表', [ 'table_name' => $table_name, 'field_name' => $field_name ]); break; } // 对特殊字段进行格式化处理 $value = $this->formatFieldValue($field_name, $value); return (string)$value; } catch (\Exception $e) { Log::error('从配置获取数据库字段值失败', [ 'config' => $config, 'student_id' => $student['id'], 'error' => $e->getMessage() ]); return ''; } } /** * 从配置中获取系统函数值 * @param array $config 字段配置 * @return string */ private function getSystemFunctionValueFromConfig($config) { try { $system_function = $config['system_function'] ?? ''; if (empty($system_function)) { return ''; } // 检查函数是否存在 if (!function_exists($system_function)) { Log::warning('系统函数不存在', [ 'function_name' => $system_function ]); return ''; } // 调用系统函数 $value = call_user_func($system_function); Log::info('系统函数调用成功', [ 'function_name' => $system_function, 'result' => $value ]); return (string)$value; } catch (\Exception $e) { Log::error('从配置获取系统函数值失败', [ 'config' => $config, 'error' => $e->getMessage() ]); return ''; } } /** * 员工端合同签署提交 * 处理员工端提交的合同签署表单数据,员工可以填写甲乙双方所有字段 * * @param array $params 提交参数 * - contract_id: 合同模板ID * - contract_sign_id: 合同签署记录ID * - personnel_id: 员工ID * - form_data: 表单数据数组 * - signature_image: 签名图片数据 * @return array 提交结果 */ public function submitStaffContractSign(array $params) { try { // 验证必要参数 if (empty($params['contract_id']) || empty($params['contract_sign_id']) || empty($params['personnel_id'])) { throw new \Exception('缺少必要参数:contract_id、contract_sign_id、personnel_id'); } $contract_id = (int)$params['contract_id']; $contract_sign_id = (int)$params['contract_sign_id']; $personnel_id = (int)$params['personnel_id']; $form_data = $params['form_data'] ?? []; $signature_image = $params['signature_image'] ?? ''; Log::info('开始处理员工端合同签署提交', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'personnel_id' => $personnel_id, 'form_data_keys' => array_keys($form_data) ]); // 验证合同签署记录是否存在 $sign_record = Db::table('school_contract_sign') ->where('id', $contract_sign_id) ->where('contract_id', $contract_id) ->find(); if (!$sign_record) { throw new \Exception('合同签署记录不存在'); } // 事务处理 Db::startTrans(); try { // 1. 保存表单数据到 school_document_data_source_config 表 $this->saveFormDataToConfig($contract_id, $contract_sign_id, $form_data, 'staff'); // 2. 更新合同签署记录状态 $this->updateContractSignStatus($contract_sign_id, $personnel_id, $signature_image); Db::commit(); Log::info('员工端合同签署成功', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'personnel_id' => $personnel_id ]); return [ 'code' => 1, 'msg' => '合同签署成功', 'data' => ['contract_sign_id' => $contract_sign_id] ]; } catch (\Exception $e) { Db::rollback(); throw $e; } } catch (\Exception $e) { Log::error('员工端合同签署失败', [ 'params' => $params, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'code' => 0, 'msg' => $e->getMessage(), 'data' => [] ]; } } /** * 学员端合同签署提交(新版本) * 处理学员端提交的合同签署表单数据,学员只能填写乙方字段 * * @param array $params 提交参数 * - contract_id: 合同模板ID * - contract_sign_id: 合同签署记录ID * - student_id: 学员ID * - form_data: 表单数据数组 * - signature_image: 签名图片数据 * @return array 提交结果 */ public function submitStudentContractSign(array $params) { try { // 验证必要参数 if (empty($params['contract_id']) || empty($params['contract_sign_id']) || empty($params['student_id'])) { throw new \Exception('缺少必要参数:contract_id、contract_sign_id、student_id'); } $contract_id = (int)$params['contract_id']; $contract_sign_id = (int)$params['contract_sign_id']; $student_id = (int)$params['student_id']; $form_data = $params['form_data'] ?? []; $signature_image = $params['signature_image'] ?? ''; Log::info('开始处理学员端合同签署提交', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'student_id' => $student_id, 'form_data_keys' => array_keys($form_data) ]); // 验证合同签署记录是否存在 $sign_record = Db::table('school_contract_sign') ->where('id', $contract_sign_id) ->where('contract_id', $contract_id) ->where('student_id', $student_id) ->find(); if (!$sign_record) { throw new \Exception('合同签署记录不存在'); } // 验证学员是否存在 $student = Db::table('school_student') ->where('id', $student_id) ->where('status', 1) ->find(); if (!$student) { throw new \Exception('学员信息不存在'); } // 事务处理 Db::startTrans(); try { // 1. 过滤学员端只能填写的字段(乙方字段) $filtered_form_data = $this->filterStudentFormData($contract_id, $contract_sign_id, $form_data); // 2. 保存表单数据到 school_document_data_source_config 表 $this->saveFormDataToConfig($contract_id, $contract_sign_id, $filtered_form_data, 'student'); // 3. 更新合同签署记录状态 $this->updateContractSignStatus($contract_sign_id, null, $signature_image, $student_id); Db::commit(); Log::info('学员端合同签署成功', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'student_id' => $student_id ]); return [ 'code' => 1, 'msg' => '合同签署成功', 'data' => ['contract_sign_id' => $contract_sign_id] ]; } catch (\Exception $e) { Db::rollback(); throw $e; } } catch (\Exception $e) { Log::error('学员端合同签署失败', [ 'params' => $params, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'code' => 0, 'msg' => $e->getMessage(), 'data' => [] ]; } } /** * 保存表单数据到 school_document_data_source_config 表的 default_value 字段 * 这是核心方法,确保数据正确写入到指定表中 * * @param int $contract_id 合同模板ID * @param int $contract_sign_id 合同签署记录ID * @param array $form_data 表单数据 * @param string $user_type 用户类型(staff/student) * @return bool */ private function saveFormDataToConfig($contract_id, $contract_sign_id, $form_data, $user_type) { try { Log::info('开始保存表单数据到 school_document_data_source_config', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'user_type' => $user_type, 'form_data_count' => count($form_data) ]); $now = date('Y-m-d H:i:s'); $success_count = 0; $total_count = count($form_data); foreach ($form_data as $placeholder => $value) { // 检查该字段配置是否已存在 $existing_config = Db::table('school_document_data_source_config') ->where('contract_id', $contract_id) ->where('contract_sign_id', $contract_sign_id) ->where('placeholder', $placeholder) ->find(); if ($existing_config) { // 更新已存在的配置记录的 default_value 字段 $update_result = Db::table('school_document_data_source_config') ->where('id', $existing_config['id']) ->update([ 'default_value' => (string)$value, 'updated_at' => $now ]); if ($update_result) { $success_count++; Log::info('更新字段配置成功', [ 'config_id' => $existing_config['id'], 'placeholder' => $placeholder, 'value' => $value ]); } else { Log::warning('更新字段配置失败', [ 'config_id' => $existing_config['id'], 'placeholder' => $placeholder, 'value' => $value ]); } } else { // 创建新的配置记录(这种情况说明配置数据可能缺失) $config_data = [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'placeholder' => $placeholder, 'data_type' => 'user_input', // 默认为用户输入类型 'field_type' => 'text', // 默认为文本类型 'default_value' => (string)$value, 'is_required' => 0, 'sign_party' => '', // 需要根据字段名推断甲乙方 'created_at' => $now, 'updated_at' => $now, 'created_by' => $user_type, 'updated_by' => $user_type, 'deleted_at' => 0 ]; $insert_result = Db::table('school_document_data_source_config')->insertGetId($config_data); if ($insert_result) { $success_count++; Log::info('创建字段配置成功', [ 'config_id' => $insert_result, 'placeholder' => $placeholder, 'value' => $value ]); } else { Log::warning('创建字段配置失败', [ 'placeholder' => $placeholder, 'value' => $value ]); } } } Log::info('表单数据保存完成', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'user_type' => $user_type, 'total_count' => $total_count, 'success_count' => $success_count ]); // 如果所有数据都保存成功,返回 true return $success_count === $total_count; } catch (\Exception $e) { Log::error('保存表单数据到配置表失败', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'user_type' => $user_type, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); throw $e; } } /** * 过滤学员端表单数据,只保留乙方字段 * * @param int $contract_id 合同模板ID * @param int $contract_sign_id 合同签署记录ID * @param array $form_data 原始表单数据 * @return array 过滤后的表单数据 */ private function filterStudentFormData($contract_id, $contract_sign_id, $form_data) { try { // 获取该签署记录的字段配置 $configs = Db::table('school_document_data_source_config') ->where('contract_id', $contract_id) ->where('contract_sign_id', $contract_sign_id) ->select() ->toArray(); $filtered_data = []; foreach ($form_data as $placeholder => $value) { // 查找对应的字段配置 $config = array_filter($configs, function ($c) use ($placeholder) { return $c['placeholder'] === $placeholder; }); if (!empty($config)) { $config = array_values($config)[0]; $sign_party = $config['sign_party'] ?? ''; // 学员只能填写乙方字段 if (in_array($sign_party, ['second_party', 'party_b', '乙方', ''])) { $filtered_data[$placeholder] = $value; Log::info('学员字段通过过滤', [ 'placeholder' => $placeholder, 'sign_party' => $sign_party, 'value' => $value ]); } else { Log::warning('学员字段被过滤', [ 'placeholder' => $placeholder, 'sign_party' => $sign_party, 'reason' => '学员只能填写乙方字段' ]); } } else { // 如果没有找到配置,保守处理:允许提交但记录警告 $filtered_data[$placeholder] = $value; Log::warning('未找到字段配置,默认允许', [ 'placeholder' => $placeholder, 'value' => $value ]); } } Log::info('学员表单数据过滤完成', [ 'original_count' => count($form_data), 'filtered_count' => count($filtered_data) ]); return $filtered_data; } catch (\Exception $e) { Log::error('过滤学员表单数据失败', [ 'contract_id' => $contract_id, 'contract_sign_id' => $contract_sign_id, 'error' => $e->getMessage() ]); // 出现异常时返回原始数据,避免阻断流程 return $form_data; } } /** * 更新合同签署记录状态 * * @param int $contract_sign_id 合同签署记录ID * @param int|null $personnel_id 员工ID(员工签署时传入) * @param string $signature_image 签名图片 * @param int|null $student_id 学员ID(学员签署时传入) * @return bool */ private function updateContractSignStatus($contract_sign_id, $personnel_id = null, $signature_image = '', $student_id = null) { try { $now = date('Y-m-d H:i:s'); $update_data = [ 'status' => 2, // 已签署 'sign_time' => $now, 'updated_at' => $now ]; // 如果有签名图片,保存签名图片路径 if (!empty($signature_image)) { $update_data['signature_image'] = $signature_image; } $result = Db::table('school_contract_sign') ->where('id', $contract_sign_id) ->update($update_data); if ($result) { Log::info('合同签署记录状态更新成功', [ 'contract_sign_id' => $contract_sign_id, 'personnel_id' => $personnel_id, 'student_id' => $student_id, 'signature_image_length' => strlen($signature_image) ]); return true; } else { Log::warning('合同签署记录状态更新失败', [ 'contract_sign_id' => $contract_sign_id, 'update_data' => $update_data ]); return false; } } catch (\Exception $e) { Log::error('更新合同签署记录状态失败', [ 'contract_sign_id' => $contract_sign_id, 'personnel_id' => $personnel_id, 'student_id' => $student_id, 'error' => $e->getMessage() ]); throw $e; } } }