在这里插入图片描述
在这里插入图片描述

实例:家庭物品清单(Household)|技术:16 件物品、六类覆盖、借还记录

一、种子数据的设计目标

实例 20 的种子数据要撑起「物品清单 + 借用记录 + 分类筛选 + 统计」,设计目标:

  1. 16 件物品:清单内容充实——多屏可滚;
  2. 六类覆盖:厨房 3 / 家用 3 / 工具 3 / 数码 3 / 书籍 2 / 运动 2——分类筛选有结果;
  3. 借出状态:3 件借出中(破壁机/冲击钻/《三体》)——「借出中」筛选有内容、状态标签红绿分明;
  4. 借用记录:5 条(3 未还 + 2 已还)——借用记录列表有归还/已还对比;
  5. emoji 多样:🍚🍟🥤🧹🤖👔🔧🛠️🔩💻🔊📷📖📚🏸🧘——每件物品有图标;
  6. 位置具体:厨房橱柜/阳台柜/工具箱/书柜第二层——位置搜索与显示有内容。

二、16 件物品种子数据

# 名称 分类 位置 emoji 数量 状态 备注
1 电饭煲 厨房 厨房橱柜 🍚 1 在家 5L 容量
2 空气炸锅 厨房 厨房台面 🍟 1 在家
3 破壁机 厨房 厨房橱柜 🥤 1 借出 借给王阿姨
4 吸尘器 家用 阳台柜 🧹 1 在家
5 扫地机器人 家用 客厅 🤖 1 在家
6 挂烫机 家用 卧室衣柜 👔 1 在家
7 电钻 工具 工具箱 🔧 1 在家 博世 12V
8 冲击钻 工具 工具箱 🛠️ 1 借出 借给李哥
9 扳手套装 工具 工具箱 🔩 2 在家
10 笔记本电脑 数码 书房书桌 💻 1 在家
11 蓝牙音箱 数码 客厅电视柜 🔊 1 在家
12 相机 数码 防潮箱 📷 1 在家 微单
13 《活着》 书籍 书柜第二层 📖 1 在家
14 《三体》全集 书籍 书柜第一层 📚 3 借出 借给小刘
15 羽毛球拍 运动 玄关柜 🏸 2 在家
16 瑜伽垫 运动 阳台 🧘 1 在家

借用记录(5 条)

# 物品 借用人 借用时间 归还时间 备注
1 破壁机(3号) 王阿姨 -5天 未还 榨豆浆用
2 冲击钻(8号) 李哥 -3天 未还 装窗帘
3 《三体》(14号) 小刘 -7天 未还
4 电饭煲(1号) 赵叔 -30天 -20天 已归还
5 笔记本电脑(10号) 表弟 -12天 -10天 已归还

设计要点

  • 借出 3 件与借用记录对应:破壁机/冲击钻/《三体》status=1 且有未还记录(-5/-3/-7 天)——「状态与流水一致」(借出的物品必有未还记录);
  • 已还 2 条历史:电饭煲(赵叔)、笔记本(表弟)——借用记录「已还」灰色对比(这些物品 status=0 在家——已还物品状态回在家);
  • 六类分布 3/3/3/3/2/2:每类 2~3 件——分类筛选有内容;
  • 位置具体:厨房橱柜/厨房台面/阳台柜/书柜第二层——「分类 · 位置」显示与位置搜索可用;
  • 数量差异:扳手套装 2、羽毛球拍 2、《三体》3——数量字段有非 1 值。

三、代码实现

const now = Date.now();
const day = 86400000;
const itemSeeds: ItemSeed[] = [ /* 16 件,见第二节表格 */ ];
const itemIds: number[] = [];
for (const s of itemSeeds) {
  const values: relationalStore.ValuesBucket = {
    name: s.name, category: s.category, location: s.location,
    emoji: s.emoji, quantity: s.quantity, status: s.status,
    note: s.note, created_time: now - (16 - itemSeeds.indexOf(s)) * 3600000,
  };
  itemIds.push(await store.insert(HouseholdDao.TABLE, values));
}
const borrowSeeds: BorrowSeed[] = [
  { itemId: itemIds[2], borrower: '王阿姨', borrowTime: now - 5 * day, returnTime: 0, note: '榨豆浆用' },
  { itemId: itemIds[7], borrower: '李哥', borrowTime: now - 3 * day, returnTime: 0, note: '装窗帘' },
  { itemId: itemIds[13], borrower: '小刘', borrowTime: now - 7 * day, returnTime: 0, note: '' },
  { itemId: itemIds[0], borrower: '赵叔', borrowTime: now - 30 * day, returnTime: now - 20 * day, note: '已归还' },
  { itemId: itemIds[9], borrower: '表弟', borrowTime: now - 12 * day, returnTime: now - 10 * day, note: '已归还' },
];
for (const b of borrowSeeds) {
  await store.insert(HouseholdDao.BORROW_TABLE, { /* b 字段 */ });
}

