import Foundation public enum SMSDirection: String, Equatable, Sendable { case incoming case outgoing case unknown public var label: String { switch self { case .incoming: return "收件" case .outgoing: return "发件" case .unknown: return "未知" } } } public struct SMSMessage: Equatable, Identifiable, Sendable { /// 上游消息 id 只在单个节点内唯一,聚合展示时不能直接当 Identifiable 用。 public let upstreamID: String public let instanceID: UUID public let instanceName: String public let phoneNumber: String public let content: String public let direction: SMSDirection public let status: String public let timestamp: String public var id: String { "\(instanceID.uuidString)#\(upstreamID)" } /// 上游 status 是英文原词,列表里直接展示会混进一行英文;未知值仍然原样显示,不做假结论。 public var statusLabel: String? { let key = status.trimmingCharacters(in: .whitespaces).lowercased() guard key.isEmpty == false else { return nil } switch key { case "received", "in", "incoming": return "已接收" case "sent": return "已发送" case "delivered": return "已送达" case "read": return "已读" case "failed", "error": return "发送失败" case "pending", "queued", "sending": return "发送中" default: return status } } /// 收件的"已接收"和方向标签说的是同一件事,只有发件状态才值得再占一个位置。 public var deliveryLabel: String? { guard direction == .outgoing else { return nil } return statusLabel } public init( upstreamID: String, instanceID: UUID, instanceName: String, phoneNumber: String, content: String, direction: SMSDirection, status: String, timestamp: String ) { self.upstreamID = upstreamID self.instanceID = instanceID self.instanceName = instanceName self.phoneNumber = phoneNumber self.content = content self.direction = direction self.status = status self.timestamp = timestamp } } public struct MessagePage: Equatable, Sendable { public let messages: [SMSMessage] public let total: Int }