197 lines
14 KiB
Swift
197 lines
14 KiB
Swift
//
|
||
// DailyThinkingPage.swift - Page 14: Daily Thinking
|
||
//
|
||
|
||
import SwiftUI
|
||
|
||
struct DailyThinkingPage: View {
|
||
@State private var answer = ""
|
||
@State private var submitted = false
|
||
|
||
var body: some View {
|
||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||
VStack(spacing: 0) {
|
||
ZXBackHeader(title: "今日思考", subtitle: "过拟合", onBack: nil, trailing: {
|
||
ZXIconBtn(icon: "bookmark", size: 36) {}
|
||
})
|
||
ScrollView { VStack(spacing: 16) {
|
||
VStack(alignment: .leading, spacing: 12) {
|
||
HStack {
|
||
Image(systemName: "sparkles").foregroundColor(Color.zxAccent)
|
||
Text("解释\"注意力机制\"在 Transformer 中的作用").font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||
}
|
||
Text("AI会从三个方面评估你的回答:核心概念理解 · 理论深度 · 实际应用能力").font(.system(size: 12)).foregroundColor(Color.zxF04)
|
||
}
|
||
.padding(16).background(ZXGradient.thinkingCard).clipShape(RoundedRectangle(cornerRadius: 16))
|
||
|
||
VStack(alignment: .leading, spacing: 8) {
|
||
Text("你的回答").font(.system(size: 13, weight: .semibold)).foregroundColor(Color.zxF04)
|
||
TextEditor(text: $answer)
|
||
.font(.system(size: 13)).foregroundColor(Color.zxF0).tint(Color.zxPurple)
|
||
.frame(minHeight: 160).scrollContentBackground(.hidden)
|
||
.padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1))
|
||
}
|
||
|
||
if !submitted {
|
||
NavigationLink(destination: AIFeedbackPageView()) {
|
||
Text("提交回答,获取 AI 反馈").font(.system(size: 14, weight: .bold)).foregroundColor(.white)
|
||
.frame(maxWidth: .infinity).frame(height: 52)
|
||
.background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16))
|
||
.shadow(color: Color(hex: "#7C6EFA", opacity: 0.3), radius: 24)
|
||
}
|
||
}
|
||
}.padding(.horizontal, 20).padding(.bottom, 120) }
|
||
.scrollIndicators(.hidden)
|
||
}
|
||
}
|
||
.navigationBarHidden(true)
|
||
}
|
||
}
|
||
|
||
// Back Header
|
||
struct ZXBackHeader<T: View>: View {
|
||
let title: String; let subtitle: String?; var onBack: (() -> Void)?
|
||
@ViewBuilder var trailing: () -> T
|
||
@Environment(\.dismiss) private var dismiss
|
||
var body: some View {
|
||
HStack {
|
||
Button { (onBack ?? { dismiss() })() } label: {
|
||
Image(systemName: "chevron.left").font(.system(size: 18)).foregroundColor(Color.zxF007)
|
||
.frame(width: 36, height: 36).background(Color.zxFill005).clipShape(RoundedRectangle(cornerRadius: 10))
|
||
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.zxBorder008, lineWidth: 1))
|
||
}
|
||
VStack(spacing: 1) {
|
||
Text(title).font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||
if let s = subtitle { Text(s).font(.system(size: 11)).foregroundColor(Color.zxF03) }
|
||
}.frame(maxWidth: .infinity)
|
||
trailing()
|
||
}
|
||
.padding(.horizontal, 16).padding(.top, ZXSpacing.statusBarH + 8).padding(.bottom, 12)
|
||
.background(Color.zxBg0)
|
||
}
|
||
}
|
||
|
||
// RecallTest
|
||
struct RecallTestPage: View {
|
||
@State private var input = ""
|
||
var body: some View {
|
||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||
VStack(spacing: 0) {
|
||
ZXBackHeader(title: "回忆测试", subtitle: "机器学习 · 偏差-方差权衡") {}
|
||
ScrollView { VStack(spacing: 16) {
|
||
Text("请回忆并写下你对「偏差-方差权衡」的理解").font(.system(size: 14)).foregroundColor(Color.zxF04)
|
||
TextEditor(text: $input).frame(minHeight: 200).scrollContentBackground(.hidden).padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1))
|
||
Button {} label: { Text("提交").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||
}
|
||
}.navigationBarHidden(true)
|
||
}
|
||
}
|
||
|
||
// WeakPoints
|
||
struct WeakPointsPage: View {
|
||
var body: some View {
|
||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||
VStack(spacing: 0) {
|
||
ZXBackHeader(title: "薄弱知识点", subtitle: "共 23 个待巩固") {}
|
||
ScrollView { VStack(spacing: 12) {
|
||
ZXWeakRow(score: 32, topic: "贝叶斯定理应用", lib: "机器学习", priority: "高")
|
||
ZXWeakRow(score: 41, topic: "正态分布性质", lib: "高等数学", priority: "高")
|
||
ZXWeakRow(score: 55, topic: "词根 spect- 相关词汇", lib: "英语词汇", priority: "中")
|
||
ZXWeakRow(score: 48, topic: "协方差与相关系数", lib: "机器学习", priority: "中")
|
||
ZXWeakRow(score: 36, topic: "梯度下降优化", lib: "机器学习", priority: "高")
|
||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||
}
|
||
}.navigationBarHidden(true)
|
||
}
|
||
}
|
||
|
||
// AIFeedback - Page 15
|
||
struct AIFeedbackPageView: View {
|
||
var body: some View {
|
||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||
VStack(spacing: 0) {
|
||
ZXBackHeader(title: "AI 反馈", subtitle: "今日思考 · 过拟合", trailing: {
|
||
ZXIconBtn(icon: "bookmark", size: 36) {}
|
||
})
|
||
ScrollView { VStack(spacing: 16) {
|
||
// Score
|
||
HStack(spacing: 20) {
|
||
ZStack {
|
||
Circle().trim(from: 0, to: 0.78).stroke(ZXGradient.brand, style: StrokeStyle(lineWidth: 10, lineCap: .round)).rotationEffect(.degrees(-90)).frame(width: 80, height: 80)
|
||
VStack(spacing: 0) { Text("78").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxPurple); Text("/ 100").font(.system(size: 9)).foregroundColor(Color.zxF04) }
|
||
}
|
||
VStack(alignment: .leading, spacing: 2) {
|
||
Text("良好掌握").font(.system(size: 18, weight: .heavy)).foregroundColor(Color.zxF0)
|
||
Text("理解核心概念,但缺少理论深度和解决方案").font(.system(size: 12)).foregroundColor(Color.zxF0045).lineSpacing(4)
|
||
}
|
||
Spacer()
|
||
}
|
||
.padding(20).background(ZXGradient.feedbackScore).clipShape(RoundedRectangle(cornerRadius: 20)).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color(hex: "#7C6EFA", opacity: 0.2), lineWidth: 1))
|
||
|
||
// 你的回答
|
||
VStack(alignment: .leading, spacing: 8) { Text("你的回答").font(.system(size: 13, weight: .semibold)).foregroundColor(Color.zxF04); Text("过拟合就像一个学生只会「死记硬背」考题,而不是真正理解知识…").font(.system(size: 13)).foregroundColor(Color.zxF007).lineSpacing(6).padding(14).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder006, lineWidth: 1)) }
|
||
|
||
// 答对的部分
|
||
VStack(alignment: .leading, spacing: 8) {
|
||
HStack(spacing: 8) { Image(systemName: "checkmark.circle.fill").foregroundColor(Color.zxGreen); Text("答对的部分").font(.system(size: 14, weight: .bold)).foregroundColor(Color.zxF0) }
|
||
ForEach([("正确识别出过拟合是\"记住训练数据\"而非\"学习规律\""),("使用了死记硬背类比,方向正确且贴切")], id: \.self) { s in
|
||
HStack(alignment: .top, spacing: 12) { Circle().fill(Color.zxGreen).frame(width: 6, height: 6).padding(.top, 6); Text(s).font(.system(size: 13)).foregroundColor(Color(hex: "#F0F0FF", opacity: 0.75)).lineSpacing(4) }
|
||
.padding(12).background(Color(hex: "#34D399", opacity: 0.07)).clipShape(RoundedRectangle(cornerRadius: 12)).overlay(RoundedRectangle(cornerRadius: 12).stroke(Color(hex: "#34D399", opacity: 0.18), lineWidth: 1))
|
||
}
|
||
}
|
||
|
||
// 需要完善
|
||
VStack(alignment: .leading, spacing: 10) {
|
||
HStack(spacing: 8) { Image(systemName: "exclamationmark.triangle.fill").foregroundColor(Color.zxYellow); Text("需要完善").font(.system(size: 14, weight: .bold)).foregroundColor(Color.zxF0) }
|
||
ForEach([("缺少对「方差」和「偏差」权衡的说明", "过拟合本质是高方差问题,可以提到偏差-方差权衡"),("未提及正则化、Dropout 等解决方案", "完整答案通常要说明\"如何解决\"")], id: \.0) { p, d in
|
||
VStack(alignment: .leading, spacing: 4) { Text(p).font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxF0); Text(d).font(.system(size: 12)).foregroundColor(Color.zxF05).lineSpacing(4) }
|
||
.padding(14).frame(maxWidth: .infinity, alignment: .leading).background(Color(hex: "#F59E0B", opacity: 0.07)).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color(hex: "#F59E0B", opacity: 0.18), lineWidth: 1))
|
||
}
|
||
}
|
||
|
||
// 参考答案
|
||
VStack(alignment: .leading, spacing: 8) {
|
||
Text("✨ 参考答案要点").font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxAccent)
|
||
Text("过拟合是模型复杂度过高导致的高方差问题。偏差-方差权衡是核心概念。解决方法包括:正则化、Dropout、数据增强、早停等。").font(.system(size: 13)).foregroundColor(Color.zxF007).lineSpacing(6)
|
||
}.padding(16).background(Color(hex: "#7C6EFA", opacity: 0.07)).clipShape(RoundedRectangle(cornerRadius: 16)).overlay(RoundedRectangle(cornerRadius: 16).stroke(Color(hex: "#7C6EFA", opacity: 0.2), lineWidth: 1))
|
||
|
||
// 操作按钮
|
||
Button {} label: { Label("加入待巩固,安排间隔复习", systemImage: "bolt.fill").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)).shadow(color: Color(hex: "#7C6EFA", opacity: 0.3), radius: 24) }
|
||
HStack(spacing: 12) { ZXOutlineBtn(text: "深入提问"); ZXOutlineBtn(text: "再来一题") }
|
||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||
}
|
||
}.navigationBarHidden(true)
|
||
}
|
||
}
|
||
struct ZXOutlineBtn: View { let text: String
|
||
var body: some View { Button {} label: { HStack(spacing: 4) { Text(text).font(.system(size: 13)); Image(systemName: "chevron.right").font(.system(size: 14)) }.foregroundColor(Color.zxF05).frame(maxWidth: .infinity).frame(height: 44).background(Color.zxFill005).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) } }
|
||
}
|
||
|
||
// AIChat - Page 11
|
||
struct AIChatPage: View {
|
||
@State private var msg = ""
|
||
@State private var msgs: [(role: String, content: String)] = [("ai", "你好!我是你的 AI 学习助手。我可以帮你解答学习问题、分析薄弱点、制定复习计划。请告诉我你想学习什么?")]
|
||
var body: some View {
|
||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||
VStack(spacing: 0) {
|
||
ZXBackHeader(title: "AI 对话", subtitle: "学习助手") {}
|
||
ScrollViewReader { proxy in ScrollView { VStack(spacing: 16) {
|
||
ForEach(Array(msgs.enumerated()), id: \.offset) { i, m in
|
||
HStack(alignment: .top, spacing: 8) {
|
||
if m.role == "ai" {
|
||
Image(systemName: "brain.head.profile").foregroundColor(Color.zxPurple).frame(width: 28, height: 28).background(Color(hex: "#7C6EFA", opacity: 0.15)).clipShape(Circle())
|
||
}
|
||
Text(m.content).font(.system(size: 14)).foregroundColor(m.role == "user" ? .white : Color.zxF007).padding(12).background(m.role == "user" ? AnyView(ZXGradient.brandPurple) : AnyView(Color.zxFill004)).clipShape(RoundedRectangle(cornerRadius: 16))
|
||
if m.role == "user" { Circle().frame(width: 28, height: 28).foregroundColor(Color.zxPurpleBG(0.2)).overlay(Text("我").font(.system(size: 10, weight: .bold)).foregroundColor(Color.zxPurple)) }
|
||
}
|
||
.frame(maxWidth: .infinity, alignment: m.role == "user" ? .trailing : .leading)
|
||
}
|
||
}.padding(.horizontal, 20).padding(.bottom, 100).id("bottom") }.scrollIndicators(.hidden)
|
||
.onChange(of: msgs.count) { withAnimation { proxy.scrollTo("bottom") } } }
|
||
ZXAIInputBar(text: $msg, onSend: { guard !msg.isEmpty else { return }; msgs.append(("user", msg)); msg = ""; DispatchQueue.main.asyncAfter(deadline: .now() + 1) { msgs.append(("ai", "好的,我理解你的问题。建议你从基础概念开始,逐步深入理解。需要我帮你制定具体的学习计划吗?")) } })
|
||
}
|
||
}.navigationBarHidden(true)
|
||
}
|
||
}
|