import Foundation @Observable final class SearchViewModel { var query = "" var results: [ContentItem] = [] var isSearching = false var isLoadingMore = false var currentPage = 1 var totalPages = 1 var error: String? var hasSearched = false @MainActor func search() async { let trimmed = query.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { return } isSearching = true error = nil hasSearched = true currentPage = 1 totalPages = 1 results = [] do { let html = try await APIClient.shared.fetchSearchPage(query: trimmed) let items = try HTMLParser.parseContentList(html: html) let pagination = try HTMLParser.parsePagination(html: html) self.results = items self.currentPage = pagination.current self.totalPages = pagination.total } catch is CancellationError { } catch let error as URLError where error.code == .cancelled { } catch { self.error = error.localizedDescription } isSearching = false } @MainActor func loadMore() async { guard !isSearching, !isLoadingMore, currentPage < totalPages else { return } isLoadingMore = true let nextPage = currentPage + 1 do { let html = try await APIClient.shared.fetchSearchPage(query: query, page: nextPage) let items = try HTMLParser.parseContentList(html: html) let pagination = try HTMLParser.parsePagination(html: html) self.results.append(contentsOf: items) self.currentPage = pagination.current self.totalPages = pagination.total } catch is CancellationError { } catch let error as URLError where error.code == .cancelled { } catch { // 静默处理 } isLoadingMore = false } @MainActor func clear() { query = "" results = [] hasSearched = false error = nil currentPage = 1 totalPages = 1 } }