【鸿蒙开发实战】智能数据洞察服务:待回礼分析与关系维护建议算法

问题描述

如何在鸿蒙应用中实现智能数据分析功能?本文以人情管理系统为例,实现以下智能洞察功能:

  1. 月度收支趋势预测
  2. 人情往来健康度评分
  3. 待回礼智能提醒与紧急度评分
  4. 关系维护建议生成

这些功能涉及复杂的业务逻辑和算法设计,是鸿蒙应用开发中的高级话题。

技术要点

  • 数据分析算法设计
  • Promise.all 并发优化
  • 业务规则引擎实现
  • 评分算法设计
  • 智能建议生成

完整实现代码

复制代码
/**
 * 智能数据洞察服务
 * 提供数据分析、趋势预测、健康度评分等功能
 */
​
import { DataService } from './DataService';
import { HumanRecord, Person, RecordType, RelationshipType } from '../model/DataModels';
​
/**
 * 数据洞察接口
 */
export interface DataInsight {
  monthlyTrend: MonthlyTrendInsight;           // 月度趋势
  healthScore: number;                          // 健康度评分(0-100)
  pendingReciprocations: RecipocationItem[];   // 待回礼列表
  relationshipSuggestions: RelationshipSuggestion[];  // 关系维护建议
}
​
/**
 * 月度趋势洞察
 */
export interface MonthlyTrendInsight {
  predictedReceived: number;     // 本月预计总收入
  predictedSent: number;         // 本月预计总支出
  actualReceived: number;        // 本月实际总收入
  actualSent: number;            // 本月实际总支出
  receivedChange: number;        // 与上月对比(百分比)
  sentChange: number;            // 与上月对比(百分比)
  trendDescription: string;      // 趋势描述
}
​
/**
 * 待回礼项
 */
export interface RecipocationItem {
  recordId: string;              // 记录ID
  personId: string;              // 人物ID
  personName: string;            // 人物姓名
  receivedAmount: number;        // 收到的金额
  suggestedAmount: number;       // 建议回礼金额
  receivedTime: number;          // 收到的时间
  eventType: string;             // 事件类型
  daysSince: number;             // 距离天数
  urgency: number;               // 紧急程度(1-5)
}
​
/**
 * 关系维护建议
 */
export interface RelationshipSuggestion {
  personId: string;              // 人物ID
  personName: string;            // 人物姓名
  relationshipType: RelationshipType;  // 关系类型
  lastInteractionTime: number;   // 最后往来时间
  daysSince: number;             // 距离天数
  suggestionType: string;        // 建议类型
  suggestionText: string;        // 建议内容
  priority: number;              // 优先级(1-5)
}
​
export class InsightService {
  private static instance: InsightService;
  private dataService: DataService;
​
  private constructor() {
    this.dataService = DataService.getInstance();
  }
​
  public static getInstance(): InsightService {
    if (!InsightService.instance) {
      InsightService.instance = new InsightService();
    }
    return InsightService.instance;
  }
​
  /**
   * 获取完整的数据洞察(并发加载提升性能)
   */
  public async getDataInsight(): Promise<DataInsight> {
    try {
      // 使用Promise.all并发执行,提升性能
      const results = await Promise.all([
        this.getMonthlyTrendInsight(),
        this.calculateHealthScore(),
        this.getPendingReciprocations(),
        this.getRelationshipSuggestions()
      ]);
​
      return {
        monthlyTrend: results[0],
        healthScore: results[1],
        pendingReciprocations: results[2],
        relationshipSuggestions: results[3]
      };
    } catch (error) {
      console.error('获取数据洞察失败:', JSON.stringify(error));
      throw new Error('获取数据洞察失败');
    }
  }
​
  /**
   * 获取月度趋势洞察(含预测)
   */
  public async getMonthlyTrendInsight(): Promise<MonthlyTrendInsight> {
    try {
      const now = new Date();
      const monthStart = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0, 0);
      const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
      
      const allRecords = await this.dataService.getAllRecords();
      
      // 手动过滤本月记录
      const currentMonthRecords = allRecords.filter(record => 
        record.eventTime >= monthStart.getTime() && record.eventTime <= monthEnd.getTime()
      );
​
      // 获取上月数据
      const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1, 0, 0, 0, 0);
      const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59, 999);
      const lastMonthRecords = allRecords.filter(record =>
        record.eventTime >= lastMonthStart.getTime() && record.eventTime <= lastMonthEnd.getTime()
      );
