| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- //
- // AddTicketViewModel.swift
- // LotteryTracker
- //
- // Created by aaa on 2026/1/22.
- //
-
- import Foundation
- import Combine
- internal import CoreData
-
- class AddTicketViewModel: ObservableObject {
- // 输入字段
- @Published var selectedType: LotteryType = .doubleColorBall
- @Published var numbers: String = ""
- @Published var betCount: Int = 1
- @Published var amountPerBet: Int = 2
-
- // 购买日期(默认今天)
- @Published var purchaseDate: Date = Date()
-
- // 开奖日期根据彩票类型自动计算
- var drawDate: Date {
- calculateDrawDate()
- }
-
- // 验证状态
- @Published var isValid: Bool = false
- @Published var errorMessage: String = ""
-
- // 计算属性
- var totalAmount: Float {
- let amount = amountPerBet
- return Float(amount * betCount)
- }
-
- var formattedPurchaseDate: String {
- let formatter = DateFormatter()
- formatter.dateFormat = "yyyy年MM月dd日"
- return formatter.string(from: purchaseDate)
- }
-
- var formattedDrawDate: String {
- let formatter = DateFormatter()
- formatter.dateFormat = "yyyy年MM月dd日"
- return formatter.string(from: drawDate)
- }
-
- private var cancellables = Set<AnyCancellable>()
-
- init() {
- setupValidation()
- }
-
- // 计算开奖日期(根据彩票类型)
- private func calculateDrawDate() -> Date {
- let calendar = Calendar.current
-
- switch selectedType {
- case .doubleColorBall:
- // 双色球:每周二、四、日开奖
- return nextDrawDate(for: [2, 4, 7], from: purchaseDate)
-
- case .superLotto:
- // 大乐透:每周一、三、六开奖
- return nextDrawDate(for: [1, 3, 6], from: purchaseDate)
-
- case .happy8:
- // 快乐八:每天开奖
- return calendar.date(byAdding: .day, value: 1, to: purchaseDate) ?? purchaseDate
-
- case .sevenStar:
- // 七星彩:每周二、五、日开奖
- return nextDrawDate(for: [2, 5, 7], from: purchaseDate)
-
- case .other:
- // 其他:默认3天后
- return calendar.date(byAdding: .day, value: 3, to: purchaseDate) ?? purchaseDate
- }
- }
-
- // 计算下一个开奖日期
- private func nextDrawDate(for weekdays: [Int], from date: Date) -> Date {
- let calendar = Calendar.current
- let currentWeekday = calendar.component(.weekday, from: date)
-
- // 查找下一个开奖日
- for weekday in weekdays.sorted() {
- if weekday >= currentWeekday {
- let daysToAdd = weekday - currentWeekday
- return calendar.date(byAdding: .day, value: daysToAdd, to: date) ?? date
- }
- }
-
- // 如果本周没有,取下一周的第一个开奖日
- let daysToAdd = (7 - currentWeekday) + weekdays.min()!
- return calendar.date(byAdding: .day, value: daysToAdd, to: date) ?? date
- }
-
- // 设置表单验证
- private func setupValidation() {
- // 只监听 numbers 的变化
- $numbers
- .map { numbers in
- // 验证 numbers 的格式和数量
- return self.validateNumbers(numbers)
- }
- .assign(to: \.isValid, on: self)
- .store(in: &cancellables)
- }
-
- private func validateNumbers(_ numbers: String) -> Bool {
- // 1. 非空检查
- guard !numbers.isEmpty else {
- errorMessage = "请填写完整信息"
- return false
- }
-
- // 2. 根据彩票类型验证
- switch selectedType {
- case .doubleColorBall:
- return validateDoubleColorBall(numbers)
- case .superLotto:
- return validateSuperLotto(numbers)
- default:
- // 其他彩票类型
- return validateDefault(numbers)
- }
- }
-
- // 双色球验证方法
- private func validateDoubleColorBall(_ numbers: String) -> Bool {
- // 双色球格式: "01 05 12 23 28 33 + 09"
- let components = numbers.split(separator: "+")
- guard components.count == 2 else { return false }
-
- let redPart = components[0].trimmingCharacters(in: .whitespaces)
- let bluePart = components[1].trimmingCharacters(in: .whitespaces)
-
- let redNumbers = redPart.split(separator: " ").compactMap { Int($0) }
- let blueNumbers = bluePart.split(separator: " ").compactMap { Int($0) }
-
- // 红球6个,蓝球1个
- if (redNumbers.count == 6 && blueNumbers.count == 1) {
- errorMessage = ""
- return true
- } else {
- errorMessage = "双色球选择个数不正确"
- return false
- }
- }
-
- // 大乐透验证方法
- private func validateSuperLotto(_ numbers: String) -> Bool {
- // 大乐透格式: "01 05 12 23 28 + 03 09"
- let components = numbers.split(separator: "+")
- guard components.count == 2 else { return false }
-
- let frontPart = components[0].trimmingCharacters(in: .whitespaces)
- let backPart = components[1].trimmingCharacters(in: .whitespaces)
-
- let frontNumbers = frontPart.split(separator: " ").compactMap { Int($0) }
- let blueNumbers = backPart.split(separator: " ").compactMap { Int($0) }
-
- // 前区5个,后区2个
- if (frontNumbers.count == 5 && blueNumbers.count == 2) {
- errorMessage = ""
- return true
- } else {
- errorMessage = "大乐透选择个数不正确"
- return false
- }
- }
-
- private func validateDefault(_ numbers: String) -> Bool {
- if (!numbers.isEmpty) {
- errorMessage = ""
- return true
- } else {
- errorMessage = "选择号码不能为空"
- return false
- }
- }
-
- // .....
-
- // 重置表单
- func resetForm() {
- selectedType = .doubleColorBall
- numbers = ""
- betCount = 1
- amountPerBet = 2
- purchaseDate = Date()
- errorMessage = ""
- }
-
- // 保存彩票记录
- func saveTicket(context: NSManagedObjectContext) -> Bool {
- guard isValid else {
- return false
- }
-
- let ticket = LotteryTicket(context: context)
- ticket.id = UUID()
- ticket.lotteryType = selectedType
- ticket.numbers = numbers
- ticket.betCount = Int16(betCount)
- ticket.amount = totalAmount
- ticket.date = purchaseDate // 使用用户选择的购买日期
- ticket.drawDate = drawDate // 自动计算的开奖日期
- ticket.ticketStatus = .pending
- ticket.prizeAmount = 0
-
- do {
- try context.save()
- print("✅ 彩票记录保存成功")
- print(" 类型: \(selectedType.rawValue)")
- print(" 注数: \(betCount)")
- print(" 金额: " + Formatters.formatCurrency(totalAmount))
- print(" 购买: \(formattedPurchaseDate)")
- print(" 开奖: \(formattedDrawDate)")
- return true
- } catch {
- errorMessage = "保存失败: \(error.localizedDescription)"
- print("❌ 保存失败: \(error)")
- context.delete(ticket)
- return false
- }
- }
-
- // 快速填充测试数据
- // func fillSampleData() {
- // selectedType = LotteryType.allCases.randomElement() ?? .doubleColorBall
- // numbers = generateSampleNumbers(for: selectedType)
- // betCount = Int.random(in: 1...5)
- // amountPerBet = String(format: "%.2f", Double.random(in: 2.0...10.0))
- // purchaseDate = Date().addingTimeInterval(Double.random(in: -30...0) * 24 * 3600)
- // }
-
- }
|