['emoji' => '🟢', 'text' => 'похоже клиент'], 'unclear' => ['emoji' => '🟡', 'text' => 'неясно'], 'spam' => ['emoji' => '🔴', 'text' => 'похоже спам'], ]; /** * @param array{ * fields:array, * classification:array{score:int,label:string,reasons:array}, * site_title:string, * form_title:string, * submitted_at:string, * reason:string, * ip:string, * user_agent:string, * is_retro:bool * } $ctx * * @return array{text:string,reply_markup:array|null} */ public static function build(array $ctx): array { $fields = $ctx['fields']; $class = $ctx['classification']; $phone = PhoneParser::parse(self::flatten_fields_for_phone($fields)); $name = self::pick($fields, ['your-name', 'name', 'имя', 'fio']); $email = self::pick($fields, ['your-email', 'email', 'e-mail', 'mail']); $message = self::pick($fields, ['your-message', 'message', 'comment', 'сообщение', 'вопрос']); $lines = []; $label_info = self::LABEL_MAP[$class['label']] ?? self::LABEL_MAP['unclear']; $header = ($ctx['is_retro'] ? '📂 Ретроспектива · ' : '') . $label_info['emoji'] . ' ' . $label_info['text']; $lines[] = $header; $lines[] = '🌐 ' . esc_html($ctx['site_title']) . ' · форма «' . esc_html($ctx['form_title']) . '»'; $lines[] = '🗓 ' . esc_html($ctx['submitted_at']); $lines[] = ''; $lines[] = '📱 ' . ($phone !== null ? esc_html($phone['pretty']) : '(не указан)'); $lines[] = '👤 ' . ($name !== '' ? esc_html($name) : '(не указано)'); $lines[] = '📧 ' . ($email !== '' ? esc_html($email) : '(не указан)'); $lines[] = ''; $lines[] = '💬 ' . ($message !== '' ? esc_html($message) : '(пусто)'); $lines[] = ''; $lines[] = '⚙️ Попало в спам: ' . esc_html($ctx['reason']); $lines[] = '📊 Классификация: ' . self::format_reasons($class['reasons']); $meta_bits = []; if ($ctx['ip'] !== '') $meta_bits[] = 'IP ' . esc_html($ctx['ip']); if ($ctx['user_agent'] !== '') $meta_bits[] = 'UA ' . esc_html(self::shorten_ua($ctx['user_agent'])); if ($meta_bits) $lines[] = '🌍 ' . implode(' · ', $meta_bits); $utms = self::extract_utms($fields); if ($utms !== '') $lines[] = '🏷 ' . $utms; $other = self::extract_other_fields($fields); if ($other !== '') $lines[] = '📋 ' . $other; $text = implode("\n", $lines); $text = self::truncate($text); $markup = null; if ($phone !== null) { $markup = [ 'inline_keyboard' => [[ ['text' => '📞 Позвонить: ' . $phone['pretty'], 'url' => 'tel:' . $phone['e164']], ]], ]; } return ['text' => $text, 'reply_markup' => $markup]; } private static function pick(array $fields, array $keys): string { foreach ($keys as $k) { if (isset($fields[$k])) { $v = $fields[$k]; if (is_array($v)) $v = implode(' ', $v); return trim((string)$v); } } return ''; } private static function flatten_fields_for_phone(array $fields): string { $out = []; foreach ($fields as $k => $v) { if (is_array($v)) $v = implode(' ', array_map('strval', $v)); $out[] = (string)$v; } return implode("\n", $out); } private static function format_reasons(array $reasons): string { if (!$reasons) return '—'; $parts = []; foreach ($reasons as $r) { $parts[] = $r['sign'] . $r['weight'] . ' ' . $r['text']; } return esc_html(implode(', ', $parts)); } private static function shorten_ua(string $ua): string { $ua = preg_replace('/\s+/', ' ', $ua) ?? $ua; if (mb_strlen($ua) > 80) $ua = mb_substr($ua, 0, 80) . '…'; return $ua; } private static function extract_utms(array $fields): string { $keys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; $parts = []; foreach ($keys as $k) { if (!empty($fields[$k])) { $v = is_array($fields[$k]) ? implode(' ', $fields[$k]) : (string)$fields[$k]; $parts[] = esc_html($k) . '=' . esc_html($v); } } return implode(' · ', $parts); } private static function extract_other_fields(array $fields): string { $known = [ 'your-name', 'name', 'имя', 'fio', 'your-email', 'email', 'e-mail', 'mail', 'your-tel', 'tel', 'phone', 'телефон', 'your-message', 'message', 'comment', 'сообщение', 'вопрос', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', '_wpcf7', '_wpcf7_version', '_wpcf7_locale', '_wpcf7_unit_tag', '_wpcf7_container_post', '_wpcf7_posted_data_hash', 'g-recaptcha-response', ]; $parts = []; foreach ($fields as $k => $v) { if (in_array($k, $known, true)) continue; if (strpos($k, 'wpcf7') === 0) continue; if (is_array($v)) $v = implode(', ', array_map('strval', $v)); $v = trim((string)$v); if ($v === '') continue; $parts[] = esc_html($k) . ': ' . esc_html($v); } return implode(' · ', $parts); } private static function truncate(string $text): string { if (mb_strlen($text) <= self::TG_MAX_LEN) return $text; $suffix = "\n…[обрезано]"; $cut = self::TG_MAX_LEN - mb_strlen($suffix); return mb_substr($text, 0, $cut) . $suffix; } }