浏览代码

更新图表数据获取

fxs 9 月之前
父节点
当前提交
8b821013a9

+ 9 - 0
src/App.vue

@@ -1,3 +1,12 @@
+<!--
+ * @Author: fxs bjnsfxs@163.com
+ * @Date: 2024-08-20 14:06:49
+ * @LastEditors: fxs bjnsfxs@163.com
+ * @LastEditTime: 2024-08-29 09:43:18
+ * @FilePath: \Game-Backstage-Management-System\src\App.vue
+ * @Description: 
+ * 
+-->
 <script setup lang="ts">
 import { zhCn } from 'element-plus/es/locales.mjs'
 </script>

+ 6 - 2
src/components/Table.vue

@@ -198,9 +198,10 @@ const changePageLimit = watch(
   { deep: true }
 )
 
-watch(
+// 监听传入的datalist的变化,然后去更新数据
+const changeDataList = watch(
   () => [props.dataList],
-  ([newList]) => {
+  () => {
     getData()
   },
   {
@@ -208,6 +209,9 @@ watch(
   }
 )
 
+// 没传入datalist则取消该监听
+if (!props.dataList) changeDataList()
+
 // 没有开启分页查询就关闭掉这个监听
 if (!props.openPageQuery) changePageLimit()
 

+ 6 - 1
src/components/dataAnalysis/HeaderCard.vue

@@ -10,7 +10,7 @@
 import DropDownSelection from './DropDownSelection.vue'
 import { useTableStore } from '@/stores/useTable'
 import type { DropDownInfo, HeaderCardProps } from '@/types/dataAnalysis'
-import { reactive, ref } from 'vue'
+import { onMounted, reactive, ref } from 'vue'
 
 const props = defineProps<HeaderCardProps>()
 
@@ -77,6 +77,11 @@ const dateChange = (val: any) => {
 const changePf = (val: any) => {
   emits('changePf', val)
 }
+
+onMounted(() => {
+  // 这里是为了让外面的组件能够获取到这个组件的默认选择日期,以便发送请求
+  dateChange(selectDate.value)
+})
 </script>
 
 <template>

+ 120 - 115
src/components/dataAnalysis/TemporalTrend.vue

@@ -23,25 +23,6 @@ const props = defineProps<TemporalTrendProps>()
 const activeTab = ref<string>('') // 激活的Tab
 const iconSize = ref(20) // 图标的尺寸
 
-// 图表上放统计数据字段信息
-const compareFieldInfo = reactive<Array<StaticField>>([
-  {
-    name: 'yesterdayCount',
-    cnName: '昨日总数',
-    value: ''
-  },
-  {
-    name: 'todayCount',
-    cnName: '今日总数',
-    value: ''
-  },
-  {
-    name: 'yesterdayThisTimeCount',
-    cnName: '昨日此时',
-    value: ''
-  }
-])
-
 // 表格数据
 const tableDataList = reactive<Array<any>>([])
 
@@ -55,11 +36,11 @@ const paginationConfig = reactive<TablePaginationSetting>({
   hasLodingData: 0 // 已经加载的数据
 })
 
-// 表格字段信息
+// 数据统计字段信息
 const filedsInfo = reactive<Array<TableFieldInfo>>([])
 
 // 图表的展示形式,曲线图或者是表格
-const selectShape = ref('trend')
+const selectShape = ref(1)
 
 // 图表的信息,包括图例,数据,以及x轴的刻度label
 const chartInfo = reactive<OptionsProps>({
@@ -73,12 +54,12 @@ const chartInfo = reactive<OptionsProps>({
  * @param {*} name 图表的展现形式,可以使table或者trend
  * @return {*}
  */
-const changeSelectShape = (name: string) => {
+const changeSelectShape = (name: number) => {
   selectShape.value = name
 }
 
 /**
- * @description: 获取数据
+ * @description: 获取数据,填充表格和趋势图,对于分小时统计和按日期统计的数据,给出不同的处理方式
  * @param {*} url 请求地址
  * @param {*} props 传入的配置参数
  * @return {*}
@@ -89,89 +70,100 @@ const getData = async (type: number) => {
     .then((data) => {
       analysisResCode(data).then((info) => {
         let data = info.data
-
-        // 总览数据赋值
-        // 根据返回数据的key给对应的字段赋值
-        compareFieldInfo.map((item) => {
-          item.value = data[item.name]
-        })
-
         // 表格赋值
         let newList = reactive<Array<any>>([])
-        if (props.type === 1) {
+        if (props.staticFields && props.tabInfo) {
+          props.staticFields.forEach((item, index, array) => {
+            array[index].value = data[item.name]
+          })
           filedsInfo.splice(0, filedsInfo.length)
+        }
 
-          let timesList = Object.keys(data.today)
-          let todayList = data.today
-          let yesterdayList = data.yesterday
+        // 总览数据赋值
+        // 根据返回数据的key给对应的字段赋值
+        if (props.staticFields && props.tabInfo) {
+          props.staticFields.forEach((item, index, array) => {
+            array[index].value = data[item.name]
+          })
+          if (props.type === 1) {
+            filedsInfo.splice(0, filedsInfo.length)
 
-          let matchItem = props.tabInfo.find((item) => item.name === activeTab.value)
+            let timesList = Object.keys(data.today)
+            let todayList = data.today
+            let yesterdayList = data.yesterday
 
-          let todayName = `today${matchItem?.name as string}`
-          let yesterDayName = `yesterday${matchItem?.name as string}`
+            let matchItem = props.tabInfo.find((item) => item.name === activeTab.value)
 
-          filedsInfo.push({
-            name: 'date',
-            cnName: `时间段`,
-            isShow: true
-          })
-          filedsInfo.push({
-            name: todayName,
-            cnName: `今日${(matchItem?.tabTitle as string).slice(0, 2)}`,
-            isShow: true
-          })
-          filedsInfo.push({
-            name: yesterDayName,
-            cnName: `昨日${(matchItem?.tabTitle as string).slice(0, 2)}`,
-            isShow: true
-          })
+            let todayName = `today${matchItem?.name as string}`
+            let yesterDayName = `yesterday${matchItem?.name as string}`
 
-          timesList.map((item, index) => {
-            newList.push({
-              date: item,
-              [todayName]: todayList[item],
-              [yesterDayName]: yesterdayList[item]
+            filedsInfo.push({
+              name: 'date',
+              cnName: `时间段`,
+              isShow: true
+            })
+            filedsInfo.push({
+              name: todayName,
+              cnName: `今日${(matchItem?.tabTitle as string).slice(0, 2)}`,
+              isShow: true
+            })
+            filedsInfo.push({
+              name: yesterDayName,
+              cnName: `昨日${(matchItem?.tabTitle as string).slice(0, 2)}`,
+              isShow: true
             })
-          })
-
-          tableDataList.splice(0, tableDataList.length, ...newList)
-          paginationConfig.total = timesList.length
-          chartInfo.legendData = [
-            `今日${matchItem?.tabTitle.slice(0, 2) as string}`,
-            `昨日${matchItem?.tabTitle.slice(0, 2) as string}`
-          ]
-          chartInfo.seriesData = [todayList, yesterdayList]
-          chartInfo.xAxisData = timesList
-          console.log(chartInfo)
-        } else {
-          filedsInfo.splice(0, filedsInfo.length)
-
-          let matchItem = props.tabInfo.find((item) => item.name === activeTab.value)
-          let timeDistribution = data.timeDistribution
-          let matchName = matchItem?.name as string
 
-          filedsInfo.push({
-            name: 'date',
-            cnName: `日期`,
-            isShow: true
-          })
+            timesList.map((item, index) => {
+              newList.push({
+                date: item,
+                [todayName]: todayList[item],
+                [yesterDayName]: yesterdayList[item]
+              })
+            })
+            tableDataList.splice(0, tableDataList.length, ...newList)
+
+            paginationConfig.total = timesList.length
+
+            chartInfo.legendData = [
+              `今日${matchItem?.tabTitle.slice(0, 2) as string}`,
+              `昨日${matchItem?.tabTitle.slice(0, 2) as string}`
+            ]
+            chartInfo.seriesData = [Object.values(todayList), Object.values(yesterdayList)]
+            chartInfo.xAxisData = timesList
+          } else {
+            filedsInfo.splice(0, filedsInfo.length)
+
+            let matchItem = props.tabInfo.find((item) => item.name === activeTab.value)
+            let timeDistribution = data.timeDistribution
+            let matchName = matchItem?.name as string
+
+            filedsInfo.push({
+              name: 'date',
+              cnName: `日期`,
+              isShow: true
+            })
 
-          filedsInfo.push({
-            name: matchName,
-            cnName: matchItem?.tabTitle as string,
-            isShow: true
-          })
-          for (const [k, v] of Object.entries(timeDistribution)) {
-            newList.push({
-              date: k,
-              [matchName]: v
+            filedsInfo.push({
+              name: matchName,
+              cnName: matchItem?.tabTitle as string,
+              isShow: true
             })
+            for (const [k, v] of Object.entries(timeDistribution)) {
+              newList.push({
+                date: k,
+                [matchName]: v
+              })
+            }
+            tableDataList.splice(0, tableDataList.length, ...newList)
+            paginationConfig.total = Object.entries(timeDistribution).length
+
+            chartInfo.legendData = [matchItem?.tabTitle]
+            chartInfo.seriesData = [Object.values(timeDistribution)]
+            chartInfo.xAxisData = Object.keys(timeDistribution)
           }
-          tableDataList.splice(0, tableDataList.length, ...newList)
-          paginationConfig.total = Object.entries(timeDistribution).length
+        } else {
+          //
         }
-
-        console.log(newList)
       })
     })
 }
@@ -182,14 +174,21 @@ const getData = async (type: number) => {
  * @return {*}
  */
 const tabChange = (tabName: string) => {
-  let type = props.tabInfo.find((item) => item.name === tabName)?.type
-  if (type) getData(type)
-  else throw new Error('No match type')
+  if (props.tabInfo) {
+    let type = props.tabInfo.find((item) => item.name === tabName)?.type
+    if (type) getData(type)
+    else throw new Error('No match type')
+  }
 }
 
+watchEffect(() => getData(1))
+
 onMounted(() => {
   getData(1)
-  activeTab.value = props.defaultActive
+  changeSelectShape(props.selectExpressForm)
+  if (props.defaultActive) {
+    activeTab.value = props.defaultActive
+  }
 })
 </script>
 
@@ -207,18 +206,22 @@ onMounted(() => {
           -->
     <div class="chartsBox">
       <el-tabs class="tabsBox" v-model="activeTab" @tab-change="tabChange">
-        <el-tab-pane
-          :lazy="true"
-          v-for="item in tabInfo"
-          :label="item.tabTitle"
-          :name="item.name"
-          :key="item.name"
-        >
-        </el-tab-pane>
-        <div class="chartContent" v-if="selectShape === 'trend'">
+        <span v-if="needTab">
+          <el-tab-pane
+            :lazy="true"
+            v-for="item in tabInfo"
+            :label="item.tabTitle"
+            :name="item.name"
+            :key="item.name"
+          >
+          </el-tab-pane>
+        </span>
+
+        <div class="chartContent" v-if="selectShape === 1">
           <div class="yesterDayDataBox">
             <StatisticText
-              :fields-info="compareFieldInfo"
+              v-if="staticFields"
+              :fields-info="staticFields"
               :value-class="'chartStaticValue'"
             ></StatisticText>
           </div>
@@ -244,15 +247,17 @@ onMounted(() => {
         </div>
       </el-tabs>
       <div class="toolsBox">
-        <span class="toolItem" @click="changeSelectShape('trend')">
-          <el-icon :size="iconSize" :color="selectShape === 'trend' ? 'blue' : 'gray'"
-            ><TrendCharts
-          /></el-icon>
-        </span>
-        <span class="toolItem" @click="changeSelectShape('table')" style="margin-right: 10px">
-          <el-icon :size="iconSize" :color="selectShape === 'table' ? 'blue' : 'gray'"
-            ><Grid
-          /></el-icon>
+        <span class="expressiveForm" v-if="needChangeExpress">
+          <span class="toolItem" @click="changeSelectShape(1)">
+            <el-icon :size="iconSize" :color="selectShape === 1 ? 'blue' : 'gray'"
+              ><TrendCharts
+            /></el-icon>
+          </span>
+          <span class="toolItem" @click="changeSelectShape(2)" style="margin-right: 10px">
+            <el-icon :size="iconSize" :color="selectShape === 2 ? 'blue' : 'gray'"
+              ><Grid
+            /></el-icon>
+          </span>
         </span>
         <span class="toolItem">
           <el-icon :size="iconSize"><Download /></el-icon>

+ 9 - 4
src/components/echarts/TimeLineChart.vue

@@ -39,10 +39,6 @@ const formatterTooltip = (params: Array<any>) => {
     result += `<br/>${data}`
   })
   return result
-
-  // let data0 = `${circle}#1495eb"></span> ${params[0]['seriesName']}`
-  // let data1 = `${circle}#00cc66"></span> ${params[1]['seriesName']}`
-  // return `${params[0].axisValueLabel}<br/>${data0}<br/>${data1}`
 }
 
 // 选项
@@ -127,10 +123,19 @@ const initOptions = () => {
   linechart.value.setOption(options)
 }
 
+watch(
+  () => [props.legendData, props.seriesData, props.xAxisData],
+  () => {
+    initOptions()
+  }
+)
+
 onMounted(() => {
   nextTick(() => {
     linechart.value = echarts.init(chart.value)
+    console.log('io')
     initOptions()
+    console.log('io2')
     /**
      * @description: 只监听window会导致当侧边栏缩放时,dom大小变化但无法resize
      *              所以需要使用ovserver对整个dom进行监听

+ 9 - 0
src/router/home.ts

@@ -13,6 +13,7 @@ import PlayerManageView from '../views/Home/InfoManage/PlayerManageView.vue'
 import HomeView from '@/views/Home/HomeView.vue'
 import OverView from '@/views/Home/Overview/OverView.vue'
 import KeepView from '@/views/Home/Analysis/KeepView.vue'
+import UserTrendView from '@/views/Home/Analysis/UserTrendView.vue'
 
 export default [
   {
@@ -54,6 +55,14 @@ export default [
         meta: {
           needKeepAlive: true
         }
+      },
+      {
+        path: 'userTrendView',
+        name: 'UserTrendView',
+        component: UserTrendView,
+        meta: {
+          needKeepAlive: true
+        }
       }
     ]
   }

+ 10 - 3
src/types/dataAnalysis.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-23 14:58:29
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-08-28 16:16:44
+ * @LastEditTime: 2024-08-29 11:32:11
  * @FilePath: \Game-Backstage-Management-System\src\types\dataAnalysis.ts
  * @Description:用于dataAnalysis相关组件的type
  *
@@ -70,10 +70,17 @@ export interface OptionsProps {
 
 // 时间趋势组件所需要的props
 export interface TemporalTrendProps {
+  needTab: boolean // 是否需要tab切换
+  selectExpressForm: number // 默认的表现形式,1为图表,2为表格
+  needChangeExpress: boolean // 是否需要切换表格/图表
   type: number // 趋势组件的类型,1为小时段,2为日期统计
-  tabInfo: Array<TabInfo> // 用于切换的tab的信息
+  tabInfo?: Array<TabInfo> // 用于切换的tab的信息
+  needTable: boolean // 是否需要表格
+  tableFieldsInfo?: any // 表格的字段信息
+  resDataFieldsInfo?: any // 返回的数据中有用的信息
   requestConfig: StaticReqConfig // 请求参数配置,需要监听,一旦变化,需要重新获取数据
-  defaultActive: string // 默认选中的tab
+  defaultActive?: string // 默认选中的tab
+  staticFields?: Array<StaticField> // 图表中统计组件的字段信息
   title: string // 上方显示的title
 }
 

+ 0 - 3
src/utils/common/img.ts

@@ -1,3 +0,0 @@
-export const getAssetsImageUrl = (url: string) => {
-  return new URL(`../../assets/${url}`, import.meta.url).href
-}

+ 25 - 0
src/utils/common/index.ts

@@ -56,3 +56,28 @@ export function formatDate(dateString: string) {
   // 生成新的日期字符串
   return `${year}-${formattedMonth}-${formattedDay}`
 }
+
+// 将date对象转为yaer-month-day的格式
+export function resetTimeToMidnight(dateTime: Date): string {
+  // 创建一个 Date 对象来解析输入的日期时间字符串
+
+  // 将时间部分设置为 00:00:00
+  dateTime.setHours(0, 0, 0, 0)
+
+  // 格式化日期为 'YYYY-MM-DD HH:mm:ss' 格式
+  const year = dateTime.getFullYear()
+  const month = String(dateTime.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
+  const day = String(dateTime.getDate()).padStart(2, '0')
+
+  // 返回格式化的字符串
+  return `${year}-${month}-${day}`
+}
+
+/**
+ * @description: 生成一个打包后可以使用的url
+ * @param {string} url  传入一个assets文件夹下的文件名
+ * @return {*}
+ */
+export const getAssetsImageUrl = (url: string) => {
+  return new URL(`../../assets/${url}`, import.meta.url).href
+}

+ 0 - 24
src/utils/common/time.ts

@@ -1,24 +0,0 @@
-/*
- * @Author: fxs bjnsfxs@163.com
- * @Date: 2024-08-26 14:06:51
- * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-08-27 16:44:39
- * @FilePath: \Game-Backstage-Management-System\src\utils\common\time.ts
- * @Description:
- *
- */
-// 待定格式
-export function resetTimeToMidnight(dateTime: Date): string {
-  // 创建一个 Date 对象来解析输入的日期时间字符串
-
-  // 将时间部分设置为 00:00:00
-  dateTime.setHours(0, 0, 0, 0)
-
-  // 格式化日期为 'YYYY-MM-DD HH:mm:ss' 格式
-  const year = dateTime.getFullYear()
-  const month = String(dateTime.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
-  const day = String(dateTime.getDate()).padStart(2, '0')
-
-  // 返回格式化的字符串
-  return `${year}-${month}-${day}`
-}

+ 242 - 0
src/views/Home/Analysis/UserTrendView.vue

@@ -0,0 +1,242 @@
+<script setup lang="ts">
+import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
+import { onMounted, reactive, watch, ref } from 'vue'
+import type { StaticField, TabInfo, StaticReqConfig } from '@/types/dataAnalysis'
+
+import StatisticText from '@/components/dataAnalysis/StatisticText.vue'
+import TemporalTrend from '@/components/dataAnalysis/TemporalTrend.vue'
+import { useCommonStore } from '@/stores/useCommon'
+import { useRequest } from '@/hooks/useRequest'
+import { useAnalysis } from '@/hooks/useAnalysis'
+import { resetTimeToMidnight } from '@/utils/common'
+
+const { updateReqConfig } = useAnalysis()
+const { AllApi } = useRequest()
+const { selectInfo } = useCommonStore()
+
+// 总览数据的ref
+const userTrendStaticRef = ref()
+
+// 目前选择的信息
+// 这里不太合理,应该根据返回的数据中的pf和game赋值,因为这个可能会变
+const userTrendSelectInfo = reactive({
+  pf: 'web'
+})
+
+// 总览数据的字段对应的信息
+const userTrendStaticFieldInfo = reactive<Array<StaticField>>([
+  {
+    name: 'activeCount',
+    cnName: '总活跃用户',
+    value: ''
+  },
+  {
+    name: 'activeTime',
+    cnName: '平时使用时长',
+    value: ''
+  },
+  {
+    name: 'dauMau',
+    cnName: 'dau/Mau',
+    value: ''
+  },
+  {
+    name: 'loginCount',
+    cnName: '总登录人数',
+    value: ''
+  },
+  {
+    name: 'registerCount',
+    cnName: '新注册用户',
+    value: ''
+  }
+])
+
+// 总览请求参数的配置
+const userTrendDataReqConfig = reactive<StaticReqConfig>({
+  url: AllApi.userTrendsOverview,
+  otherOptions: {
+    pf: userTrendSelectInfo.pf,
+    gid: selectInfo.gid,
+    startTime: resetTimeToMidnight(new Date()),
+    endTime: resetTimeToMidnight(new Date())
+  }
+})
+
+// 数据趋势请求参数配置
+const dataTrendReqConfig = reactive<StaticReqConfig>({
+  url: AllApi.userDataTrades,
+  otherOptions: {
+    pf: userTrendSelectInfo.pf,
+    gid: selectInfo.gid
+  }
+})
+
+// 数据趋势组件据需要的tab信息
+const dataTrendTabList = reactive<Array<TabInfo>>([
+  {
+    name: 'newUser',
+    tabTitle: '新增用户',
+    type: 1
+  },
+  {
+    name: 'dailyActiveUser',
+    tabTitle: '日活跃用户',
+    type: 2
+  },
+  {
+    name: 'weeklyActiveUser',
+    tabTitle: '周活跃用户',
+    type: 3
+  },
+  {
+    name: 'detailDatalyActiveUser',
+    tabTitle: '月活跃用户',
+    type: 4
+  },
+  {
+    name: 'launchCount',
+    tabTitle: '启动次数',
+    type: 5
+  },
+  {
+    name: 'dailyUsageTime',
+    tabTitle: '单日使用时长',
+    type: 6
+  }
+])
+
+// 数据趋势统计数据字段信息
+const dataTrendChartsStaticFieldInfo = reactive<Array<StaticField>>([
+  {
+    name: 'avg',
+    cnName: '均值',
+    value: ''
+  },
+  {
+    name: 'count',
+    cnName: '总数',
+    value: ''
+  }
+])
+
+// 数据详情组件请求参数配置
+const detailDataReqConfig = reactive<StaticReqConfig>({
+  url: AllApi.userMouthDistributionData,
+  otherOptions: {
+    pf: userTrendSelectInfo.pf,
+    gid: selectInfo.gid,
+    startTime: resetTimeToMidnight(new Date()),
+    endTime: resetTimeToMidnight(new Date())
+  }
+})
+
+/**
+ * @description: 监听pf和gid的变化,数据变化后立即重新请求所有相关数据
+ * @tip watch监听reactive的数据时,必须以getter形式,不然会警告
+ * @return {*}
+ */
+watch(
+  () => [userTrendSelectInfo.pf, selectInfo.gid],
+  ([newPf, newGid]) => {
+    updateReqConfig(userTrendDataReqConfig, { pf: newPf, gid: newGid })
+    updateReqConfig(dataTrendReqConfig, { pf: newPf, gid: newGid })
+    updateReqConfig(detailDataReqConfig, { pf: newPf, gid: newGid })
+  }
+)
+
+/**
+ * @description: 选择的平台改变
+ * @param {*} pf  平台名
+ * @return {*}
+ */
+const changePf = (pf: string) => {
+  userTrendSelectInfo.pf = pf
+}
+
+const changeDate = (date: Array<Date>) => {
+  updateReqConfig(userTrendDataReqConfig, {
+    startTime: resetTimeToMidnight(date[0]),
+    endTime: resetTimeToMidnight(date[1])
+  })
+  updateReqConfig(detailDataReqConfig, {
+    startTime: resetTimeToMidnight(date[0]),
+    endTime: resetTimeToMidnight(date[1])
+  })
+}
+
+onMounted(() => {})
+</script>
+<template>
+  <div class="userTrendBox">
+    <div class="header">
+      <HeaderCard
+        :open-date-select="true"
+        :default-pf="userTrendSelectInfo.pf"
+        @change-pf="changePf"
+        @change-date="changeDate"
+        :title="'数据总览'"
+      ></HeaderCard>
+    </div>
+    <div class="staticBox">
+      <StatisticText
+        ref="userTrendStaticRef"
+        :fields-info="userTrendStaticFieldInfo"
+        :request-config="userTrendDataReqConfig"
+      ></StatisticText>
+    </div>
+    <div class="dataTrendBox">
+      <TemporalTrend
+        :need-table="false"
+        :need-tab="true"
+        :select-express-form="1"
+        :need-change-express="false"
+        :static-fields="dataTrendChartsStaticFieldInfo"
+        :type="1"
+        :request-config="dataTrendReqConfig"
+        :title="'时段分布'"
+        :defaultActive="dataTrendTabList[0].name"
+        :tabInfo="dataTrendTabList"
+      ></TemporalTrend>
+    </div>
+    <div class="onedetailDataTrendBox">
+      <TemporalTrend
+        :need-table="true"
+        :need-tab="false"
+        :select-express-form="2"
+        :need-change-express="false"
+        :type="2"
+        :request-config="detailDataReqConfig"
+        :title="'30日内趋势'"
+      ></TemporalTrend>
+    </div>
+  </div>
+</template>
+
+<style scoped>
+.userTrendBox {
+  width: 98%;
+  margin: 1% auto;
+  /* background-color: white; */
+  box-sizing: border-box;
+  /* border: 1px solid #e5e6eb; */
+}
+
+.header,
+.staticBox,
+.dataTrendTrendBox,
+.onedetailDataTrendBox {
+  box-sizing: border-box;
+  background-color: white;
+  width: 100%;
+  padding: 0 24px;
+}
+.header {
+  padding: 0;
+  box-shadow: none;
+}
+
+.staticBox {
+  margin-bottom: 2px;
+}
+</style>

+ 5 - 1
src/views/Home/HomeView.vue

@@ -4,7 +4,7 @@ import { onMounted, reactive, ref } from 'vue'
 import { ElMessage } from 'element-plus'
 import { getAllGameInfo } from '@/utils/table/table'
 import router from '@/router'
-import { getAssetsImageUrl } from '@/utils/common/img'
+import { getAssetsImageUrl } from '@/utils/common'
 import type { DropDownInfo, DropDownItem } from '@/types/dataAnalysis'
 import DropDownSelection from '@/components/dataAnalysis/DropDownSelection.vue'
 import { useCommonStore } from '@/stores/useCommon'
@@ -43,6 +43,10 @@ const menuList = [
       {
         pathName: 'KeepView',
         title: '留存分析'
+      },
+      {
+        pathName: 'UserTrendView',
+        title: '用户趋势'
       }
     ]
   }

+ 60 - 57
src/views/Home/Overview/OverView.vue

@@ -85,6 +85,41 @@ const periodTabList = reactive<Array<TabInfo>>([
   }
 ])
 
+// 分时段统计数据字段信息
+const periodChartsStaticFieldInfo = reactive<Array<StaticField>>([
+  {
+    name: 'yesterdayCount',
+    cnName: '昨日',
+    value: ''
+  },
+  {
+    name: 'todayCount',
+    cnName: '今日',
+    value: ''
+  },
+  {
+    name: 'yesterdayThisTimeCount',
+    cnName: '昨日此时',
+    value: ''
+  }
+])
+
+// 返回数据中有用的字段
+const resDataField = {
+  xAxis: 'today', // x轴的刻度信息所在的字段
+  values: ['yesterday', 'today'] // 值所在的字段
+}
+
+// 表格字段
+// 除了索引字段,其他字段需要与上方的resDataField的values字段对应
+const tableFields = {
+  index: {
+    type: 1 // 索引字段, 0 没有索引字段 1 直接使用x轴的刻度作为信息
+  },
+  today: '今日',
+  yesterday: '昨日'
+}
+
 // 一个月内组件请求参数配置
 const monthDataReqConfig = reactive<StaticReqConfig>({
   url: AllApi.userMouthDistributionData,
@@ -94,7 +129,7 @@ const monthDataReqConfig = reactive<StaticReqConfig>({
   }
 })
 
-// 模拟一个月内组件需要的tab信息
+// 一个月内组件需要的tab信息
 const monthTabList = reactive<Array<TabInfo>>([
   {
     name: 'newUser',
@@ -123,6 +158,20 @@ const monthTabList = reactive<Array<TabInfo>>([
   }
 ])
 
+// 一个月内统计数据字段信息
+const monthChartsStaticFieldInfo = reactive<Array<StaticField>>([
+  {
+    name: 'avg',
+    cnName: '平均值',
+    value: ''
+  },
+  {
+    name: 'count',
+    cnName: '总数',
+    value: ''
+  }
+])
+
 /**
  * @description: 监听pf和gid的变化,数据变化后立即重新请求所有相关数据
  * @tip watch监听reactive的数据时,必须以getter形式,不然会警告
@@ -146,62 +195,6 @@ const changePf = (pf: string) => {
   overViewSelectInfo.pf = pf
 }
 
-// // 模拟函数
-// function generateRandomArray(numOfArrays: number, lengthOfArray: number) {
-//   return Array.from({ length: numOfArrays }, () =>
-//     Array.from({ length: lengthOfArray }, () => Math.floor(Math.random() * 100))
-//   )
-// }
-
-// // 模拟时间段图表数据
-// const periodData = reactive<OptionsProps>({
-//   xAxisData: generateHourlyArray(23),
-//   legendData: ['今日新增', '昨日新增'],
-//   seriesData: generateRandomArray(2, 24)
-// })
-
-// 一个月的日期模拟
-// const oneMonthDate = [
-//   '20240801',
-//   '20240802',
-//   '20240803',
-//   '20240804',
-//   '20240805',
-//   '20240806',
-//   '20240807',
-//   '20240808',
-//   '20240809',
-//   '20240810',
-//   '20240811',
-//   '20240812',
-//   '20240813',
-//   '20240814',
-//   '20240815',
-//   '20240816',
-//   '20240817',
-//   '20240818',
-//   '20240819',
-//   '20240820',
-//   '20240821',
-//   '20240822',
-//   '20240823',
-//   '20240824',
-//   '20240825',
-//   '20240826',
-//   '20240827',
-//   '20240828',
-//   '20240829',
-//   '20240830',
-//   '20240831'
-// ]
-
-// 模拟30天内图表数据
-// const oneMonthData = reactive<OptionsProps>({
-//   xAxisData: oneMonthDate.map((item) => formatDate(item)),
-//   legendData: ['新增'],
-//   seriesData: generateRandomArray(1, 31)
-// })
-
 onMounted(() => {})
 </script>
 <template>
@@ -223,6 +216,11 @@ onMounted(() => {})
     </div>
     <div class="periodTrendBox">
       <TemporalTrend
+        :need-table="true"
+        :need-tab="true"
+        :select-express-form="1"
+        :need-change-express="true"
+        :static-fields="periodChartsStaticFieldInfo"
         :type="1"
         :request-config="periodDataReqConfig"
         :title="'时段分布'"
@@ -232,6 +230,11 @@ onMounted(() => {})
     </div>
     <div class="oneMonthTrendBox">
       <TemporalTrend
+        :need-table="true"
+        :need-tab="true"
+        :select-express-form="1"
+        :need-change-express="true"
+        :static-fields="monthChartsStaticFieldInfo"
         :type="2"
         :request-config="monthDataReqConfig"
         :title="'30日内趋势'"

+ 1 - 1
src/views/Login/LoginView.vue

@@ -7,7 +7,7 @@ import axiosInstance from '@/utils/axios/axiosInstance'
 import MyButton from '@/components/form/MyButton.vue'
 import MyInput from '@/components/form/MyInput.vue'
 
-import { getAssetsImageUrl } from '@/utils/common/img'
+import { getAssetsImageUrl } from '@/utils/common'
 
 const { AllApi, analysisResCode } = useRequest()