关键点

  • itemIds 数组记录插入返回的 iditemIds.push(await store.insert(...))——借用种子用 itemIds[2](破壁机)等引用物品 id——**「先插物品收集 id,再插借用引用 id」**的种子关联(确保外键指向真实插入的物品);
  • created_time 递减now - (16 - index) * 3600000——物品录入时间按顺序递减(电饭煲最新?index 0 最旧——16-0=16 小时前,瑜伽垫 index 15 = 1 小时前最新)——「物品录入时间递进」
  • 借用时间now - n * day——相对天数(-5 天/-3 天/-7 天…);
  • 幂等保护:查 household_item COUNT,非空即返回。

四、注入后的物品清单效果预测

区块 预期效果
标题栏 「共 16 件 · 借出 3」
物品列表 借出在前(status DESC):破壁机 🥤「借出中」红标 → 冲击钻 🛠️ → 《三体》📚 → 在家 13 件(电饭煲🍚…瑜伽垫🧘)
状态筛选 点「借出中」→ 3 件红标(无「借出」按钮);点「在家」→ 13 件(有「借出」按钮)
分类筛选 点「工具」→ 3 件(电钻🔧/冲击钻🛠️/扳手🔩)
借用记录 5 条:小刘《三体》(-7天) → 王阿姨破壁机(-5天) → 李哥冲击钻(-3天) → 表弟笔记本(已还)→ 赵叔电饭煲(已还)——时间倒序 + 3 条「归还」绿钮 + 2 条「已还」灰字

演示脚本:指着列表说「我家 16 件物品登记在册,3 件借出去了」→ 指破壁机「这个借给王阿姨 5 天了」→ 点「借出中」筛选 → 3 件 → 点「借出」→ 弹窗借出登记 → 填「羽毛球拍 借给小明」→ 确认 → Toast「📤 借用已登记」→ 羽毛球拍变红标、借用记录多一条 → 点新记录的「归还」→ Toast「📥 已归还」→ 羽毛球拍回在家、记录变「已还」——借还闭环完整演示

五、验证方法

  1. hilog 日志:搜 HouseholdDao,看到「已填充 16 件物品 + 5 条借用记录种子数据」;
  2. 页面显示:标题栏「16 件 · 借出 3」、借出在前列表、借用记录 5 条;
  3. 数据库直查
    SELECT COUNT(*) FROM household_item;  -- 16
    SELECT category, COUNT(*) FROM household_item GROUP BY category;  -- 厨房3 家用3 工具3 数码3 书籍2 运动2
    SELECT COUNT(*) FROM household_item WHERE status = 1;  -- 3(借出)
    SELECT COUNT(*) FROM borrow_record;  -- 5
    SELECT COUNT(*) FROM borrow_record WHERE return_time = 0;  -- 3(未还)
    SELECT b.item_id, i.name FROM borrow_record b JOIN household_item i ON i.id = b.item_id;
    -- 破壁机/冲击钻/《三体》/电饭煲/笔记本电脑
    
  4. 交互验证:分类筛选、状态筛选、借出登记(事务)、归还(事务)、删除(级联)。

六、FAQ

Q1:为什么借出的 3 件物品对应 3 条未还记录?
A:数据自洽——status=1(借出)的物品必有 return_time=0 的借用记录(借出 = 写记录 + 改状态,事务保证)。**「状态与流水一致」**让筛选与记录互相对得上(演示借出 3 件 + 未还 3 条数字吻合)。

Q2:已还的 2 条记录(电饭煲/笔记本)对应的物品为什么在家?
A:归还 = 更新 return_time + 状态回 0(事务)——「已还记录 → 物品在家」的闭环。种子里这两件 status=0 与已还记录匹配——「历史记录 + 当前状态」双语义自洽

Q3:itemIds 数组是什么作用?
A:insert 返回的自增 id 存入数组——借用种子用 itemIds[2](第 3 件插入 = 破壁机)引用物品——「用返回 id 关联种子」:避免手写 id 与自增错位(自增从 1 开始且可能被清库重置)。**「程序引用而非硬编码 id」**是种子关联的正确做法。

