类型标记:s字符串/i整数/d日期/n数字) */ const COMPANY_FIELDS = [ 'name_zh' => 's', 'name_en' => 's', 'display_name' => 's', 'business_role' => 's', 'country' => 's', 'registration_number' => 's', 'address' => 's', 'legal_form' => 's', 'legal_representative' => 's', 'business_scope' => 's', 'established_date' => 'd', 'registered_capital' => 's', 'industry' => 's', 'industry_subdivision' => 's', 'latest_employee_count' => 'i', 'latest_annual_revenue' => 's', 'is_listed' => 'i', 'stock_code' => 's', 'website' => 's', 'source_channel' => 's', 'source_detail' => 's', ]; /** 人员表可写入字段白名单 */ const PERSON_FIELDS = [ 'union_id' => 's', 'full_name' => 's', 'gender' => 's', 'nationality' => 's', 'id_type' => 's', 'id_number' => 's', 'education' => 's', 'graduated_from' => 's', 'hometown' => 's', 'work_location' => 's', 'source_channel' => 's', 'source_detail' => 's', ]; /** 媒体(社交账号)表可写入字段白名单 */ const MEDIA_FIELDS = [ 'owner_type' => 's', 'owner_id' => 'i', 'platform' => 's', 'account_id' => 's', 'profile_url' => 's', 'remark' => 's', 'is_primary' => 'i', 'is_defult' => 'i', ]; /** 媒体商业属性表可写入字段白名单 */ const MEDIA_ATTR_FIELDS = [ 'account_level' => 's', 'content_categories' => 's', 'follower_count' => 'i', 'avg_read_count' => 'i', 'certification_type' => 's', 'special_requirements' => 's', 'media_remark' => 's', ]; /** 需求表可写入字段白名单 */ const NEED_FIELDS = [ 'company_id' => 'i', 'contact_person' => 's', 'need_category' => 's', 'target_product_category' => 's', 'application_scenario' => 's', 'description' => 's', ]; /** * 从 POST 中按白名单提取并清洗数据 * @param array $allowlist * @return array */ function extractFields($allowlist) { $data = []; foreach ($allowlist as $key => $type) { $val = $_POST[$key] ?? null; if ($val === null) { continue; } $val = trim((string)$val); if ($val === '') { continue; } switch ($type) { case 'i': $data[$key] = (int)$val; break; case 'd': $data[$key] = (strtotime($val) !== false) ? date('Y-m-d', strtotime($val)) : null; break; default: $data[$key] = $val; } } return $data; } /** 生成 INSERT 语句片段:字段名列表 + 占位符 */ function buildInsert($data) { $cols = array_keys($data); $sql = '(`' . implode('`,`', $cols) . '`) VALUES (' . rtrim(str_repeat('?,', count($cols)), ',') . ')'; return [$sql, array_values($data)]; } /** 生成 UPDATE SET 片段 */ function buildUpdate($data) { $sets = []; foreach (array_keys($data) as $col) { $sets[] = "`$col` = ?"; } return [implode(',', $sets), array_values($data)]; } /** 数字字符串或 null(空串转 null,避免写入空值) */ function numOrNull($v) { $v = trim((string)$v); return ($v === '') ? null : $v; } /** 字符串或 null(空串转 null) */ function strOrNull($v) { if ($v === null) { return null; } $v = trim((string)$v); return ($v === '') ? null : $v; } /** * 保存人员工作履历(整表替换:先删后插) * @param PDO $pdo * @param int $personId * @param array $experiences JSON 解码后的数组 [{company_id,position,department,job_level,start_date,end_date,is_current}] */ function savePersonExperiences($pdo, $personId, $experiences) { $del = $pdo->prepare("DELETE FROM person_work_experiences WHERE person_id = ?"); $del->execute([$personId]); if (empty($experiences)) { return; } $ins = $pdo->prepare( "INSERT INTO person_work_experiences (person_id, company_id, position, department, job_level, start_date, end_date, is_current) VALUES (?,?,?,?,?,?,?,?)" ); foreach ($experiences as $e) { if (!is_array($e)) { continue; } $companyId = (int)($e['company_id'] ?? 0); if ($companyId <= 0) { continue; } $start = strOrNull($e['start_date'] ?? null); $end = strOrNull($e['end_date'] ?? null); $ins->execute([ $personId, $companyId, strOrNull($e['position'] ?? null), strOrNull($e['department'] ?? null), strOrNull($e['job_level'] ?? null), $start !== null && strtotime($start) !== false ? date('Y-m-d', strtotime($start)) : null, $end !== null && strtotime($end) !== false ? date('Y-m-d', strtotime($end)) : null, !empty($e['is_current']) ? 1 : 0, ]); } } /** * 保存企业联系方式(social_accounts,整表替换:先删后插) * 只操作 owner_type = 'company' 的记录 * @param PDO $pdo * @param int $companyId * @param array $accounts JSON 解码后的数组 [{platform,account_id,profile_url,remark,is_active,is_defult}] */ function saveCompanyAccounts($pdo, $companyId, $accounts) { $del = $pdo->prepare("DELETE FROM social_accounts WHERE owner_type = 'company' AND owner_id = ?"); $del->execute([$companyId]); if (empty($accounts)) { return; } $ins = $pdo->prepare( "INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, remark, is_primary, is_defult, is_active) VALUES ('company', ?, ?, ?, ?, ?, 0, ?, ?)" ); foreach ($accounts as $a) { if (!is_array($a)) { continue; } $platform = trim($a['platform'] ?? ''); $accountId = trim($a['account_id'] ?? ''); if ($platform === '' || $accountId === '') { continue; } $ins->execute([ $companyId, $platform, $accountId, strOrNull($a['profile_url'] ?? null), strOrNull($a['remark'] ?? null), !empty($a['is_defult']) ? 1 : 0, !empty($a['is_active']) ? 1 : 0, ]); } } /** * 保存企业年度财务明细(整表替换:先删后插) * @param PDO $pdo * @param int $companyId * @param array $financials JSON 解码后的数组 */ function saveCompanyFinancials($pdo, $companyId, $financials) { $del = $pdo->prepare("DELETE FROM company_financials WHERE company_id = ?"); $del->execute([$companyId]); if (empty($financials)) { return; } $ins = $pdo->prepare( "INSERT INTO company_financials (company_id, fiscal_year, employee_count, total_revenue, net_profit, total_assets, total_liabilities, owner_equity, gross_margin, net_margin, debt_ratio, financial_report_url, data_source) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)" ); $seen = []; foreach ($financials as $f) { if (!is_array($f)) { continue; } $year = (int)($f['fiscal_year'] ?? 0); if ($year < 1990 || $year > 2100) { continue; } if (isset($seen[$year])) { continue; // 同一财年只保留一条 } $seen[$year] = true; $ins->execute([ $companyId, $year, numOrNull($f['employee_count'] ?? null), numOrNull($f['total_revenue'] ?? null), numOrNull($f['net_profit'] ?? null), numOrNull($f['total_assets'] ?? null), numOrNull($f['total_liabilities'] ?? null), numOrNull($f['owner_equity'] ?? null), numOrNull($f['gross_margin'] ?? null), numOrNull($f['net_margin'] ?? null), numOrNull($f['debt_ratio'] ?? null), strOrNull($f['financial_report_url'] ?? null), strOrNull($f['data_source'] ?? null) ?? '手动录入', ]); } } /** * 保存企业资质认证(整表替换:先删后插) * @param PDO $pdo * @param int $companyId * @param array $certifications JSON 解码后的数组 */ function saveCompanyCertifications($pdo, $companyId, $certifications) { $del = $pdo->prepare("DELETE FROM company_certifications WHERE company_id = ?"); $del->execute([$companyId]); if (empty($certifications)) { return; } $valid = $pdo->prepare("SELECT id FROM data_dict_certificate WHERE id = ?"); $ins = $pdo->prepare( "INSERT INTO company_certifications (company_id, certification_type_id, certificate_number, level, issuing_authority, issue_date, expiry_date) VALUES (?,?,?,?,?,?,?)" ); $seen = []; foreach ($certifications as $ct) { if (!is_array($ct)) { continue; } $tid = (int)($ct['certification_type_id'] ?? 0); if ($tid <= 0 || isset($seen[$tid])) { continue; } $valid->execute([$tid]); if (!$valid->fetch()) { continue; // 认证类型不存在 } $seen[$tid] = true; $ins->execute([ $companyId, $tid, strOrNull($ct['certificate_number'] ?? null), strOrNull($ct['level'] ?? null), strOrNull($ct['issuing_authority'] ?? null), strOrNull($ct['issue_date'] ?? null), strOrNull($ct['expiry_date'] ?? null), ]); } }