HarmonyOS 宠物档案完整源码:三表联动通用模板


实例:宠物档案(Pet Profile)|技术:全量代码解读、操作剧本、1主N从+时间序列模式抽象
一、本篇定位
前两篇分别讲了数据层与 UI 层,本篇完成三件事:
- 全量源码逐段解读——PetDao 与 PetPage 从头到尾过一遍;
- 运行效果演示——从建档到疫苗提醒的完整操作剧本;
- 模式抽象——"1 主 N 从 + 时间序列"通用模板,附两个改写场景。
二、完整源码:PetDao.ets
/**
* 宠物档案数据访问对象(DAO)
* 对应文章:32_宠物档案/32-1 建表与数据层设计、32-2 页面UI与操作实现、32-3 完整代码与运行效果
* 核心能力:宠物主表 + 喂食/体重记录从表(时间序列)、疫苗到期提醒、体重趋势数据
*/
import { relationalStore } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
/** 宠物实体,对应 pet 表结构 */
export interface Pet {
id: number;
name: string;
species: string;
breed: string;
gender: number; // 0 男 / 1 女
birthday: number;
avatar: string;
nextVaccine: number; // 下次疫苗日期(0=无)
note: string;
createdAt: number;
}
/** 体重记录实体,对应 weight_record 表结构 */
export interface WeightRecord {
id: number;
petId: number;
weight: number;
createdAt: number;
}
/** 喂食记录实体,对应 feed_record 表结构 */
export interface FeedRecord {
id: number;
petId: number;
food: string;
amount: string;
feedTime: number;
}
/** 宠物视图:宠物 + 最新体重 + 疫苗状态 */
export interface PetView {
pet: Pet;
latestWeight: number;
weightCount: number;
vaccineDueDays: number;
feedCount: number; // 今日喂食次数
}
const DOMAIN = 0x0001;
const TAG = 'PetDao';
/** 疫苗提醒阈值(天) */
export const VACCINE_WARN_DAYS = 30;
export class PetDao {
private static readonly TABLE = 'pet';
private static readonly WEIGHT_TABLE = 'weight_record';
private static readonly FEED_TABLE = 'feed_record';
private static store?: relationalStore.RdbStore;
// getStore / 行映射 / CRUD / 记录 / 统计 / 种子数据(见上篇逐段解读)
}
逐段解读总表
| 代码段 | 职责 | 关键决策 |
|---|---|---|
| 实体接口 | Pet / WeightRecord / FeedRecord / PetView | PetView 封装 4 派生数据 |
| VACCINE_WARN_DAYS | 疫苗阈值常量 | 徽标与筛选同步 |
| getStore | 单例 + 建 3 表 + 3 索引 | 1 主 2 从 |
| insertPet / updatePet | 建档与更新 | updatePet 支持疫苗设置 |
| deletePet | 循环删两从表再删主表 | 无孤儿 |
| addWeight / addFeed | 时间序列追加 | 只增不改 |
| queryWeights / queryFeeds | 记录倒序查询 | 详情流数据 |
| latestWeight | 最新值查询 | 倒序+limit 范式 |
| todayFeedCount | 今日统计 | 0 点边界 |
| queryPetViews | 视图组装 | 4 派生数据 |
| vaccineDue / summary | 临期筛选 + 统计 | reduce 聚合 |
| initSeedData | 2 宠物双记录 | 疫苗/体重演示 |
三、完整源码:PetPage.ets
/**
* 宠物档案页面
* 对应文章:32_宠物档案/32-1 ~ 32-3
* 功能:宠物卡片列表 + 新增宠物 + 详情(体重记录/喂食记录/疫苗提醒)+ 记录体重/喂食
*/
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';
import { PetDao, Pet, PetView, WeightRecord, FeedRecord, VACCINE_WARN_DAYS } from '../../database/PetDao';
@Entry
@Component
struct PetPage {
@State views: PetView[] = [];
@State summaryText: string = '';
@State formVisible: boolean = false;
@State fName: string = '';
@State fSpecies: string = '';
@State fBreed: string = '';
@State detailVisible: boolean = false;
@State current: PetView | null = null;
@State weights: WeightRecord[] = [];
@State feeds: FeedRecord[] = [];
@State wFormVisible: boolean = false;
@State fWeight: string = '';
@State feedFormVisible: boolean = false;
@State fFood: string = '';
@State fAmount: string = '';
@State vaccineFormVisible: boolean = false;
@State fVaccine: string = '';
private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
aboutToAppear(): void {
this.refresh();
}
// refresh/onAddPet/openDetail/onAddWeight/onAddFeed/onSaveVaccine/onDelete/vaccineInfo/fmtDate/fmtTime 见中篇
}
页面组织纪律回顾
- 状态量五组:列表态、建档表单(f*)、详情态(current/weights/feeds)、体重表单、喂食表单、疫苗表单——6 组 @State 清晰分区;
- 5 个弹层互斥:form/detail/wForm/feedForm/vaccineForm;
- UI 零 SQL:疫苗徽标、今日喂食全部来自 PetView。
四、接入工程三步
Step 1:放文件
PetDao.ets→entry/src/main/ets/database/PetPage.ets→entry/src/main/ets/pages/samples/
Step 2:注册路由(main_pages.json)
"pages/samples/PetPage",
Step 3:首页入口(Index.ets)
Button('🐾 32 宠物档案')
.fontSize(14)
.width('80%')
.onClick(() => {
this.getUIContext().getRouter().pushUrl({ url: 'pages/samples/PetPage' });
})
五、运行效果演示(操作剧本)
场景一:首次打开
| 步骤 | 界面表现 | 数据来源 |
|---|---|---|
| 1 | 标题栏:“🐾 宠物档案”,统计:“宠物 2 只 · 今日已喂 3 次 · 疫苗临期 1 只” | summary |
| 2 | 列表 2 只:🐈 咪咪(中华田园猫 ♂,橙徽标"疫苗临期 25 天")、🐕 旺财(金毛 ♀,灰徽标"疫苗未设") | queryPetViews |
| 3 | 咪咪卡片:“体重 4.6 kg(4 次)· 今日已喂 2 次”;旺财:“体重 19.0 kg(2 次)· 今日已喂 1 次” | latestWeight/todayFeedCount |
场景二:记录体重
- 点咪咪 → 详情抽屉:体重记录 4 条(4.2 → 4.4 → 4.5 → 4.6 kg,上升趋势);
- 点"⚖️ 记体重"→ 输入 4.7 → 保存 → toast"✅ 体重已记录";
- 抽屉体重列表顶部出现"4.7 kg",卡片摘要更新"4.7 kg(5 次)"。
场景三:记录喂食
- 抽屉点"🍖 记喂食"→ 食物"猫粮"、分量"30克"→ 记录 → toast"🍖 已记录喂食";
- 喂食记录列表顶部新增,标题栏统计"今日已喂 3 次"。
场景四:疫苗设置与提醒
- 抽屉点"设置疫苗日期"→ 输入 2026-07-01 → 保存 → toast"✅ 疫苗日期已更新";
- 徽标按剩余天数变化:>30 天绿色"疫苗正常"、≤30 橙色"疫苗临期 X 天"、已过红色"疫苗已到期 X 天";
- 留空保存 → 清除疫苗日期,徽标变灰"疫苗未设"。
场景五:新增宠物
点 + → 名"豆豆"、种类"仓鼠"、品种"三线"→ 建档 → toast"✅ 宠物已建档",列表出现 🐈(非狗默认猫 emoji)豆豆。
场景六:删除
打开任意宠物 → “🗑 删除宠物"→ 确认(提示连同全部记录)→ toast"🗑 已删除”,统计减 1。
场景七:数据持久性
杀应用重开 → 数据仍在。
六、模式抽象:"1 主 N 从 + 时间序列"通用模板
6.1 模型
┌───────────────────────────────────────────────┐
│ 主体档案表(如 pet) │
│ id / 标识字段 / 状态字段(next_vaccine) │
│ ── 主体是谁、当前状态 │
└───────┬────────────────────┬──────────────────┘
│ 1:N │ 1:N
┌───────┴───────┐ ┌────────┴───────┐
│ 时间序列 A │ │ 时间序列 B │
│(weight) │ │(feed) │
│ 值 + 时间戳 │ │ 文本 + 时间戳 │
│ 只追加 │ │ 只追加 │
└───────────────┘ └────────────────┘
6.2 六个约定
- 主体档案一张表:标识 + 状态字段集中;
- 异构时间序列分表:字段结构不同的记录(数值体重 vs 文本喂食)分开建表;
- 时间序列只追加:INSERT 为主,修改谨慎、删除按需;
- 最新值 = 倒序 + limit:最新体重/最近喂食的固定查询范式;
- 按日统计用 0 点边界:今日喂食、今日体重等每日聚合;
- 到期提醒 = 状态字段差值:next_vaccine 与 now 的天数差,负值=到期。
6.3 两个改写场景
场景 A:婴儿成长记录
| 宠物实例 | 婴儿改写 |
|---|---|
| pet | baby(婴儿:姓名/性别/生日/下次体检日) |
| weight_record | 身高体重记录(height/weight) |
| feed_record | 喂养记录(奶粉/辅食/奶量) |
| 疫苗提醒 | 体检/疫苗接种提醒 |
场景 B:健身训练日志
| 宠物实例 | 健身改写 |
|---|---|
| pet | trainee(训练者:姓名/目标/下次体测日) |
| weight_record | 体测记录(体重/体脂率) |
| feed_record | 训练日志(动作/组数/重量) |
场景 C:车辆/设备日志——主体 + 运行记录 + 加油/充电记录,模板复用。
三个场景的共同点:“一个主体 + 多维度时间记录”。掌握 32,任何"记录某个对象的多类历史数据"的业务都能落地。
七、三篇内容总对照
| 篇章 | 核心知识点 | 一句话总结 |
|---|---|---|
| 32-1 建表与数据层设计 | 1 主 2 从、最新值、今日统计 | 异构序列分表,三种查询形态 |
| 32-2 页面UI与操作实现 | 疫苗四态、双记录流、三弹窗 | 状态颜色化,多记录同屏 |
| 32-3 完整代码与运行效果 | 全量源码、操作剧本、N 从模板 | 主体+多维记录,改表名即复用 |
八、FAQ(三篇汇总补遗)
Q1:26-32 的从表语义完整总结?
A:26 事件、27 交易、28 交易+计划、29 审计、30 结构、31 时间片、32 多维度时间序列。从表从"记录型"演进到"结构型",再到"多从表并行"。本系列的数据库能力已覆盖个人应用的绝大多数建模场景。
Q2:为什么体重和喂食不用一张"pet_log(type+value)"?
A:见上篇深度扩展——字段异构(REAL vs TEXT)分表类型安全。若将来类型很多且同构(加"洗澡/遛弯"都是文本备注),可考虑合并。按字段结构决定分合。
Q3:疫苗提醒的阈值 30 天合理吗?
A:猫狗疫苗一般一年一次,提前 30 天提醒合理(准备预约)。不同宠物可配置不同阈值(next_vaccine 字段已有,阈值按需)。阈值常量 + 参数化筛选已支持自定义。
Q4:体重趋势图在哪里实现?
A:23 数据图表的 ChartCanvas 可画折线。把 weights 数组(时间升序)传给它即可。本实例记录流展示数据,图表扩展零数据层改动。
Q5:删除宠物真的需要三张表清理吗?
A:是——体重、喂食、宠物本体。循环删两从表 + 删主表。若启用物理外键 ON DELETE CASCADE 可自动,本实例保持显式两步(同 26 的讨论)。
Q6:avatar 头像怎么做?
A:photoAccessHelper 选图 → 复制到沙箱 → avatar 存路径 → image 组件加载。参考 21 签名板的保存与读取流程。本实例预留字段,实现留作练习。
九、结语
三篇文章完整走完了宠物档案的"设计 → 实现 → 复用"闭环:
- 1 教你多从表建模:异构时间序列分表、最新值/今日/到期三种查询;
- 2 教你多记录展示:疫苗四态徽标、双记录流、三录入弹窗;
- 3 教你模式复用:1 主 N 从模板,改表名即覆盖婴儿记录、健身日志。
更多推荐


所有评论(0)