Pārlūkot izejas kodu

Merge branch 'dev-ly' into dev-cmn

cmy 5 dienas atpakaļ
vecāks
revīzija
5a7f4ae5ca
1 mainītis faili ar 245 papildinājumiem un 56 dzēšanām
  1. 245 56
      src/views/count/main/trend/index.vue

+ 245 - 56
src/views/count/main/trend/index.vue

@@ -92,15 +92,9 @@
                </div>
             </template>
          </Lcard>
-         <Lcard :height="975">          
-            <el-date-picker
-               style="float: left;"
-               v-model="timeRange"
-               type="datetimerange"
-               range-separator="To"
-               start-placeholder="Start date"
-               end-placeholder="End date"
-            />
+         <Lcard :height="975">
+            <el-date-picker style="float: left;" v-model="timeRange" type="datetimerange" range-separator="To"
+               start-placeholder="Start date" end-placeholder="End date" />
             <div class="link" style="float: right;">订阅</div>
             <div class="link" style="float: right;">编辑指标</div>
             <div class="link" style="float: right;">生成AI简报</div>
@@ -115,27 +109,81 @@
                   </el-form-item>
                </el-form>
                <div class="flex items-center">
-                  <el-radio-group size="small">
+                  <el-radio-group v-model="lineChartUser">
                      <el-radio-button label="hour">新增用户</el-radio-button>
                      <el-radio-button label="day">活跃用户</el-radio-button>
                      <el-radio-button label="week">启动次数</el-radio-button>
                      <el-radio-button label="month">累计用户</el-radio-button>
                   </el-radio-group>
                </div>
-				</div>
+            </div>
             <div class="relative">
                <div ref="qChartRef" style="width: 100%; height: 320px"></div>
             </div>
+            <div class="mt-3">
+               <div class="flex items-center justify-between mb-2">
+                  <div class="text-base font-medium cursor-pointer select-none" @click="showDetail1 = !showDetail1">
+                     {{ showDetail1 ? '收起明细数据' : '展开明细数据' }}
+                  </div>
+                  <div>
+                     <el-button>导出</el-button>
+                  </div>
+               </div>
+               <el-table v-if="showDetail1" :data="pagedTableRows" border>
+                  <el-table-column prop="date" label="日期" min-width="140" />
+                  <el-table-column label="新增用户(占比)" min-width="220">
+                     <template #default="scope">
+                        <div class="flex items-center justify-between w-full">
+                           <span>{{ scope.row.newUsers }}</span>
+                           <span class="text-gray-500 text-xs">{{ scope.row.ratio }}</span>
+                        </div>
+                     </template>
+                  </el-table-column>
+               </el-table>
+               <div v-if="showDetail1" class="flex justify-end mt-3">
+                  <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" background
+                     layout="total, prev, pager, next, sizes" :total="tableRows.length" :page-sizes="[5, 10, 20]" />
+               </div>
+            </div>
          </Lcard>
-      <Lcard :height="440" />
-      <Lcard :height="440" />
-      <Lcard :height="440" />
-   </div>
+         <Lcard :height="660">
+            <div class="msg">
+               <el-icon class="ml-1" style="color: #a4b8cf; vertical-align: middle;">
+                  <InfoFilled />
+               </el-icon>
+               点击下列环形图中单个版本/渠道将跳转到对应的详情页
+            </div>
+            <div class="box1">
+               <lcard :height="540" style="margin-right: 20px;">
+                  <div class="box1-title" style="float: left;">TOP版本</div>
+                  <div class="link" style="float: right;">详情</div>
+                  <div class="line" style="margin-top: 40px;"></div>
+                  <el-radio-group v-model="circleEchartUser1">
+                     <el-radio-button label="hour">新增用户</el-radio-button>
+                     <el-radio-button label="day">活跃用户</el-radio-button>
+                     <el-radio-button label="month">累计用户</el-radio-button>
+                  </el-radio-group>
+                  <div ref="circleEchartRef1" style="width: 100%; height: 380px;"></div>
+               </lcard>
+               <lcard :height="540">
+                  <div class="box1-title" style="float: left;">TOP版本</div>
+                  <div class="link" style="float: right;">详情</div>
+                  <div class="line" style="margin-top: 40px;"></div>
+                  <el-radio-group v-model="circleEchartUser1">
+                     <el-radio-button label="hour">新增用户</el-radio-button>
+                     <el-radio-button label="day">活跃用户</el-radio-button>
+                     <el-radio-button label="month">累计用户</el-radio-button>
+                  </el-radio-group>
+                  <div ref="circleEchartRef2" style="width: 100%; height: 380px;"></div>
+               </lcard>
+            </div>
+         </Lcard>
+      </div>
    </div>
 </template>
 
 <script lang="ts" name="countMainTrend" setup>
