鸿蒙应用开发实战【94】— 实战多卡号场景管理最佳实践

鸿蒙应用开发实战【94】--- 实战多卡号场景管理最佳实践

本文是「号码助手全栈开发系列」第 94 篇,持续更新中...

开源社区:https://openharmonycrossplatform.csdn.net


前言

多卡管理是号码助手区别于普通通讯录的核心能力。用户可能有工作号、生活号、备用号等多张 SIM 卡,需要在各页面中随时切换卡号上下文。本篇讲解多卡号场景下的数据模型设计、UI 联动和数据隔离策略。

本篇涵盖:CardEntity 设计、多卡切换实现方案、按卡号筛选(chip 筛选器)、卡号颜色主题、跨页面传递选中卡号。


一、CardEntity 数据模型

文件features/data/Models.ets

typescript 复制代码
export interface CardEntity {
  id?: number          // 自增主键
  label: string        // 卡号标签("工作号" / "生活号" / "卡1")
  phone_number: string // 手机号
  carrier: string      // 运营商(中国移动 / 联通 / 电信)
  remark: string       // 备注
  color: string        // 卡片颜色('blue' / 'orange' / 'green' / 'pink' / 'purple')
  sort_order: number   // 排序序号
  created_at: number   // 创建时间
  updated_at: number   // 更新时间
}

设计要点

字段 用途 说明 示例值
label 用户给卡号起的名字 便于区分多张卡 "工作号"、"卡1"
color 卡号主题色 列表/卡片中通过颜色区分不同卡号 'blue'、'orange'
sort_order 自定义排序 常用卡号排前面 0、1、2
idapp_bindings.card_id 外键关联 一个卡号关联多个应用绑定 主键自增

二、多卡号筛选实现

2.1 首页 Chip 筛选

typescript 复制代码
// HomePage.ets --- chip 切换卡号筛选
const cards = await CardDao.listAll()
// chipBar 中展示:全部 | 工作号 | 生活号 | 卡3 ...

// 筛选逻辑
private getFilteredRows(): AppRow[] {
  return this.rows.filter(r => {
    const catOk = this.filterCatIdx === 0 ||
      r.binding.category === CATEGORIES[this.filterCatIdx]
    const cardOk = this.filterCardIdx === 0 ||
      r.cardLabel === this.cards[this.filterCardIdx - 1]?.label
    const statOk = this.filterStatIdx === 0 ||
      r.binding.status === STATUS_FILTERS[this.filterStatIdx]
    return catOk && cardOk && statOk
  })
}

2.2 状态列表页 Chip 筛选

文件pages/StatusListPage.ets

typescript 复制代码
// chip 二次筛选:分类 + 卡号
private getFilteredRows(): AppRow[] {
  const CATEGORIES = ['全部', 'APP', '网站', '小程序']
  return this.rows.filter(r => {
    const catOk = this.chipCatIdx === 0 ||
      r.binding.category === CATEGORIES[this.chipCatIdx]
    const cardOk = this.chipCardIdx === 0 ||
      r.cardLabel === this.cards[this.chipCardIdx - 1]?.label
    return catOk && cardOk
  })
}

三、首页卡片上的多卡号统计

首页统计卡片展示每个状态的汇总数据,点击后跳转到对应的 StatusListPage

typescript 复制代码
// 跳转到待换绑列表,携带 status 参数
Text(this.pendingSwitch.toString())
  .onClick(() => {
    router.pushUrl({
      url: 'pages/StatusListPage',
      params: { status: '待换绑' } as StatusRouteParams
    })
  })

在 StatusListPage 通过路由参数接收:

typescript 复制代码
aboutToAppear(): void {
  const params = this.getUIContext().getRouter().getParams()
  if (params && typeof params['status'] === 'string') {
    this.statusLabel = params['status']
  }
  this.loadData()
}

四、添加应用时选择卡号

AddAppPagePasteImportPage 中,用户需要通过 ActionMenu 选择目标卡号:

typescript 复制代码
// PasteImportPage --- 选择绑定的卡号
private async pickCard(): Promise<void> {
  const buttons = this.cards.map(c => ({
    text: `${c.label} · ${c.phone_number}`,
    color: AppColors.TEXT
  }))
  const result = await promptAction.showActionMenu({
    title: '选择绑定卡号',
    buttons: buttons
  })
  this.selectedCardIndex = result.index
}

五、卡号管理页面(AddCardPage)

文件pages/AddCardPage.ets