​
      // 计算本月实际数据
      let actualReceived = 0;
      let actualSent = 0;
      for (const record of currentMonthRecords) {
        if (record.type === RecordType.RECEIVED) {
          actualReceived += record.amount;
        } else {
          actualSent += record.amount;
        }
      }
​
      // 计算上月数据
      let lastMonthReceived = 0;
      let lastMonthSent = 0;
      for (const record of lastMonthRecords) {
        if (record.type === RecordType.RECEIVED) {
          lastMonthReceived += record.amount;
        } else {
          lastMonthSent += record.amount;
        }
      }
​
      // 预测本月剩余数据(基于当前进度)
      const daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
      const currentDay = now.getDate();
      const progressRatio = currentDay / daysInMonth;
      
      const predictedReceived = progressRatio > 0 ? Math.round(actualReceived / progressRatio) : actualReceived;
      const predictedSent = progressRatio > 0 ? Math.round(actualSent / progressRatio) : actualSent;
​
      // 计算变化百分比
      const receivedChange = lastMonthReceived > 0 
        ? Math.round(((predictedReceived - lastMonthReceived) / lastMonthReceived) * 100)
        : 0;
      const sentChange = lastMonthSent > 0
        ? Math.round(((predictedSent - lastMonthSent) / lastMonthSent) * 100)
        : 0;
​
      // 生成趋势描述
      const trendDescription = this.generateTrendDescription(receivedChange, sentChange);
​
      return {
        predictedReceived,
        predictedSent,
        actualReceived,
        actualSent,
        receivedChange,
        sentChange,
        trendDescription
      };
    } catch (error) {
      console.error('获取月度趋势失败:', JSON.stringify(error));
      return {
        predictedReceived: 0,
        predictedSent: 0,
        actualReceived: 0,
        actualSent: 0,
        receivedChange: 0,
        sentChange: 0,
        trendDescription: '暂无数据'
      };
    }
  }
​
  /**
   * 生成趋势描述
   */
  private generateTrendDescription(receivedChange: number, sentChange: number): string {
    const descriptions: string[] = [];
​
    if (receivedChange > 20) {
      descriptions.push('收入显著增长');
    } else if (receivedChange > 0) {
      descriptions.push('收入稳步增长');
    } else if (receivedChange < -20) {
      descriptions.push('收入明显下降');
    } else {
      descriptions.push('收入保持稳定');
    }
​
    if (sentChange > 20) {
      descriptions.push('支出显著增加');
    } else if (sentChange > 0) {
      descriptions.push('支出稳步增加');
    } else if (sentChange < -20) {
      descriptions.push('支出明显减少');
    } else {
      descriptions.push('支出保持稳定');
    }
​
    return descriptions.join(',');
  }
​
  /**
   * 计算人情往来健康度评分(0-100)
   */
  public async calculateHealthScore(): Promise<number> {
    try {
      let score = 100;
      
      // 获取最近6个月的数据
      const sixMonthsAgo = Date.now() - (180 * 24 * 60 * 60 * 1000);
      const allRecords = await this.dataService.getAllRecords();
      const records = allRecords.filter(record => record.eventTime >= sixMonthsAgo);
​
      if (records.length === 0) {
        return 50; // 无数据时返回中等分数
      }
​
      // 1. 收支平衡度(30分)
      let totalReceived = 0;
      let totalSent = 0;
      for (const record of records) {
        if (record.type === RecordType.RECEIVED) {
          totalReceived += record.amount;
        } else {
          totalSent += record.amount;
        }
      }
​
      const balanceRatio = totalReceived > 0 ? totalSent / totalReceived : 0;
      if (balanceRatio >= 0.8 && balanceRatio <= 1.2) {
        // 收支平衡,满分
      } else if (balanceRatio >= 0.5 && balanceRatio <= 1.5) {
        score -= 10;
      } else if (balanceRatio >= 0.3 && balanceRatio <= 2.0) {
        score -= 20;
      } else {
        score -= 30;
      }
​
      // 2. 往来频率(25分)
      const avgMonthlyRecords = records.length / 6;
      if (avgMonthlyRecords >= 4) {
        // 频率适中
      } else if (avgMonthlyRecords >= 2) {
        score -= 10;
      } else if (avgMonthlyRecords >= 1) {
        score -= 15;
      } else {
        score -= 25;
      }
​
      // 3. 待回礼情况(25分)
      const pendingReciprocations = await this.getPendingReciprocations();
      const urgentCount = pendingReciprocations.filter(item => item.urgency >= 4).length;
      
      if (urgentCount === 0) {
        // 无紧急待回礼
      } else if (urgentCount <= 2) {
        score -= 10;
      } else if (urgentCount <= 5) {
        score -= 15;
      } else {
        score -= 25;
      }
​
      // 4. 关系维护(20分)
      const suggestions = await this.getRelationshipSuggestions();
      const highPriorityCount = suggestions.filter(item => item.priority >= 4).length;
      
      if (highPriorityCount === 0) {
        // 关系维护良好
      } else if (highPriorityCount <= 2) {
        score -= 8;
      } else if (highPriorityCount <= 5) {
        score -= 12;
      } else {
        score -= 20;
      }
​
      return Math.max(0, Math.min(100, score));
    } catch (error) {
      console.error('计算健康度评分失败:', JSON.stringify(error));
      return 50;
    }
  }
