text($item, 'Title'); if ($title === '') { throw new InvalidArgumentException('新闻缺少标题'); } $newsId = $this->text($item, 'NewsId'); $id = $this->text($item, 'Id'); $url = $this->text($item, 'Url'); $identity = $newsId !== '' ? 'news:'.$newsId : ($id !== '' ? 'id:'.$id : 'url:'.$url); if ($newsId === '' && $id === '' && $url === '') { throw new InvalidArgumentException('新闻缺少 NewsId、Id 和原文链接,无法去重'); } foreach (['NewsId' => 255, 'Id' => 255, 'Source' => 255, 'EmotionType' => 50] as $field => $max) { if (mb_strlen($this->text($item, $field)) > $max) { throw new InvalidArgumentException($field.' 字段过长'); } } $published = $this->text($item, 'PublishTime'); if ($published !== '' && !Carbon::hasFormat($published, 'Y-m-d H:i:s')) { throw new InvalidArgumentException('新闻发布时间格式不正确'); } $codes = $this->parts($this->text($item, 'Category')); $names = $this->parts($this->text($item, 'CategoryDesc')); $categories = []; foreach ($codes as $i => $code) { $categories[] = ['code' => $code, 'name' => $names[$i] ?? '']; } $news = CompanyNews::firstOrNew([ 'company_id' => $task->company_id, 'provider' => 'yuanhe-qcc', 'dedup_key' => hash('sha256', $identity), ]); $new = !$news->exists; if ($new) { $news->fill([ 'company_name_snapshot' => $task->company_name, 'title' => $title, 'first_seen_at' => now(), 'first_task_id' => $task->id, 'review_status' => 'pending', 'is_visible' => false, ]); } // Never write editorial fields, review decisions or visibility on a repeated import. $news->fill([ 'external_id' => $id ?: null, 'external_news_id' => $newsId ?: null, 'source_title' => $title, 'source_name' => $this->text($item, 'Source'), 'source_url' => $url, 'source_content' => $this->text($item, 'Content'), 'source_published_at' => $published ?: null, 'news_tags' => $this->parts($this->text($item, 'NewsTags')), 'categories' => $categories, 'emotion_type' => $this->text($item, 'EmotionType'), 'raw_payload' => $item, 'last_seen_at' => now(), 'last_task_id' => $task->id, ])->save(); return $new; } private function text(array $item, string $key): string { if (isset($item[$key]) && !is_scalar($item[$key])) { throw new InvalidArgumentException($key.' 字段格式不正确'); } return trim((string) ($item[$key] ?? '')); } private function parts(string $text): array { return array_values(array_filter(array_map('trim', explode(',', $text)), fn ($v) => $v !== '')); } }