统计分析模块 - Cordova与OpenHarmony混合开发实战
·
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

📌 概述
统计分析模块用于分析宠物日记的统计数据。这个模块提供了日记数量、宠物分布、标签使用频率等多维度的统计分析。通过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的文件系统能力,为用户提供完整的数据分析体验。
在实际开发中,建议实现更多的统计维度,提供数据对比功能,并支持自定义报告生成。
更多推荐



所有评论(0)