当前位置: 首页 > news >正文

HarmonyOS5 运动健康app(三):健康睡眠(附代码)

智能睡眠监测应用

一、睡眠监测系统的数据建模与状态定义

该应用通过四层数据结构构建睡眠监测的数字基础:

  1. 睡眠阶段枚举(SleepStageType
    定义清醒(AWAKE)、浅度(LIGHT)、深度(DEEP)三种核心状态,为睡眠周期分析建立分类标准:
enum SleepStageType {AWAKE = 'awake',LIGHT = 'light',DEEP = 'deep'
}
  1. 阶段配置接口(SleepSTyeS
    存储各阶段的可视化属性与时间参数,如图标路径、持续时间范围及转换概率:
interface SleepSTyeS {icon: string;          // 阶段图标title: string;         // 阶段名称color: string;         // 对应颜色minDuration: number;   // 最小持续时间(秒)maxDuration: number;   // 最大持续时间(秒)transitionChance: number; // 切换概率
}
  1. 阶段数据接口(SleepStage
    记录单次阶段的完整信息,包括开始/结束时间、时长及占比数据:
interface SleepStage {type: SleepStageType;  // 阶段类型icon: string;          // 图标路径title: string;         // 阶段标题duration: string;      // 持续时长color: string;         // 阶段颜色startTime: Date;       // 开始时间endTime: Date;         // 结束时间percentage: string;    // 时长占比
}
  1. 睡眠记录接口(SleepRecord
    聚合完整睡眠周期数据,形成可追溯的历史记录:
interface SleepRecord {id: string;            // 记录IDstartTime: Date;       // 开始时间endTime: Date;         // 结束时间duration: string;      // 总时长stages: SleepStage[];  // 阶段列表qualityScore: number;  // 质量评分(0-100)
}

这种分层建模方式使数据既能满足实时展示需求(如当前阶段),又能支持深度分析(如历史周期趋势),为算法评估提供结构化支撑。

二、睡眠周期的动态模拟与状态机实现

应用通过状态机模式驱动睡眠阶段的自动切换,核心逻辑集中在三个关键方法:

  1. 计时器驱动的状态更新
    通过setInterval实现1秒精度的时间追踪,同时触发阶段检查:
startSleep() {this.timerId = setInterval(() => {this.sleepDuration = this.calculateDuration(this.startTime, new Date());this.currentStageDuration++;this.checkStageTransition();  // 检查阶段切换}, 1000);
}
  1. 阶段切换策略算法
    结合时间阈值与随机概率实现自然的周期波动:
checkStageTransition() {const config = this.stageConfig[this.currentStage];if (this.currentStageDuration >= config.minDuration) {if (this.currentStageDuration >= config.maxDuration) {this.transitionToNextStage();  // 强制切换} else if (Math.random() < config.transitionChance) {this.transitionToNextStage();  // 概率切换}}
}
    • 达到最小持续时间后,按配置概率触发切换(如浅度睡眠以40%概率进入深度睡眠)
    • 超过最大持续时间则强制切换,模拟真实睡眠周期规律
  1. 状态流转控制
    通过定义阶段转换规则,模拟睡眠周期的自然波动:
transitionToNextStage() {const now = new Date();this.saveCurrentStage(now);  // 保存当前阶段// 按规则计算下一阶段(如清醒阶段80%概率进入浅度睡眠)switch (this.currentStage) {case SleepStageType.AWAKE:this.currentStage = Math.random() < 0.8 ? SleepStageType.LIGHT : SleepStageType.DEEP;break;// 其余阶段转换逻辑...}
}

这种动态模拟机制无需真实传感器数据,即可通过算法还原睡眠周期的自然波动,为用户提供接近真实场景的阶段分析。

三、睡眠质量评估的多维度算法设计

应用通过三层指标体系构建睡眠质量评分(0-100分),算法实现兼顾专业性与可解释性:

  1. 深度睡眠占比分析
    以深度睡眠占比20%-30%为基准,每超出1%加1分,不足1%减1分:
const deepStage = this.sleepStages.find(s => s.type === SleepStageType.DEEP);
if (deepStage) {const deepPercentage = (deepSeconds / totalSeconds) * 100;score += deepPercentage > 30 ? Math.min(20, Math.round(deepPercentage - 30)) : deepPercentage < 20 ? -Math.min(20, Math.round(20 - deepPercentage)) : 0;
}
  1. 清醒状态惩罚机制
    清醒占比超过10%后,每超出1%减2分,量化碎片化睡眠的影响:
const awakeStage = this.sleepStages.find(s => s.type === SleepStageType.AWAKE);
if (awakeStage) {const awakePercentage = (awakeSeconds / totalSeconds) * 100;score -= awakePercentage > 10 ? Math.min(30, Math.round((awakePercentage - 10) * 2)) : 0;
}
  1. 周期完整性评估
    每完成3个阶段(约一个完整睡眠周期)加2分,最多加10分:
const cycleCount = Math.floor(this.sleepStages.length / 3);
score += Math.min(10, cycleCount * 2);

最终评分会转换为自然语言描述(如"良好:睡眠质量不错"),降低非专业用户的理解门槛。

四、交互界面的分层设计与数据可视化

应用采用"状态卡片+阶段分析"的双层UI架构,通过ArkTS声明式UI实现动态渲染:

  1. 睡眠状态主卡片
Stack() {Circle().fill(this.isSleeping ? '#3498db' : '#4682b4').width(200).height(200).opacity(0.9);Column({ space: 8 }) {Text(this.sleepDuration).fontSize(32).fontWeight(FontWeight.Bold);if (this.isSleeping) {Text(`当前: ${this.stageConfig[this.currentStage].title}`).backgroundColor(this.stageConfig[this.currentStage].color + '50').padding(5).borderRadius(5);}}
}
    • 圆形进度条背景(蓝色表示睡眠中,深蓝色表示已结束)
    • 实时显示睡眠时长、阶段状态及时间信息
    • 状态切换按钮通过颜色区分操作(绿色"开始"、红色"起床")
  1. 阶段分析面板
ForEach(this.sleepStages, (stage: SleepStage) => {Column({ space: 8 }) {Image(stage.icon).width(60).height(60).backgroundColor(stage.color + '10').borderRadius(10);Text(stage.duration).fontSize(14).fontColor('#666666');Text(stage.percentage).fontSize(12).backgroundColor(stage.color + '10').padding(5);}
});
    • 横向排列各阶段卡片,包含图标、时长及占比数据
    • 评分卡片采用"数字+描述"双行显示(如"75/100 良好:睡眠质量不错")
    • 空状态提示优化无数据场景的用户体验

这种设计遵循"数据可视化金字塔"原则——顶层展示核心指标(时长/评分),中层呈现阶段分布,底层隐藏时间戳等辅助数据,使信息层级清晰可辨。

五、附:代码
import promptAction from '@ohos.promptAction';// 睡眠阶段类型
enum SleepStageType {AWAKE = 'awake',LIGHT = 'light',DEEP = 'deep'
}// 睡眠阶段数据接口
interface SleepStage {type: SleepStageType;  // 睡眠阶段类型icon: string;          // 图标资源路径title: string;         // 睡眠阶段标题duration: string;      // 该阶段持续时长color: string;         // 阶段对应颜色startTime: Date;       // 阶段开始时间endTime: Date;         // 阶段结束时间percentage: string;    // 占总睡眠时长百分比
}// 睡眠记录接口
interface SleepRecord {id: string;startTime: Date;endTime: Date;duration: string;stages: SleepStage[];qualityScore: number;  // 睡眠质量评分 (0-100)
}interface SleepSTye {SleepStageType:SleepStageTypeSleepSTyeS:SleepSTyeS
}interface SleepSTyeS {icon: string;title: string;color: string;minDuration: number;maxDuration: number;transitionChance: number;
}@Entry
@Component
export struct Index {@State sleepDuration: string = "0时0分0秒";    // 总睡眠时长@State startTime: Date = new Date();            // 开始时间@State endTimeStr: string = "0:0:0";            // 结束时间字符串@State isSleeping: boolean = false;             // 是否正在睡眠@State timerId: number = -1;                    // 计时器ID@State currentStage: SleepStageType = SleepStageType.LIGHT; // 当前睡眠阶段@State currentStageStartTime: Date = new Date(); // 当前阶段开始时间@State currentStageDuration: number = 0;        // 当前阶段持续时间(秒)@State sleepStages: SleepStage[] = [];          // 所有睡眠阶段记录@State sleepRecords: SleepRecord[] = [];        // 历史睡眠记录// 睡眠阶段配置private stageConfig: Record<SleepStageType, SleepSTyeS> = {[SleepStageType.AWAKE]: {icon: "$r('app.media.awake_sleep_icon')",title: "清醒睡眠",color: "#e74c3c",minDuration: 30,maxDuration: 180,transitionChance: 0.7},[SleepStageType.LIGHT]: {icon: "$r('app.media.light_sleep_icon')",title: "浅度睡眠",color: "#2ecc71",minDuration: 120,maxDuration: 600,transitionChance: 0.4},[SleepStageType.DEEP]: {icon: "$r('app.media.deep_sleep_icon')",title: "深度睡眠",color: "#3498db",minDuration: 300,maxDuration: 1200,transitionChance: 0.2}}// 开始睡觉startSleep() {this.isSleeping = true;this.startTime = new Date();this.endTimeStr = "睡眠中...";this.sleepDuration = "0时0分0秒";this.currentStage = SleepStageType.LIGHT; // 初始为浅度睡眠this.currentStageStartTime = new Date();this.currentStageDuration = 0;this.sleepStages = [];// 启动计时器this.timerId = setInterval(() => {const now = new Date();this.sleepDuration = this.calculateDuration(this.startTime, now);this.currentStageDuration++;// 检查是否需要切换睡眠阶段this.checkStageTransition();}, 1000);promptAction.showToast({ message: "开始记录睡眠" });}// 结束睡觉endSleep() {clearInterval(this.timerId);this.isSleeping = false;const endTime = new Date();this.endTimeStr = this.formatTime(endTime);this.sleepDuration = this.calculateDuration(this.startTime, endTime);// 保存最后一个睡眠阶段this.saveCurrentStage(endTime);// 计算各阶段百分比this.calculateStagePercentages();// 计算睡眠质量评分const qualityScore = this.calculateQualityScore();// 保存睡眠记录const newRecord: SleepRecord = {id: Date.now().toString(),startTime: this.startTime,endTime: endTime,duration: this.sleepDuration,stages: this.sleepStages,qualityScore: qualityScore};this.sleepRecords = [newRecord, ...this.sleepRecords];promptAction.showToast({message: `睡眠记录已保存,质量评分: ${qualityScore}`});}// 检查是否需要切换睡眠阶段checkStageTransition() {const config = this.stageConfig[this.currentStage];// 如果达到最小持续时间,随机决定是否切换if (this.currentStageDuration >= config.minDuration) {// 达到最大持续时间,强制切换if (this.currentStageDuration >= config.maxDuration) {this.transitionToNextStage();return;}// 随机概率切换if (Math.random() < config.transitionChance) {this.transitionToNextStage();}}}// 切换到下一睡眠阶段transitionToNextStage() {const now = new Date();// 保存当前阶段this.saveCurrentStage(now);// 决定下一阶段let nextStage: SleepStageType;switch (this.currentStage) {case SleepStageType.AWAKE:nextStage = Math.random() < 0.8 ? SleepStageType.LIGHT : SleepStageType.DEEP;break;case SleepStageType.LIGHT:nextStage = Math.random() < 0.6 ? SleepStageType.DEEP : SleepStageType.AWAKE;break;case SleepStageType.DEEP:nextStage = Math.random() < 0.8 ? SleepStageType.LIGHT : SleepStageType.AWAKE;break;}// 更新当前阶段this.currentStage = nextStage;this.currentStageStartTime = now;this.currentStageDuration = 0;}// 保存当前睡眠阶段saveCurrentStage(endTime: Date) {const config = this.stageConfig[this.currentStage];const duration = this.currentStageDuration;// 计算小时和分钟const hours = Math.floor(duration / 3600);const minutes = Math.floor((duration % 3600) / 60);const seconds = duration % 60;// 格式化持续时间let durationStr = '';if (hours > 0) durationStr += `${hours}小时`;if (minutes > 0) durationStr += `${minutes}分`;if (seconds > 0 || durationStr === '') durationStr += `${seconds}秒`;// 添加到睡眠阶段列表this.sleepStages.push({type: this.currentStage,icon: config.icon,title: config.title,duration: durationStr,color: config.color,startTime: new Date(this.currentStageStartTime),endTime: new Date(endTime),percentage: "0%"});}// 计算各阶段百分比calculateStagePercentages() {const totalSeconds = this.getTotalSeconds(this.sleepDuration);if (totalSeconds === 0) return;for (const stage of this.sleepStages) {const stageSeconds = (stage.endTime.getTime() - stage.startTime.getTime()) / 1000;const percentage = Math.round((stageSeconds / totalSeconds) * 100);stage.percentage = `${percentage}%`;}}// 计算睡眠质量评分calculateQualityScore(): number {let score = 50; // 基础分// 深度睡眠占比越高,分数越高const deepStage = this.sleepStages.find(s => s.type === SleepStageType.DEEP);if (deepStage) {const deepSeconds = (deepStage.endTime.getTime() - deepStage.startTime.getTime()) / 1000;const totalSeconds = this.getTotalSeconds(this.sleepDuration);const deepPercentage = (deepSeconds / totalSeconds) * 100;// 深度睡眠占比20%-30%为正常,每超出1%加1分,不足1%减1分if (deepPercentage > 30) {score += Math.min(20, Math.round(deepPercentage - 30));} else if (deepPercentage < 20) {score -= Math.min(20, Math.round(20 - deepPercentage));}}// 清醒阶段越少,分数越高const awakeStage = this.sleepStages.find(s => s.type === SleepStageType.AWAKE);if (awakeStage) {const awakeSeconds = (awakeStage.endTime.getTime() - awakeStage.startTime.getTime()) / 1000;const totalSeconds = this.getTotalSeconds(this.sleepDuration);const awakePercentage = (awakeSeconds / totalSeconds) * 100;// 清醒占比10%以下为正常,每超出1%减2分if (awakePercentage > 10) {score -= Math.min(30, Math.round((awakePercentage - 10) * 2));}}// 睡眠周期越多,分数越高const cycleCount = Math.floor(this.sleepStages.length / 3); // 每3个阶段算一个周期score += Math.min(10, cycleCount * 2);// 确保分数在0-100范围内return Math.max(0, Math.min(100, score));}// 计算时间差calculateDuration(start: Date, end: Date): string {const diffMs = end.getTime() - start.getTime();const hours = Math.floor(diffMs / (1000 * 60 * 60));const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));const seconds = Math.floor((diffMs % (1000 * 60)) / 1000);return `${hours}时${minutes}分${seconds}秒`;}// 格式化时间formatTime(date: Date): string {return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`;}// 获取总秒数getTotalSeconds(duration: string): number {const parts = duration.split('时');const hourPart = parts[0];const minutePart = parts[1].split('分')[0];const secondPart = parts[1].split('分')[1].split('秒')[0];const hours = Number(hourPart);const minutes = Number(minutePart);const seconds = Number(secondPart || 0);return hours * 3600 + minutes * 60 + seconds;}build() {Column({ space: 15 }) {// 睡眠状态卡片Column({ space: 20 }) {Stack() {// 圆形进度条Circle().fill(this.isSleeping ? '#3498db' : '#4682b4').width(200).height(200).opacity(0.9);Column({ space: 8 }) {Text(this.sleepDuration).fontSize(32).fontColor('#FFFFFF').fontWeight(FontWeight.Bold);Text(`开始时间: ${this.formatTime(this.startTime)}`).fontSize(14).fontColor('#FFFFFF');Text(`结束时间: ${this.endTimeStr}`).fontSize(14).fontColor('#FFFFFF');if (this.isSleeping) {Text(`当前: ${this.stageConfig[this.currentStage].title}`).fontSize(14).fontColor('#FFFFFF').backgroundColor(this.stageConfig[this.currentStage].color + '50').padding(5).borderRadius(5);}}}.margin({ top: 20 });// 睡眠控制按钮Button(this.isSleeping ? '起床' : '开始睡觉').width(150).height(50).backgroundColor('#FFFFFF').fontColor(this.isSleeping ? '#e74c3c' : '#3498db').fontSize(18).fontWeight(FontWeight.Bold).onClick(() => {this.isSleeping ? this.endSleep() : this.startSleep();});}.width('100%').height(this.isSleeping ? 350 : 320).backgroundColor(this.isSleeping ? '#3498db' : '#4682b4').borderRadius(20).shadow({ radius: 5, color: '#0000001A' });// 睡眠阶段展示Text('睡眠阶段分析').fontSize(18).fontColor('#333').fontWeight(FontWeight.Bold).margin({ top: 10, bottom: 15 });// 睡眠阶段统计if (!this.isSleeping && this.sleepStages.length > 0) {Row({ space: 15 }) {ForEach(this.sleepStages, (stage: SleepStage) => {Column({ space: 8 }) {Image(stage.icon).width(60).height(60).backgroundColor(stage.color + '10').borderRadius(10);Text(stage.title).fontSize(16).fontColor('#333333').fontWeight(FontWeight.Medium);Text(stage.duration).fontSize(14).fontColor('#666666');Text(stage.percentage).fontSize(12).fontColor(stage.color).backgroundColor(stage.color + '10').padding(5).borderRadius(10);}.flexGrow(1).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center);});}.width('100%').padding({ left: 15, right: 15 });// 睡眠质量评分if (this.sleepRecords.length > 0) {Column() {Text(`睡眠质量评分: ${this.sleepRecords[0].qualityScore}/100`).fontSize(16).fontColor('#333').fontWeight(FontWeight.Medium);Text(this.getQualityDescription(this.sleepRecords[0].qualityScore)).fontSize(14).fontColor('#666').margin({ top: 5 });}.width('100%').padding(15).backgroundColor('#f5f7fa').borderRadius(15).margin({ top: 15 });}} else {Text(this.isSleeping ? '睡眠中,阶段数据将在结束后显示' : '暂无睡眠阶段数据').fontSize(14).fontColor('#666').width('100%').textAlign(TextAlign.Center).margin({ top: 15 });}}.height('100%').padding(15);}// 根据睡眠质量评分获取描述getQualityDescription(score: number): string {if (score >= 90) return '优秀:睡眠质量极佳,身心充分恢复';if (score >= 75) return '良好:睡眠质量不错,身体得到较好休息';if (score >= 60) return '一般:睡眠质量一般,建议调整作息';if (score >= 40) return '较差:睡眠质量不佳,可能影响日常状态';return '很差:睡眠质量严重不足,建议就医检查';}
}

相关文章:

  • springboot项目中整合高德地图
  • Java中extends与implements深度解析:继承与接口实现的本质区别
  • SpringBoot 日志管理
  • 什么是探索式测试,应该怎么做?
  • 视觉语言模型的“视而不见“
  • 初认Flask框架
  • 基于深度学习的智能语音合成系统:技术与实践
  • pmset - 控制 macOS 系统电源、睡眠、唤醒与节能
  • 隧道代理IP的使用与技术优势分析
  • 学习笔记:Redis入门
  • Trae国内版Builder模式VS Chat模式
  • 表格对比工具推荐,快速比对Excel文件
  • 开疆智能ModbusTCP转Devicenet网关连接西门子200Smart与费托斯阀岛案例
  • 数据库中的Schema是什么?不同数据库中Schema的含义
  • Charles 抓包工具使用教程
  • OpenLayers 图层叠加控制
  • 芯片测试之VIL/VIH(输入电平)Test全解析:从原理到实战
  • 服务器上安装配置vsftpd
  • Webpack:现代前端构建工具的核心解析
  • 深入理解 @JsonGetter:精准掌控前端返回数据格式!
  • wordpress 哪个好用/seo技巧是什么
  • 泉州市第一建设有限公司网站/网站建设公司是怎么找客户
  • 网站制作公司站建设/杭州排名优化公司
  • 做建筑钢材的b2b网站有哪些/小游戏推广接单平台
  • 云服务器网站崩溃的原因/竹子建站官网
  • 做企业网站通常哪找素材/软件推广