ソースを参照

Merge remote-tracking branch 'origin/fix/bug-6149-6148-6144'

ethanfly 4 日 前
コミット
d7a7a98ea2

+ 53 - 15
client/src/views/Analytics/Account/index.vue

@@ -583,16 +583,19 @@ function handleQuickDate(type: string) {
       endDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
       break;
     case 'last3days':
-      startDate.value = today.subtract(3, 'day').format('YYYY-MM-DD');
-      endDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 3 天:今天/昨天/前天
+      startDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
+      endDate.value = today.format('YYYY-MM-DD');
       break;
     case 'last7days':
-      startDate.value = today.subtract(7, 'day').format('YYYY-MM-DD');
-      endDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 7 天
+      startDate.value = today.subtract(6, 'day').format('YYYY-MM-DD');
+      endDate.value = today.format('YYYY-MM-DD');
       break;
     case 'lastMonth':
-      startDate.value = today.subtract(30, 'day').format('YYYY-MM-DD');
-      endDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 30 天
+      startDate.value = today.subtract(29, 'day').format('YYYY-MM-DD');
+      endDate.value = today.format('YYYY-MM-DD');
       break;
   }
 
@@ -730,16 +733,19 @@ function handleDetailQuickDate(type: string) {
       detailEndDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
       break;
     case 'last3days':
-      detailStartDate.value = today.subtract(3, 'day').format('YYYY-MM-DD');
-      detailEndDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 3 天:今天/昨天/前天
+      detailStartDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
+      detailEndDate.value = today.format('YYYY-MM-DD');
       break;
     case 'last7days':
-      detailStartDate.value = today.subtract(7, 'day').format('YYYY-MM-DD');
-      detailEndDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 7 天
+      detailStartDate.value = today.subtract(6, 'day').format('YYYY-MM-DD');
+      detailEndDate.value = today.format('YYYY-MM-DD');
       break;
     case 'lastMonth':
-      detailStartDate.value = today.subtract(30, 'day').format('YYYY-MM-DD');
-      detailEndDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 30 天
+      detailStartDate.value = today.subtract(29, 'day').format('YYYY-MM-DD');
+      detailEndDate.value = today.format('YYYY-MM-DD');
       break;
   }
 
@@ -843,9 +849,41 @@ function updateAccountChart(trendData: { dates: string[]; fans: number[]; views:
   });
 }
 
