()
| 311 | * @returns {Promise<Object>} 统计数据对象 |
| 312 | */ |
| 313 | const getDashboardData = async () => { |
| 314 | await loadUsageData(); |
| 315 | // 最近10次使用的工具及时间 |
| 316 | const recent = []; |
| 317 | const recentDetail = []; |
| 318 | const dates = Object.keys(usageData.dailyUsage).sort((a, b) => b.localeCompare(a)); |
| 319 | for (const date of dates) { |
| 320 | for (const tool of Object.keys(usageData.dailyUsage[date].tools || {})) { |
| 321 | if (!recent.includes(tool)) { |
| 322 | recent.push(tool); |
| 323 | recentDetail.push({ tool, date }); |
| 324 | if (recent.length >= 10) break; |
| 325 | } |
| 326 | } |
| 327 | if (recent.length >= 10) break; |
| 328 | } |
| 329 | // 工具使用总次数排行 |
| 330 | const mostUsed = Object.entries(usageData.tools) |
| 331 | .sort((a, b) => b[1] - a[1]) |
| 332 | .slice(0, 10) |
| 333 | .map(([name, count]) => ({ name, count })); |
| 334 | const totalCount = Object.values(usageData.tools).reduce((a, b) => a + b, 0); |
| 335 | const activeDays = Object.keys(usageData.dailyUsage).length; |
| 336 | const allDates = Object.keys(usageData.dailyUsage).sort(); |
| 337 | // 最近10天每日使用情况 |
| 338 | const dailyTrend = allDates.slice(-10).map(date => ({ |
| 339 | date, |
| 340 | count: Object.values(usageData.dailyUsage[date].tools || {}).reduce((a, b) => a + b, 0) |
| 341 | })); |
| 342 | // 首次和最近活跃日期 |
| 343 | const firstDate = allDates[0] || ''; |
| 344 | const lastDate = allDates[allDates.length - 1] || ''; |
| 345 | // 连续活跃天数 |
| 346 | let maxStreak = 0, curStreak = 0, prev = ''; |
| 347 | for (let i = 0; i < allDates.length; i++) { |
| 348 | if (i === 0 || (new Date(allDates[i]) - new Date(prev) === 86400000)) { |
| 349 | curStreak++; |
| 350 | } else { |
| 351 | maxStreak = Math.max(maxStreak, curStreak); |
| 352 | curStreak = 1; |
| 353 | } |
| 354 | prev = allDates[i]; |
| 355 | } |
| 356 | maxStreak = Math.max(maxStreak, curStreak); |
| 357 | // 本月/本周统计 |
| 358 | const now = new Date(); |
| 359 | const thisMonth = now.toISOString().slice(0, 7); |
| 360 | const thisWeekMonday = new Date(now.setDate(now.getDate() - now.getDay() + 1)).toISOString().slice(0, 10); |
| 361 | let monthCount = 0, weekCount = 0; |
| 362 | allDates.forEach(date => { |
| 363 | const cnt = Object.values(usageData.dailyUsage[date].tools || {}).reduce((a, b) => a + b, 0); |
| 364 | if (date.startsWith(thisMonth)) monthCount += cnt; |
| 365 | if (date >= thisWeekMonday) weekCount += cnt; |
| 366 | }); |
| 367 | // 平均每日使用次数 |
| 368 | const avgPerDay = activeDays ? Math.round(totalCount / activeDays * 10) / 10 : 0; |
| 369 | // 最活跃的一天 |
| 370 | let maxDay = { date: '', count: 0 }; |
nothing calls this directly
no test coverage detected