Bladeren bron

优化消息统计页面

guoziyun 8 maanden geleden
bovenliggende
commit
5beb19b5ef

+ 1 - 1
oms/public/app/index.html

@@ -9,5 +9,5 @@
   <style>body,html{width:100%;height:100%}*,:after,:before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}body{margin:0;color:#000000d9;font-size:14px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-variant:tabular-nums;line-height:1.5715;background-color:#fff;font-feature-settings:"tnum"}html{--antd-wave-shadow-color:#1890ff;--scroll-bar:0}</style><link rel="stylesheet" href="styles-LXBSU6DF.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-LXBSU6DF.css"></noscript></head>
   <body>
     <app-root></app-root>
-  <script src="polyfills-B6TNHZQ6.js" type="module"></script><script src="main-HPK4W4ID.js" type="module"></script></body>
+  <script src="polyfills-B6TNHZQ6.js" type="module"></script><script src="main-DUKLU2H3.js" type="module"></script></body>
 </html>

File diff suppressed because it is too large
+ 0 - 0
oms/public/app/main-DUKLU2H3.js


+ 66 - 40
omsapp/src/app/pages/message-dashboard.component.html

@@ -23,15 +23,15 @@
       nz-button
       nzType="primary"
       (click)="refreshData()"
-      [nzLoading]="isLoading"
+      [nzLoading]="overallLoading"
     >
       <span nz-icon nzType="sync"></span>刷新数据
     </button>
   </div>
 
-  <nz-spin [nzSpinning]="isLoading">
-    <!-- 整体统计卡片 -->
-    <nz-card nzTitle="整体统计" style="margin-top: 16px">
+  <!-- 整体统计卡片 -->
+  <nz-card nzTitle="整体统计" style="margin-top: 16px">
+    <nz-spin [nzSpinning]="overallLoading">
       <div nz-row [nzGutter]="16" *ngIf="overallStats">
         <div nz-col [nzSpan]="4">
           <nz-statistic
@@ -105,12 +105,14 @@
           </div>
         </div> -->
       </div>
-    </nz-card>
+    </nz-spin>
+  </nz-card>
 
-    <!-- 图表区域 -->
-    <div nz-row [nzGutter]="16" style="margin-top: 16px">
-      <div nz-col [nzSpan]="24">
-        <nz-card nzTitle="每日消息量与转化率">
+  <!-- 图表区域 -->
+  <div nz-row [nzGutter]="16" style="margin-top: 16px">
+    <div nz-col [nzSpan]="24">
+      <nz-card nzTitle="每日消息量与转化率">
+        <nz-spin [nzSpinning]="chartLoading">
           <div class="chart-container">
             <canvas
               baseChart
@@ -186,14 +188,16 @@
               用户点击率
             </div>
           </div>
-        </nz-card>
-      </div>
+        </nz-spin>
+      </nz-card>
     </div>
+  </div>
 
-    <!-- 新增:每日趋势数据表格 -->
-    <div nz-row [nzGutter]="16" style="margin-top: 16px">
-      <div nz-col [nzSpan]="24">
-        <nz-card nzTitle="每日趋势详细数据">
+  <!-- 新增:每日趋势数据表格 -->
+  <div nz-row [nzGutter]="16" style="margin-top: 16px">
+    <div nz-col [nzSpan]="24">
+      <nz-card nzTitle="每日趋势详细数据">
+        <nz-spin [nzSpinning]="dailyTrendsLoading">
           <nz-table
             [nzData]="dailyTrends"
             [nzFrontPagination]="false"
@@ -234,20 +238,32 @@
                 <td>{{ formatPercentage(daily.deliveredRate || 0) }}</td>
                 <td>{{ formatPercentage(daily.displayRate || 0) }}</td>
                 <td>{{ formatPercentage(daily.clickThroughRate || 0) }}</td>
-                <td>{{ formatPercentage(daily.actualClickThroughRate || 0) }}</td>
-                <td>{{ formatPercentage(daily.tokenInvalidationRate || 0) }}</td>
+                <td>
+                  {{ formatPercentage(daily.actualClickThroughRate || 0) }}
+                </td>
+                <td>
+                  {{ formatPercentage(daily.tokenInvalidationRate || 0) }}
+                </td>
               </tr>
             </tbody>
           </nz-table>
-          <nz-empty *ngIf="dailyTrends.length === 0 && !isLoading"></nz-empty>
-        </nz-card>
-      </div>
+          <nz-empty
+            *ngIf="dailyTrends.length === 0 && !dailyTrendsLoading"
+          ></nz-empty>
+        </nz-spin>
+      </nz-card>
     </div>
+  </div>
 
-    <!-- 统计表格标签页 -->
-    <nz-tabset [(nzSelectedIndex)]="activeTab" style="margin-top: 16px">
-      <!-- 按策略统计表格 -->
-      <nz-tab nzTitle="按策略统计">
+  <!-- 统计表格标签页 -->
+  <nz-tabset
+    [(nzSelectedIndex)]="activeTab"
+    (nzSelectedIndexChange)="onTabChange($event)"
+    style="margin-top: 16px"
+  >
+    <!-- 按策略统计表格 -->
+    <nz-tab nzTitle="按策略统计">
+      <nz-spin [nzSpinning]="strategyLoading">
         <nz-table
           #strategyTable
           [nzData]="strategyStats"
@@ -559,11 +575,15 @@
             </ng-template>
           </tbody>
         </nz-table>
-        <nz-empty *ngIf="strategyStats.length === 0 && !isLoading"></nz-empty>
-      </nz-tab>
+        <nz-empty
+          *ngIf="strategyStats.length === 0 && !strategyLoading"
+        ></nz-empty>
+      </nz-spin>
+    </nz-tab>
 
-      <!-- 按模板统计表格 -->
-      <nz-tab nzTitle="按模板统计">
+    <!-- 按模板统计表格 -->
+    <nz-tab nzTitle="按模板统计">
+      <nz-spin [nzSpinning]="templateLoading">
         <nz-table
           #templateTable
           [nzData]="templateStats"
@@ -874,11 +894,15 @@
             </ng-template>
           </tbody>
         </nz-table>
-        <nz-empty *ngIf="templateStats.length === 0 && !isLoading"></nz-empty>
-      </nz-tab>
+        <nz-empty
+          *ngIf="templateStats.length === 0 && !templateLoading"
+        ></nz-empty>
+      </nz-spin>
+    </nz-tab>
 
-      <!-- 按国家统计表格 -->
-      <nz-tab nzTitle="按国家统计">
+    <!-- 按国家统计表格 -->
+    <nz-tab nzTitle="按国家统计">
+      <nz-spin [nzSpinning]="ccLoading">
         <nz-table
           #ccTable
           [nzData]="ccStats"
@@ -1151,11 +1175,13 @@
             </ng-template>
           </tbody>
         </nz-table>
-        <nz-empty *ngIf="ccStats.length === 0 && !isLoading"></nz-empty>
-      </nz-tab>
+        <nz-empty *ngIf="ccStats.length === 0 && !ccLoading"></nz-empty>
+      </nz-spin>
+    </nz-tab>
 
-      <!-- 按图片统计表格 -->
-      <nz-tab nzTitle="按图片统计">
+    <!-- 按图片统计表格 -->
+    <nz-tab nzTitle="按图片统计">
+      <nz-spin [nzSpinning]="imageLoading">
         <nz-table
           #imageTable
           [nzData]="imageStats"
@@ -1457,8 +1483,8 @@
             </ng-template>
           </tbody>
         </nz-table>
-        <nz-empty *ngIf="imageStats.length === 0 && !isLoading"></nz-empty>
-      </nz-tab>
-    </nz-tabset>
-  </nz-spin>
+        <nz-empty *ngIf="imageStats.length === 0 && !imageLoading"></nz-empty>
+      </nz-spin>
+    </nz-tab>
+  </nz-tabset>
 </nz-card>

+ 161 - 81
omsapp/src/app/pages/message-dashboard.component.ts

@@ -77,7 +77,14 @@ import {
   styleUrls: ['./message-dashboard.component.css'],
 })
 export class MessageDashboardComponent implements OnInit {
-  isLoading = false;
+  overallLoading = false;
+  strategyLoading = false;
+  templateLoading = false;
+  ccLoading = false;
+  imageLoading = false;
+  dailyTrendsLoading = false;
+  chartLoading = false;
+
   overallStats: any = null;
   strategyStats: any[] = [];
   templateStats: any[] = [];
@@ -317,15 +324,11 @@ export class MessageDashboardComponent implements OnInit {
       return;
     }
 
-    this.isLoading = true;
-
-    console.log(this.dateRange[0], this.dateRange[1]); // 打印: Mon Sep 15 2025 02:22:55 GMT+0800 (中国标准时间) Mon Sep 15 2025 02:22:55 GMT+0800 (中国标准时间)
-    this.dateRange[0]
-      ? console.log(this.formatDateForApi(this.dateRange[0]))
-      : ''; // 打印 2025-09-14
-    this.dateRange[1]
-      ? console.log(this.formatDateForApi(this.dateRange[1]))
-      : ''; // 打印 2025-09-14  为什么
+    // 仅重置当前激活标签页的数据
+    if (this.activeTab === 0) this.strategyStats = [];
+    if (this.activeTab === 1) this.templateStats = [];
+    if (this.activeTab === 2) this.ccStats = [];
+    if (this.activeTab === 3) this.imageStats = [];
 
     const params = new HttpParams()
       .set(
@@ -338,104 +341,174 @@ export class MessageDashboardComponent implements OnInit {
       )
       .set('strategyName', this.selectedStrategy || '');
 
-    forkJoin({
-      overall: this.http
-        .get(`/api/message/statistics/overall`, { params })
-        .pipe(
-          map((res: any) => res?.data || null),
-          catchError((err) => {
-            console.error('Failed to load overall statistics:', err);
-            this.message.error('加载整体统计失败');
-            return of(null);
-          })
-        ),
-      strategies: this.http
-        .get(`/api/message/statistics/by-strategy`, { params })
-        .pipe(
-          map((res: any) => res?.data || []),
-          catchError((err) => {
-            console.error('Failed to load strategy statistics:', err);
-            this.message.error('加载策略统计失败');
-            return of([]);
-          })
-        ),
-      templates: this.http
-        .get(`/api/message/statistics/by-template`, { params })
-        .pipe(
-          map((res: any) => res?.data || []),
-          catchError((err) => {
-            console.error('Failed to load template statistics:', err);
-            this.message.error('加载模板统计失败');
-            return of([]);
-          })
-        ),
-      ccs: this.http.get(`/api/message/statistics/by-cc`, { params }).pipe(
+    // 始终加载整体统计和图表数据
+    this.overallLoading = true;
+    this.http
+      .get(`/api/message/statistics/overall`, { params })
+      .pipe(
+        map((res: any) => res?.data || null),
+        catchError((err) => {
+          console.error('Failed to load overall statistics:', err);
+          this.message.error('加载整体统计失败');
+          return of(null);
+        }),
+        finalize(() => (this.overallLoading = false))
+      )
+      .subscribe((data) => {
+        this.overallStats = data;
+      });
+
+    // 加载每日趋势(图表数据)
+    this.chartLoading = true;
+    this.http
+      .get(`/api/message/statistics/daily-trends`, { params })
+      .pipe(
         map((res: any) => res?.data || []),
         catchError((err) => {
-          console.error('Failed to load cc statistics:', err);
-          this.message.error('加载国家统计失败');
+          console.error('Failed to load daily trends:', err);
+          this.message.error('加载每日趋势失败');
           return of([]);
-        })
-      ),
-      images: this.http
-        .get(`/api/message/statistics/by-image`, { params })
-        .pipe(
-          map((res: any) => res?.data || []),
-          catchError((err) => {
-            console.error('Failed to load image statistics:', err);
-            this.message.error('加载图片统计失败');
-            return of([]);
-          })
-        ),
-      dailyTrends: this.http
-        .get(`/api/message/statistics/daily-trends`, { params })
-        .pipe(
-          map((res: any) => res?.data || []),
-          catchError((err) => {
-            console.error('Failed to load daily trends:', err);
-            this.message.error('加载每日趋势失败');
-            return of([]);
-          })
-        ),
-    })
+        }),
+        finalize(() => (this.chartLoading = false))
+      )
+      .subscribe((data) => {
+        this.dailyTrends = data;
+        this.updateChartData();
+      });
+
+    // 根据当前激活的标签页加载对应数据
+    this.loadActiveTabData(params);
+  }
+
+  // 加载当前激活标签页的数据
+  loadActiveTabData(params: HttpParams): void {
+    switch (this.activeTab) {
+      case 0: // 策略统计
+        this.loadStrategyData(params);
+        break;
+      case 1: // 模板统计
+        this.loadTemplateData(params);
+        break;
+      case 2: // 国家统计
+        this.loadCcData(params);
+        break;
+      case 3: // 图片统计
+        this.loadImageData(params);
+        break;
+    }
+  }
+
+  // 拆分各标签页数据加载方法
+  private loadStrategyData(params: HttpParams): void {
+    this.strategyLoading = true;
+    this.http
+      .get(`/api/message/statistics/by-strategy`, { params })
       .pipe(
-        finalize(() => {
-          this.isLoading = false;
-          this.cd.detectChanges();
-        })
+        map((res: any) => res?.data || []),
+        catchError((err) => {
+          console.error('Failed to load strategy statistics:', err);
+          this.message.error('加载策略统计失败');
+          return of([]);
+        }),
+        finalize(() => (this.strategyLoading = false))
       )
-      .subscribe((results: any) => {
-        this.overallStats = results.overall;
-        this.strategyStats = results.strategies.map((item: any) => ({
+      .subscribe((data) => {
+        this.strategyStats = data.map((item: any) => ({
           ...item,
           expanded: false,
           dailyData: null,
           loading: false,
         }));
-        this.templateStats = results.templates.map((item: any) => ({
+      });
+  }
+
+  private loadTemplateData(params: HttpParams): void {
+    this.templateLoading = true;
+    this.http
+      .get(`/api/message/statistics/by-template`, { params })
+      .pipe(
+        map((res: any) => res?.data || []),
+        catchError((err) => {
+          console.error('Failed to load template statistics:', err);
+          this.message.error('加载模板统计失败');
+          return of([]);
+        }),
+        finalize(() => (this.templateLoading = false))
+      )
+      .subscribe((data) => {
+        this.templateStats = data.map((item: any) => ({
           ...item,
           expanded: false,
           dailyData: null,
           loading: false,
         }));
-        this.ccStats = results.ccs.map((item: any) => ({
+      });
+  }
+
+  private loadCcData(params: HttpParams): void {
+    this.ccLoading = true;
+    this.http
+      .get(`/api/message/statistics/by-cc`, { params })
+      .pipe(
+        map((res: any) => res?.data || []),
+        catchError((err) => {
+          console.error('Failed to load cc statistics:', err);
+          this.message.error('加载国家统计失败');
+          return of([]);
+        }),
+        finalize(() => (this.ccLoading = false))
+      )
+      .subscribe((data) => {
+        this.ccStats = data.map((item: any) => ({
           ...item,
           expanded: false,
           dailyData: null,
           loading: false,
         }));
-        this.imageStats = results.images.map((item: any) => ({
+      });
+  }
+
+  private loadImageData(params: HttpParams): void {
+    this.imageLoading = true;
+    this.http
+      .get(`/api/message/statistics/by-image`, { params })
+      .pipe(
+        map((res: any) => res?.data || []),
+        catchError((err) => {
+          console.error('Failed to load image statistics:', err);
+          this.message.error('加载图片统计失败');
+          return of([]);
+        }),
+        finalize(() => (this.imageLoading = false))
+      )
+      .subscribe((data) => {
+        this.imageStats = data.map((item: any) => ({
           ...item,
           expanded: false,
           dailyData: null,
           loading: false,
         }));
-        this.dailyTrends = results.dailyTrends;
-
-        this.updateChartData();
       });
   }
 
+  // 添加标签页切换事件处理
+  onTabChange(index: number): void {
+    this.activeTab = index;
+    // 当切换到新标签页时加载对应数据
+    const params = new HttpParams()
+      .set(
+        'startDate',
+        this.dateRange[0] ? this.formatDateForApi(this.dateRange[0]) : ''
+      )
+      .set(
+        'endDate',
+        this.dateRange[1] ? this.formatDateForApi(this.dateRange[1]) : ''
+      )
+      .set('strategyName', this.selectedStrategy || '');
+
+    this.loadActiveTabData(params);
+  }
+
   // 验证日期范围是否有效
   private isDateRangeValid(): boolean {
     // 如果只选择了一个日期或未选择日期,视为有效
@@ -707,6 +780,11 @@ export class MessageDashboardComponent implements OnInit {
 
   // 加载每日数据
   private loadDailyData(element: any, type: string): void {
+    // 如果已有请求,先取消
+    if (element.subscription) {
+      element.subscription.unsubscribe();
+    }
+
     element.loading = true;
     let url = '';
     const params = new HttpParams()
@@ -747,7 +825,8 @@ export class MessageDashboardComponent implements OnInit {
         return;
     }
 
-    this.http
+    // 保存订阅以便取消
+    element.subscription = this.http
       .get(url, { params })
       .pipe(
         map((res: any) => res?.data || []),
@@ -758,6 +837,7 @@ export class MessageDashboardComponent implements OnInit {
         }),
         finalize(() => {
           element.loading = false;
+          element.subscription = null;
         })
       )
       .subscribe((data) => {

Some files were not shown because too many files changed in this diff