Просмотр исходного кода

fix: refine domestic operating overview layout

Yi Jiarui 1 месяц назад
Родитель
Сommit
e99027b379

+ 31 - 0
src/modules/domestic-voc/operating-overview.component.scss

@@ -253,6 +253,15 @@
 .kpi-cell.tone-caution { box-shadow: inset 0 3px #b45309; }
 .kpi-cell.tone-primary { box-shadow: inset 0 3px #2563eb; }
 
+// 指标身份色:只作用于顶部色条和迷你趋势线,不与下方同比的好坏状态色混用。
+.kpi-cell.metric-gmv { box-shadow: inset 0 3px #2563eb; }
+.kpi-cell.metric-orders { box-shadow: inset 0 3px #4f46e5; }
+.kpi-cell.metric-aov { box-shadow: inset 0 3px #7c3aed; }
+.kpi-cell.metric-visitors { box-shadow: inset 0 3px #0891b2; }
+.kpi-cell.metric-conversion { box-shadow: inset 0 3px #15803d; }
+.kpi-cell.metric-refund { box-shadow: inset 0 3px #b45309; }
+.kpi-cell.metric-refund.tone-critical { box-shadow: inset 0 3px #b91c1c; }
+
 .kpi-label {
   color: #667085;
   font-size: 11px;
@@ -313,6 +322,14 @@
 .tone-caution .kpi-spark { color: #b45309; }
 .tone-critical .kpi-spark { color: #b91c1c; }
 
+.metric-gmv .kpi-spark { color: #2563eb; }
+.metric-orders .kpi-spark { color: #4f46e5; }
+.metric-aov .kpi-spark { color: #7c3aed; }
+.metric-visitors .kpi-spark { color: #0891b2; }
+.metric-conversion .kpi-spark { color: #15803d; }
+.metric-refund .kpi-spark { color: #b45309; }
+.metric-refund.tone-critical .kpi-spark { color: #b91c1c; }
+
 .kpi-spark polygon {
   fill: currentColor;
   opacity: 0.12;
@@ -809,6 +826,20 @@
   white-space: nowrap;
 }
 
+// 表格内容投影到 data-table-shell 后,外壳的基础 th 规则会晚于本组件加载。
+// 明确锁定表头与单元格的对齐方式,避免数值表头左对齐、数值内容右对齐造成视觉错列。
+.analytics-table th.numeric,
+.analytics-table td.numeric {
+  text-align: right !important;
+}
+
+.analytics-table th.rank-col,
+.analytics-table td.rank-col,
+.analytics-table th.risk-col,
+.analytics-table td.risk-col {
+  text-align: center !important;
+}
+
 .analytics-table ::ng-deep .pi-title {
   max-width: 280px;
   overflow: hidden;

+ 35 - 22
src/modules/domestic-voc/operating-overview.component.ts

@@ -140,7 +140,7 @@ interface OverviewConclusion {
 
         <section class="kpi-strip" aria-label="核心经营指标">
           @for (card of vm.kpis; track card.key) {
-            <button type="button" class="kpi-cell" [ngClass]="['tone-' + card.tone, 'trend-' + card.trendState]" [title]="card.helpText" (click)="runKpiAction(card.key)">
+            <button type="button" class="kpi-cell" [ngClass]="['metric-' + card.key, 'tone-' + card.tone, 'trend-' + card.trendState]" [title]="card.helpText" (click)="runKpiAction(card.key)">
               <span class="kpi-label">{{ card.label }}</span>
               <strong>{{ card.value }}</strong>
               <span class="kpi-description">{{ card.description }}</span>
@@ -246,7 +246,7 @@ interface OverviewConclusion {
             <button type="button" (click)="goProducts()">查看全量</button>
           </div>
           <table class="analytics-table">
-            <thead><tr><th class="rank-col">#</th><th class="product-col">商品</th><th>类目</th><th class="numeric">成交金额</th><th class="numeric">贡献</th><th class="numeric">访客</th><th class="numeric">成交单转化</th><th class="numeric">退款金额</th><th class="numeric">退款率</th><th>风险</th></tr></thead>
+            <thead><tr><th class="rank-col">#</th><th class="product-col">商品</th><th>类目</th><th class="numeric">成交金额</th><th class="numeric">贡献</th><th class="numeric">访客</th><th class="numeric">成交单转化</th><th class="numeric">退款金额</th><th class="numeric">退款率</th><th class="risk-col">风险</th></tr></thead>
             <tbody>
               @for (product of vm.topProducts; track product.productKey; let index = $index) {
                 <tr>
@@ -269,7 +269,7 @@ interface OverviewConclusion {
                   <td class="numeric">{{ percent(product.summary.conversionRate) }}</td>
                   <td class="numeric">{{ currency(product.summary.refundAmount) }}</td>
                   <td class="numeric">{{ percent(product.summary.refundToGmvRate) }}</td>
-                  <td><span class="risk-tag" [ngClass]="refundRiskClass(product.summary.refundToGmvRate)">{{ refundRiskLabel(product.summary.refundToGmvRate) }}</span></td>
+                  <td class="risk-col"><span class="risk-tag" [ngClass]="refundRiskClass(product.summary.refundToGmvRate)">{{ refundRiskLabel(product.summary.refundToGmvRate) }}</span></td>
                 </tr>
               }
             </tbody>
@@ -525,6 +525,18 @@ export class DomesticOperatingOverviewComponent {
         previous: average(previous, (row) => row.transactionOrders),
         higherIsBetter: true,
       }),
+      compose({
+        key: 'aov',
+        label: '成交客单价',
+        tone: 'neutral',
+        value: this.currency(ratio(totals.gmv, totals.transactionOrders)),
+        description: '成交金额 ÷ 成交订单',
+        helpText: `口径:成交金额 ÷ 成交单量;变化:后 ${current.length} 日与前 ${previous.length} 日的聚合客单价;周期:${period}`,
+        series: rows.map((row) => ratio(row.gmv, row.transactionOrders)),
+        current: ratio(kpiSeriesSum(current, (row) => row.gmv), kpiSeriesSum(current, (row) => row.transactionOrders)),
+        previous: ratio(kpiSeriesSum(previous, (row) => row.gmv), kpiSeriesSum(previous, (row) => row.transactionOrders)),
+        higherIsBetter: true,
+      }),
       compose({
         key: 'visitors',
         label: '商品访客',
@@ -563,18 +575,6 @@ export class DomesticOperatingOverviewComponent {
         higherIsBetter: false,
         deltaMode: 'points',
       }),
-      compose({
-        key: 'aov',
-        label: '成交客单价',
-        tone: 'neutral',
-        value: this.currency(ratio(totals.gmv, totals.transactionOrders)),
-        description: '成交金额 ÷ 成交订单',
-        helpText: `口径:成交金额 ÷ 成交单量;变化:后 ${current.length} 日与前 ${previous.length} 日的聚合客单价;周期:${period}`,
-        series: rows.map((row) => ratio(row.gmv, row.transactionOrders)),
-        current: ratio(kpiSeriesSum(current, (row) => row.gmv), kpiSeriesSum(current, (row) => row.transactionOrders)),
-        previous: ratio(kpiSeriesSum(previous, (row) => row.gmv), kpiSeriesSum(previous, (row) => row.transactionOrders)),
-        higherIsBetter: true,
-      }),
     ];
   }
 
@@ -604,12 +604,17 @@ export class DomesticOperatingOverviewComponent {
       title: [
         { text: '成交金额', subtext: '元', left: 0, top: 0, textStyle: { fontSize: 12, fontWeight: 700, color: '#334155' }, subtextStyle: { fontSize: 10, color: '#94a3b8' } },
         { text: '成交单转化率', subtext: '订单 / 商品访客', left: 0, top: 128, textStyle: { fontSize: 12, fontWeight: 700, color: '#334155' }, subtextStyle: { fontSize: 10, color: '#94a3b8' } },
-        { text: '退款金额占比', subtext: '8% 关注 · 12% 严重', left: 0, top: 256, textStyle: { fontSize: 12, fontWeight: 700, color: '#334155' }, subtextStyle: { fontSize: 10, color: '#94a3b8' } },
+        {
+          text: '退款金额占比',
+          left: 0,
+          top: 256,
+          textStyle: { fontSize: 12, fontWeight: 700, color: '#334155' },
+        },
       ],
       grid: [
-        { left: 112, right: 54, top: 16, height: 88 },
-        { left: 112, right: 54, top: 144, height: 88 },
-        { left: 112, right: 54, top: 272, height: 88 },
+        { left: 124, right: 54, top: 16, height: 88 },
+        { left: 124, right: 54, top: 144, height: 88 },
+        { left: 124, right: 54, top: 272, height: 88 },
       ],
       xAxis: [
         { type: 'category', gridIndex: 0, data: dates, boundaryGap: false, axisTick: { show: false }, axisLabel: { show: false }, axisLine: { lineStyle: { color: '#e2e8f0' } } },
@@ -632,10 +637,18 @@ export class DomesticOperatingOverviewComponent {
             silent: true,
             symbol: 'none',
             lineStyle: { type: 'dashed', width: 1 },
-            label: { fontSize: 9, formatter: '{b}' },
+            // 标签跟随各自阈值线定位,并放在绘图区左侧的留白中,而不是压在曲线上。
+            label: {
+              show: true,
+              position: 'start',
+              distance: 38,
+              fontSize: 9,
+              fontWeight: 700,
+              formatter: '{b}',
+            },
             data: [
-              { name: '关注 8%', yAxis: 8, lineStyle: { color: '#b45309' }, label: { color: '#b45309' } },
-              { name: '严重 12%', yAxis: 12, lineStyle: { color: '#b91c1c' }, label: { color: '#b91c1c' } },
+              { name: '8% 关注', yAxis: 8, lineStyle: { color: '#b45309' }, label: { color: '#b45309' } },
+              { name: '12% 严重', yAxis: 12, lineStyle: { color: '#b91c1c' }, label: { color: '#b91c1c' } },
             ],
           },
           emphasis: { focus: 'series' },