import SwiftUI struct B4ProgressView: View { var onComplete: () -> Void @State private var step: Int = 1 @State private var pulse = false @State private var glow = false @State private var rotate: Double = 0 @State private var elapsed: Double = 0.2 private let lineLabels = [ "正在本地识别第 1 / 3 页…", "正在本地识别第 2 / 3 页…", "正在本地识别第 3 / 3 页…", "提取指标 · 共 28 项", "生成整体摘要…", ] var body: some View { ZStack { backgroundGradient.ignoresSafeArea() VStack(spacing: 0) { Spacer() chip.padding(.bottom, 36) Text("本地 AI · 正在解读") .font(.system(size: 22, weight: .semibold)) .tracking(1) .foregroundStyle(Color.white.opacity(0.95)) .padding(.bottom, 6) Text("QWEN2.5-VL · ON-DEVICE · SME2") .font(.system(size: 11, design: .monospaced)) .tracking(0.5) .foregroundStyle(Color.white.opacity(0.55)) .padding(.bottom, 30) lineList .padding(.horizontal, 28) speedBadge.padding(.top, 32) Spacer() Text("本地处理中 · 不会上传任何内容") .font(.system(size: 10, design: .monospaced)) .tracking(0.5) .foregroundStyle(Color.white.opacity(0.45)) .padding(.bottom, 30) } .padding(.horizontal, 28) } .preferredColorScheme(.dark) .onAppear { startAnimations() } } private var backgroundGradient: some View { RadialGradient( colors: [ Color(red: 0.22, green: 0.21, blue: 0.18), Color(red: 0.13, green: 0.12, blue: 0.10), Color(red: 0.08, green: 0.075, blue: 0.06), ], center: .init(x: 0.5, y: 0.3), startRadius: 60, endRadius: 700 ) } private var chip: some View { ZStack { Circle() .fill(Color(red: 0.93, green: 0.75, blue: 0.40).opacity(glow ? 0.18 : 0.0)) .frame(width: 176, height: 176) .blur(radius: 30) Circle() .strokeBorder(Color.white.opacity(0.18), style: StrokeStyle(lineWidth: 1, dash: [4, 4])) .frame(width: 140, height: 140) .rotationEffect(.degrees(rotate)) RoundedRectangle(cornerRadius: 22, style: .continuous) .fill( LinearGradient( colors: [Color(red: 0.36, green: 0.34, blue: 0.30), Color(red: 0.22, green: 0.21, blue: 0.18)], startPoint: .topLeading, endPoint: .bottomTrailing ) ) .overlay( RoundedRectangle(cornerRadius: 22, style: .continuous) .strokeBorder(Color.white.opacity(0.10), lineWidth: 1) ) .frame(width: 96, height: 96) .shadow(color: .black.opacity(0.4), radius: 20, x: 0, y: 12) .overlay(ChipGlyph()) .overlay(alignment: .topTrailing) { Circle() .fill(Color(red: 0.95, green: 0.78, blue: 0.40)) .frame(width: 6, height: 6) .opacity(pulse ? 1 : 0.35) .shadow(color: Color(red: 0.95, green: 0.78, blue: 0.40), radius: 6) .padding(10) } .scaleEffect(pulse ? 1.06 : 1.0) .opacity(pulse ? 0.92 : 1.0) } } private var lineList: some View { VStack(alignment: .leading, spacing: 10) { ForEach(Array(lineLabels.enumerated()), id: \.offset) { idx, label in LineRow( text: label, done: step > idx + 1, active: step == idx + 1, isLast: idx == lineLabels.count - 1 ) .opacity(step >= idx + 1 ? 1 : 0) .offset(y: step >= idx + 1 ? 0 : 6) .animation(.easeOut(duration: 0.4).delay(Double(idx) * 0.05), value: step) } } .frame(maxWidth: .infinity, alignment: .leading) } private var speedBadge: some View { Text(String(format: "已处理 %.1fs · 比云端快 4.2×", elapsed)) .font(.system(size: 10, design: .monospaced)) .tracking(0.6) .foregroundStyle(Color.white.opacity(0.75)) .padding(.horizontal, 12) .padding(.vertical, 6) .background(Capsule().fill(Color.white.opacity(0.08))) } private func startAnimations() { withAnimation(.easeInOut(duration: 2.0).repeatForever(autoreverses: true)) { pulse.toggle() } withAnimation(.easeInOut(duration: 2.4).repeatForever(autoreverses: true)) { glow.toggle() } withAnimation(.linear(duration: 14).repeatForever(autoreverses: false)) { rotate = 360 } Task { for _ in 0..