欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

在这里插入图片描述

📌 概述

统计分析模块用于分析宠物日记的统计数据。这个模块提供了日记数量、宠物分布、标签使用频率等多维度的统计分析。通过Cordova框架,我们能够在Web层实现灵活的统计展示,同时利用OpenHarmony的数据聚合能力执行复杂的统计计算。

统计分析模块采用了可视化设计,使用图表展示统计数据,帮助用户直观地了解数据分布。

🔗 完整流程

数据聚合流程:应用从数据库中收集所有日记数据,按不同维度进行聚合,计算各项统计指标。

统计展示流程:应用使用图表库(如Chart.js)将统计数据可视化,生成柱状图、饼图、折线图等。

数据导出流程:用户可以将统计报告导出为PDF或图片格式。

🔧 Web代码实现

// 计算统计数据
async function calculateStatistics() {
    try {
        const diaries = await db.getAllDiaries();
        const pets = await db.getAllPets();
        const tags = await db.getAllTags();
        
        return {
            totalDiaries: diaries.length,
            totalPets: pets.length,
            averageDiariesPerPet: (diaries.length / pets.length).toFixed(2),
            tagUsage: calculateTagUsage(diaries, tags),
            diariesByMonth: calculateDiariesByMonth(diaries),
            diariesByPet: calculateDiariesByPet(diaries, pets)
        };
    } catch (error) {
        console.error('计算统计失败:', error);
        return null;
    }
}

// 计算标签使用频率
function calculateTagUsage(diaries, tags) {
    const usage = {};
    
    tags.forEach(tag => {
        usage[tag.name] = diaries.filter(d => 
            d.tags && d.tags.includes(tag.name)
        ).length;
    });
    
    return Object.entries(usage)
        .sort((a, b) => b[1] - a[1])
        .slice(0, 10)
        .map(([name, count]) => ({ name, count }));
}

// 按月份计算日记数
function calculateDiariesByMonth(diaries) {
    const monthData = {};
    
    diaries.forEach(diary => {
        const date = new Date(diary.date);
        const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
        monthData[monthKey] = (monthData[monthKey] || 0) + 1;
    });
    
    return Object.entries(monthData)
        .sort()
        .map(([month, count]) => ({ month, count }));
}

// 按宠物计算日记数
function calculateDiariesByPet(diaries, pets) {
    const petData = {};
    
    pets.forEach(pet => {
        petData[pet.name] = diaries.filter(d => d.petId === pet.id).length;
    });
    
    return Object.entries(petData)
        .map(([name, count]) => ({ name, count }));
}

这些函数处理统计数据的计算。

// 渲染统计分析页面
async function renderStatistics() {
    const stats = await calculateStatistics();
    
    if (!stats) {
        showError('无法加载统计数据');
        return;
    }
    
    const html = `
        <div class="statistics-container">
            <div class="stats-header">
                <h1>统计分析</h1>
            </div>
            
            <div class="stats-cards">
                <div class="stat-card">
                    <h3>总日记数</h3>
                    <p class="stat-value">${stats.totalDiaries}</p>
                </div>
                <div class="stat-card">
                    <h3>宠物总数</h3>
                    <p class="stat-value">${stats.totalPets}</p>
                </div>
                <div class="stat-card">
                    <h3>平均每宠物日记数</h3>
                    <p class="stat-value">${stats.averageDiariesPerPet}</p>
                </div>
            </div>
            
            <div class="charts-grid">
                <div class="chart-container">
                    <h2>热门标签</h2>
                    <canvas id="tags-chart"></canvas>
                </div>
                
                <div class="chart-container">
                    <h2>每月日记数</h2>
                    <canvas id="monthly-chart"></canvas>
                </div>
                
                <div class="chart-container">
                    <h2>宠物日记分布</h2>
                    <canvas id="pets-chart"></canvas>
                </div>
            </div>
            
            <div class="export-section">
                <button class="btn-primary" onclick="exportStatisticsReport()">导出报告</button>
            </div>
        </div>
    `;
    
    document.getElementById('page-container').innerHTML = html;
    
    // 绘制图表
    drawTagsChart(stats.tagUsage);
    drawMonthlyChart(stats.diariesByMonth);
    drawPetsChart(stats.diariesByPet);
}

