行业资讯

SwiftUI与HealthKit实战:构建一体化iOS卡路里追踪应用

发布时间:2026/8/19 4:56:43
SwiftUI与HealthKit实战:构建一体化iOS卡路里追踪应用 之前为了管理自己的健康数据我手机里同时装着三个不同的健身应用一个记录饮食卡路里一个追踪运动消耗还有一个负责同步体重和睡眠。数据分散、操作繁琐不说不同应用间的数据还经常打架体验非常割裂。一怒之下我决定自己动手用 SwiftUI 开发一个功能聚合的 iOS 卡路里追踪器目标是替代那三个 App。本文将完整分享从需求分析、技术选型到核心功能实现的全过程包含完整的 SwiftUI 代码、数据模型设计以及 HealthKit 集成方案。无论你是想学习 SwiftUI 实战还是希望构建自己的健康类应用这篇文章都能提供一套可直接复用的解决方案。1. 项目背景与核心需求分析1.1 为什么需要自建卡路里追踪器市面上的健康应用功能往往非常垂直。你可能需要App A手动输入或扫描食物条形码来记录卡路里摄入。App B连接 Apple Watch 或手动记录运动类型与时长计算消耗。App C查看体重趋势、分析睡眠质量。这种模式的问题显而易见数据孤岛摄入、消耗、体重数据分散无法在一个界面直观看到每日热量盈亏。操作冗余每天需要在多个 App 间切换体验不连贯。同步成本部分应用与苹果健康HealthKit的同步权限有限数据无法自由流通。因此我们的核心目标是构建一个“All-in-One”的应用它能够统一数据源以苹果的HealthKit作为核心数据仓库读写摄入、消耗、体重等所有健康数据。聚合展示在一个简洁的仪表盘上同时展示今日摄入卡路里、运动消耗卡路里、净卡路里摄入-消耗以及体重趋势。便捷记录提供快速入口记录食物、饮水、运动或体重。数据持久化对于 HealthKit 不擅长存储的复杂数据如自定义食物库使用本地数据库如 Core Data 或 SwiftData进行管理。1.2 技术栈选型SwiftUI HealthKit SwiftData为了实现上述目标我们选择苹果生态最新的技术组合SwiftUI声明式 UI 框架能够高效构建美观、响应式的用户界面。对于这类数据驱动型应用其数据绑定特性非常合适。HealthKit苹果提供的健康数据框架。它是我们应用的“数据引擎”负责安全地读取和写入用户的健康数据。这是本项目的核心。SwiftData(或Core Data)用于持久化存储 HealthKit 不直接支持的结构化数据例如用户自定义创建的食物条目、常用的膳食模板等。SwiftData 是苹果在 iOS 17 推出的现代化持久化框架语法更简洁。这个组合确保了应用能深度集成 iOS 系统拥有最佳的性能和安全性同时利用最新的开发工具提升效率。2. 环境准备与项目配置2.1 开发环境要求macOS建议使用最新稳定版 macOS如 Sonoma 或更高。Xcode版本 15.0 或更高以支持完整的 SwiftUI 和 SwiftData 功能。本文示例基于 Xcode 15.2。目标设备运行 iOS 17.0 的 iPhone 或 iPad。部分 HealthKit 功能需要实体设备进行测试无法在模拟器上完全运行。开发者账号需要加入 Apple Developer Program以便配置 HealthKit 权限和真机测试。2.2 创建新项目与基础配置打开 Xcode选择 “Create New Project”。模板选择 “App”点击 Next。输入产品名称例如CalorieHub。Interface 选择SwiftUILifecycle 选择SwiftUI App语言选择Swift。暂时不要勾选 “Use SwiftData” 或 “Include Tests”我们后续手动添加。选择项目保存位置点击 Create。2.3 配置 HealthKit 权限HealthKit 涉及用户敏感健康数据必须在Info.plist文件中明确声明需要访问的数据类型否则应用会崩溃。在项目导航器中点击CalorieHub项目文件选择CalorieHubTarget切换到Info标签页。在 “Custom iOS Target Properties” 区域点击按钮。添加一个新的键Privacy - Health Share Usage Description。值填写向用户解释为何需要读取健康数据的描述例如“我们需要读取您的活动能量、饮食能量和体重数据以便为您计算每日卡路里平衡。”再添加一个键Privacy - Health Update Usage Description。值填写向用户解释为何需要写入健康数据的描述例如“我们需要写入您记录的食物卡路里和体重数据到健康App以便统一管理。”除了Info.plist还需要在Capabilities中启用 HealthKit在项目导航器中点击CalorieHub项目文件选择CalorieHubTarget切换到Signing Capabilities标签页。点击 Capability搜索并添加HealthKit。2.4 添加 SwiftData 支持可选用于自定义食物库如果你计划支持用户自定义食物库强烈建议需要添加 SwiftData 框架。在项目导航器中选中CalorieHub项目文件。在 Targets 下选中CalorieHub切换到Build Phases标签页。展开 “Link Binary With Libraries”点击搜索并添加SwiftData.framework。至此项目的基础环境和权限配置完成。3. 核心数据模型与 HealthKit 管理器设计在编写 UI 之前我们先设计应用的数据层。这是应用稳定性的基石。3.1 定义健康数据模型我们创建一个HealthData模型用于在应用内部统一表示从 HealthKit 获取或将要写入的数据。// 文件Models/HealthData.swift import Foundation import HealthKit struct HealthData { // 能量单位千卡 (kcal) struct Energy { var consumed: Double // 摄入能量 var burned: Double // 消耗能量 var net: Double { // 净能量摄入 - 消耗 consumed - burned } } // 体重单位千克 (kg) var weight: Double? // 数据对应的日期 var date: Date // 今日能量数据 var todayEnergy: Energy? // 过去一周的每日净能量数据用于图表展示 var weeklyNetEnergy: [DailyData]? struct DailyData { let date: Date let value: Double } }3.2 构建 HealthKit 管理器这是与 HealthKit 交互的核心单例类负责所有数据的读写请求。// 文件Managers/HealthKitManager.swift import Foundation import HealthKit class HealthKitManager: ObservableObject { // HealthKit 存储库 private let healthStore HKHealthStore() // 我们需要用到的健康数据类型标识符 private let dietaryEnergyType HKQuantityType.quantityType(forIdentifier: .dietaryEnergyConsumed)! // 饮食能量消耗 private let activeEnergyType HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned)! // 活动能量消耗 private let bodyMassType HKQuantityType.quantityType(forIdentifier: .bodyMass)! // 体重 // 发布今日数据供 SwiftUI 视图订阅 Published var todayData: HealthData? init() { // 在初始化时检查授权状态并请求权限 requestAuthorization() } /// 请求 HealthKit 授权 func requestAuthorization() { // 定义我们要读取和写入的数据类型集合 let typesToRead: SetHKObjectType [ dietaryEnergyType, activeEnergyType, bodyMassType, HKObjectType.categoryType(forIdentifier: .sleepAnalysis)! // 示例睡眠分析 ] let typesToWrite: SetHKSampleType [ dietaryEnergyType, bodyMassType ] // 检查 HealthKit 在设备上是否可用 guard HKHealthStore.isHealthDataAvailable() else { print(HealthKit is not available on this device.) return } // 请求授权 healthStore.requestAuthorization(toShare: typesToWrite, read: typesToRead) { [weak self] success, error in if success { print(HealthKit authorization granted.) // 授权成功后开始获取今日数据 self?.fetchTodayData() } else { print(HealthKit authorization denied. Error: \(error?.localizedDescription ?? Unknown error)) } } } /// 获取今日的健康数据摄入、消耗、体重 func fetchTodayData() { let calendar Calendar.current let now Date() let startOfDay calendar.startOfDay(for: now) let endOfDay calendar.date(byAdding: .day, value: 1, to: startOfDay)! let predicate HKQuery.predicateForSamples(withStart: startOfDay, end: endOfDay, options: .strictStartDate) // 创建调度组等待所有查询完成 let group DispatchGroup() var consumed: Double 0 var burned: Double 0 var latestWeight: Double? nil // 查询摄入能量 group.enter() let consumedQuery HKStatisticsQuery(quantityType: dietaryEnergyType, quantitySamplePredicate: predicate, options: .cumulativeSum) { _, result, error in if let sum result?.sumQuantity() { consumed sum.doubleValue(for: .kilocalorie()) // 转换为千卡单位 } group.leave() } healthStore.execute(consumedQuery) // 查询活动消耗能量 group.enter() let burnedQuery HKStatisticsQuery(quantityType: activeEnergyType, quantitySamplePredicate: predicate, options: .cumulativeSum) { _, result, error in if let sum result?.sumQuantity() { burned sum.doubleValue(for: .kilocalorie()) } group.leave() } healthStore.execute(burnedQuery) // 查询最新体重 group.enter() let weightQuery HKSampleQuery(sampleType: bodyMassType, predicate: predicate, limit: 1, sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)]) { _, samples, error in if let sample samples?.first as? HKQuantitySample { latestWeight sample.quantity.doubleValue(for: .gramUnit(with: .kilo)) // 转换为千克 } group.leave() } healthStore.execute(weightQuery) // 所有查询完成后在主线程更新数据 group.notify(queue: .main) { [weak self] in let energy HealthData.Energy(consumed: consumed, burned: burned) let data HealthData(weight: latestWeight, date: now, todayEnergy: energy) self?.todayData data print(今日数据更新摄入 \(consumed) kcal, 消耗 \(burned) kcal, 净 \(energy.net) kcal) } } /// 保存一条食物摄入记录到 HealthKit /// - Parameters: /// - calories: 卡路里数千卡 /// - foodName: 食物名称 func saveFoodEntry(calories: Double, foodName: String) { let quantity HKQuantity(unit: .kilocalorie(), doubleValue: calories) let metadata [HKMetadataKeyFoodType: foodName] let sample HKQuantitySample(type: dietaryEnergyType, quantity: quantity, start: Date(), end: Date(), metadata: metadata) healthStore.save(sample) { success, error in if success { print(成功保存食物记录\(foodName) - \(calories) kcal) // 保存成功后重新获取今日数据以更新UI DispatchQueue.main.async { self.fetchTodayData() } } else { print(保存食物记录失败\(error?.localizedDescription ?? Unknown error)) } } } /// 保存体重记录到 HealthKit /// - Parameter weightInKg: 体重千克 func saveWeightEntry(weightInKg: Double) { let quantity HKQuantity(unit: .gramUnit(with: .kilo), doubleValue: weightInKg) let sample HKQuantitySample(type: bodyMassType, quantity: quantity, start: Date(), end: Date()) healthStore.save(sample) { success, error in if success { print(成功保存体重记录\(weightInKg) kg) DispatchQueue.main.async { self.fetchTodayData() } } else { print(保存体重记录失败\(error?.localizedDescription ?? Unknown error)) } } } }这个HealthKitManager类封装了授权、查询和写入的核心逻辑并通过Published属性包装器与 SwiftUI 视图实现数据绑定。4. SwiftUI 界面构建与功能实现有了数据层我们开始构建用户界面。应用主要包含三个视图仪表盘主页、添加记录页面和设置/历史页面。4.1 主视图 (ContentView) - 数据仪表盘主视图负责展示今日概览是用户打开应用首先看到的界面。// 文件Views/ContentView.swift import SwiftUI struct ContentView: View { // 通过环境对象注入 HealthKitManager EnvironmentObject var healthKitManager: HealthKitManager State private var showingAddSheet false var body: some View { NavigationStack { ScrollView { VStack(spacing: 24) { // 1. 欢迎标题 headerView // 2. 今日数据概览卡片 if let data healthKitManager.todayData { todayOverviewCard(data: data) } else { ProgressView(正在加载健康数据...) .frame(height: 200) } // 3. 快速操作按钮组 quickActionsView // 4. 周趋势图表 (占位需实现数据获取逻辑) weeklyTrendCard Spacer() } .padding() } .navigationTitle(卡路里中心) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { showingAddSheet.toggle() }) { Image(systemName: plus.circle.fill) .font(.title2) } } } .sheet(isPresented: $showingAddSheet) { AddRecordView() .environmentObject(healthKitManager) } } .onAppear { // 视图出现时尝试获取数据 if healthKitManager.todayData nil { healthKitManager.fetchTodayData() } } } // MARK: - 子视图组件 private var headerView: some View { VStack(alignment: .leading, spacing: 8) { Text(今日概况) .font(.largeTitle) .fontWeight(.bold) Text(Date().formatted(date: .complete, time: .omitted)) .font(.subheadline) .foregroundColor(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) } private func todayOverviewCard(data: HealthData) - some View { VStack(alignment: .leading, spacing: 20) { HStack { VStack(alignment: .leading) { Text(净卡路里) .font(.headline) .foregroundColor(.secondary) Text(\(Int(data.todayEnergy?.net ?? 0))) .font(.system(size: 48, weight: .heavy, design: .rounded)) .foregroundColor(colorForNetEnergy(data.todayEnergy?.net ?? 0)) } Spacer() VStack(alignment: .trailing) { if let weight data.weight { Text(体重) .font(.headline) .foregroundColor(.secondary) Text(String(format: %.1f kg, weight)) .font(.title2) .fontWeight(.semibold) } } } Divider() HStack { DataMetricView( title: 摄入, value: \(Int(data.todayEnergy?.consumed ?? 0)), unit: kcal, color: .blue, icon: fork.knife ) Spacer() DataMetricView( title: 消耗, value: \(Int(data.todayEnergy?.burned ?? 0)), unit: kcal, color: .orange, icon: flame ) } } .padding() .background(Color(.systemBackground)) .cornerRadius(20) .shadow(color: .black.opacity(0.05), radius: 10, x: 0, y: 5) } private var quickActionsView: some View { VStack(alignment: .leading, spacing: 12) { Text(快速记录) .font(.headline) .padding(.horizontal) HStack(spacing: 16) { QuickActionButton(title: 添加食物, icon: plus.circle, color: .blue) { showingAddSheet.toggle() } QuickActionButton(title: 记录运动, icon: figure.run, color: .green) { // 跳转到记录运动页面 } QuickActionButton(title: 记录体重, icon: scalemass, color: .purple) { // 跳转到记录体重页面 } } } } private var weeklyTrendCard: some View { VStack(alignment: .leading, spacing: 12) { HStack { Text(本周趋势) .font(.headline) Spacer() Button(查看更多) { } .font(.caption) .foregroundColor(.blue) } .padding(.horizontal) // 这里可以集成 Charts 框架绘制折线图 RoundedRectangle(cornerRadius: 12) .fill(Color.gray.opacity(0.1)) .frame(height: 150) .overlay( Text(周趋势图表区域) .foregroundColor(.secondary) ) .padding(.horizontal) } } private func colorForNetEnergy(_ value: Double) - Color { // 净能量为负消耗大于摄入通常显示为绿色为正则显示为红色 value 0 ? .green : .red } } // 数据指标组件 struct DataMetricView: View { let title: String let value: String let unit: String let color: Color let icon: String var body: some View { VStack { Image(systemName: icon) .font(.title2) .foregroundColor(color) .frame(width: 50, height: 50) .background(color.opacity(0.1)) .clipShape(Circle()) Text(title) .font(.caption) .foregroundColor(.secondary) Text(value) .font(.title3) .fontWeight(.bold) Text( \(unit)) .font(.caption) .foregroundColor(.secondary) } } } // 快速操作按钮组件 struct QuickActionButton: View { let title: String let icon: String let color: Color let action: () - Void var body: some View { Button(action: action) { VStack(spacing: 8) { Image(systemName: icon) .font(.title2) .foregroundColor(.white) .frame(width: 50, height: 50) .background(color) .clipShape(Circle()) Text(title) .font(.caption) .fontWeight(.medium) .foregroundColor(.primary) } } .frame(maxWidth: .infinity) } }4.2 添加记录视图 (AddRecordView)这是一个表单视图用于快速添加食物或体重记录。// 文件Views/AddRecordView.swift import SwiftUI struct AddRecordView: View { EnvironmentObject var healthKitManager: HealthKitManager Environment(\.dismiss) var dismiss State private var recordType: RecordType .food State private var foodName: String State private var calories: String State private var weight: String enum RecordType { case food, weight } var body: some View { NavigationStack { Form { Section { Picker(记录类型, selection: $recordType) { Text(食物).tag(RecordType.food) Text(体重).tag(RecordType.weight) } .pickerStyle(.segmented) } if recordType .food { Section(食物信息) { TextField(食物名称例如苹果, text: $foodName) TextField(卡路里 (kcal), text: $calories) .keyboardType(.decimalPad) } } else { Section(体重信息) { TextField(体重 (kg), text: $weight) .keyboardType(.decimalPad) } } Section { Button(action: saveRecord) { HStack { Spacer() Text(保存记录) .fontWeight(.semibold) Spacer() } } .disabled(!isFormValid) .foregroundColor(.white) .listRowBackground(isFormValid ? Color.blue : Color.gray) } } .navigationTitle(添加记录) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button(取消) { dismiss() } } } } } // 表单验证逻辑 private var isFormValid: Bool { switch recordType { case .food: return !foodName.isEmpty Double(calories) ! nil case .weight: return Double(weight) ! nil } } // 保存记录到 HealthKit private func saveRecord() { switch recordType { case .food: if let calorieValue Double(calories) { healthKitManager.saveFoodEntry(calories: calorieValue, foodName: foodName) } case .weight: if let weightValue Double(weight) { healthKitManager.saveWeightEntry(weightInKg: weightValue) } } dismiss() } }4.3 应用入口与依赖注入最后我们需要在CalorieHubApp.swift中初始化HealthKitManager并将其注入到环境中。// 文件CalorieHubApp.swift import SwiftUI main struct CalorieHubApp: App { // 创建 HealthKitManager 实例并使其在整个应用生命周期内保持 StateObject private var healthKitManager HealthKitManager() var body: some Scene { WindowGroup { ContentView() .environmentObject(healthKitManager) // 注入环境 .onAppear { // 应用启动时可以在这里触发一些初始化操作 print(CalorieHub 启动) } } } }5. 功能扩展与进阶实现基础版本已经可以运行但要真正替代多个专业应用还需要更多功能。以下是几个关键的扩展方向。5.1 集成条形码扫描与食物数据库手动输入食物卡路里很麻烦。可以集成第三方 API如 Open Food Facts或商业数据库如 Nutritionix。添加相机权限在Info.plist中添加NSCameraUsageDescription。使用AVCaptureSession或第三方库如CodeScanner来扫描条形码。扫描到 EAN/UPC 码后向食物数据库 API 发起请求获取食物名称和营养信息。将获取的数据通过HealthKitManager.saveFoodEntry保存。5.2 运动类型选择与消耗计算除了读取 Apple Watch 的主动消耗也可以让用户手动记录运动。创建运动类型枚举如跑步、游泳、骑行等并为每种运动定义每公斤体重每分钟的 MET代谢当量值。构建运动记录表单让用户选择运动类型、输入时长分钟和体重可自动从 HealthKit 获取最新体重。计算消耗消耗 (kcal) MET * 体重 (kg) * 时间 (小时)。计算结果可以写入 HealthKit 的activeEnergyBurned样本但更常见的做法是让用户确认后作为一个独立的“手动记录”保存在本地SwiftData并在仪表盘中累加显示。直接写入 HealthKit 可能会与 Apple Watch 的数据重复计算。5.3 使用 SwiftData 管理自定义食物库HealthKit 适合存储时间序列数据但不适合存储复杂的、用户自定义的结构化数据如“我的常吃食物列表”。定义 SwiftData 模型import SwiftData import Foundation Model class CustomFood { var name: String var caloriesPerServing: Double var servingSize: String? var brand: String? var dateCreated: Date init(name: String, caloriesPerServing: Double, servingSize: String? nil, brand: String? nil) { self.name name self.caloriesPerServing caloriesPerServing self.servingSize servingSize self.brand brand self.dateCreated Date() } }在AddRecordView中可以添加一个按钮从CustomFood列表中快速选择而无需每次手动输入。5.4 数据可视化与历史趋势使用苹果的Charts框架来增强数据展示。在HealthKitManager中添加fetchWeeklyData方法查询过去 7 天每天的净卡路里。在主视图中将weeklyTrendCard中的占位符替换为真正的Chart视图。这能直观地帮助用户了解自己的长期热量平衡趋势。6. 常见问题与调试技巧6.1 HealthKit 授权失败现象应用请求健康权限时用户点击“允许”后fetchTodayData仍然获取不到数据或者success为false。排查检查Info.plist中的使用描述NSHealthShareUsageDescription和NSHealthUpdateUsageDescription是否填写完整。检查 Capabilities 中 HealthKit 是否已启用。在真机的设置 隐私与安全性 健康 CalorieHub中确认读写权限已为你需要的具体数据类型如“活动能量”、“饮食能量”开启。在requestAuthorization的回调中打印error信息。解决确保权限描述清晰并在首次请求权限前在合适的时机如用户点击“同步健康数据”按钮时调用授权方法而不是在应用一启动就请求。6.2 模拟器上 HealthKit 不可用现象在模拟器上运行应用控制台打印 “HealthKit is not available on this device.”原因HealthKit 仅在真实 iOS 设备上可用。解决必须使用真机进行开发和测试。将 iPhone 连接到 Mac在 Xcode 顶部 Scheme 选择你的设备然后运行。6.3 数据写入成功但读取不到现象调用saveFoodEntry后回调success为true但立即调用fetchTodayData却看不到刚写入的数据。原因HealthKit 的数据写入是异步的并且可能存在轻微的延迟。此外查询谓词的时间范围需要精确匹配。解决在保存成功的回调中延迟一小段时间如 0.5 秒再调用fetchTodayData。确保查询的startDate和endDate能覆盖你写入样本的时间点。上面的示例使用了strictStartDate确保样本的开始时间在查询区间内。6.4 SwiftUI 预览崩溃现象在编写ContentView时SwiftUI 预览画布崩溃提示与 HealthKit 相关。原因预览在 Mac 上运行无法访问 HealthKit。解决在预览代码中提供一个模拟的HealthKitManager。// 在 ContentView.swift 文件底部 #Preview { let mockManager HealthKitManager() // 可以在这里设置 mockManager.todayData 为一些模拟数据 return ContentView() .environmentObject(mockManager) }7. 最佳实践与上架建议7.1 数据隐私与安全最小权限原则只请求应用功能必需的健康数据类型。不必要的权限会降低用户信任。清晰说明在权限描述和应用内的隐私政策中明确说明收集哪些数据、用于什么目的、如何存储本地以及是否会共享通常不应共享。本地处理优先所有计算尽量在设备端完成。如果使用第三方食物数据库 API确保传输的数据不包含个人身份信息。7.2 用户体验优化增量保存在添加食物时可以提供“100 kcal”、“200 kcal”的快速按钮减少输入。数据缓存将HealthKitManager.todayData用AppStorage或本地文件缓存起来这样应用启动后能立即显示上次的数据提升响应速度后台再同步最新数据。Widget 支持开发一个 iOS 桌面小组件直接展示今日净卡路里让用户无需打开应用即可查看。iCloud 同步如果使用了 SwiftData 管理自定义食物库可以启用 iCloud 同步让用户的个人食物列表在所有设备上保持一致。7.3 性能考量批量查询HealthKitManager.fetchTodayData中使用了DispatchGroup来并发执行多个查询这是好的做法。对于更复杂的历史数据查询注意使用合理的limit和predicate避免一次加载过多数据导致内存压力。后台刷新使用BGTaskScheduler安排后台任务定期从 HealthKit 获取最新数据确保小组件或应用内数据相对及时。7.4 提交 App Store 审核注意事项健康数据声明在 App Store Connect 的 App 信息中需要准确声明应用使用了健康数据。隐私问卷仔细填写苹果的隐私数据收集问卷如实反映通过 HealthKit 访问的数据类型。功能演示准备屏幕录制或截图清晰展示应用如何请求、使用和展示健康数据。审核员需要确认应用的核心功能确实需要这些权限。遵守指南严格遵循 App Store Review Guidelines 中关于健康、健身和数据的条款特别是 5.1.3 和 5.1.5。通过以上步骤你不仅构建了一个可用的 iOS 卡路里追踪器更掌握了一套整合 SwiftUI、HealthKit 和 SwiftData 开发数据驱动型健康应用的完整方法论。这个项目骨架具有很强的可扩展性你可以根据自己的需求继续添加饮水追踪、睡眠分析、营养宏量蛋白质、碳水、脂肪记录等功能最终打造出一个完全符合个人习惯的、高度集成的健康管理中心。