根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:

```
docs(readme): 更新文档说明

- 添加了项目使用指南
- 完善了API接口说明
- 修正了一些文字错误
```

注:由于未提供具体的代码差异信息,以上为示例格式。请提供具体的代码变更内容以便生成准确的commit message。
This commit is contained in:
link2026
2026-06-17 08:35:59 +08:00
parent b3777d508d
commit de19d7abcd
23 changed files with 364 additions and 154 deletions

View File

@@ -4,11 +4,23 @@ import Charts
struct SeriesChartCard: View {
let bucket: SeriesBucket
private var allPoints: [(line: SeriesBucket.SeriesLine, point: SeriesBucket.Point)] {
bucket.lines.flatMap { line in line.points.map { (line, $0) } }
// bucket , init let, body
// header / chart / daysSpanLabel 访 flatMap / min / max
private let allPoints: [(line: SeriesBucket.SeriesLine, point: SeriesBucket.Point)]
private let dateDomain: ClosedRange<Date>?
private let valueDomain: ClosedRange<Double>?
init(bucket: SeriesBucket) {
self.bucket = bucket
let pts = bucket.lines.flatMap { line in line.points.map { (line, $0) } }
self.allPoints = pts
self.dateDomain = Self.makeDateDomain(pts)
self.valueDomain = Self.makeValueDomain(pts, lines: bucket.lines)
}
private var dateDomain: ClosedRange<Date>? {
private static func makeDateDomain(
_ allPoints: [(line: SeriesBucket.SeriesLine, point: SeriesBucket.Point)]
) -> ClosedRange<Date>? {
let dates = allPoints.map(\.point.date)
guard let lo = dates.min(), let hi = dates.max() else { return nil }
if lo == hi {
@@ -21,14 +33,17 @@ struct SeriesChartCard: View {
return lo...hi
}
private var valueDomain: ClosedRange<Double>? {
private static func makeValueDomain(
_ allPoints: [(line: SeriesBucket.SeriesLine, point: SeriesBucket.Point)],
lines: [SeriesBucket.SeriesLine]
) -> ClosedRange<Double>? {
var lo = Double.greatestFiniteMagnitude
var hi = -Double.greatestFiniteMagnitude
for (_, p) in allPoints {
lo = min(lo, p.value)
hi = max(hi, p.value)
}
for line in bucket.lines {
for line in lines {
if let r = line.referenceRange {
lo = min(lo, r.lowerBound)
hi = max(hi, r.upperBound)

View File

@@ -506,7 +506,11 @@ private struct TrendInsightCard: View {
do {
text = try await TrendInsightService.shared.generate(for: bucket)
} catch {
failedMessage = String(appLoc: "AI 解读暂不可用(模型未就绪或繁忙)")
// ,(CLAUDE.md §4)
let downloaded = ModelStore.shared.isComplete(for: .mnnLLM) || ModelStore.shared.isComplete(for: .llm)
failedMessage = downloaded
? String(appLoc: "本地推理这次没成功,点右上「解读」重试")
: String(appLoc: "AI 解读需先在「我的 · 模型管理」下载模型")
}
running = false
}

View File

@@ -22,36 +22,32 @@ struct TrendsView: View {
customMetrics: customMetrics)
}
private var monitorBuckets: [SeriesBucket] {
seriesBuckets.filter { $0.kind == .monitor }
}
private var labBuckets: [SeriesBucket] {
seriesBuckets.filter { $0.kind == .lab }
}
private func filtered(_ buckets: [SeriesBucket]) -> [SeriesBucket] {
let q = query.trimmingCharacters(in: .whitespaces)
guard !q.isEmpty else { return buckets }
return buckets.filter { $0.title.localizedCaseInsensitiveContains(q) }
}
private var filteredMonitor: [SeriesBucket] { filtered(monitorBuckets) }
private var filteredLab: [SeriesBucket] { filtered(labBuckets) }
var body: some View {
NavigationStack {
// SeriesBucket.build ,monitor / lab /
// () build ~7
let series = seriesBuckets
let monitor = filtered(series.filter { $0.kind == .monitor })
let lab = filtered(series.filter { $0.kind == .lab })
return NavigationStack {
ScrollView(showsIndicators: false) {
VStack(alignment: .leading, spacing: 18) {
header.padding(.top, 4)
if seriesBuckets.isEmpty {
if series.isEmpty {
emptyState
} else if filteredMonitor.isEmpty && filteredLab.isEmpty {
} else if monitor.isEmpty && lab.isEmpty {
noMatchState
} else {
if !filteredMonitor.isEmpty {
section(title: String(appLoc: "长期监测"), buckets: filteredMonitor)
if !monitor.isEmpty {
section(title: String(appLoc: "长期监测"), buckets: monitor)
}
if !filteredLab.isEmpty {
section(title: String(appLoc: "化验指标趋势"), buckets: filteredLab)
if !lab.isEmpty {
section(title: String(appLoc: "化验指标趋势"), buckets: lab)
}
}
}