-import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
+// import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
 import { useI18n } from 'vue-i18n';
 import * as echarts from 'echarts';
 // 引入组件
@@ -146,56 +194,196 @@ const { t } = useI18n();
 const timeRange = ref(null);
 let qualityChart: echarts.ECharts | null = null;
 const qChartRef = ref(null);
+const lineChartUser = ref(null);
 onMounted(() => {
-	// initLineChart();
-	initQualityChart();
+   setTimeout(() => {
+      initQualityChart();
+      initCircleChart1();
+      initCircleChart2();
+   }, 500)
    console.log(qualityChart);
-	// initBehaviorChart();
 });
 const qualityXAxis = ref<string[]>([
-	'2025-07-01',
-	'2025-07-08',
-	'2025-07-15',
-	'2025-07-22',
-	'2025-07-29',
-	'2025-08-05',
-	'2025-08-12',
-	'2025-08-19',
-	'2025-08-26',
-	'2025-09-02',
-	'2025-09-09',
-	'2025-09-16',
+   '2025-07-01',
+   '2025-07-08',
+   '2025-07-15',
+   '2025-07-22',
+   '2025-07-29',
+   '2025-08-05',
+   '2025-08-12',
+   '2025-08-19',
+   '2025-08-26',
+   '2025-09-02',
+   '2025-09-09',
+   '2025-09-16',
 ]);
 const retentionSeries = ref<number[]>([20, 23, 27, 24, 22, 15, 5, 4, 16, 26, 25, 2]);
 const industryAvgSeries = ref<number[]>([16, 18, 20, 24, 25, 24, 16, 10, 15, 22, 21, 12]);
 const peerSameScaleSeries = ref<number[]>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 function initQualityChart(): void {
-   console.log(qChartRef.value);
-	if (!qChartRef.value) return;
-	if (qualityChart) qualityChart.dispose();
-	qualityChart = echarts.init( qChartRef.value);
-   debugger
-	const option: echarts.EChartsOption = {
-		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}%` },
-		legend: { data: ['留存率', '同行业App', '同行业同规模App'] },
-		grid: { left: 40, right: 20, top: 30, bottom: 30 },
-		xAxis: { type: 'category', data: qualityXAxis.value },
-		yAxis: {
-			type: 'value',
-			min: 0,
-			max: 30,
-			axisLabel: { formatter: '{value}%' },
-			splitLine: { lineStyle: { color: '#f3f4f6' } },
-		},
-		series: [
-			{ name: '留存率', type: 'line', smooth: true, data: retentionSeries.value },
-			{ name: '同行业App', type: 'line', smooth: true, data: industryAvgSeries.value, color: '#f59e0b' },
-			{ name: '同行业同规模App', type: 'line', smooth: true, data: peerSameScaleSeries.value, color: '#60a5fa' },
-		],
-	};
-	qualityChart.setOption(option);
+   console.log(qChartRef.value, qChartRef);
+   if (!qChartRef.value) return;
+   if (qualityChart) qualityChart.dispose();
+   qualityChart = echarts.init(qChartRef.value);
+   const option: echarts.EChartsOption = {
+      tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}%` },
+      legend: { data: ['留存率', '同行业App', '同行业同规模App'] },
+      grid: { left: 40, right: 20, top: 30, bottom: 30 },
+      xAxis: { type: 'category', data: qualityXAxis.value },
+      yAxis: {
+         type: 'value',
+         min: 0,
+         max: 30,
+         axisLabel: { formatter: '{value}%' },
+         splitLine: { lineStyle: { color: '#f3f4f6' } },
+      },
+      series: [
+         { name: '留存率', type: 'line', smooth: true, data: retentionSeries.value },
+         { name: '同行业App', type: 'line', smooth: true, data: industryAvgSeries.value, color: '#f59e0b' },
+         { name: '同行业同规模App', type: 'line', smooth: true, data: peerSameScaleSeries.value, color: '#60a5fa' },
+      ],
+   };
+   qualityChart.setOption(option);
+}
+
+
+interface TableRow {
+	date: string;
+	newUsers: number;
+	ratio: string;
 }