typescript 复制代码
async addCard() {
  const now = Date.now()
  const newCard: CardEntity = {
    label: this.label,               // 用户输入的名称
    phone_number: this.phoneNumber,  // 用户输入的号码
    carrier: this.carrier || '未识别',
    color: this.selectedColor,       // 用户选择的主题色
    remark: this.remark,
    sort_order: 0,
    created_at: now,
    updated_at: now
  }
  const id = await CardDao.create(newCard)
  if (id > 0) {
    // 刷新首页统计数据
    AppStorage.Set<number>('cardCount', await CardDao.countByStatus())
    router.back()
  }
}

六、卡号颜色主题系统

每个卡号可以设置颜色,在 UI 中以卡片颜色 AppColors 映射展示:

typescript 复制代码
// AppColors.ets --- 卡号颜色映射
static cardColor(colorName: string): ResourceColor {
  const map: Record<string, ResourceColor> = {
    'blue':   '#4F7CFF',
    'orange': '#FF7A1E',
    'green':  '#3CC463',
    'pink':   '#FF6B9D',
    'purple': '#7B61FF'
  }
  return map[colorName] ?? '#4F7CFF'
}

在 CardDao 反序列化时保留颜色字符串:

typescript 复制代码
private static parseRow(rs: relationalStore.ResultSet): CardEntity {
  return {
    id: rs.getLong(rs.getColumnIndex('id')),
    label: rs.getString(rs.getColumnIndex('label')),
    color: rs.getString(rs.getColumnIndex('color')) as CardColor,
    // ...
  }
}

七、跨页面当前卡号状态同步

多卡号场景下需要一种轻量级「当前选中卡号」共享机制:

方案:AppStorage + @Watch

typescript 复制代码
// 全局状态
AppStorage.SetOrCreate<number>('currentCardId', 0)
AppStorage.SetOrCreate<string>('currentCardLabel', '')

// 页面监听
@StorageProp('currentCardId') currentCardId: number = 0

// 切换卡号时更新
onCardSwitch(card: CardEntity) {
  AppStorage.Set('currentCardId', card.id ?? 0)
  AppStorage.Set('currentCardLabel', card.label)
  // 重新加载该卡号下的应用列表
  this.loadBindings(card.id ?? 0)
}

八、多卡号场景性能注意事项

场景 问题 优化
首页加载 CardDao.listAll() + AppBindingDao.countByStatus() 并行 Promise.all()
筛选切换 内存中 filter 全部数据 使用 getFilteredRows() 计算属性
卡号切换 重新加载应用列表 只在切换时加载,不做预加载
统计卡片 每次 onPageShow 都重新查询 配合 AppStorage 缓存统计值

小结

功能 实现方式 涉及文件
卡号模型 CardEntity union type Models.ets
卡号 CRUD CardDao.create / update / deleteById CardDao.ets
卡号列表 CardDao.listAll(按 sort_order 排序) CardDao.ets
颜色映射 AppColors.cardColor() AppColors.ets
Chip 筛选 数组 filter(分类 + 卡号 + 状态) HomePage.ets
卡号切换 AppStorage + @StorageProp 全局状态共享

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

相关推荐
用户41659673693551 小时前
视频源文件音频轨异常分析记录
android
花开彼岸天~1 小时前
鸿蒙应用开发实战【97】— 应用发布AGC上架全流程
华为·harmonyos·鸿蒙系统
绝世番茄1 小时前
HarmonyOS Next 深入解析:Scroll 组件与 onScroll 滚动监听实战
华为·harmonyos·鸿蒙
2501_919749031 小时前
华为鸿蒙免费铃声APP—小羊免费铃声
华为·harmonyos
不羁的木木1 小时前
《HarmonyOS技术精讲-NearLink Kit(星闪服务)》第3篇:数据收发——点对点数据传输实战
pytorch·华为·harmonyos
春卷同学2 小时前
HarmonyOS掌上记账APP开发实践第25篇:Image 组件高级用法 — 资源引用、网络图片与首字符占位方案
网络·华为·harmonyos
2501_919749032 小时前
华为鸿蒙免费记账与统计APP—小羊统计
华为·harmonyos
AD02272 小时前
32-Token明文存储-把凭据边界收到安全仓储里
harmonyos·arkts·鸿蒙开发
特立独行的猫a3 小时前
Node.js三方库鸿蒙 PC 移植:鸿蒙PC开发者面对面 · 线下课件分享
华为·harmonyos·三方库移植·鸿蒙pc