import Foundation @MainActor final class MessagesViewModel: ObservableObject { enum DirectionFilter: String, CaseIterable, Identifiable { case all = "全部" case incoming = "收件" case outgoing = "发件" var id: String { rawValue } } @Published var rows: [SMSMessage] = [] @Published var instances: [Instance] = [] @Published var selectedInstanceID: UUID? @Published var searchText = "" @Published var direction: DirectionFilter = .all @Published var isLoading = false @Published var errorMessage: String? @Published var showingSendForm = false private let repository: any InstanceRepository private let service: MessageService init(repository: any InstanceRepository, service: MessageService) { self.repository = repository self.service = service } var filteredRows: [SMSMessage] { rows.filter { message in selectedInstanceID == nil || message.instanceID == selectedInstanceID }.filter { message in switch direction { case .all: return true case .incoming: return message.direction == .incoming case .outgoing: return message.direction == .outgoing } }.filter { message in let query = searchText.trimmingCharacters(in: .whitespacesAndNewlines) guard !query.isEmpty else { return true } return message.phoneNumber.localizedCaseInsensitiveContains(query) || message.content.localizedCaseInsensitiveContains(query) || message.instanceName.localizedCaseInsensitiveContains(query) } } var selectedInstance: Instance? { instances.first { $0.id == selectedInstanceID } } func refresh() async { isLoading = true errorMessage = nil do { let loaded = try await repository.list(InstanceQuery()) instances = loaded if selectedInstanceID == nil || !loaded.contains(where: { $0.id == selectedInstanceID }) { selectedInstanceID = nil } let page = try await service.messages(loaded, limit: 100) rows = page.messages } catch MessageServiceError.unauthorized { errorMessage = "有实例需要登录,未获取受保护消息。" } catch { errorMessage = "无法加载消息。" } isLoading = false } func send(phoneNumber: String, content: String) async throws { guard let instance = selectedInstance ?? instances.first else { throw MessageServiceError.invalidInput } try await service.send(instance, phoneNumber: phoneNumber, content: content) await refresh() } func delete(_ message: SMSMessage) async { guard let instance = instances.first(where: { $0.id == message.instanceID }) else { return } do { try await service.delete([message.id], from: instance) rows.removeAll { $0.id == message.id && $0.instanceID == message.instanceID } } catch { errorMessage = "删除消息失败。" } } }