+// 展开/收起明细
+const showDetail1 = ref(true);
+const pagedTableRows = computed(() => {
+	const startIndex = (currentPage.value - 1) * pageSize.value;
+	return tableRows.value.slice(startIndex, startIndex + pageSize.value);
+});
+// 表格相关(静态数据)
+const currentPage = ref(1);
+const pageSize = ref(5);
+const tableRows = ref<TableRow[]>(
+	Array.from({ length: 42 }).map((_, idx) => ({
+		date: `2025-08-${String(11).padStart(2, '0')}`,
+		newUsers: 727,
+		ratio: '97.45%',
+	}))
+);
+
 
+// 环形图
+// 添加圆环图相关的引用和数据
+const circleEchartRef1 = ref(null);
+let circleChart1: echarts.ECharts | null = null;
+const circleEchartUser1 = ref('hour');
+
+const circleEchartRef2 = ref(null);
+let circleChart2: echarts.ECharts | null = null;
+const circleEchartUser2 = ref('hour');
+
+// 初始化圆环图
+function initCircleChart1(): void {
+  if (!circleEchartRef1.value) return;
+  if (circleChart1) circleChart1.dispose();
+  
+  circleChart1 = echarts.init(circleEchartRef1.value);
+  
+  const option: echarts.EChartsOption = {
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      bottom: '0',
+      left: 'center'
+    },
+    series: [
+      {
+        name: '版本分布',
+        type: 'pie',
+        radius: ['50%', '70%'], // 设置内半径和外半径,形成圆环效果
+        avoidLabelOverlap: false,
+        padAngle: 2, // 扇区间隙
+        itemStyle: {
+          borderRadius: 5 // 扇区圆角
+        },
+        label: {
+          show: true,
+          formatter: '{b}: {d}%' // 显示标签和百分比
+        },
+        emphasis: {
+          label: {
+            show: true,
+            fontSize: 14,
+            fontWeight: 'bold'
+          }
+        },
+        labelLine: {
+          show: true
+        },
+        data: [
+          { value: 35, name: 'v3.2.1' },
+          { value: 25, name: 'v3.1.5' },
+          { value: 20, name: 'v3.0.8' },
+          { value: 10, name: 'v2.9.3' },
+          { value: 10, name: '其他' }
+        ]
+      }
+    ]
+  };
+  
+  circleChart1.setOption(option);
+}
+// 初始化圆环图
+function initCircleChart2(): void {
+  if (!circleEchartRef2.value) return;
+  if (circleChart2) circleChart2.dispose();
+  
+  circleChart2 = echarts.init(circleEchartRef2.value);
+  
+  const option: echarts.EChartsOption = {
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      bottom: '0',
+      left: 'center'
+    },
+    series: [
+      {
+        name: '版本分布',
+        type: 'pie',
+        radius: ['50%', '70%'], // 设置内半径和外半径,形成圆环效果
+        avoidLabelOverlap: false,
+        padAngle: 2, // 扇区间隙
+        itemStyle: {
+          borderRadius: 5 // 扇区圆角
+        },
+        label: {
+          show: true,
+          formatter: '{b}: {d}%' // 显示标签和百分比
+        },
+        emphasis: {
+          label: {
+            show: true,
+            fontSize: 14,
+            fontWeight: 'bold'
+          }
+        },
+        labelLine: {
+          show: true
+        },
+        data: [
+          { value: 35, name: 'v3.2.1' },
+          { value: 25, name: 'v3.1.5' },
+          { value: 20, name: 'v3.0.8' },
+          { value: 10, name: 'v2.9.3' },
+          { value: 10, name: '其他' }
+        ]
+      }
+    ]
+  };
+  
+  circleChart2.setOption(option);
+}
 
 
 </script>
@@ -235,8 +423,9 @@ function initQualityChart(): void {
       }
    }
 }
+
 .line {
-   margin: 90px -30px 30px;
+   margin: 60px -30px 30px;
    height: 1px;
    background-color: #E6E6E6;
 }