|
@@ -1,24 +1,243 @@
|
|
<template>
|
|
<template>
|
|
- <div class="layout-padding">
|
|
|
|
|
|
+ <div class="layout-padding">
|
|
<div class="!overflow-auto px-1">
|
|
<div class="!overflow-auto px-1">
|
|
<Lcard :height="440">
|
|
<Lcard :height="440">
|
|
- <div class="tit1">整体趋势</div>
|
|
|
|
-
|
|
|
|
|
|
+ <template #default>
|
|
|
|
+ <Title style="margin-bottom: 10px;" title="整体趋势">
|
|
|
|
+ <el-popover class="box-item" placement="right" trigger="hover" width="250">
|
|
|
|
+ <template #reference>
|
|
|
|
+ <el-icon class="ml-1" style="color: #a4b8cf">
|
|
|
|
+ <InfoFilled />
|
|
|
|
+ </el-icon>
|
|
|
|
+ </template>
|
|
|
|
+ <template #default>
|
|
|
|
+ <div class="ant-popover-inner-content">
|
|
|
|
+ <div class="um-page-tips-content" style="line-height: 24px">
|
|
|
|
+ <p><span class="highlight">新增用户:</span><span>第一次启动应用的用户(以设备为判断标准)</span></p>
|
|
|
|
+ <p><span class="highlight">新增账号:</span><span>第一次启动应用的账号</span></p>
|
|
|
|
+ <p><span class="highlight">新增用户占比:</span><span>某时段内新增用户占该时段活跃用户的比例</span></p>
|
|
|
|
+ <p>
|
|
|
|
+ <span>
|
|
|
|
+ 按天、周或月查看数据可进行版本、渠道的交叉筛选,小时数据最多展示7天并且不支持筛选。周区间定义为周日至次周周六。按周(按月)显示时,界面上用每周的周日(每个月的第一日)来代表该周(该月)
|
|
|
|
+ </span>
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </el-popover>
|
|
|
|
+ </Title>
|
|
|
|
+ <div class="msg">
|
|
|
|
+ <el-icon class="ml-1" style="color: #a4b8cf; vertical-align: middle;">
|
|
|
|
+ <InfoFilled />
|
|
|
|
+ </el-icon>
|
|
|
|
+ 前往
|
|
|
|
+ <span class="link">U-DOP数据开放平台</span>
|
|
|
|
+ ,获取用户访问明细日志,点击查看
|
|
|
|
+ <span class="link">支持返还的字段</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="box1">
|
|
|
|
+ <Lcard :height="280" style="margin-right: 20px;">
|
|
|
|
+ <div class="card-box1">
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon1.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon2.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon3.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon4.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ </div>
|
|
|
|
+ </Lcard>
|
|
|
|
+ <Lcard :height="280">
|
|
|
|
+ <div class="card-box2">
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon5.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon6.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon7.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon8.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
|
|
|
|
+ <template #icon>
|
|
|
|
+ <img src="./icons/icon9.svg" alt="icon">
|
|
|
|
+ </template>
|
|
|
|
+ </InfoCard>
|
|
|
|
+ </div>
|
|
|
|
+ </Lcard>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
</Lcard>
|
|
</Lcard>
|
|
- <Lcard :height="440"/>
|
|
|
|
- <Lcard :height="440"/>
|
|
|
|
- <Lcard :height="440"/>
|
|
|
|
- <Lcard :height="440"/>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <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>
|
|
|
|
+ <div class="line"></div>
|
|
|
|
+ <div class="flex items-center justify-between mb-2 mt-3">
|
|
|
|
+ <el-form>
|
|
|
|
+ <el-form-item>
|
|
|
|
+ <el-select style="width: 140px" placeholder="渠道对比">
|
|
|
|
+ <!-- <el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" /> -->
|
|
|
|
+ </el-select>
|
|
|
|
+ <el-button class="ml-2">对比时间</el-button>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-form>
|
|
|
|
+ <div class="flex items-center">
|
|
|
|
+ <el-radio-group size="small">
|
|
|
|
+ <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 class="relative">
|
|
|
|
+ <div ref="qChartRef" style="width: 100%; height: 320px"></div>
|
|
|
|
+ </div>
|
|
|
|
+ </Lcard>
|
|
|
|
+ <Lcard :height="440" />
|
|
|
|
+ <Lcard :height="440" />
|
|
|
|
+ <Lcard :height="440" />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script lang="ts" name="countMainTrend" setup>
|
|
<script lang="ts" name="countMainTrend" setup>
|
|
|
|
+import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
+import * as echarts from 'echarts';
|
|
// 引入组件
|
|
// 引入组件
|
|
const Lcard = defineAsyncComponent(() => import('/@/components/LYcom/Lcard/index.vue'));
|
|
const Lcard = defineAsyncComponent(() => import('/@/components/LYcom/Lcard/index.vue'));
|
|
|
|
+const Title = defineAsyncComponent(() => import('/@/components/Title/index.vue'));
|
|
|
|
+const InfoCard = defineAsyncComponent(() => import('./infoCard.vue'));
|
|
const { t } = useI18n();
|
|
const { t } = useI18n();
|
|
|
|
+const timeRange = ref(null);
|
|
|
|
+let qualityChart: echarts.ECharts | null = null;
|
|
|
|
+const qChartRef = ref(null);
|
|
|
|
+onMounted(() => {
|
|
|
|
+ // initLineChart();
|
|
|
|
+ initQualityChart();
|
|
|
|
+ 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',
|
|
|
|
+]);
|
|
|
|
+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);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
</script>
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
|
+.msg {
|
|
|
|
+ height: 30px;
|
|
|
|
+ background-color: #f4f5fa;
|
|
|
|
+ line-height: 30px;
|
|
|
|
+ font-size: 12px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.link {
|
|
|
|
+ color: #167af0;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.box1 {
|
|
|
|
+ display: flex;
|
|
|
|
+ margin-top: 30px;
|
|
|
|
+
|
|
|
|
+ .card-box1,
|
|
|
|
+ .card-box2 {
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
+ justify-content: start;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .card-box1 {
|
|
|
|
+ .info-card {
|
|
|
|
+ width: 48%;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ .card-box2 {
|
|
|
|
+ .info-card {
|
|
|
|
+ width: 33%;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+.line {
|
|
|
|
+ margin: 90px -30px 30px;
|
|
|
|
+ height: 1px;
|
|
|
|
+ background-color: #E6E6E6;
|
|
|
|
+}
|
|
</style>
|
|
</style>
|