HarmonyOS律愈实战02:ArkTS五音数据模型设计
ArkTS 数据建模实战用五音元数据驱动疗愈 App本文适合标签ArkTS、HarmonyOS、数据建模、前端架构、五音疗愈对应文件entry/src/main/ets/data/models/WuYinData.ets1. 为什么先做数据模型很多应用一开始会直接写页面写着写着就会出现几个问题五音名称、颜色、脏腑、频率散落在不同页面。首页、疗愈页、卡片页各维护一份数据后期很容易不一致。推荐算法拿不到统一的 Session 数据。“律愈”项目的做法是先把五音领域数据抽出来页面只消费模型。2. 核心类型设计五音 key 被限制为联合类型exporttypeToneKeyjiao|zhi|gong|shang|yu;这样做比直接写string更安全。比如函数参数声明为ToneKey后调用方就不能随便传入abc。五音元数据模型如下exportinterfaceWuYinMeta{key:ToneKey;name:string;element:string;organ:string;emotion:string;color:string;glow:string;visualEmoji:string;description:string;traits:string[];frequencyHz:number;recommendedTime:string;}这里的字段设计比较完整name角音、徵音、宫音、商音、羽音。element/organ五行和脏腑映射。color/glow直接服务 UI 主题色。frequencyHz服务音频生成。traits服务辨证结果展示。recommendedTime服务时辰推荐。这就是一个典型的“领域数据驱动 UI”的写法。3. Session 数据设计疗愈内容不是只靠五音本身还需要一个可播放的 SessionexportinterfaceSessionItem{id:string;name:string;tone:ToneKey;durationMin:number;visualEmoji:string;}Session 和 Tone 的关系是多对一一个音色下面可以有多个疗愈场景。functionmkSession(id:string,name:string,tone:ToneKey,durationMin:number,visualEmoji:string):SessionItem{consts:SessionItem{id:id,name:name,tone:tone,durationMin:durationMin,visualEmoji:visualEmoji};returns;}为什么要写mkSession()因为 ArkTS 对对象字面量和类型推断有更严格的规则用显式构造函数可以减少类型检查问题也让列表数据更统一。4. 五音顺序很重要项目里固定了五音顺序exportconstTONE_ORDER:ToneKey[][jiao,zhi,gong,shang,yu];这个顺序不仅用于 UI 展示还用于辨证算法的分数数组。例如一个问题选项的分数[3,0,0,0,0]表示角音加 3 分。只要顺序固定数组评分就可以非常轻量。functiontoneScores(a:number,b:number,c:number,d:number,e:number):number[]{constout:number[][];out.push(a);out.push(b);out.push(c);out.push(d);out.push(e);returnout;}5. 查询函数封装页面并不直接遍历元数据而是通过函数取值exportfunctionwuYinMetaOf(tone:ToneKey):WuYinMeta{switch(tone){casejiao:returnWU_JIAO;casezhi:returnWU_ZHI;casegong:returnWU_GONG;caseshang:returnWU_SHANG;caseyu:returnWU_YU;default:returnWU_GONG;}}这种写法看起来比RecordToneKey, WuYinMeta啰嗦但在 ArkTS 严格检查场景下更稳。尤其是项目启用了严格构建选项后显式 switch 更容易通过校验。6. 时辰推荐模型首页“今日时辰推荐”来自HourRecommendRowexportinterfaceHourRecommendRow{start:number;end:number;tone:ToneKey;title:string;sessionId:string;}根据当前小时选择推荐音色exportfunctiongetToneByHour(hour:number):ToneKey{for(constrowofHOUR_RECOMMEND){if(hourrow.starthourrow.end){returnrow.tone;}}returngong;}再根据sessionId找到首页展示的 SessionexportfunctiongetHeroSessionForHour(hour:number):SessionItem{for(constrowofHOUR_RECOMMEND){if(hourrow.starthourrow.end){constfoundSESSION_LIST.find((s:SessionItem)s.idrow.sessionId);if(found){returnfound;}}}returnSESSION_LIST.find((s:SessionItem)s.idgong_01)asSessionItem;}7. 数据流图WuYinData.etsIndexToneStripIndexHeroCardTriageEngineToneAudioPlayerYulvPlayerCard五音选择时辰推荐辨证得分频率生成 WAV桌面卡片展示8. 这一层的设计收益这套模型带来三个明显收益UI 只负责展示不需要知道每个音色的细节。算法可以直接复用五音顺序和 Session 列表。后续扩展真实音频、更多疗愈场景、更多问卷题目时不需要大改页面结构。如果你也在写 HarmonyOS 项目建议先把“会被多个页面共同使用的数据”抽出来。尤其是音频、内容库、推荐算法这类应用数据模型的稳定程度会直接影响后续开发效率。9. ArkTS 严格模式下的数据建模经验HarmonyOS ArkTS 对类型和对象字面量的要求比普通 JavaScript 更严格。律愈项目里没有大量使用松散的 ny而是用明确的接口约束领域数据这一点很适合写给初学者。s export interface WuYinMetaMap { jiao: WuYinMeta; zhi: WuYinMeta; gong: WuYinMeta; shang: WuYinMeta; yu: WuYinMeta; }这段代码看起来只是声明了一个 map但它解决的是“键名必须完整且合法”的问题。如果使用普通对象随意拼接 key页面在读取 wuYinMetaOf(tone) 时就可能遇到空值。10. 为什么不用魔法字符串项目中很多地方都要判断五音例如播放器、卡片、辨证结果、疗愈库过滤。如果都写成字符串很容易出现 jiao、Jiao、jue 混用的问题。联合类型能把错误提前到编译期。s function parseToneKey(raw: string): ToneKey { if (raw jiao || raw zhi || raw gong || raw shang || raw yu) { return raw; } return gong; }这种解析函数尤其适合用在 Want 参数、卡片消息、Preferences 存储读取这些“外部输入”场景。原则是内部使用强类型外部输入先校验再进入系统。11. Session 列表如何服务多个页面SESSION_LIST 同时被首页、疗愈页、疗愈库和辨证结果页使用。它的好处是所有页面看到的是同一批内容 sexport function sessionsForTone(tone: ToneKey): SessionItem[] {return SESSION_LIST.filter((s: SessionItem) s.tone tone);}export function sessionById(id: string): SessionItem | undefined {return SESSION_LIST.find((s: SessionItem) s.id id);}这段封装的价值在于列表过滤函数看似简单但它把数据查询集中到了模型文件中页面不用重复写 filter 逻辑。12. 可扩展字段设计如果后续要把律愈做成更完整的内容型应用可以在不破坏现有结构的情况下继续加字段s export interface SessionItem { id: string; name: string; tone: ToneKey; durationMin: number; visualEmoji: string; cover?: Resource; audioAsset?: string; tags?: string[]; scene?: sleep | focus | relax | breath; }这说明一开始的模型设计不需要非常复杂但要给未来扩展留下位置。文章可以把这点作为“从 Demo 到产品”的思考。reath’;}这说明一开始的模型设计不需要非常复杂但要给未来扩展留下位置。文章可以把这点作为“从 Demo 到产品”的思考。