// // ScenicQueueAnnouncementState.swift // suixinkan // // Created by Codex on 2026/6/25. // import Foundation /// 排队语音播报内容。 struct ScenicQueueAnnouncement: Equatable { enum Kind: Equatable { case newTickets(count: Int) case calledTicket(id: Int64) } let kind: Kind let text: String } /// 排队播报去重状态,避免同一批队列反复播报。 struct ScenicQueueAnnouncementState { private var knownTicketIds = Set() private var calledTicketIds = Set() /// 根据最新统计和列表计算下一条需要播报的内容。 mutating func nextAnnouncement( stats: ScenicQueueStatsData, tickets: [ScenicQueueTicket], customCallText: String? ) -> ScenicQueueAnnouncement? { let currentIds = Set(tickets.map(\.id)) let newTickets = tickets.filter { !knownTicketIds.contains($0.id) } knownTicketIds = currentIds if let ticket = tickets.first(where: { ($0.isCalled == 1 || $0.statusText.contains("已叫号")) && !calledTicketIds.contains($0.id) }) { calledTicketIds.insert(ticket.id) return ScenicQueueAnnouncement(kind: .calledTicket(id: ticket.id), text: Self.callText(for: ticket, customText: customCallText)) } guard !newTickets.isEmpty else { return nil } let text = "排队提醒,当前新增\(newTickets.count)位游客,在排人数\(stats.queueCount)人。" return ScenicQueueAnnouncement(kind: .newTickets(count: newTickets.count), text: text) } /// 重置播报去重状态。 mutating func reset() { knownTicketIds.removeAll() calledTicketIds.removeAll() } /// 生成叫号播报文案。 static func callText(for ticket: ScenicQueueTicket, customText: String?) -> String { callText(forQueueCode: ticket.queueCode, customText: customText) } /// 生成叫号播报文案。 static func callText(forQueueCode queueCode: String, customText: String?) -> String { let custom = customText?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" if !custom.isEmpty, custom != "A0001" { return custom.replacingOccurrences(of: "{number}", with: queueCode) } let code = queueCode.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? "当前游客" : ttsLabel(for: queueCode) return "请\(code)到拍摄点拍摄。" } /// 将排队号拆成更适合语音播报的文本。 static func ttsLabel(for queueCode: String) -> String { let trimmed = queueCode.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { return "当前游客" } return trimmed.map(String.init).joined(separator: " ") } }