getPdo(); $stmt = $pdo->prepare("SELECT * FROM preliminary_data WHERE id = ? AND is_active = 1"); $stmt->execute([$id]); $frag = $stmt->fetch(); if (!$frag) { Response::error('碎片不存在'); } if ($frag['converted_id']) { Response::error('该碎片已处理(已转换)'); } $companyName = trim($_POST['company_name'] ?? ($frag['company_name'] ?? '')); $personName = trim($_POST['person_name'] ?? ($frag['person_name'] ?? '')); $phone = trim($_POST['contact_phone'] ?? ($frag['contact_phone'] ?? '')); $email = trim($_POST['contact_email'] ?? ($frag['contact_email'] ?? '')); $industry = trim($_POST['industry'] ?? ($frag['industry'] ?? '')); // 核心-企业(转软碎片必填) $registrationNum = trim($_POST['registration_number'] ?? ($frag['registration_number'] ?? '')); // 核心-企业(转软碎片必填) $businessRole = trim($_POST['business_role'] ?? ($frag['business_role'] ?? '')); $country = trim($_POST['country'] ?? ($frag['country'] ?? '')); $address = trim($_POST['address'] ?? ($frag['address'] ?? '')); $workLocation = trim($_POST['work_location'] ?? ($frag['work_location'] ?? '')); $idNumber = trim($_POST['id_number'] ?? ($frag['id_number'] ?? '')); $platform = trim($_POST['platform'] ?? ($frag['platform'] ?? '')); $accountId = trim($_POST['account_id'] ?? ($frag['account_id'] ?? '')); $profileUrl = trim($_POST['profile_url'] ?? ($frag['profile_url'] ?? '')); $sourceChannel = $frag['source_channel'] ?? null; $convertedId = 0; // 格式校验:手机 / 邮箱 / 身份证 / 主页链接 checkFieldFormat('phone', $phone); checkFieldFormat('email', $email); checkFieldFormat('id_number', $idNumber); if ($profileUrl !== '' && !preg_match('/^https?:\/\//i', $profileUrl)) { Response::error('主页链接格式不正确(应以 http:// 或 https:// 开头)', 400); } // 各类型转软碎片基本要求 switch ($targetType) { case 'company': if ($companyName === '') { Response::error('企业类型转软碎片:企业名称为必填项,请先「手动补全」', 400); } if ($industry === '') { Response::error('企业类型转软碎片:行业为必填项,请先「手动补全」填写行业', 400); } if ($registrationNum === '') { Response::error('企业类型转软碎片:注册号为必填项,请先「手动补全」填写注册号', 400); } break; case 'person': if ($personName === '') { Response::error('人员类型转软碎片:姓名为必填项,请先「手动补全」', 400); } if ($phone === '' && $email === '') { Response::error('人员类型转软碎片:手机号码、邮箱至少填写一项,请先「手动补全」', 400); } break; case 'product': if ($companyName === '') { Response::error('产品类型转软碎片:公司名称为必填项,请先「手动补全」', 400); } break; case 'need': if ($companyName === '') { Response::error('需求类型转软碎片:公司名称为必填项,请先「手动补全」', 400); } break; } // 唯一性校验:按目标类型,收集全部重复 $dups = []; if ($targetType === 'company' && $companyName !== '') { $dup = findDuplicate($pdo, 'company_name', $companyName); if ($dup) $dups[] = $dup; } if (in_array($targetType, ['person', 'company'], true)) { $dups = array_merge($dups, checkSingleAccountDuplicate($pdo, $phone !== '' ? 'phone' : '', $phone, '')); $dups = array_merge($dups, checkSingleAccountDuplicate($pdo, $email !== '' ? 'email' : '', $email, '')); } if (!empty($dups)) Response::duplicates($dups); /** 创建 social_accounts(phone/email,常用) */ $saveContacts = function ($ownerType, $ownerId) use ($pdo, $phone, $email) { if ($phone !== '') { $pdo->prepare( "INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, is_primary, is_defult) VALUES (?, ?, 'phone', ?, 1, 1)" )->execute([$ownerType, $ownerId, $phone]); } if ($email !== '') { $pdo->prepare( "INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, is_primary, is_defult) VALUES (?, ?, 'email', ?, 1, 1)" )->execute([$ownerType, $ownerId, $email]); } }; /** 写入社媒账号(platform + account_id,主页链接作备注) */ function saveSocialAccountIfAny(PDO $pdo, $ownerType, $ownerId, $platform, $accountId, $profileUrl = '') { $platform = trim((string)$platform); $accountId = trim((string)$accountId); if ($platform === '' || $accountId === '' || in_array($platform, ['phone', 'email'], true)) { return; } $pdo->prepare( "INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, is_primary, is_defult) VALUES (?, ?, ?, ?, ?, 0, 0)" )->execute([$ownerType, $ownerId, $platform, $accountId, trim((string)$profileUrl) !== '' ? $profileUrl : null]); } /** 按名称找公司,找不到则自动创建 */ $resolveCompany = function () use ($pdo, $companyName, $sourceChannel, $industry, $registrationNum) { $stmt = $pdo->prepare("SELECT id FROM companies WHERE display_name = ? AND is_active = 1 LIMIT 1"); $stmt->execute([$companyName]); $cid = (int)$stmt->fetchColumn(); if ($cid > 0) { return $cid; } $pdo->prepare( "INSERT INTO companies (display_name, name_zh, industry, registration_number, source_channel) VALUES (?, ?, ?, ?, ?)" )->execute([$companyName, $companyName, $industry !== '' ? $industry : null, $registrationNum !== '' ? $registrationNum : null, $sourceChannel]); return (int)$pdo->lastInsertId(); }; switch ($targetType) { case 'company': $pdo->prepare( "INSERT INTO companies (display_name, name_zh, industry, registration_number, business_role, country, address, source_channel) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" )->execute([ $companyName, $companyName, $industry !== '' ? $industry : null, $registrationNum !== '' ? $registrationNum : null, $businessRole !== '' ? $businessRole : null, $country !== '' ? $country : null, $address !== '' ? $address : null, $sourceChannel, ]); $convertedId = (int)$pdo->lastInsertId(); $saveContacts('company', $convertedId); saveSocialAccountIfAny($pdo, 'company', $convertedId, $platform, $accountId, $profileUrl); updateIncomplete($pdo, 'companies', $convertedId); updateAccountsIncomplete($pdo, 'company', $convertedId); break; case 'person': $unionId = 'P' . date('YmdHis') . substr(uniqid(), -6); $pdo->prepare( "INSERT INTO persons (union_id, full_name, work_location, id_number, source_channel) VALUES (?, ?, ?, ?, ?)" )->execute([ $unionId, $personName, $workLocation !== '' ? $workLocation : null, $idNumber !== '' ? $idNumber : null, $sourceChannel, ]); $convertedId = (int)$pdo->lastInsertId(); $saveContacts('person', $convertedId); saveSocialAccountIfAny($pdo, 'person', $convertedId, $platform, $accountId, $profileUrl); updateIncomplete($pdo, 'persons', $convertedId); updateAccountsIncomplete($pdo, 'person', $convertedId); break; case 'product': $companyId = $resolveCompany(); // 品类字段已在 preliminary 移除(非必要/待定),转换时默认「未分类」 $pdo->prepare( "INSERT INTO company_products (company_id, category_name) VALUES (?, '未分类')" )->execute([$companyId]); $convertedId = (int)$pdo->lastInsertId(); updateIncomplete($pdo, 'companies', $companyId); break; case 'need': $companyId = $resolveCompany(); $contactPerson = trim($_POST['contact_person'] ?? ($frag['person_name'] ?? '')); $pdo->prepare( "INSERT INTO company_needs (company_id, contact_person, description) VALUES (?, ?, ?)" )->execute([ $companyId, $contactPerson !== '' ? $contactPerson : null, null, ]); $convertedId = (int)$pdo->lastInsertId(); updateIncomplete($pdo, 'companies', $companyId); break; } // 标记碎片已转换(v1.0.50 起不再写 status 字段,以 converted_id 非空标识已转换) $pdo->prepare( "UPDATE preliminary_data SET converted_type = ?, converted_id = ?, processed_at = NOW() WHERE id = ?" )->execute([$targetType, $convertedId, $id]); logCurrent('convert', 'fragment', 'preliminary_data', $id, [ 'target_type' => $targetType, 'converted_id' => $convertedId, 'fields' => ['company_name' => $companyName, 'person_name' => $personName, 'phone' => $phone, 'email' => $email], ]); Response::success(['converted_type' => $targetType, 'converted_id' => $convertedId], '转换成功');