From e4f8a370f63dec412114fd1bb58a56f687faaab6 Mon Sep 17 00:00:00 2001 From: songjie Date: Sat, 24 Jan 2026 11:05:51 +0800 Subject: [PATCH] =?UTF-8?q?7=E5=A4=A9=E7=99=BB=E5=BD=95=E8=B6=8B=E5=8A=BF?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=AF=B9=E6=8E=A5=E5=AE=8C=E6=88=90=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/platformData.js | 23 ++++++ src/views/PlatformData/UserLoginStats.vue | 129 ++++++++++++++++++++++-------- 2 files changed, 118 insertions(+), 34 deletions(-) diff --git a/src/api/platformData.js b/src/api/platformData.js index 55e5e96..b0008d7 100644 --- a/src/api/platformData.js +++ b/src/api/platformData.js @@ -85,3 +85,26 @@ export function getUserLoginList(params) { data: formData }) } + +// 获取用户登录趋势数据 +export function getUserLoginTrend(params) { + const formData = new FormData(); + formData.append('token', localStorage.getItem('token')); + if (params) { + if (params.region) formData.append('region', params.region); + if (params.start_time) formData.append('start_time', params.start_time); + if (params.end_time) formData.append('end_time', params.end_time); + } + + return request({ + url: 'http://7a1b8c9e.r40.cpolar.top/admin/user/login/trend', + method: 'post', + headers: { + 'token': localStorage.getItem('token'), + 'client': 'ios', + 'version': '1', + 'Content-Type': 'multipart/form-data' + }, + data: formData + }) +} diff --git a/src/views/PlatformData/UserLoginStats.vue b/src/views/PlatformData/UserLoginStats.vue index e68f239..f3deade 100644 --- a/src/views/PlatformData/UserLoginStats.vue +++ b/src/views/PlatformData/UserLoginStats.vue @@ -37,8 +37,8 @@ end-placeholder="结束时间" size="default" /> - 搜索 - 重置 + 搜索 + 重置 数据导出 @@ -92,7 +92,7 @@
-
近7天登录趋势
+
{{ chartTrendTitle }}
@@ -223,7 +223,7 @@ import { ref, onMounted, nextTick, watch } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import * as echarts from 'echarts'; -import { getUserLoginList } from '../../api/platformData'; +import { getUserLoginList, getUserLoginTrend } from '../../api/platformData'; const route = useRoute(); const router = useRouter(); @@ -235,6 +235,7 @@ const searchRegion = ref(''); const dateRangeRegion = ref(''); const chartTrendRef = ref(null); +let chartTrendInstance = null; const chartRegionBarRef = ref(null); const chartRegionPieRef = ref(null); const chartRegionMemberPieRef = ref(null); @@ -251,6 +252,8 @@ const loginStats = ref({ }); // 获取增长率的样式类 +const chartTrendTitle = ref('近7天登录趋势'); + const getGrowthClass = (growthStr) => { if (!growthStr) return ''; return growthStr.startsWith('-') ? 'down' : 'up'; @@ -266,6 +269,14 @@ const getGrowthText = (growthStr) => { return `${prefix}${arrow} ${value}`; }; +// 格式化日期 +const formatDate = (date) => { + if (!date) return ''; + const d = new Date(date); + const pad = (n) => n < 10 ? '0' + n : n; + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; +}; + const fetchLoginData = async () => { try { const res = await getUserLoginList(); @@ -282,6 +293,83 @@ const fetchLoginData = async () => { } }; +const fetchTrendData = async () => { + let params = {}; + if (dateRange.value && dateRange.value.length === 2) { + params.start_time = formatDate(dateRange.value[0]); + params.end_time = formatDate(dateRange.value[1]); + chartTrendTitle.value = `${params.start_time} 至 ${params.end_time} 登录趋势`; + } else { + chartTrendTitle.value = '近7天登录趋势'; + } + + try { + const res = await getUserLoginTrend(params); + console.log("获取用户登录趋势响应:", res); + + // 兼容处理拦截器 + const data = res.list ? res : (res.data && res.data.list ? res.data : null); + + if (data && data.list) { + updateTrendChart(data.list); + } + } catch (e) { + console.error('获取用户登录趋势失败:', e); + } +}; + +const updateTrendChart = (list) => { + if (!chartTrendRef.value) return; + + if (!chartTrendInstance) { + chartTrendInstance = echarts.init(chartTrendRef.value); + } + + const dates = list.map(item => item.date); + const allUser = list.map(item => item.all_user); + const member = list.map(item => item.member); + + const option = { + tooltip: { trigger: 'axis' }, + legend: { data: ['所有用户', '会员用户'], top: 'top' }, + grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, + xAxis: { + type: 'category', + boundaryGap: false, + data: dates + }, + yAxis: { type: 'value' }, + series: [ + { + name: '所有用户', + type: 'line', + data: allUser, + smooth: true, + itemStyle: { color: '#40a9ff' } + }, + { + name: '会员用户', + type: 'line', + data: member, + smooth: true, + itemStyle: { color: '#52c41a' } + } + ] + }; + chartTrendInstance.setOption(option); +}; + +const handleSearch = () => { + fetchTrendData(); + // 这里也可以加上 fetchLoginData() 如果登录统计也支持搜索参数 +}; + +const handleReset = () => { + dateRange.value = ''; + selectedRegion.value = ''; + fetchTrendData(); +}; + // Tab 1 数据 const loginTableData1 = [ { channel: 'App Store', total: '154,832', dailyNew: '', percent: '38%' }, @@ -333,36 +421,9 @@ const regionColors = ['#68B2FF', '#D94F41', '#69D2AF', '#FFD360', '#ADADAD', '#B const initCharts = () => { nextTick(() => { if (activeTab.value === 'loginData') { - if (chartTrendRef.value) { - const chart = echarts.init(chartTrendRef.value); - chart.setOption({ - tooltip: { trigger: 'axis' }, - legend: { data: ['新用户', '老用户'], top: 'top' }, - grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, - xAxis: { - type: 'category', - boundaryGap: false, - data: ['六天前', '五天前', '四天前', '三天前', '两天前', '昨天', '今天'] - }, - yAxis: { type: 'value' }, - series: [ - { - name: '新用户', - type: 'line', - data: [1350, 1250, 1100, 1050, 1050, 1300, 1000], - smooth: true, - itemStyle: { color: '#40a9ff' } - }, - { - name: '老用户', - type: 'line', - data: [300, 600, 320, 320, 400, 550, 650], - smooth: true, - itemStyle: { color: '#52c41a' } - } - ] - }); - } + // 趋势图已经在 fetchTrendData -> updateTrendChart 中初始化和更新 + // 这里只需要处理初始无数据时的状态,或者等待 fetchTrendData 调用 + fetchTrendData(); } else if (activeTab.value === 'regionalData') { // 柱状图 if (chartRegionBarRef.value) {