​
  /**
   * 获取待回礼列表(智能计算)
   */
  public async getPendingReciprocations(): Promise<RecipocationItem[]> {
    try {
      const persons = await this.dataService.getAllPersons();
      const recipocations: RecipocationItem[] = [];
      const now = Date.now();
      
      const allRecords = await this.dataService.getAllRecords();
​
      for (const person of persons) {
        // 过滤该人物的所有记录
        const records = allRecords.filter(record => record.personId === person.id);
        records.sort((a, b) => b.eventTime - a.eventTime);
​
        // 计算收支差额
        let balance = 0;
        let lastReceivedRecord: HumanRecord | null = null;
​
        for (const record of records) {
          if (record.type === RecordType.RECEIVED) {
            balance += record.amount;
            if (!lastReceivedRecord) {
              lastReceivedRecord = record;
            }
          } else {
            balance -= record.amount;
          }
        }
​
        // 如果余额为正且有收入记录,说明需要回礼
        if (balance > 0 && lastReceivedRecord) {
          const daysSince = Math.floor((now - lastReceivedRecord.eventTime) / (24 * 60 * 60 * 1000));
          
          // 计算紧急程度(基于时间)
          let urgency = 1;
          if (daysSince > 180) {
            urgency = 5; // 超过半年,非常紧急
          } else if (daysSince > 90) {
            urgency = 4; // 超过3个月,紧急
          } else if (daysSince > 30) {
            urgency = 3; // 超过1个月,较紧急
          } else if (daysSince > 7) {
            urgency = 2; // 超过1周,一般
          }
​
          // 建议回礼金额(略高于收到的金额)
          const suggestedAmount = Math.round(balance * 1.2);
​
          recipocations.push({
            recordId: lastReceivedRecord.id,
            personId: person.id,
            personName: person.name,
            receivedAmount: balance,
            suggestedAmount,
            receivedTime: lastReceivedRecord.eventTime,
            eventType: lastReceivedRecord.eventType,
            daysSince,
            urgency
          });
        }
      }
​
      // 按紧急程度和时间排序
      recipocations.sort((a, b) => {
        if (a.urgency !== b.urgency) {
          return b.urgency - a.urgency;
        }
        return b.daysSince - a.daysSince;
      });
​
      return recipocations;
    } catch (error) {
      console.error('获取待回礼列表失败:', JSON.stringify(error));
      return [];
    }
  }
​
  /**
   * 获取关系维护建议
   */
  public async getRelationshipSuggestions(): Promise<RelationshipSuggestion[]> {
    try {
      const persons = await this.dataService.getAllPersons();
      const suggestions: RelationshipSuggestion[] = [];
      const now = Date.now();
      
      const allRecords = await this.dataService.getAllRecords();
​
      for (const person of persons) {
        const records = allRecords.filter(record => record.personId === person.id);
        
        if (records.length === 0) continue;
​
        // 获取最后往来时间
        const sortedRecords = records.sort((a, b) => b.eventTime - a.eventTime);
        const lastInteractionTime = sortedRecords[0].eventTime;
        const daysSince = Math.floor((now - lastInteractionTime) / (24 * 60 * 60 * 1000));
​
        // 根据关系类型设置不同的提醒阈值
        let threshold = 365;
        switch (person.relationshipType) {
          case RelationshipType.RELATIVE:
            threshold = 180;
            break;
          case RelationshipType.COLLEAGUE:
          case RelationshipType.LEADER:
            threshold = 180;
            break;
          case RelationshipType.FRIEND:
          case RelationshipType.CLASSMATE:
            threshold = 365;
            break;
        }
​
        // 如果超过阈值的一半,开始提醒
        if (daysSince > threshold / 2) {
          let suggestionText = '';
          let priority = 1;
​
          if (daysSince > threshold) {
            suggestionText = `已超过${Math.floor(daysSince / 30)}个月未联系,建议主动问候`;
            priority = 5;
          } else if (daysSince > threshold * 0.75) {
            suggestionText = `已${Math.floor(daysSince / 30)}个月未联系,可以找机会联络`;
            priority = 3;
          } else {
            suggestionText = `已${Math.floor(daysSince / 30)}个月未联系,保持关注`;
            priority = 2;
          }
​
          suggestions.push({
            personId: person.id,
            personName: person.name,
            relationshipType: person.relationshipType as RelationshipType,
            lastInteractionTime,
            daysSince,
            suggestionType: 'long_time_no_contact',
            suggestionText,
            priority
          });
        }
      }
​
      // 按优先级排序
      suggestions.sort((a, b) => {
        if (a.priority !== b.priority) {
          return b.priority - a.priority;
        }
        return b.daysSince - a.daysSince;
      });
​
      return suggestions.slice(0, 10); // 最多返回10条建议
    } catch (error) {
      console.error('获取关系维护建议失败:', JSON.stringify(error));
      return [];
    }
  }
