import SwiftUI enum RecordKind: String, Identifiable, CaseIterable { case quick, indicator, healthExport, archive, diary, symptom, reminder var id: String { rawValue } /// RecordSheet 列表的展示顺序(从上到下)。与 enum 声明序解耦,改顺序只动这里。 /// 注:`.quick`(指标速记)已并入 `.indicator`(记录指标)内的「拍照识别」; /// `.symptom`(记录症状)与拍药盒一起并入 `.diary`(健康日记)顶部三选一,不再单列。 static let displayOrder: [RecordKind] = [.diary, .reminder, .indicator, .healthExport, .archive] /// 健康日记行的功能提示 pill(代替 subtitle,让"症状/药盒在日记里"一眼可见)。 /// 计算属性:每次按当前语言解析,语言切换即时更新(同 ProfileEditView 的 presets 约定)。 static var diaryFeaturePills: [String] { [String(appLoc: "写日记"), String(appLoc: "拍药盒"), String(appLoc: "记症状")] } var title: String { switch self { case .quick: return String(appLoc: "指标速记") case .indicator: return String(appLoc: "记录指标") case .healthExport: return String(appLoc: "身体档案") case .archive: return String(appLoc: "体检报告归档") case .diary: return String(appLoc: "健康日记") case .symptom: return String(appLoc: "记录症状") case .reminder: return String(appLoc: "开启一个提醒") } } var subtitle: String { switch self { case .quick: return String(appLoc: "拍一张化验单,VL 自动识别") case .indicator: return String(appLoc: "手动填写,或拍照自动识别") case .healthExport: return String(appLoc: "多轮问答后生成给医生看的整理报告") case .archive: return String(appLoc: "完整保存整份报告(可多页)") case .diary: return String(appLoc: "写日记或拍药盒记录用药 · 可让 AI 辅助") case .symptom: return String(appLoc: "开始一个持续症状,结束时再点结束") case .reminder: return String(appLoc: "管理用药、复查、监测的周期提醒") } } var icon: String { switch self { case .quick: return "camera.fill" case .indicator: return "number.square.fill" case .healthExport: return "doc.text.below.ecg" case .archive: return "doc.fill" case .diary: return "heart.text.square" case .symptom: return "waveform.path.ecg" case .reminder: return "bell.badge" } } var accent: Color { switch self { case .quick: return Tj.Palette.brick case .indicator: return Tj.Palette.brick case .healthExport: return Tj.Palette.ink case .archive: return Tj.Palette.ink case .diary: return Tj.Palette.leaf case .symptom: return Tj.Palette.amber case .reminder: return Tj.Palette.leaf } } } struct RecordSheet: View { var onPick: (RecordKind) -> Void var body: some View { VStack(spacing: 0) { Capsule() .fill(Tj.Palette.line) .frame(width: 40, height: 4) .padding(.top, 10) .padding(.bottom, 16) HStack { Text("记录什么?") .font(.tjH2()) .foregroundStyle(Tj.Palette.text) Spacer() Text("本地处理 · 永不上传") .font(.tjScaled( 12)) .foregroundStyle(Tj.Palette.text3) } .padding(.bottom, 14) // ScrollView 包裹:6 个入口在小屏固定 detent 下可能溢出,滚动确保都能触达。 ScrollView { VStack(spacing: 10) { ForEach(RecordKind.displayOrder) { kind in Button { onPick(kind) } label: { HStack(spacing: 14) { ZStack { RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous) .fill(kind.accent) Image(systemName: kind.icon) .font(.tjScaled( 18, weight: .medium)) .foregroundStyle(Tj.Palette.paper) } .frame(width: 44, height: 44) VStack(alignment: .leading, spacing: 3) { Text(kind.title) .font(.tjScaled( 15, weight: .semibold)) .foregroundStyle(Tj.Palette.text) if kind == .diary { // 醒目提示:症状/药盒已并入日记,用 pill 直接点名 HStack(spacing: 5) { ForEach(RecordKind.diaryFeaturePills, id: \.self) { pill in Text(pill) .font(.tjScaled( 10, weight: .medium)) .foregroundStyle(Tj.Palette.ink) .padding(.horizontal, 7) .padding(.vertical, 2) .background(Capsule().fill(Tj.Palette.sand2)) } } } else { Text(kind.subtitle) .font(.tjScaled( 12)) .foregroundStyle(Tj.Palette.text3) } } Spacer() Image(systemName: "chevron.right") .font(.tjScaled( 14, weight: .medium)) .foregroundStyle(Tj.Palette.text3) } .padding(16) .tjCard() } .buttonStyle(.plain) } // 语音直达提示:长按 + 即可说话,不用翻菜单 HStack(spacing: 5) { Image(systemName: "mic.fill") .font(.tjScaled( 10)) Text("下次试试长按 + ,直接说出想记的内容") .font(.tjScaled( 11)) } .foregroundStyle(Tj.Palette.text3) .frame(maxWidth: .infinity) .padding(.top, 6) } .padding(.bottom, 22) } .scrollIndicators(.hidden) } .padding(.horizontal, 18) .background( Tj.Palette.sand .clipShape(RoundedRectangle(cornerRadius: Tj.Radius.xl, style: .continuous)) .ignoresSafeArea(edges: .bottom) ) .presentationDetents([.fraction(0.8)]) .presentationDragIndicator(.hidden) .presentationBackground(Tj.Palette.sand) .presentationCornerRadius(Tj.Radius.xl) } } #Preview("RecordSheet · 直接渲染") { RecordSheet { kind in print("picked: \(kind)") } .frame(width: 390, height: 560) .background(Tj.Palette.sand) } #Preview("RecordSheet · sheet 模式") { PreviewContainer() } private struct PreviewContainer: View { @State private var show = true var body: some View { Text("点这里再开一次") .onTapGesture { show = true } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Tj.Palette.sand.ignoresSafeArea()) .sheet(isPresented: $show) { RecordSheet { kind in print("picked: \(kind)"); show = false } } } }