HarmonyOS NEXT AI 智能生活助手:AI 每日花语
·
HarmonyOS NEXT AI 智能生活助手:AI 每日花语
前言
在第11篇中,我们实现了 AI 翻译助手。本文将实现一个更具趣味性和互动性的功能——AI 每日花语。
花语 是花卉文化的核心,每种花都有独特的花语和寓意。AI 每日花语不仅告诉用户"这是什么花",还讲述花的故事、寓意、送花建议,甚至引用相关的诗句。
本文将实现:
- 花语查询:输入花名 → 获取花语、寓意、故事
- 每日推荐:首页随机展示一种花语
- FlowerManager:花语查询管理
- 花语卡片:精美的展示组件
- 收藏功能:收藏喜爱的花语

图1:每日花语页面布局展示
一、花语功能设计
1.1 页面布局
┌─────────────────────────┐
│ ← 返回 每日花语 │
├─────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ │ │
│ │ [向日葵图标] │ │ ← 花名/图标
│ │ │ │
│ └─────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ 花语:沉默的爱 │ │
│ │ │ │
│ │ 寓意: │ │
│ │ 忠诚、希望、光明 │ │ ← 花语信息
│ │ │ │
│ │ 送花建议: │ │
│ │ 适合送给正在 │ │
│ │ 奋斗的朋友... │ │
│ └─────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ [书图标] 历史故事 │ │ ← 故事区域
│ │ 向日葵的故事... │ │
│ └─────────────────┘ │
│ │
│ [分享] [收藏] [换一朵] │
├─────────────────────────┤
│ [换一朵] [搜索其他花] │
└─────────────────────────┘
1.2 技术架构
// 花语模块架构图(代码描述)
/*
┌─────────────────────────────────────────┐
│ FlowerPage.ets │
│ (UI 展示与交互层) │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ FlowerManager.ts │
│ (业务逻辑 + 缓存管理) │
└─────────────────┬───────────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│AIService│ │CacheMgr │ │relational│
│(AI调用) │ │(缓存) │ │Store │
└─────────┘ └─────────┘ └─────────┘
*/
二、数据模型
2.1 花语数据结构
// model/FlowerInfo.ts
export interface FlowerInfo {
name: string; // 花名
alias?: string[]; // 别名
language: string; // 花语
meaning: string; // 寓意
description: string; // 描述
suggestion: string; // 送花建议
story: string; // 历史故事/传说
poem?: string; // 相关诗句
season?: string; // 花期
color?: string; // 花色
origin?: string; // 原产地
imageUrl?: string; // 图片 URL
tags: string[]; // 标签
}
// 花语收藏
export interface FlowerFavorite {
flowerName: string;
language: string;
savedAt: number;
}
// 花语数据库表定义
export const FLOWER_FAVORITES_TABLE = {
tableName: 'flower_favorites',
columns: [
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
{ name: 'flower_name', type: 'TEXT NOT NULL' },
{ name: 'language', type: 'TEXT' },
{ name: 'saved_at', type: 'INTEGER' }
]
};
2.2 花语响应解析器
// parser/FlowerResponseParser.ts
export class FlowerResponseParser {
static parse(content: string, defaultName: string): FlowerInfo {
try {
// 尝试提取 JSON
const jsonMatch = content.match(/\{[\s\S]*\}/);
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[0]);
return {
name: parsed.name || defaultName,
alias: parsed.alias || [],
language: parsed.language || '暂无',
meaning: parsed.meaning || '暂无',
description: parsed.description || '',
suggestion: parsed.suggestion || '暂无建议',
story: parsed.story || '暂无相关故事',
poem: parsed.poem,
season: parsed.season,
color: parsed.color,
origin: parsed.origin,
tags: parsed.tags || [defaultName]
};
}
} catch {}
// fallback
return {
name: defaultName,
language: '暂无信息',
meaning: '暂无信息',
description: '',
suggestion: '暂无建议',
story: '暂无相关故事',
tags: [defaultName]
};
}
}
三、FlowerManager
3.1 核心花语管理器
// ai/FlowerManager.ts
export class FlowerManager {
private static instance: FlowerManager;
private aiService = AIService.getInstance();
private promptManager = PromptManager.getInstance();
private cacheManager = CacheManager.getInstance();
private favorites: FlowerFavorite[] = [];
static getInstance(): FlowerManager {
if (!FlowerManager.instance) {
FlowerManager.instance = new FlowerManager();
}
return FlowerManager.instance;
}
// 查询花语(核心方法)
async queryFlower(flowerName: string): Promise<FlowerInfo> {
// 1. 检查缓存
const cached = this.cacheManager.get<FlowerInfo>(`flower_${flowerName}`);
if (cached) return cached;
// 2. 构建 Prompt
const prompt = this.promptManager.buildPrompt('flower', {
flowerName: flowerName
});
// 3. 调用 AI(支持多 Provider:OpenAI/DeepSeek/Qwen/智谱/豆包)
const response = await this.aiService.chat([
{ role: 'system', content: prompt },
{ role: 'user', content: `请查询"${flowerName}"的花语和相关信息` }
]);
// 4. 解析 AI 返回的 JSON
const flowerInfo = FlowerResponseParser.parse(response.content, flowerName);
// 5. 写入缓存(内存 + 持久化)
this.cacheManager.set(`flower_${flowerName}`, flowerInfo, 24 * 60 * 60 * 1000);
await this.cacheManager.persist(`flower_${flowerName}`, flowerInfo);
return flowerInfo;
}
// 获取每日推荐花语
async getDailyFlower(): Promise<FlowerInfo> {
const today = new Date();
const seed = today.getFullYear() * 10000 + (today.getMonth() + 1) * 100 + today.getDate();
const flowerList = [
'向日葵', '玫瑰', '百合', '康乃馨', '郁金香',
'雏菊', '紫罗兰', '勿忘我', '樱花', '梅花',
'荷花', '牡丹', '茉莉', '栀子花', '风信子'
];
const index = seed % flowerList.length;
return this.queryFlower(flowerList[index]);
}
// 收藏花语
addFavorite(flower: FlowerInfo): void {
const existing = this.favorites.find(f => f.flowerName === flower.name);
if (!existing) {
this.favorites.unshift({
flowerName: flower.name,
language: flower.language,
savedAt: Date.now()
});
}
}
// 取消收藏
removeFavorite(flowerName: string): void {
this.favorites = this.favorites.filter(f => f.flowerName !== flowerName);
}
// 是否已收藏
isFavorite(flowerName: string): boolean {
return this.favorites.some(f => f.flowerName === flowerName);
}
// 获取收藏列表
getFavorites(): FlowerFavorite[] {
return [...this.favorites];
}
// 搜索花
async searchFlowers(keyword: string): Promise<string[]> {
const commonFlowers = [
'玫瑰', '百合', '郁金香', '向日葵', '康乃馨', '紫罗兰',
'雏菊', '勿忘我', '樱花', '梅花', '荷花', '牡丹',
'茉莉', '栀子花', '风信子', '薰衣草', '马蹄莲', '桔梗',
'满天星', '铃兰', '海棠', '山茶', '杜鹃', '木兰'
];
return commonFlowers.filter(f => f.includes(keyword));
}
}
3.2 安全区适配工具
// utils/SafeAreaUtil.ts
import { display } from '@kit.ArkUI';
export class SafeAreaUtil {
static getStatusBarHeight(): number {
return AppStorage.get<number>('statusBarHeight') || 0;
}
static getNavBarHeight(): number {
return AppStorage.get<number>('navBarHeight') || 0;
}
// 使用 display.getDefaultDisplaySync().densityPixels 转换 px 到 vp
static px2vp(px: number): number {
const density = display.getDefaultDisplaySync().densityPixels;
return px / density;
}
}
四、FlowerPage 页面
4.1 主页面实现
// pages/FlowerPage.ets
@Entry
@Component
struct FlowerPage {
@State flowerName: string = '';
@State flowerInfo: FlowerInfo | null = null;
@State isLoading: boolean = false;
@State isFavorite: boolean = false;
@State searchResults: string[] = [];
@State showSearch: boolean = false;
@State cardScale: number = 0.95;
@State cardOpacity: number = 0;
@State statusBarHeight: number = 0;
@State navBarHeight: number = 0;
private flowerManager = FlowerManager.getInstance();
aboutToAppear() {
// 安全区适配
this.statusBarHeight = AppStorage.get<number>('statusBarHeight') || 0;
this.navBarHeight = AppStorage.get<number>('navBarHeight') || 0;
this.loadDailyFlower();
}
async loadDailyFlower() {
this.isLoading = true;
try {
const flower = await this.flowerManager.getDailyFlower();
this.flowerInfo = flower;
this.flowerName = flower.name;
this.isFavorite = this.flowerManager.isFavorite(flower.name);
this.animateCard();
} catch {
ToastUtil.show('获取花语失败');
} finally {
this.isLoading = false;
}
}
async queryFlower(name: string) {
if (!name.trim()) return;
this.isLoading = true;
this.flowerName = name;
this.showSearch = false;
try {
const flower = await this.flowerManager.queryFlower(name);
this.flowerInfo = flower;
this.isFavorite = this.flowerManager.isFavorite(name);
this.animateCard();
} catch {
ToastUtil.show('查询失败');
} finally {
this.isLoading = false;
}
}
animateCard() {
this.cardScale = 0.95;
this.cardOpacity = 0;
animateTo({ duration: 400, curve: Curve.FastOutSlowIn }, () => {
this.cardScale = 1;
this.cardOpacity = 1;
});
}
build() {
Column() {
// 状态栏占位
Row().width('100%').height(this.statusBarHeight);
// 导航栏
Row() {
Image($r('app.media.ic_back')).width(24).height(24)
.onClick(() => RouterUtil.back());
Text('每日花语').fontSize(18).fontWeight(FontWeight.Bold).margin({ left: 12 });
Blank();
Image($r('app.media.ic_search')).width(22).height(22)
.onClick(() => { this.showSearch = !this.showSearch; });
}
.width('100%').height(56).padding({ left: 16, right: 16 });
// 搜索栏
if (this.showSearch) {
Row() {
TextInput({ placeholder: '输入花名...', text: this.flowerName })
.layoutWeight(1).height(40).backgroundColor('#F5F6FA')
.borderRadius(20).padding({ left: 16 })
.onChange((value: string) => {
this.flowerName = value;
this.flowerManager.searchFlowers(value).then(r => this.searchResults = r);
})
.onSubmit(() => this.queryFlower(this.flowerName));
Button('查询').backgroundColor('#6C5CE7').fontColor(Color.White)
.borderRadius(20).margin({ left: 8 })
.onClick(() => this.queryFlower(this.flowerName));
}
.padding(16);
// 搜索建议
if (this.searchResults.length > 0) {
Column() {
ForEach(this.searchResults, (name: string) => {
Text(name).fontSize(15).padding(12).width('100%')
.onClick(() => this.queryFlower(name));
}, (name: string) => name);
}
.backgroundColor(Color.White).borderRadius(12).margin({ left: 16, right: 16 });
}
}
// 加载状态
if (this.isLoading) {
LoadingView({ text: '正在查询花语...' }).layoutWeight(1);
return;
}
// 花语内容
if (this.flowerInfo) {
Scroll() {
Column() {
// 花名头部
Column() {
Text(this.flowerInfo.name)
.fontSize(32).fontWeight(FontWeight.Bold).fontColor('#2D3436');
if (this.flowerInfo.alias?.length) {
Text(`别名:${this.flowerInfo.alias.join('、')}`)
.fontSize(14).fontColor(Color.Gray).margin({ top: 4 });
}
}
.width('100%').padding(24)
.backgroundColor(LinearGradient.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#6C5CE7', 0], ['#A29BFE', 0.5], ['#E8E8FF', 1]]
}))
.borderRadius({ bottomLeft: 24, bottomRight: 24 });
// 花语卡片
Column() {
// 花语
this.infoRow('花语', this.flowerInfo.language);
// 寓意
this.infoRow('寓意', this.flowerInfo.meaning);
// 送花建议
this.infoRow('送花建议', this.flowerInfo.suggestion);
}
.width('100%').padding(16)
.backgroundColor(Color.White).borderRadius(16)
.margin(16)
.opacity(this.cardOpacity).scale({ x: this.cardScale, y: this.cardScale });
// 历史故事
Column() {
Text('历史故事').fontSize(16).fontWeight(FontWeight.Bold)
.width('100%').margin({ bottom: 8 });
Text(this.flowerInfo.story).fontSize(15).lineHeight(24).fontColor('#636E72');
}
.width('100%').padding(16)
.backgroundColor(Color.White).borderRadius(16)
.margin({ left: 16, right: 16, bottom: 16 });
// 相关诗句
if (this.flowerInfo.poem) {
Column() {
Text('相关诗句').fontSize(16).fontWeight(FontWeight.Bold)
.width('100%').margin({ bottom: 8 });
Text(this.flowerInfo.poem).fontSize(15).fontStyle(FontStyle.Italic)
.fontColor('#6C5CE7').lineHeight(24);
}
.width('100%').padding(16)
.backgroundColor('#F8F6FF').borderRadius(16)
.margin({ left: 16, right: 16, bottom: 16 });
}
// 操作按钮
Row() {
this.actionButton('收藏', this.isFavorite ? '#E17055' : '#B2BEC3', () => {
if (this.isFavorite) {
this.flowerManager.removeFavorite(this.flowerInfo!.name);
} else {
this.flowerManager.addFavorite(this.flowerInfo!);
}
this.isFavorite = !this.isFavorite;
});
this.actionButton('换一朵', '#6C5CE7', () => {
this.loadDailyFlower();
});
this.actionButton('分享', '#0984E3', () => {
this.shareFlower();
});
}
.width('100%').padding(16);
}
}
.layoutWeight(1);
}
// 底部导航栏占位
Row().width('100%').height(this.navBarHeight);
}
.width('100%').height('100%').backgroundColor('#F5F6FA');
}
@Builder
infoRow(label: string, value: string) {
Column() {
Text(label).fontSize(13).fontColor('#6C5CE7').fontWeight(FontWeight.Medium);
Text(value).fontSize(15).fontColor('#2D3436').lineHeight(22)
.margin({ top: 4 }).width('100%');
}
.width('100%').padding({ top: 8, bottom: 8 })
.border({ bottom: { width: 0.5, color: '#F0F0F0' } });
}
@Builder
actionButton(label: string, color: string, action: () => void) {
Button() {
Text(label).fontSize(13).fontColor(Color.White);
}
.backgroundColor(color).borderRadius(20).height(36)
.layoutWeight(1).margin({ left: 4, right: 4 })
.onClick(() => action());
}
shareFlower() {
if (!this.flowerInfo) return;
const shareText = `${this.flowerInfo.name} — ${this.flowerInfo.language}\n\n花语:${this.flowerInfo.language}\n寓意:${this.flowerInfo.meaning}\n\n来自 HarmonyAI 智能生活助手`;
const clipboard = getContext(this).clipboard;
clipboard.set({ primary: shareText });
ToastUtil.show('已复制分享内容');
}
}
五、Prompt 模板
5.1 flower.md
---
name: flower
version: 1.2.0
description: AI 每日花语查询
---
你是一位博学的花语专家和植物文化研究者。请查询「{{flowerName}}」的详细信息。
## 输出要求
请用以下 JSON 格式回答:
{
"name": "花名",
"alias": ["别名1", "别名2"],
"language": "一句话花语概括",
"meaning": "详细寓意解析,2-3句话",
"description": "花卉描述",
"suggestion": "送花建议及适用场合",
"story": "相关的历史故事、神话传说或文化典故,100-150字",
"poem": "一首与该花相关的经典诗句",
"season": "花期季节",
"color": "主要花色",
"origin": "原产地",
"tags": ["花名", "花语", "花卉文化"]
}
## 注意事项
1. 花语须符合传统花语文化
2. 故事需有出处,不可编造
3. 诗句须标注出处
4. 送花建议要实用、具体
六、花期与花语对照表
6.1 四季花期速查
export const SEASONAL_FLOWERS: Record<string, FlowerInfo[]> = {
spring: [
{ name: '樱花', language: '生命之美', season: '3-4月', meaning: '生命、美丽' },
{ name: '郁金香', language: '完美的爱情', season: '3-5月', meaning: '博爱、体贴' },
{ name: '牡丹', language: '富贵吉祥', season: '4-5月', meaning: '圆满、浓情' }
],
summer: [
{ name: '荷花', language: '出淤泥而不染', season: '6-8月', meaning: '纯洁、坚贞' },
{ name: '向日葵', language: '沉默的爱', season: '7-8月', meaning: '忠诚、希望' },
{ name: '百合', language: '百年好合', season: '6-7月', meaning: '顺利、祝福' }
],
autumn: [
{ name: '菊花', language: '清净高洁', season: '9-11月', meaning: '长寿、隐逸' },
{ name: '桂花', language: '收获与吉祥', season: '9-10月', meaning: '吉祥、友好' },
{ name: '木芙蓉', language: '纤细之美', season: '10-11月', meaning: '贞操、高洁' }
],
winter: [
{ name: '梅花', language: '坚强不屈', season: '12-2月', meaning: '坚韧、高洁' },
{ name: '水仙', language: '纯洁高雅', season: '1-2月', meaning: '自尊、高雅' },
{ name: '山茶', language: '理想的爱', season: '1-3月', meaning: '谦让、魅力' }
]
};
| 季节 | 代表花卉 | 花期 | 关键词 |
|---|---|---|---|
| 春季 | 樱花、郁金香、牡丹 | 3-5月 | 生命、爱情、富贵 |
| 夏季 | 荷花、向日葵、百合 | 6-8月 | 纯洁、忠诚、祝福 |
| 秋季 | 菊花、桂花、木芙蓉 | 9-11月 | 高洁、吉祥、美丽 |
| 冬季 | 梅花、水仙、山茶 | 12-2月 | 坚韧、高雅、谦让 |
选花建议:送花时不仅要考虑花语,还要结合季节性。应季花卉不仅价格更优,花期也更持久。
6.2 花色与花语关系
export const COLOR_FLOWER_MEANING: Record<string, string> = {
'红色': '热情、爱情、尊重',
'粉色': '温柔、浪漫、幸福',
'白色': '纯洁、真诚、谦逊',
'黄色': '友谊、快乐、温暖',
'紫色': '高贵、神秘、优雅',
'蓝色': '宁静、深邃、永恒',
'橙色': '活力、热情、希望',
'绿色': '平和、生机、健康'
};
export function getFlowerMeaningByColor(flower: string, color: string): string {
const base = COLOR_FLOWER_MEANING[color] || '美好';
return `${flower}(${color}色):${base},适合表达${getOccasion(color)}的情感`;
}
function getOccasion(color: string): string {
const occasions: Record<string, string> = {
'红色': '热烈真挚',
'粉色': '甜蜜温馨',
'白色': '纯洁崇高',
'黄色': '阳光积极',
'紫色': '深邃浪漫',
'蓝色': '沉静安宁'
};
return occasions[color] || '美好';
}
七、送花场景指南
7.1 不同场合的送花建议
| 场合 | 推荐花卉 | 花语 | 禁忌 |
|---|---|---|---|
| 生日 | 康乃馨、百合 | 祝福、健康 | 白色系慎选 |
| 求婚/表白 | 红玫瑰、郁金香 | 爱情、热恋 | 黄色玫瑰(分手) |
| 探病 | 向日葵、康乃馨 | 康复、温暖 | 浓郁花香花卉 |
| 母亲节 | 康乃馨、萱草 | 感恩、母爱 | — |
| 教师节 | 向日葵、剑兰 | 感恩、尊敬 | — |
| 开业 | 发财树、百合 | 财运、顺利 | 白色花卉 |
| 道歉 | 黄玫瑰、风信子 | 歉意、悔过 | 红玫瑰 |
| 葬礼 | 白菊、白百合 | 哀悼、怀念 | 鲜艳色彩 |
7.2 送花数量寓意
export const FLOWER_COUNT_MEANING: Record<number, string> = {
1: '一见钟情、唯一的爱',
11: '一心一意',
19: '一世长久',
33: '三生三世',
99: '天长地久',
101: '百里挑一',
520: '我爱你',
999: '长长久久',
1314: '一生一世'
};
export function getCountSuggestion(relationship: string): number {
const suggestions: Record<string, number> = {
'恋人': 99,
'配偶': 33,
'朋友': 11,
'父母': 19,
'同事': 6,
'长辈': 12
};
return suggestions[relationship] || 11;
}
数量讲究:送花数量在中国文化中有特定的寓意。一般来说,双数花朵在中国传统中更吉利,但表白常用 99 朵寓意长久。
7.3 保鲜与养护
export class FlowerCareGuide {
static getCareTips(flowerType: string): string[] {
const tips: Record<string, string[]> = {
'rose': ['每天换水', '斜剪根茎', '避免阳光直射', '远离水果'],
'tulip': ['浅水养护', '避免高温', '花茎会继续生长', '不要与其他花混插'],
'sunflower': ['深水养护', '每天换水', '添加保鲜剂', '避免风吹'],
'lily': ['去除花粉', '浅水养护', '避免猫接触', '花朵开放后摘除花蕊'],
'default': ['每天换水', '斜剪根茎45度', '去除水面以下叶片', '放在阴凉通风处']
};
return tips[flowerType] || tips['default'];
}
static readonly WATER_TEMPERATURE: Record<string, string> = {
'温水': '郁金香、百合、风信子',
'凉水': '玫瑰、菊花、康乃馨',
'冰水': '兰花、马蹄莲'
};
}
| 花卉类型 | 换水频率 | 剪根周期 | 保鲜期 |
|---|---|---|---|
| 玫瑰 | 每天 | 每2天 | 7-10天 |
| 百合 | 2天 | 每3天 | 10-14天 |
| 郁金香 | 每天 | 不需要 | 5-7天 |
| 康乃馨 | 2天 | 每3天 | 14-21天 |
| 向日葵 | 每天 | 每天 | 7-10天 |
| 菊花 | 3天 | 每5天 | 14-21天 |
八、花语文化在APP中的运用
8.1 每日花语推送机制
export class DailyFlowerPush {
private flowerManager = FlowerManager.getInstance();
private pushDate: string = '';
async checkAndPush(): Promise<void> {
const today = new Date().toDateString();
if (this.pushDate === today) return;
const flower = await this.flowerManager.getDailyFlower();
this.pushDate = today;
// 保存到本地通知
await this.scheduleNotification(flower);
}
private async scheduleNotification(flower: FlowerInfo): Promise<void> {
// 使用 HarmonyOS 通知能力
const notificationContent = {
title: '每日花语',
text: `今日推荐:${flower.name} — ${flower.language}`,
additionalText: flower.meaning
};
// 发送通知...
}
}
8.2 花语社交分享
export class FlowerShareUtil {
static buildShareCard(flower: FlowerInfo): string {
return `${flower.name}
花语:${flower.language}
寓意:${flower.meaning}
送花建议:${flower.suggestion}
${flower.story?.slice(0, 100)}...
—— 来自 HarmonyAI 智能生活助手`;
}
static async shareToSocial(flower: FlowerInfo): Promise<void> {
const text = this.buildShareCard(flower);
try {
await getContext().share(text);
} catch (error) {
console.error('Share failed:', error);
}
}
}
九、数据持久化与缓存
9.1 使用 relationalStore 存储收藏
// database/FlowerDatabase.ts
import { relationalStore } from '@kit.ArkData';
export class FlowerDatabase {
private static instance: FlowerDatabase;
private rdbStore: relationalStore.RdbStore | null = null;
static getInstance(): FlowerDatabase {
if (!FlowerDatabase.instance) {
FlowerDatabase.instance = new FlowerDatabase();
}
return FlowerDatabase.instance;
}
async init(context: Context): Promise<void> {
const config: relationalStore.StoreConfig = {
name: 'flower.db',
securityLevel: relationalStore.SecurityLevel.S1
};
this.rdbStore = await relationalStore.getRdbStore(context, config);
await this.rdbStore?.executeSql(`
CREATE TABLE IF NOT EXISTS flower_favorites (
id INTEGER PRIMARY KEY AUTOINCREMENT,
flower_name TEXT NOT NULL,
language TEXT,
saved_at INTEGER
)
`);
}
async addFavorite(favorite: FlowerFavorite): Promise<number> {
const bucket: relationalStore.ValuesBucket = {
flower_name: favorite.flowerName,
language: favorite.language,
saved_at: favorite.savedAt
};
return await this.rdbStore?.insert('flower_favorites', bucket) || -1;
}
async getAllFavorites(): Promise<FlowerFavorite[]> {
const predicates = new relationalStore.RdbPredicates('flower_favorites');
predicates.orderByDesc('saved_at');
const resultSet = await this.rdbStore?.query(predicates);
const list: FlowerFavorite[] = [];
while (resultSet?.goToNextRow()) {
list.push({
flowerName: resultSet.getString(resultSet.getColumnIndex('flower_name')),
language: resultSet.getString(resultSet.getColumnIndex('language')),
savedAt: resultSet.getLong(resultSet.getColumnIndex('saved_at'))
});
}
resultSet?.close();
return list;
}
}
9.2 CacheManager 缓存花语数据
// cache/CacheManager.ts
export class CacheManager {
private static instance: CacheManager;
private memoryCache: Map<string, CacheEntry> = new Map();
static getInstance(): CacheManager {
if (!CacheManager.instance) {
CacheManager.instance = new CacheManager();
}
return CacheManager.instance;
}
set<T>(key: string, value: T, ttl: number = 24 * 60 * 60 * 1000): void {
this.memoryCache.set(key, {
data: value,
expireAt: Date.now() + ttl
});
}
get<T>(key: string): T | null {
const entry = this.memoryCache.get(key);
if (!entry) return null;
if (Date.now() > entry.expireAt) {
this.memoryCache.delete(key);
return null;
}
return entry.data as T;
}
async persist<T>(key: string, value: T): Promise<void> {
const pref = await getPreferences(getContext(), 'flower_cache');
await pref.put(key, JSON.stringify(value));
await pref.flush();
}
clear(): void {
this.memoryCache.clear();
}
}
interface CacheEntry {
data: unknown;
expireAt: number;
}
十、Git 提交
git add .
git commit -m "feat(flower): 完成 AI 每日花语功能
- 实现 FlowerManager(查询/每日推荐/搜索)
- 实现 FlowerPage(花语展示/搜索/收藏)
- 设计花语数据模型
- 实现每日推荐算法
- 实现花语卡片动画
- 实现收藏功能
- 集成 relationalStore 持久化收藏数据
- 实现 CacheManager 内存缓存 + 持久化缓存
- 支持 OpenAI/DeepSeek/Qwen/智谱/豆包 多 Provider
- 实现安全区适配(AppStorage + display)
- 使用 SVG 矢量图替代 emoji
- 实现 PromptManager 版本控制
Co-Authored-By: AtomCode (deepseek-v4-flash) <noreply@atomgit.com>"
git tag v0.1.1
总结
本文实现了 AI 每日花语 功能。核心要点:
- 花语查询:输入花名获取花语、寓意、故事、诗句
- 每日推荐:每天自动推荐一种花
- FlowerManager:查询 + 缓存 + 收藏
- 精美卡片:渐变背景 + 入场动画
- 搜索功能:内置 24 种常见花卉
- 多 Provider 支持:OpenAI、DeepSeek、Qwen、智谱、豆包
- PromptManager:独立管理 prompt,支持版本控制
- 安全区适配:通过 AppStorage 获取 statusBarHeight 和 navBarHeight
- 数据持久化:使用 relationalStore 保存收藏数据
- 双层缓存:CacheManager 内存缓存 + 持久化缓存
- SVG 图标:所有图标使用矢量图,不使用 emoji
如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!
相关资源
更多推荐



所有评论(0)