Browse Source

修改快乐八界面选号界面

afan 3 days ago
parent
commit
a6d49b4975

+ 25
- 0
LotteryTracker/Models/LotteryTicket+Extensions.swift View File

@@ -32,6 +32,31 @@ enum TicketStatus: String {
32 32
     case lost = "未中奖"
33 33
 }
34 34
 
35
+// 定义快乐8类型枚举
36
+enum Happy8Type: Int, CaseIterable, Identifiable {
37
+    case happy8One = 1
38
+    case happy8Two = 2
39
+    case happy8Three = 3
40
+    case happy8Four = 4
41
+    case happy8Five = 5
42
+    case happy8Six = 6
43
+    case happy8Seven = 7
44
+    case happy8Eight = 8
45
+    case happy8Nine = 9
46
+    case happy8Ten = 10
47
+    
48
+    var id: Int { rawValue }
49
+    
50
+    var string: String {
51
+        let chineseNumbers = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十"]
52
+        return "选\(chineseNumbers[rawValue - 1])"
53
+    }
54
+    
55
+    var displayName: String {
56
+        "选\(rawValue)" // 备用显示
57
+    }
58
+}
59
+
35 60
 // 扩展 LotteryTicket 类
36 61
 extension LotteryTicket {
37 62
     // 计算属性:获取彩票类型

+ 56
- 52
LotteryTracker/Views/AddTicket/DoubleColorBallCompoents.swift View File

@@ -80,12 +80,14 @@ struct DoubleColorBallSection: View {
80 80
     
81 81
     // MARK: -方法
82 82
     private func generateRandomNumbers() {
83
-        redNumbers = Array(Set((1...33).shuffled().prefix(6))).sorted()
84
-        blueNumbers = [Int.random(in: 1...16)]
83
+        withAnimation(.spring(response: 0.4)) {
84
+            redNumbers = Array(Set((1...33).shuffled().prefix(6))).sorted()
85
+            blueNumbers = [Int.random(in: 1...16)]
86
+        }
85 87
     }
86 88
     
87 89
     private func clearAllNumbers() {
88
-        withAnimation {
90
+        withAnimation(.spring(response: 0.3)) {
89 91
             redNumbers.removeAll()
90 92
             blueNumbers.removeAll()
91 93
         }
@@ -123,62 +125,64 @@ struct SelectedNumbersViewDoubleColorBall: View {
123 125
     let onClear: () -> Void
124 126
     
125 127
     var body: some View {
126
-        HStack(spacing: 8) {
127
-            // 标签
128
-            Capsule()
129
-                .fill(Color(.gray).opacity(0.1))
130
-                .frame(width: 36, height: 28)
131
-                .overlay(
132
-                    Text("已选")
133
-                        .font(.caption2)
134
-                        .fontWeight(.medium)
135
-                        .foregroundColor(Color(.black))
136
-                )
137
-            
138
-            // 号码显示
139
-            ScrollView(.horizontal, showsIndicators: false) {
140
-                HStack(spacing: 6) {
141
-                    ForEach(reds.sorted(), id: \.self) { number in
142
-                        Text(String(format: "%02d", number))
143
-                            .font(.system(size: 14, weight: .medium, design: .monospaced))
144
-                            .frame(width: 28, height: 28)
145
-                            .background(Color(.red).opacity(0.15))
146
-                            .foregroundColor(Color(.red))
147
-                            .clipShape(Circle())
148
-                    }
149
-                    
150
-                    ForEach(blues.sorted(), id: \.self) { number in
151
-                        Text(String(format: "%02d", number))
152
-                            .font(.system(size: 14, weight: .medium, design: .monospaced))
153
-                            .frame(width: 28, height: 28)
154
-                            .background(Color(.blue).opacity(0.15))
155
-                            .foregroundColor(Color(.blue))
156
-                            .clipShape(Circle())
128
+        VStack(alignment: .leading, spacing: 12) {
129
+            HStack {
130
+                // 标签
131
+                Text("双色球")
132
+                    .font(.subheadline)
133
+                    .fontWeight(.semibold)
134
+                    .foregroundColor(.primary)
135
+                
136
+            }
137
+                
138
+            HStack {
139
+                // 号码显示
140
+                ScrollView(.horizontal, showsIndicators: false) {
141
+                    HStack(spacing: 6) {
142
+                        ForEach(reds.sorted(), id: \.self) { number in
143
+                            Text(String(format: "%02d", number))
144
+                                .font(.system(size: 16, weight: .bold, design: .rounded))
145
+                                .frame(width: 36, height: 36)
146
+                                .background(Color(.red).opacity(0.15))
147
+                                .foregroundColor(Color(.red))
148
+                                .clipShape(Circle())
149
+                        }
150
+                        
151
+                        ForEach(blues.sorted(), id: \.self) { number in
152
+                            Text(String(format: "%02d", number))
153
+                                .font(.system(size: 16, weight: .bold, design: .rounded))
154
+                                .frame(width: 36, height: 36)
155
+                                .background(Color(.blue).opacity(0.15))
156
+                                .foregroundColor(Color(.blue))
157
+                                .clipShape(Circle())
158
+                        }
157 159
                     }
158 160
                 }
159
-            }
160
-            
161
-            Spacer()
162
-            
163
-            // 清空按钮
164
-            if (!reds.isEmpty || !blues.isEmpty) {
165
-                Button(action: {
166
-                    withAnimation {
167
-                        onClear()
161
+                
162
+                Spacer()
163
+                
164
+                // 清空按钮
165
+                if (!reds.isEmpty || !blues.isEmpty) {
166
+                    Button(action: {
167
+                        withAnimation {
168
+                            onClear()
169
+                        }
170
+                    }) {
171
+                        Image(systemName: "xmark.circle.fill")
172
+                            .font(.system(size: 16))
173
+                            .foregroundColor(.secondary)
174
+                            .padding(4)
168 175
                     }
169
-                }) {
170
-                    Image(systemName: "xmark.circle.fill")
171
-                        .font(.system(size: 16))
172
-                        .foregroundColor(.secondary)
173
-                        .padding(4)
174 176
                 }
175 177
             }
176 178
         }
177
-        .padding(.horizontal, 16)
178
-        .padding(.vertical, 12)
179
+        .padding(16)
179 180
         .background(Color(.systemBackground))
180
-        .cornerRadius(10)
181
-        .shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1)
181
+        .cornerRadius(12)
182
+        .overlay(
183
+            RoundedRectangle(cornerRadius: 12)
184
+                .stroke(Color.blue.opacity(0.1), lineWidth: 1)
185
+        )
182 186
     }
183 187
 }
184 188
 

+ 127
- 35
LotteryTracker/Views/AddTicket/HappyEightCompoents.swift View File

@@ -10,14 +10,26 @@ import SwiftUI
10 10
 struct HappyEightSection: View {
11 11
     @Binding var numbers: String
12 12
     @State private var selectedNumbers: [Int] = []
13
+    @State private var selectionType: Happy8Type = .happy8One // 默认为选一
13 14
     
14
-    private let maxSelection = 10
15 15
     private let columns = Array(repeating: GridItem(.flexible()), count: 10) // 10列网格
16 16
     
17 17
     var body: some View {
18 18
         VStack(alignment: .leading, spacing: 16) {
19 19
             // 头部标题
20
-            SectionHeader(title: "选择号码", icon: "number.circle")
20
+            HStack {
21
+                SectionHeader(title: "选择号码", icon: "number.circle")
22
+                
23
+                Picker(selectionType.string, selection: $selectionType) {
24
+                    ForEach(Happy8Type.allCases) { type in  // ✅ 使用 ForEach 简化
25
+                        Text(type.string).tag(type)
26
+                    }
27
+                }
28
+                .pickerStyle(.menu)
29
+            }
30
+            
31
+            // 选号类型选择器
32
+            SelectionTypePicker(selectedType: $selectionType)
21 33
             
22 34
             // 选择区号码网格(1-80)
23 35
             VStack(alignment: .leading, spacing: 12) {
@@ -26,11 +38,11 @@ struct HappyEightSection: View {
26 38
                     title: "号码区",
27 39
                     color: .primary,
28 40
                     range: 1...80,
29
-                    maxSelection: 10,
41
+                    maxSelection: selectionType.rawValue,
30 42
                     selectedNumbers: $selectedNumbers
31 43
                 )
32 44
             }
33
-
45
+            
34 46
             // 快速操作栏
35 47
             QuickActionsBar2(
36 48
                 maxSelection: 1,
@@ -49,10 +61,8 @@ struct HappyEightSection: View {
49 61
         .onChange(of: selectedNumbers) {
50 62
             updateNumbers()
51 63
         }
52
-        .onAppear {
53
-            if numbers.isEmpty {
54
-                generateRandomNumbers()
55
-            }
64
+        .onChange(of: selectionType) {
65
+            adjustSelectedNumbers()
56 66
         }
57 67
     }
58 68
     
@@ -64,26 +74,26 @@ struct HappyEightSection: View {
64 74
                 .font(.caption)
65 75
                 .foregroundColor(selectedNumbers.count >= 5 ? .green : .orange)
66 76
             
67
-            Text("\(selectedNumbers.count)/\(maxSelection)")
77
+            Text("\(selectedNumbers.count)/\(selectionType.rawValue)")
68 78
                 .font(.system(size: 14, weight: .bold))
69
-                .foregroundColor(selectedNumbers.count == maxSelection ? .white : .primary)
79
+                .foregroundColor(selectedNumbers.count == selectionType.rawValue ? .white : .primary)
70 80
         }
71 81
         .padding(.horizontal, 12)
72 82
         .padding(.vertical, 8)
73 83
         .background(
74 84
             Capsule()
75
-                .fill(selectedNumbers.count == maxSelection ?
85
+                .fill(selectedNumbers.count == selectionType.rawValue ?
76 86
                       Color.green.gradient :
77
-                      Color(.systemGray6).gradient)
87
+                        Color(.systemGray6).gradient)
78 88
         )
79 89
         .overlay(
80 90
             Capsule()
81
-                .stroke(selectedNumbers.count == maxSelection ?
91
+                .stroke(selectedNumbers.count == selectionType.rawValue ?
82 92
                         Color.green.opacity(0.5) :
83
-                        Color.gray.opacity(0.3),
93
+                            Color.gray.opacity(0.3),
84 94
                         lineWidth: 1)
85 95
         )
86
-        .shadow(color: selectedNumbers.count == maxSelection ?
96
+        .shadow(color: selectedNumbers.count == selectionType.rawValue ?
87 97
                 Color.green.opacity(0.3) : Color.clear,
88 98
                 radius: 3, x: 0, y: 2)
89 99
     }
@@ -91,14 +101,28 @@ struct HappyEightSection: View {
91 101
     private func SelectedNumbersDisplay() -> some View {
92 102
         VStack(alignment: .leading, spacing: 12) {
93 103
             HStack {
94
-                Text("已选号码")
95
-                    .font(.subheadline)
96
-                    .fontWeight(.semibold)
97
-                    .foregroundColor(.primary)
104
+                HStack {
105
+                    Text(" 快乐8")
106
+                        .font(.subheadline)
107
+                        .fontWeight(.semibold)
108
+                        .foregroundColor(.primary)
109
+                    
110
+                    Spacer()
111
+                    
112
+                    Capsule()
113
+                        .fill(Color(.gray).opacity(0.2))
114
+                        .frame(width: 48, height: 28)
115
+                        .overlay(
116
+                            Text(selectionType.string)
117
+                                .font(.subheadline)
118
+                                .fontWeight(.semibold)
119
+                                .foregroundColor(Color(.black))
120
+                        )
121
+                }
98 122
                 
99 123
                 Spacer()
100 124
                 
101
-                if selectedNumbers.count == maxSelection {
125
+                if selectedNumbers.count == selectionType.rawValue {
102 126
                     HStack(spacing: 4) {
103 127
                         Image(systemName: "checkmark.seal.fill")
104 128
                             .font(.caption)
@@ -133,13 +157,13 @@ struct HappyEightSection: View {
133 157
             Text(String(format: "%02d", number))
134 158
                 .font(.system(size: 16, weight: .bold, design: .rounded))
135 159
             
136
-//            Button {
137
-//                removeNumber(number)
138
-//            } label: {
139
-//                Image(systemName: "xmark.circle.fill")
140
-//                    .font(.caption)
141
-//                    .foregroundColor(.red.opacity(0.7))
142
-//            }
160
+            //            Button {
161
+            //                removeNumber(number)
162
+            //            } label: {
163
+            //                Image(systemName: "xmark.circle.fill")
164
+            //                    .font(.caption)
165
+            //                    .foregroundColor(.red.opacity(0.7))
166
+            //            }
143 167
         }
144 168
         .frame(width: 22, height: 22)
145 169
         .padding(.horizontal, 10)
@@ -161,16 +185,16 @@ struct HappyEightSection: View {
161 185
     
162 186
     // MARK: - 功能方法
163 187
     
164
-//    private func removeNumber(_ number: Int) {
165
-//        withAnimation(.spring(response: 0.3)) {
166
-//            selectedNumbers.removeAll { $0 == number }
167
-//        }
168
-//    }
188
+    //    private func removeNumber(_ number: Int) {
189
+    //        withAnimation(.spring(response: 0.3)) {
190
+    //            selectedNumbers.removeAll { $0 == number }
191
+    //        }
192
+    //    }
169 193
     
170 194
     private func generateRandomNumbers() {
171 195
         withAnimation(.spring(response: 0.4)) {
172 196
             var numbers = Set<Int>()
173
-            while numbers.count < maxSelection {
197
+            while numbers.count < selectionType.rawValue {
174 198
                 numbers.insert(Int.random(in: 1...80))
175 199
             }
176 200
             selectedNumbers = Array(numbers).sorted()
@@ -188,9 +212,10 @@ struct HappyEightSection: View {
188 212
         // 确保有5个奇数,5个偶数
189 213
         let oddNumbers = (1...80).filter { $0 % 2 == 1 }.shuffled()
190 214
         let evenNumbers = (1...80).filter { $0 % 2 == 0 }.shuffled()
215
+        let odds = selectionType.rawValue / 2
191 216
         
192
-        selected.formUnion(oddNumbers.prefix(5))
193
-        selected.formUnion(evenNumbers.prefix(5))
217
+        selected.formUnion(oddNumbers.prefix(odds))
218
+        selected.formUnion(evenNumbers.prefix(selectionType.rawValue - odds))
194 219
         
195 220
         withAnimation(.spring(response: 0.4)) {
196 221
             selectedNumbers = Array(selected).sorted()
@@ -207,6 +232,73 @@ struct HappyEightSection: View {
207 232
         let numberStr = selectedNumbers.sorted().map { String(format: "%02d", $0) }.joined(separator: " ")
208 233
         numbers = numberStr
209 234
     }
235
+    
236
+    private func adjustSelectedNumbers() {
237
+        clearAllNumbers()
238
+    }
239
+}
240
+
241
+
242
+// MARK: - 子视图
243
+
244
+// 选号类型选择器
245
+struct SelectionTypePicker: View {
246
+    @Binding var selectedType: Happy8Type
247
+    private let types = Happy8Type.allCases // 使用枚举
248
+    
249
+    var body: some View {
250
+        VStack {
251
+            ScrollView(.horizontal, showsIndicators: false) {
252
+                HStack {
253
+                    ForEach(types) { type in
254
+                        SelectionTypeButton(
255
+                            type: type,
256
+                            isSelected: selectedType == type,
257
+                            action: { selectedType = type }
258
+                        )
259
+                    }
260
+                }
261
+                .padding(.horizontal, 2)
262
+                .padding(.vertical, 2)
263
+            }
264
+        }
265
+        .padding(.horizontal, 4)
266
+    }
210 267
 }
211 268
 
269
+// 选号类型按钮
270
+struct SelectionTypeButton: View {
271
+    let type: Happy8Type
272
+    let isSelected: Bool
273
+    let action: () -> Void
274
+    
275
+    var body: some View {
276
+        Button(action: {
277
+            action()
278
+        }) {
279
+            Text(type.string)
280
+                .font(.system(size: 14, weight: .medium))
281
+                .foregroundColor(isSelected ? .blue : .primary)
282
+                .frame(width: 52, height: 36)
283
+                .background(
284
+                    Capsule()
285
+                        .fill(isSelected ? Color.blue.opacity(0.1) : Color.clear)
286
+                )
287
+                .overlay(
288
+                    Capsule()
289
+                        .stroke(isSelected ? Color.blue : Color.gray.opacity(0.2), lineWidth: 1)
290
+                )
291
+        }
292
+        .buttonStyle(SelectionTypeButtonStyle())
293
+    }
294
+}
212 295
 
296
+// 自定义按钮样式
297
+struct SelectionTypeButtonStyle: ButtonStyle {
298
+    func makeBody(configuration: Configuration) -> some View {
299
+        configuration.label
300
+            .scaleEffect(configuration.isPressed ? 0.95 : 1.0)
301
+            .opacity(configuration.isPressed ? 0.8 : 1.0)
302
+            .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
303
+    }
304
+}

+ 60
- 56
LotteryTracker/Views/AddTicket/SuperLottoCompoents.swift View File

@@ -76,15 +76,17 @@ struct SuperLottoSection: View {
76 76
     // MARK: - 方法
77 77
     
78 78
     private func generateRandomNumbers() {
79
-        // 前区:从1-35中随机选择5个不重复的号码
80
-        frontNumbers = Array(Set((1...35).shuffled().prefix(5))).sorted()
81
-        
82
-        // 后区:从1-12中随机选择2个不重复的号码
83
-        backNumbers = Array(Set((1...12).shuffled().prefix(2))).sorted()
79
+        withAnimation(.spring(response: 0.4)) {
80
+            // 前区:从1-35中随机选择5个不重复的号码
81
+            frontNumbers = Array(Set((1...35).shuffled().prefix(5))).sorted()
82
+            
83
+            // 后区:从1-12中随机选择2个不重复的号码
84
+            backNumbers = Array(Set((1...12).shuffled().prefix(2))).sorted()
85
+        }
84 86
     }
85 87
     
86 88
     private func clearAllNumbers() {
87
-        withAnimation {
89
+        withAnimation(.spring(response: 0.3)) {
88 90
             frontNumbers.removeAll()
89 91
             backNumbers.removeAll()
90 92
         }
@@ -105,63 +107,65 @@ struct SelectedNumbersViewSuperLotto: View {
105 107
     let onClear: () -> Void
106 108
     
107 109
     var body: some View {
108
-        HStack(spacing: 8) {
109
-            // 标签
110
-            Capsule()
111
-                .fill(Color(.gray).opacity(0.1))
112
-                .frame(width: 36, height: 28)
113
-                .overlay(
114
-                    Text("已选")
115
-                        .font(.caption2)
116
-                        .fontWeight(.medium)
117
-                        .foregroundColor(Color(.black))
118
-                )
110
+        VStack(alignment: .leading, spacing: 12) {
111
+            HStack {
112
+                // 标签
113
+                Text("大乐透")
114
+                    .font(.subheadline)
115
+                    .fontWeight(.semibold)
116
+                    .foregroundColor(.primary)
117
+            }
119 118
             
120
-            // 号码显示
121
-            ScrollView(.horizontal, showsIndicators: false) {
122
-                HStack(spacing: 6) {
123
-                    // 前区号码
124
-                    ForEach(fronts.sorted(), id: \.self) { number in
125
-                        Text(String(format: "%02d", number))
126
-                            .font(.system(size: 14, weight: .medium, design: .monospaced))
127
-                            .frame(width: 28, height: 28)
128
-                            .background(Color.orange.opacity(0.15))
129
-                            .foregroundColor(Color.orange)
130
-                            .clipShape(Circle())
131
-                    }
132
-                    
133
-                    // 后区号码
134
-                    ForEach(backs.sorted(), id: \.self) { number in
135
-                        Text(String(format: "%02d", number))
136
-                            .font(.system(size: 14, weight: .medium, design: .monospaced))
137
-                            .frame(width: 28, height: 28)
138
-                            .background(Color.blue.opacity(0.15))
139
-                            .foregroundColor(Color.blue)
140
-                            .clipShape(Circle())
119
+            HStack {
120
+                // 号码显示
121
+                ScrollView(.horizontal, showsIndicators: false) {
122
+                    HStack(spacing: 6) {
123
+                        // 前区号码
124
+                        ForEach(fronts.sorted(), id: \.self) { number in
125
+                            Text(String(format: "%02d", number))
126
+                                .font(.system(size: 16, weight: .bold, design: .rounded))
127
+                                .frame(width: 36, height: 36)
128
+                                .background(Color.orange.opacity(0.15))
129
+                                .foregroundColor(Color.orange)
130
+                                .clipShape(Circle())
131
+                        }
132
+                        
133
+                        // 后区号码
134
+                        ForEach(backs.sorted(), id: \.self) { number in
135
+                            Text(String(format: "%02d", number))
136
+                                .font(.system(size: 16, weight: .bold, design: .rounded))
137
+                                .frame(width: 36, height: 36)
138
+                                .background(Color.blue.opacity(0.15))
139
+                                .foregroundColor(Color.blue)
140
+                                .clipShape(Circle())
141
+                        }
141 142
                     }
142 143
                 }
143
-            }
144
-            
145
-            Spacer()
146
-            
147
-            // 清空按钮
148
-            if !fronts.isEmpty || !backs.isEmpty {
149
-                Button(action: {
150
-                    withAnimation {
151
-                        onClear()
144
+                
145
+                Spacer()
146
+                
147
+                // 清空按钮
148
+                if !fronts.isEmpty || !backs.isEmpty {
149
+                    Button(action: {
150
+                        withAnimation {
151
+                            onClear()
152
+                        }
153
+                    }) {
154
+                        Image(systemName: "xmark.circle.fill")
155
+                            .font(.system(size: 16))
156
+                            .foregroundColor(.secondary)
157
+                            .padding(4)
152 158
                     }
153
-                }) {
154
-                    Image(systemName: "xmark.circle.fill")
155
-                        .font(.system(size: 16))
156
-                        .foregroundColor(.secondary)
157
-                        .padding(4)
158 159
                 }
159 160
             }
161
+            
160 162
         }
161
-        .padding(.horizontal, 16)
162
-        .padding(.vertical, 12)
163
+        .padding(16)
163 164
         .background(Color(.systemBackground))
164
-        .cornerRadius(10)
165
-        .shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1)
165
+        .cornerRadius(12)
166
+        .overlay(
167
+            RoundedRectangle(cornerRadius: 12)
168
+                .stroke(Color.blue.opacity(0.1), lineWidth: 1)
169
+        )
166 170
     }
167 171
 }