Q4:为什么物品录入时间按 index 递减?
A:now - (16 - index) * 3600000——index 0(电饭煲)最旧、index 15(瑜伽垫)最新——「先列的物品录入早」(模拟逐步录入)。虽然列表排序是 status+category(不用录入时间),但 created_time 有值且有序(真实感 + 可排序)。

Q5:16 件物品够演示借还闭环吗?
A:够——3 件借出中(筛选可见)+ 13 件在家(可借出)+ 5 条记录(3 未还可归还 + 2 已还对比)——借出/归还/已还三种状态全路径可演示。数量再多(30+)滚动疲劳。

Q6:借用记录的时间倒序,为什么小刘《三体》(-7 天)排最前?
A:ORDER BY b.borrow_time DESC——借用时间新的在前:-3 天(李哥冲击钻)应该比 -7 天(小刘《三体》)新——descending 排序:-3 > -7,李哥第一? 检查:borrow_time = now - 3day > now - 7day——李哥(-3 天)最新排第一,其次王阿姨(-5 天)、小刘(-7 天)、表弟(-12 天)、赵叔(-30 天)——「最近借出的排最前」(演示脚本里顺序要按此描述)。

七、文章小结

本篇文章展示了实例 20 的种子数据:16 件物品六类覆盖(厨房/家用/工具/数码 3 件 + 书籍/运动 2 件 + 3 件借出中)+ 5 条借用记录(3 未还 + 2 已还)。核心是「借还闭环的种子设计」——借出物品与未还记录一一对应(状态自洽)、已还记录对应在家物品(闭环)、itemIds 数组程序引用物品 id(关联可靠)。物品清单一开屏就有借还状态与历史流水。

下一篇(20-5)是实例 20(也是整个系列)的收官文章,展示 HouseholdPage 全量代码与运行效果。

八、种子数据全量复盘与完整实现

前面七节按「目标 → 表格 → 代码 → 效果 → 验证 → FAQ」拆解了种子数据,本节做一次全量复盘:16 件物品核对表(补上录入时间)、5 条借用记录、initSeedData 完整代码(itemIds 收集)、注入效果预测与验证 SQL 速查——演示前的「数据总账」。

8.1 十六件物品全量核对表(含录入时间)

# 名称 分类 位置 emoji 数量 状态 备注 录入
1 电饭煲 厨房 厨房橱柜 🍚 1 在家 5L 容量 -16h
2 空气炸锅 厨房 厨房台面 🍟 1 在家 -15h
3 破壁机 厨房 厨房橱柜 🥤 1 借出 借给王阿姨 -14h
4 吸尘器 家用 阳台柜 🧹 1 在家 -13h
5 扫地机器人 家用 客厅 🤖 1 在家 -12h
6 挂烫机 家用 卧室衣柜 👔 1 在家 -11h
7 电钻 工具 工具箱 🔧 1 在家 博世 12V -10h
8 冲击钻 工具 工具箱 🛠️ 1 借出 借给李哥 -9h
9 扳手套装 工具 工具箱 🔩 2 在家 -8h
10 笔记本电脑 数码 书房书桌 💻 1 在家 -7h
11 蓝牙音箱 数码 客厅电视柜 🔊 1 在家 -6h
12 相机 数码 防潮箱 📷 1 在家 微单 -5h
13 《活着》 书籍 书柜第二层 📖 1 在家 -4h
14 《三体》全集 书籍 书柜第一层 📚 3 借出 借给小刘 -3h
15 羽毛球拍 运动 玄关柜 🏸 2 在家 -2h
16 瑜伽垫 运动 阳台 🧘 1 在家 -1h

5 条借用记录:王阿姨借破壁机(-5天/未还)、李哥借冲击钻(-3天/未还)、小刘借《三体》(-7天/未还)、赵叔借电饭煲(-30天/-20天已还)、表弟借笔记本(-12天/-10天已还)。

8.2 种子设计复盘:两处闭环

  • 借出与流水对应:3 件借出(破壁机/冲击钻/《三体》)↔ 3 条未还记录(王阿姨/李哥/小刘)——「借出中」筛选 3 件与「未还」3 条数字吻合,物品状态与借用流水一一对应
  • 已还与在家闭环:2 条已还记录(电饭煲/笔记本)对应物品 status=0 在家——「还了就是在家」,历史流水与当前状态自洽

8.3 initSeedData 完整实现(itemIds 收集)

