主体:多语言支持(简体中文源 + 英/日/韩)
- 基础设施:Localizable.xcstrings(String Catalog,sourceLanguage=zh-Hans)
+ pbxproj developmentRegion/knownRegions 注册 en/ja/ko
- 全部硬编码 Locale("zh_CN") → Locale.current;中文 dateFormat → Date.FormatStyle(跟随系统)
- UI 中文字面量统一为 String(appLoc:)(显式绑定所选语言 bundle+locale,即时切换)
Text 字面量走环境 \.locale + Bundle 重定向
- 549 个 catalog key 全部 en/ja/ko 翻译完成(0 未翻译)
- App 内语言切换:我的 → 语言(LanguageManager + 即时生效,无需重启)
- 双用预设(症状/监测指标/慢病)本地化:static→computed 避免缓存
注:本提交为 WIP,一并打包了并行进行的功能模块
(HealthExport 健康导出、Security/Face ID 锁、DiaryAssist 日记 AI 辅助)
及 App 图标、CLAUDE.md、docs/scripts。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
125 lines
4.3 KiB
Swift
125 lines
4.3 KiB
Swift
import SwiftUI
|
||
|
||
struct A3BatchItem {
|
||
let name: String
|
||
let value: String
|
||
let unit: String
|
||
let range: String
|
||
let status: IndicatorStatus
|
||
}
|
||
|
||
struct A3BatchView: View {
|
||
var onAddMore: () -> Void
|
||
var onFinish: () -> Void
|
||
var onBack: () -> Void
|
||
|
||
let items: [A3BatchItem] = [
|
||
.init(name: String(appLoc: "低密度脂蛋白胆固醇"), value: "3.84", unit: "mmol/L", range: "< 3.40", status: .high),
|
||
.init(name: String(appLoc: "甘油三酯 TG"), value: "1.78", unit: "mmol/L", range: "< 1.70", status: .high),
|
||
.init(name: String(appLoc: "空腹血糖 GLU"), value: "5.4", unit: "mmol/L", range: "3.9–6.1", status: .normal),
|
||
]
|
||
|
||
var body: some View {
|
||
VStack(spacing: 0) {
|
||
header
|
||
ScrollView(showsIndicators: false) {
|
||
VStack(spacing: 10) {
|
||
ForEach(Array(items.enumerated()), id: \.offset) { idx, it in
|
||
BatchRow(index: idx + 1, item: it)
|
||
}
|
||
addRow
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.padding(.bottom, 16)
|
||
}
|
||
HStack(spacing: 10) {
|
||
Button {
|
||
onFinish()
|
||
} label: {
|
||
Text("全部保存(\(items.count))").frame(maxWidth: .infinity)
|
||
}
|
||
.buttonStyle(TjPrimaryButton())
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.padding(.bottom, 14)
|
||
}
|
||
.background(Tj.Palette.sand.ignoresSafeArea())
|
||
}
|
||
|
||
private var header: some View {
|
||
HStack(spacing: 6) {
|
||
Button(action: onBack) {
|
||
Image(systemName: "chevron.left")
|
||
.font(.system(size: 18, weight: .semibold))
|
||
.foregroundStyle(Tj.Palette.text)
|
||
.frame(width: 36, height: 36)
|
||
}
|
||
VStack(alignment: .leading, spacing: 2) {
|
||
Text("本次已记录 \(items.count) 项")
|
||
.font(.system(size: 15, weight: .semibold))
|
||
.foregroundStyle(Tj.Palette.text)
|
||
Text("核对后一次保存")
|
||
.font(.system(size: 11))
|
||
.foregroundStyle(Tj.Palette.text3)
|
||
}
|
||
Spacer()
|
||
Text("· · ·")
|
||
.font(.system(size: 14, design: .monospaced))
|
||
.foregroundStyle(Tj.Palette.text3)
|
||
.padding(.trailing, 12)
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.padding(.top, 4)
|
||
.padding(.bottom, 12)
|
||
}
|
||
|
||
private var addRow: some View {
|
||
Button(action: onAddMore) {
|
||
HStack(spacing: 8) {
|
||
Image(systemName: "camera").font(.system(size: 14))
|
||
Text("再拍一项")
|
||
.font(.system(size: 13))
|
||
}
|
||
.foregroundStyle(Tj.Palette.text3)
|
||
.frame(maxWidth: .infinity)
|
||
.padding(.vertical, 14)
|
||
.overlay(
|
||
RoundedRectangle(cornerRadius: Tj.Radius.md, style: .continuous)
|
||
.strokeBorder(Tj.Palette.line, style: StrokeStyle(lineWidth: 1.5, dash: [4, 4]))
|
||
)
|
||
}
|
||
.buttonStyle(.plain)
|
||
}
|
||
}
|
||
|
||
private struct BatchRow: View {
|
||
let index: Int
|
||
let item: A3BatchItem
|
||
|
||
var body: some View {
|
||
HStack(spacing: 12) {
|
||
TjPlaceholder(label: "#\(index)")
|
||
.frame(width: 60, height: 44)
|
||
VStack(alignment: .leading, spacing: 2) {
|
||
Text(item.name)
|
||
.font(.system(size: 13, weight: .semibold))
|
||
.foregroundStyle(Tj.Palette.text)
|
||
.lineLimit(1)
|
||
Text("范围 \(item.range) \(item.unit)")
|
||
.font(.system(size: 11))
|
||
.foregroundStyle(Tj.Palette.text3)
|
||
}
|
||
Spacer(minLength: 8)
|
||
VStack(alignment: .trailing, spacing: 2) {
|
||
Text(item.value)
|
||
.font(.system(size: 17, weight: .semibold))
|
||
.foregroundStyle(item.status == .high ? Tj.Palette.brick : Tj.Palette.text)
|
||
TjBadge(text: item.status == .high ? String(appLoc: "偏高") : String(appLoc: "正常"),
|
||
style: item.status == .high ? .brick : .leaf)
|
||
}
|
||
}
|
||
.padding(12)
|
||
.tjCard()
|
||
}
|
||
}
|