// 绘制标签图表
function drawTagsChart(tagUsage) {
    const ctx = document.getElementById('tags-chart').getContext('2d');
    
    new Chart(ctx, {
        type: 'bar',
        data: {
            labels: tagUsage.map(t => t.name),
            datasets: [{
                label: '使用次数',
                data: tagUsage.map(t => t.count),
                backgroundColor: '#409EFF'
            }]
        },
        options: {
            responsive: true,
            plugins: {
                legend: { display: false }
            }
        }
    });
}

// 绘制月份图表
function drawMonthlyChart(monthData) {
    const ctx = document.getElementById('monthly-chart').getContext('2d');
    
    new Chart(ctx, {
        type: 'line',
        data: {
            labels: monthData.map(m => m.month),
            datasets: [{
                label: '日记数',
                data: monthData.map(m => m.count),
                borderColor: '#67c23a',
                backgroundColor: 'rgba(103, 194, 58, 0.1)',
                tension: 0.4
            }]
        },
        options: {
            responsive: true,
            plugins: {
                legend: { display: true }
            }
        }
    });
}

// 绘制宠物图表
function drawPetsChart(petData) {
    const ctx = document.getElementById('pets-chart').getContext('2d');
    
    new Chart(ctx, {
        type: 'doughnut',
        data: {
            labels: petData.map(p => p.name),
            datasets: [{
                data: petData.map(p => p.count),
                backgroundColor: ['#409EFF', '#67c23a', '#e6a23c', '#f56c6c']
            }]
        },
        options: {
            responsive: true,
            plugins: {
                legend: { position: 'bottom' }
            }
        }
    });
}

这个渲染函数生成了统计分析界面,包括统计卡片和多个图表。

🔌 原生代码实现

// StatisticsPlugin.ets - 统计分析原生插件
import { fileIo } from '@kit.BasicServicesKit';

@Entry
@Component
struct StatisticsPlugin {
    // 生成统计报告
    generateStatisticsReport(stats: string, callback: (path: string) => void): void {
        try {
            const data = JSON.parse(stats);
            const report = `
统计分析报告
============
总日记数: ${data.totalDiaries}
宠物总数: ${data.totalPets}
平均每宠物日记数: ${data.averageDiariesPerPet}
生成时间: ${new Date().toISOString()}
            `;
            
            const reportPath = `/data/reports/statistics_${Date.now()}.txt`;
            const file = fileIo.openSync(reportPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE);
            fileIo.writeSync(file.fd, report);
            fileIo.closeSync(file.fd);
            
            callback(reportPath);
        } catch (error) {
            console.error('[StatisticsPlugin] 生成报告失败:', error);
            callback('');
        }
    }
    
    build() {
        Column() {
            Web({ src: 'resource://rawfile/www/index.html', controller: new WebviewController() })
        }
    }
}

这个原生插件提供了报告生成功能。

Web-Native通信代码

// 导出统计报告
async function exportStatisticsReport() {
    try {
        const stats = await calculateStatistics();
        const reportPath = await generateNativeReport(stats);
        
        if (reportPath) {
            showSuccess(`报告已生成: ${reportPath}`);
        }
    } catch (error) {
        showError('导出失败: ' + error.message);
    }
}

// 生成原生报告
function generateNativeReport(stats) {
    return new Promise((resolve, reject) => {
        cordova.exec(
            (path) => {
                if (path) {
                    resolve(path);
                } else {
                    reject(new Error('生成失败'));
                }
            },
            (error) => {
                console.error('生成失败:', error);
                reject(error);
            },
            'StatisticsPlugin',
            'generateStatisticsReport',
            [JSON.stringify(stats)]
        );
    });
}

这段代码展示了如何通过Cordova调用原生的报告生成功能。

📝 总结

统计分析模块展示了Cordova与OpenHarmony在数据分析方面的应用。在Web层,我们实现了灵活的统计展示和图表可视化。在原生层,我们提供了报告生成功能。

通过多维度的统计分析,用户可以深入了解自己的日记数据。通过图表可视化,数据变得更加直观易懂。通过Web-Native通信,我们能够充分利用OpenHarmony的文件系统能力,为用户提供完整的数据分析体验。

在实际开发中,建议实现更多的统计维度,提供数据对比功能,并支持自定义报告生成。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