​
  /**
   * 获取健康度评级文本
   */
  public getHealthScoreLevel(score: number): string {
    if (score >= 90) return '优秀';
    if (score >= 80) return '良好';
    if (score >= 70) return '中等';
    if (score >= 60) return '及格';
    return '需要改善';
  }
​
  /**
   * 获取健康度评级颜色
   */
  public getHealthScoreColor(score: number): string {
    if (score >= 90) return '#4CAF50';
    if (score >= 80) return '#8BC34A';
    if (score >= 70) return '#FFC107';
    if (score >= 60) return '#FF9800';
    return '#F44336';
  }
}

核心算法解析

1. 月度趋势预测算法

复制代码
// 基于当前进度预测全月数据
const progressRatio = currentDay / daysInMonth;
const predictedReceived = actualReceived / progressRatio;

2. 健康度评分算法

评分维度(总分 100 分):

  • 收支平衡度: 30 分
  • 往来频率: 25 分
  • 待回礼情况: 25 分
  • 关系维护: 20 分

3. 紧急度评分算法

复制代码
if (daysSince > 180) urgency = 5;      // 超过半年
else if (daysSince > 90) urgency = 4;   // 超过3个月
else if (daysSince > 30) urgency = 3;   // 超过1个月
else if (daysSince > 7) urgency = 2;    // 超过1周
else urgency = 1;                       // 1周内

4. 关系维护阈值

不同关系类型设置不同的联系阈值:

  • 亲戚/领导/同事: 6 个月
  • 朋友/同学: 1 年
  • 邻居: 6 个月

性能优化

1. 并发加载

复制代码
const results = await Promise.all([
  this.getMonthlyTrendInsight(),
  this.calculateHealthScore(),
  this.getPendingReciprocations(),
  this.getRelationshipSuggestions()
]);

2. 数据预加载

一次性加载所有记录,避免重复查询:

复制代码
const allRecords = await this.dataService.getAllRecords();

3. 内存过滤

使用 JavaScript 数组方法过滤,减少数据库查询。

最佳实践

  1. 算法可配置化: 将阈值提取为配置项
  2. 分级评分: 采用多维度评分体系
  3. 智能建议: 根据业务规则生成建议
  4. 性能优化: 使用并发加载提升速度

应用场景

  • 数据分析报告
  • 智能提醒系统
  • 用户行为分析
  • 个性化推荐

总结

本文实现了一套完整的智能数据洞察系统,包括:

  • ✅ 趋势预测算法
  • ✅ 健康度评分体系
  • ✅ 智能提醒生成
  • ✅ 性能优化方案

适用于需要数据分析和智能建议的鸿蒙应用。

相关推荐
橘子编程35 分钟前
经典排序算法全解析
java·算法·排序算法
风筝在晴天搁浅36 分钟前
代码随想录 279.完全平方数
算法
不穿格子的程序员39 分钟前
从零开始刷算法——字串与区间类经典题:前缀和 + 单调队列双杀
算法·前缀和·哈希表·双向队列·单调队列
坚持就完事了40 分钟前
十大排序算法
数据结构·算法·排序算法
im_AMBER1 小时前
Leetcode 63 定长子串中元音的最大数目
c++·笔记·学习·算法·leetcode
啊董dong1 小时前
noi-11月30日当堂练习
算法·深度优先·图论
小白程序员成长日记2 小时前
2025.11.29 力扣每日一题
数据结构·算法·leetcode
学历真的很重要2 小时前
LangChain V1.0 Short-term Memory 详细指南
后端·python·语言模型·面试·langchain·agent·ai编程
在黎明的反思3 小时前
进程通信之消息队列(IPC)
算法