static async initSeedData(context: common.Context): Promise<void> {
  const store = await HouseholdDao.getStore(context);
  // 幂等保护:已有物品直接返回
  const rs = await store.querySql(`SELECT COUNT(*) AS c FROM ${HouseholdDao.TABLE}`);
  if (rs.goToFirstRow() && rs.getLong(rs.getColumnIndex('c')) > 0) { rs.close(); return; }
  rs.close();

  const now = Date.now();
  const day = 86400000;
  const itemSeeds: ItemSeed[] = [ /* 16 件,见 8.1 表 */ ];
  const itemIds: number[] = [];   // 收集 insert 返回的自增 id
  for (let i = 0; i < itemSeeds.length; i++) {
    const s = itemSeeds[i];
    const values: relationalStore.ValuesBucket = {
      name: s.name, category: s.category, location: s.location,
      emoji: s.emoji, quantity: s.quantity, status: s.status,
      note: s.note, created_time: now - (itemSeeds.length - i) * 3600000,
    };
    itemIds.push(await store.insert(HouseholdDao.TABLE, values));
  }
  const borrowSeeds: BorrowSeed[] = [
    { itemId: itemIds[2], borrower: '王阿姨', borrowTime: now - 5 * day, returnTime: 0, note: '榨豆浆用' },
    { itemId: itemIds[7], borrower: '李哥', borrowTime: now - 3 * day, returnTime: 0, note: '装窗帘' },
    { itemId: itemIds[13], borrower: '小刘', borrowTime: now - 7 * day, returnTime: 0, note: '' },
    { itemId: itemIds[0], borrower: '赵叔', borrowTime: now - 30 * day, returnTime: now - 20 * day, note: '已归还' },
    { itemId: itemIds[9], borrower: '表弟', borrowTime: now - 12 * day, returnTime: now - 10 * day, note: '已归还' },
  ];
  for (const b of borrowSeeds) {
    await store.insert(HouseholdDao.BORROW_TABLE, {
      item_id: b.itemId, borrower: b.borrower,
      borrow_time: b.borrowTime, return_time: b.returnTime, note: b.note,
    });
  }
}

itemIds 下标 ↔ 物品对照itemIds[0] 电饭煲、[2] 破壁机、[7] 冲击钻、[9] 笔记本、[13]《三体》——先插物品收集 id,再插借用引用 id,不硬编码自增值(清库后自增会重置、可能错位)。

8.4 注入后的清单效果预测

区块 预期效果
标题栏 「共 16 件 · 借出 3」
列表 借出在前:破壁机🥤→冲击钻🛠️→《三体》📚红标,后跟 13 件在家
分类/位置筛选 「工具」3 件、「位置=工具箱」3 件(电钻/冲击钻/扳手)
借用记录 5 条倒序:李哥(-3天)→王阿姨(-5天)→小刘(-7天)→表弟(已还)→赵叔(已还)

8.5 验证 SQL 速查

SELECT COUNT(*) FROM household_item;                            -- 16
SELECT COUNT(*) FROM household_item WHERE status = 1;            -- 3(借出)
SELECT category, COUNT(*) FROM household_item GROUP BY category; -- 3/3/3/3/2/2
SELECT COUNT(*) FROM borrow_record;                              -- 5
SELECT COUNT(*) FROM borrow_record WHERE return_time = 0;        -- 3(未还)
SELECT i.name, b.borrower, b.borrow_time FROM borrow_record b
  LEFT JOIN household_item i ON i.id = b.item_id ORDER BY b.borrow_time DESC;

8.6 FAQ

Q1:16 件物品的录入时间为什么从 -16h 到 -1h?
A:now - (itemSeeds.length - i) * 3600000——下标 0(电饭煲)最旧、下标 15(瑜伽垫)最新,模拟一周内逐件录入;created_time 因此有值且有序,即使页面按录入时间排序也成立。

Q2:改种子数据时最容易犯什么错?
A:只改物品表忘了改借用记录(或反之)——「借出了却没流水」或「流水指向已在家物品」;借出/归还都要两处联动改(status + 记录),这正是运行时用事务保证原子性的原因。

Q3:演示前为什么要先跑验证 SQL?
A:SQL 是种子的「验收单」——16/3/5/3 四个数字全对再上台,避免「借出 4 件却只有 3 条未还记录」这类对不上的翻车现场。

Q4:itemIds 为什么不直接写死 1~16?
A:自增 id 由 SQLite 分配,清库重建后从 1 重新计数,硬编码会错位;insert 返回值动态收集——**「程序引用 id」**在种子注入与运行时借还中都可靠。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