-// 导出数据
-function handleExport() {
-  ElMessage.info('导出功能开发中');
+// 导出数据(客户端生成 xlsx,无需后端支持)
+async function handleExport() {
+  if (!filteredAccounts.value.length) {
+    ElMessage.warning('暂无数据可导出');
+    return;
+  }
+  try {
+    const headers = ['账号', '平台', '播放(阅读)量', '评论量', '点赞量', '涨粉量', '更新时间', '状态'];
+    const rows = filteredAccounts.value.map((row) => [
+      row.nickname || row.username || '',
+      getPlatformName(row.platform),
+      row.viewsCount ?? 0,
+      row.commentsCount ?? 0,
+      row.likesCount ?? 0,
+      row.fansIncrease ?? 0,
+      formatTime(row.updateTime),
+      row.status === 'active' ? '正常' : '异常',
+    ]);
+    const data = [headers, ...rows];
+    const ws = XLSX.utils.aoa_to_sheet(data);
+    const wb = XLSX.utils.book_new();
+    XLSX.utils.book_append_sheet(wb, ws, '账号数据');
+    const arrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
+    const blob = new Blob([arrayBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    const url = URL.createObjectURL(blob);
+    const a = document.createElement('a');
+    a.href = url;
+    a.download = `账号数据_${dayjs().format('YYYYMMDD_HHmmss')}.xlsx`;
+    a.click();
+    URL.revokeObjectURL(url);
+    ElMessage.success('导出成功');
+  } catch (error) {
+    console.error('导出失败:', error);
+    ElMessage.error('导出失败,请稍后重试');
+  }
 }
 
 // 监听抽屉关闭

+ 61 - 8
client/src/views/Analytics/PlatformDetail/index.vue

@@ -630,9 +630,59 @@ function handleViewReport() {
   ElMessage.info('查看报表功能开发中');
 }
 
-// 导出数据
+// 导出平台数据(客户端生成 xlsx,无需后端支持)
 function handleExport() {
-  ElMessage.info('导出数据功能开发中');
+  try {
+    const wb = XLSX.utils.book_new();
+
+    // Sheet1: 每日汇总
+    if (dailyData.value.length > 0) {
+      const dailyHeaders = ['日期', '播放(阅读)量', '评论量', '点赞量', '涨粉量'];
+      const dailyRows = dailyData.value.map((row) => [
+        row.date || '',
+        row.viewsCount ?? 0,
+        row.commentsCount ?? 0,
+        row.likesCount ?? 0,
+        row.fansIncrease ?? 0,
+      ]);
+      const dailySheet = XLSX.utils.aoa_to_sheet([[...dailyHeaders], ...dailyRows]);
+      XLSX.utils.book_append_sheet(wb, dailySheet, '每日汇总');
+    }
+
+    // Sheet2: 账号数据
+    if (accountList.value.length > 0) {
+      const accountHeaders = ['账号', '平台', '播放(阅读)量', '评论量', '点赞量', '涨粉量', '更新时间'];
+      const accountRows = accountList.value.map((row) => [
+        row.nickname || row.username || '',
+        getPlatformName(row.platform as PlatformType),
+        row.viewsCount ?? 0,
+        row.commentsCount ?? 0,
+        row.likesCount ?? 0,
+        row.fansIncrease ?? 0,
+        row.updateTime ? dayjs(row.updateTime).format('YYYY-MM-DD HH:mm') : '',
+      ]);
+      const accountSheet = XLSX.utils.aoa_to_sheet([[...accountHeaders], ...accountRows]);
+      XLSX.utils.book_append_sheet(wb, accountSheet, '账号数据');
+    }
+
+    if (dailyData.value.length === 0 && accountList.value.length === 0) {
+      ElMessage.warning('暂无数据可导出');
+      return;
+    }
+
+    const arrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
+    const blob = new Blob([arrayBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    const url = URL.createObjectURL(blob);
+    const a = document.createElement('a');
+    a.href = url;
+    a.download = `平台数据_${dayjs().format('YYYYMMDD_HHmmss')}.xlsx`;
+    a.click();
+    URL.revokeObjectURL(url);
+    ElMessage.success('导出成功');
+  } catch (error) {
+    console.error('导出失败:', error);
+    ElMessage.error('导出失败,请稍后重试');
+  }
 }
 
 // 账号详情
@@ -670,16 +720,19 @@ function handleDetailQuickDate(type: string) {
       detailEndDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
       break;
     case 'last3days':
-      detailStartDate.value = today.subtract(3, 'day').format('YYYY-MM-DD');
-      detailEndDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 3 天:今天/昨天/前天
+      detailStartDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
+      detailEndDate.value = today.format('YYYY-MM-DD');
       break;
     case 'last7days':
-      detailStartDate.value = today.subtract(7, 'day').format('YYYY-MM-DD');
-      detailEndDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 7 天
+      detailStartDate.value = today.subtract(6, 'day').format('YYYY-MM-DD');
+      detailEndDate.value = today.format('YYYY-MM-DD');
       break;
     case 'lastMonth':
-      detailStartDate.value = today.subtract(30, 'day').format('YYYY-MM-DD');
-      detailEndDate.value = today.subtract(1, 'day').format('YYYY-MM-DD');
+      // 含今天,共 30 天
+      detailStartDate.value = today.subtract(29, 'day').format('YYYY-MM-DD');
+      detailEndDate.value = today.format('YYYY-MM-DD');
       break;
   }
 

+ 6 - 3
client/src/views/Analytics/Work/index.vue

@@ -620,15 +620,18 @@ function handleQuickDate(type: string) {
   
   switch (type) {
     case 'last3days':
-      startDate.value = today.subtract(3, 'day').format('YYYY-MM-DD');
+      // 含今天,共 3 天:今天/昨天/前天
+      startDate.value = today.subtract(2, 'day').format('YYYY-MM-DD');
       endDate.value = today.format('YYYY-MM-DD');
       break;
     case 'last7days':
-      startDate.value = today.subtract(7, 'day').format('YYYY-MM-DD');
+      // 含今天,共 7 天
+      startDate.value = today.subtract(6, 'day').format('YYYY-MM-DD');
       endDate.value = today.format('YYYY-MM-DD');
       break;
     case 'lastMonth':
-      startDate.value = today.subtract(30, 'day').format('YYYY-MM-DD');
+      // 含今天,共 30 天
+      startDate.value = today.subtract(29, 'day').format('YYYY-MM-DD');
       endDate.value = today.format('YYYY-MM-DD');
       break;
   }

+ 4 - 0
client/src/views/Analytics/index.vue

@@ -79,6 +79,7 @@ import { Refresh } from '@element-plus/icons-vue';
 import { PLATFORMS } from '@media-manager/shared';
 import type { PlatformComparison, PlatformType } from '@media-manager/shared';
 import { useAuthStore } from '@/stores/auth';
+import { ElMessage } from 'element-plus';
 import dayjs from 'dayjs';
 import request from '@/api/request';
 
@@ -112,6 +113,9 @@ async function handleRefresh() {
   refreshing.value = true;
   try {
     await loadData();
+  } catch (error) {
+    console.error('刷新数据失败:', error);
+    ElMessage.error('刷新数据失败,请稍后重试');
   } finally {
     refreshing.value = false;
   }