import SwiftUI struct MessagesView: View { @StateObject private var model: MessagesViewModel 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 { AICard { Text(errorMessage) .font(.subheadline) .foregroundStyle(AITheme.warning) } } if model.filteredRows.isEmpty && !model.isLoading { AICard { VStack(spacing: 10) { Image(systemName: "message") .font(.system(size: 28)) .foregroundStyle(AITheme.muted) Text("暂无消息") .font(.headline) Text("刷新后从实例同步短信。") .font(.subheadline) .foregroundStyle(AITheme.muted) } .frame(maxWidth: .infinity) .padding(.vertical, 18) } } ForEach(model.filteredRows) { message in messageCard(message) } } .padding(16) } } .navigationTitle("消息中心") .toolbar { ToolbarItemGroup(placement: .primaryAction) { Button { model.showingSendForm = true } label: { Label("发送", systemImage: "paperplane") } .buttonStyle(AIButtonStyle(kind: .primary, size: .regular)) } } .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) TextField("搜索号码或内容", text: $model.searchText) .textFieldStyle(.plain) .padding(.horizontal, 12) .frame(minHeight: AITheme.buttonHeight) .background(AITheme.canvas) .clipShape(RoundedRectangle(cornerRadius: AITheme.buttonRadius)) .overlay { RoundedRectangle(cornerRadius: AITheme.buttonRadius) .strokeBorder(AITheme.line) } } } } 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) HStack { Text(message.instanceName) .font(.caption) .foregroundStyle(AITheme.muted) Spacer() Button("删除") { Task { await model.delete(message) } } .buttonStyle(AIButtonStyle(kind: .danger, size: .compact)) } } } } }