import SwiftUI struct MessagesView: View { @StateObject private var model: MessagesViewModel @State private var pendingDeleteMessage: SMSMessage? init(model: MessagesViewModel? = nil) { _model = StateObject(wrappedValue: model ?? DefaultContainer.makeMessagesModel()) } var body: some View { ZStack { AITheme.canvas.ignoresSafeArea() ScrollView { LazyVStack(spacing: 12) { filterBar if let errorMessage = model.errorMessage { AIStatusBanner(errorMessage, tint: AITheme.warning, systemImage: "exclamationmark.triangle") } if model.isLoading && model.filteredRows.isEmpty { AILoadingCard("正在同步消息") } if model.filteredRows.isEmpty && !model.isLoading { AICard { AIEmptyState( systemImage: "message", title: "暂无消息", message: "刷新后从实例同步短信。" ) } } ForEach(model.filteredRows) { message in messageCard(message) } } .padding(16) } } .navigationTitle("消息中心") .aiBottomActionBar { Button { model.showingSendForm = true } label: { Label("发送消息", systemImage: "paperplane") } .buttonStyle(AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true)) } .confirmationDialog( "删除这条消息?操作不可恢复。", isPresented: Binding( get: { pendingDeleteMessage != nil }, set: { if !$0 { pendingDeleteMessage = nil } } ), titleVisibility: .visible ) { Button("删除消息", role: .destructive) { guard let message = pendingDeleteMessage else { return } Task { await model.delete(message) } } Button("取消", role: .cancel) {} } .refreshable { await model.refresh() } .task { await model.refresh() } .sheet(isPresented: $model.showingSendForm) { SendMessageFormView(model: model) } } private var filterBar: some View { AICard { VStack(spacing: 10) { Picker("方向", selection: $model.direction) { ForEach(MessagesViewModel.DirectionFilter.allCases) { item in Text(item.rawValue).tag(item) } } .pickerStyle(.segmented) Picker("实例", selection: $model.selectedInstanceID) { Text("全部实例").tag(Optional.none) ForEach(model.instances) { instance in Text(instance.name).tag(Optional(instance.id)) } } .pickerStyle(.menu) .aiSelectSurface() AISearchField("搜索号码或内容", text: $model.searchText) } } } private func messageCard(_ message: SMSMessage) -> some View { AICard { VStack(alignment: .leading, spacing: 10) { HStack(spacing: 8) { Text(message.phoneNumber.isEmpty ? "未知号码" : message.phoneNumber) .font(.headline) Spacer() AITag(message.direction.label, tint: message.direction == .outgoing ? AITheme.primary : AITheme.success) } Text(message.content) .font(.subheadline) .foregroundStyle(AITheme.ink) .fixedSize(horizontal: false, vertical: true) HStack { Text(message.instanceName) .font(.caption) .foregroundStyle(AITheme.muted) .lineLimit(1) .truncationMode(.middle) .layoutPriority(1) Spacer() Button("删除") { pendingDeleteMessage = message } .buttonStyle( AIButtonStyle( kind: .danger, size: .compact, fixedWidth: AITheme.listActionButtonWidth ) ) } } } } }