Quellcode durchsuchen

更新留存页,更新用户趋势

fxs vor 9 Monaten
Ursprung
Commit
6f6c93b77c

+ 0 - 9
components.d.ts

@@ -10,7 +10,6 @@ declare module 'vue' {
     DropDownSelection: typeof import('./src/components/dataAnalysis/DropDownSelection.vue')['default']
     ElButton: typeof import('element-plus/es')['ElButton']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
-    ElCol: typeof import('element-plus/es')['ElCol']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
     ElDialog: typeof import('element-plus/es')['ElDialog']
@@ -25,9 +24,7 @@ declare module 'vue' {
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPopover: typeof import('element-plus/es')['ElPopover']
-    ElRow: typeof import('element-plus/es')['ElRow']
     ElSelect: typeof import('element-plus/es')['ElSelect']
-    ElStatistic: typeof import('element-plus/es')['ElStatistic']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElTable: typeof import('element-plus/es')['ElTable']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
@@ -41,20 +38,14 @@ declare module 'vue' {
     IconIcBaselineVisibility: typeof import('~icons/ic/baseline-visibility')['default']
     IconIcBaselineVisibilityOff: typeof import('~icons/ic/baseline-visibility-off')['default']
     IconIconParkGameThree: typeof import('~icons/icon-park/game-three')['default']
-    IconLogosChrome: typeof import('~icons/logos/chrome')['default']
     IconMaterialSymbolsLightLogout: typeof import('~icons/material-symbols-light/logout')['default']
-    IconMdiHome: typeof import('~icons/mdi/home')['default']
     IconMdiPassword: typeof import('~icons/mdi/password')['default']
-    IconSvg: typeof import('./src/components/svgIcon/IconSvg.vue')['default']
     MyButton: typeof import('./src/components/form/MyButton.vue')['default']
     MyInput: typeof import('./src/components/form/MyInput.vue')['default']
     RegreshBtn: typeof import('./src/components/toolsBtn/RegreshBtn.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
-    StaticText: typeof import('./src/components/dataAnalysis/StaticText.vue')['default']
     StatisticText: typeof import('./src/components/dataAnalysis/StatisticText.vue')['default']
-    SvgIcon: typeof import('./src/components/svgIcon/SvgIcon.vue')['default']
-    SvgIcon2: typeof import('./src/components/svgIcon/SvgIcon2.vue')['default']
     Table: typeof import('./src/components/Table.vue')['default']
     TemporalTrend: typeof import('./src/components/dataAnalysis/TemporalTrend.vue')['default']
     TimeLineChart: typeof import('./src/components/echarts/TimeLineChart.vue')['default']

+ 49 - 20
src/components/Table.vue

@@ -17,7 +17,14 @@ const toolsIconSize = ref(25)
 const queryFormRef = ref<FormInstance>()
 
 // 传过来的配置
-const props = defineProps<PropsParams>()
+const props = withDefaults(defineProps<PropsParams>(), {
+  needRowindex: true,
+  needAverage: false,
+  needLeftTools: false,
+  needRightTools: false,
+  openFilterQuery: false,
+  openPageQuery: false
+})
 
 // 父组件触发的方法
 const emits = defineEmits(['addNewItem'])
@@ -90,18 +97,19 @@ const getData = () => {
       tableData.splice(0, tableData.length, ...props.dataList)
 
       loading.value = false
+      resolve(true)
     } else {
       if (props.requestConfig) {
         if (props.openPageQuery) {
           // 如果开启了分页查询,那么要计算出需要展示的页码位置所对应的偏移量
           // 同时要将查询的条数改为对应的用户选择的展示条数
-          props.requestConfig.other.offset =
+          props.requestConfig.otherOptions.offset =
             (props.paginationConfig.currentPage - 1) * props.paginationConfig.limit
-          props.requestConfig.other.limit = props.paginationConfig.limit
+          props.requestConfig.otherOptions.limit = props.paginationConfig.limit
         }
 
         // 查询时要根据是否开启分页查询传入对应参数
-        getTableData(props.requestConfig.url, props.requestConfig.other, props.openPageQuery)
+        getTableData(props.requestConfig.url, props.requestConfig.otherOptions, props.openPageQuery)
           .then(() => {
             resolve(true)
           })
@@ -116,6 +124,25 @@ const getData = () => {
         throw new Error('no match requestConfig')
       }
     }
+    if (props.needAverage) {
+      let rowData: any = {}
+      let oldList: Array<any> = JSON.parse(JSON.stringify(tableData))
+      Object.values(props.tableFieldsInfo).map((item, index) => {
+        let sum = oldList
+          .map((item) => item.count)
+          .reduce((accumulator, currentValue) => accumulator + currentValue, 0)
+        let averageList = oldList.map((val) => val[item.name]).filter((item) => item !== undefined)
+        if (index === 0) rowData[item.name] = '均值'
+        else if (item.name === 'count') rowData[item.name] = sum
+        else
+          rowData[item.name] =
+            (
+              averageList.reduce((accumulator, currentValue) => accumulator + currentValue, 0) /
+              averageList.length
+            ).toFixed(2) + '%'
+      })
+      insertRow(0, rowData)
+    }
   })
 }
 
@@ -127,7 +154,7 @@ const resetTableData = () => {
 // 按条件查询
 const queryTableData = () => {
   if (props.requestConfig) {
-    props.requestConfig.other = { ...props.requestConfig.other, ...queryFormData }
+    props.requestConfig.otherOptions = { ...props.requestConfig.otherOptions, ...queryFormData }
     getData()
   } else {
     throw new Error('no match requestConfig')
@@ -154,10 +181,20 @@ const insertRow = (start: number, rowData: any) => {
   if (props.openPageQuery) {
     tableData[start].splice(0, 0, rowData)
   } else {
-    // tableData.push(rowData)
     tableData.splice(start, 0, rowData)
   }
-  // tableData.splice(0, 0, rowData)
+}
+
+/**
+ * @description: 根据计算出来的值去返回对应的颜色深度
+ * @return {*}
+ */
+const getDecimalFromRange = (number: number) => {
+  if (number === null || number === undefined) return 0
+  if (number < 25) return 0.25
+  else if (number < 50) return 0.5
+  else if (number < 75) return 0.75
+  else return 1.0 // 如果number >= 75,则直接返回1.00
 }
 
 /**
@@ -172,9 +209,9 @@ const tableCellStyle = (info: any) => {
     return {
       'font-weight': 'bold'
     }
-  else if (info.columnIndex > 1 && props.needAverage) {
+  else if (info.column.property != 'count' && info.column.property != 'date' && props.needAverage) {
     return {
-      'background-color': `rgba(59, 157, 247,${info.row[info.column.property] / 100})`
+      'background-color': `rgba(59, 157, 247,${getDecimalFromRange(info.row[info.column.property])})`
     }
   } else return {}
 }
@@ -222,17 +259,9 @@ defineExpose({
 })
 
 onMounted(() => {
-  getData().then(() => {
-    // 插入一行均值行
-    if (props.needAverage) {
-      let rowData: any = {}
-      Object.values(props.tableFieldsInfo).map((item, index) => {
-        if (index === 0) rowData[item.name] = '均值'
-        else rowData[item.name] = Math.random() * 100
-      })
-      insertRow(0, rowData)
-    }
-  })
+  if (!props.dataList) {
+    getData()
+  }
 })
 </script>
 

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

@@ -8,7 +8,6 @@
 
 <script setup lang="ts">
 import DropDownSelection from './DropDownSelection.vue'
-import { useTableStore } from '@/stores/useTable'
 import type { DropDownInfo, HeaderCardProps } from '@/types/dataAnalysis'
 import { onMounted, reactive, ref } from 'vue'
 

+ 10 - 15
src/components/dataAnalysis/StatisticText.vue

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-26 13:57:37
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-08-28 15:32:44
+ * @LastEditTime: 2024-08-29 18:23:28
  * @FilePath: \Game-Backstage-Management-System\src\components\dataAnalysis\StatisticText.vue
  * @Description: 用于展示统计数据,如总览页面上方的总览数据
  * 
@@ -13,9 +13,6 @@ import type { StaticDataInfo, StaticField } from '@/types/dataAnalysis'
 import { decimalToPercentage } from '@/utils/common'
 import { onMounted, reactive, watchEffect } from 'vue'
 import axiosInstance from '@/utils/axios/axiosInstance'
-import { useRequest } from '@/hooks/useRequest'
-
-const { analysisResCode } = useRequest()
 const props = defineProps<StaticDataInfo>()
 const dataList = reactive<Array<StaticField>>([])
 
@@ -26,16 +23,14 @@ const dataList = reactive<Array<StaticField>>([])
  */
 const getData = () => {
   if (props.requestConfig) {
-    axiosInstance.post(props.requestConfig.url, props.requestConfig.otherOptions).then((data) => {
-      analysisResCode(data).then((info) => {
-        dataList.splice(0, dataList.length) // 清空一下
-        let data = info.data
-        props.fieldsInfo.map((item) => {
-          dataList.push({
-            name: item.name,
-            cnName: item.cnName,
-            value: data[item.name]
-          })
+    axiosInstance.post(props.requestConfig.url, props.requestConfig.otherOptions).then((info) => {
+      dataList.splice(0, dataList.length) // 清空一下
+      let data = info.data
+      props.fieldsInfo.map((item) => {
+        dataList.push({
+          name: item.name,
+          cnName: item.cnName,
+          value: data[item.name]
         })
       })
     })
@@ -60,7 +55,7 @@ watchEffect(() => getData())
 onMounted(() => {})
 
 defineExpose({
-  getData
+  // getData
 })
 </script>
 

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

@@ -7,18 +7,15 @@
 -->
 
 <script setup lang="ts">
-import { onMounted, reactive, ref, watch, watchEffect } from 'vue'
-import { type StaticField, type TemporalTrendProps, type OptionsProps } from '@/types/dataAnalysis'
+import { onMounted, reactive, ref, watch } from 'vue'
+import { type TemporalTrendProps, type OptionsProps } from '@/types/dataAnalysis'
 import type { TablePaginationSetting, TableFieldInfo } from '@/types/table'
 import Table from '../Table.vue'
 import TimeLineChart from '../echarts/TimeLineChart.vue'
 import StatisticText from './StatisticText.vue'
-import { useRequest } from '@/hooks/useRequest'
+
 import axiosInstance from '@/utils/axios/axiosInstance'
-import { useAnalysis } from '@/hooks/useAnalysis'
 
-const { updateReqConfig } = useAnalysis()
-const { AllApi, analysisResCode } = useRequest()
 const props = defineProps<TemporalTrendProps>()
 const activeTab = ref<string>('') // 激活的Tab
 const iconSize = ref(20) // 图标的尺寸
@@ -36,8 +33,8 @@ const paginationConfig = reactive<TablePaginationSetting>({
   hasLodingData: 0 // 已经加载的数据
 })
 
-// 数据统计字段信息
-const filedsInfo = reactive<Array<TableFieldInfo>>([])
+// 表格字段信息
+const tableFieldsInfo = reactive<Array<TableFieldInfo>>([])
 
 // 图表的展示形式,曲线图或者是表格
 const selectShape = ref(1)
@@ -59,112 +56,102 @@ const changeSelectShape = (name: number) => {
 }
 
 /**
- * @description: 获取数据,填充表格和趋势图,对于分小时统计和按日期统计的数据,给出不同的处理方式
- * @param {*} url 请求地址
- * @param {*} props 传入的配置参数
+ * @description: 生成表格字段信息,必须要调用,因为legend的字段也依赖这里
+ * @return {*}
+ */
+const createTableField = () => {
+  //  生成表格的字段信息
+  tableFieldsInfo.splice(0, tableFieldsInfo.length)
+
+  for (const [key, value] of Object.entries(props.tableFieldsInfo)) {
+    // 根据传入的信息,生成table需要的字段信息
+    tableFieldsInfo.push({
+      name: key,
+      cnName: value as string,
+      isShow: true
+    })
+  }
+}
+
+/**
+ * @description: 生成表格需要的信息,包括表格的字段信息及表格数据
+ * @param {*} data  返回的data数据
+ * @return {*} 返回生成x轴信息和所有的数据
+ */
+const createTableData = (data: any) => {
+  // 图表的x轴信息
+  const xInfo = Object.keys(data[props.resDataFieldsInfo['xAxis']])
+  const valInfo: any = {}
+  // 把所有的表格需要的数据假如valInfo,其中index字段需要单独拿出来用x轴的信息填充
+  props.resDataFieldsInfo['values'].map((key: string) => {
+    valInfo[key] = Object.values(data[key])
+  })
+  valInfo['index'] = xInfo
+  // 生成表格数据
+  let newList = reactive<Array<any>>([])
+
+  // 以x轴字段的数据作为循环条件
+  // 拿到所有的字段name
+  let fieldList = tableFieldsInfo.map((field) => field.name)
+
+  // 生成每一行的数据
+  xInfo.map(() => {
+    let newItem: any = {}
+    fieldList.map((item, index) => {
+      newItem[item] = valInfo[item][index]
+    })
+    newList.push(newItem)
+  })
+
+  tableDataList.splice(0, tableDataList.length, ...newList)
+  paginationConfig.total = xInfo.length
+}
+
+/**
+ * @description: 生成图表的信息
+ * @param {*} data 返回的数据
  * @return {*}
  */
+const createOptions = (data: any) => {
+  const valInfo: any = {}
+  const xInfo = Object.keys(data[props.resDataFieldsInfo['xAxis']])
+  // 把所有的表格需要的数据假如valInfo,其中index字段需要单独拿出来用x轴的信息填充
+  props.resDataFieldsInfo['values'].map((key: string) => {
+    valInfo[key] = Object.values(data[key])
+  })
+
+  chartInfo.xAxisData = xInfo
+
+  chartInfo.legendData = tableFieldsInfo
+    .filter((item) => item.name !== 'index')
+    .map((val) => val.cnName)
+
+  chartInfo.seriesData = Object.values(valInfo)
+}
+
 const getData = async (type: number) => {
   axiosInstance
     .post(props.requestConfig.url, { ...props.requestConfig.otherOptions, type })
-    .then((data) => {
-      analysisResCode(data).then((info) => {
-        let data = info.data
-        // 表格赋值
-        let newList = reactive<Array<any>>([])
-        if (props.staticFields && props.tabInfo) {
-          props.staticFields.forEach((item, index, array) => {
-            array[index].value = data[item.name]
-          })
-          filedsInfo.splice(0, filedsInfo.length)
-        }
-
-        // 总览数据赋值
-        // 根据返回数据的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 timesList = Object.keys(data.today)
-            let todayList = data.today
-            let yesterdayList = data.yesterday
-
-            let matchItem = props.tabInfo.find((item) => item.name === activeTab.value)
-
-            let todayName = `today${matchItem?.name as string}`
-            let yesterDayName = `yesterday${matchItem?.name as string}`
-
-            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
-            })
-
-            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
-              })
-            }
-            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)
-          }
-        } else {
-          //
-        }
-      })
+    .then((info) => {
+      let data = info.data
+      // 生成表格字段
+      createTableField()
+      // 生成表格数据
+      if (props.needTable) {
+        createTableData(info.data)
+      }
+
+      // 如果有统计数据的配置,则生成
+      if (props.staticFields) {
+        props.staticFields.forEach((item, index, array) => {
+          array[index].value = data[item.name]
+        })
+      }
+
+      // options配置赋值
+      if (props.needCharts) {
+        createOptions(info.data)
+      }
     })
 }
 
@@ -181,14 +168,24 @@ const tabChange = (tabName: string) => {
   }
 }
 
-watchEffect(() => getData(1))
+/**
+ * @description: 监听请求参数的变化,有变化了之后重新请求数据,并且把tab置为第一个
+ * @return {*}
+ */
+watch(
+  () => [props.requestConfig.otherOptions],
+  () => {
+    if (props.tabInfo) activeTab.value = props.tabInfo[0].name
+    getData(1)
+  },
+  {
+    deep: true
+  }
+)
 
 onMounted(() => {
   getData(1)
-  changeSelectShape(props.selectExpressForm)
-  if (props.defaultActive) {
-    activeTab.value = props.defaultActive
-  }
+  if (props.tabInfo) activeTab.value = props.tabInfo[0].name
 })
 </script>
 
@@ -206,7 +203,7 @@ onMounted(() => {
           -->
     <div class="chartsBox">
       <el-tabs class="tabsBox" v-model="activeTab" @tab-change="tabChange">
-        <span v-if="needTab">
+        <span v-if="tabInfo">
           <el-tab-pane
             :lazy="true"
             v-for="item in tabInfo"
@@ -226,6 +223,7 @@ onMounted(() => {
             ></StatisticText>
           </div>
           <TimeLineChart
+            v-if="props.needCharts"
             :legend-data="chartInfo.legendData"
             :series-data="chartInfo.seriesData"
             :x-axis-data="chartInfo.xAxisData"
@@ -234,12 +232,13 @@ onMounted(() => {
         </div>
         <div class="tableContent" v-else>
           <Table
+            v-if="props.needTable"
             :data-list="tableDataList"
             :need-rowindex="true"
             :need-average="false"
             :need-right-tools="false"
             :pagination-config="paginationConfig"
-            :table-fields-info="filedsInfo"
+            :table-fields-info="tableFieldsInfo"
             :need-left-tools="false"
             :open-filter-query="false"
             :open-page-query="false"

+ 3 - 3
src/components/echarts/TimeLineChart.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { onMounted, reactive, ref, shallowRef, watch, watchEffect } from 'vue'
+import { onMounted, ref, shallowRef, watch } from 'vue'
 import echarts from '.'
 import { nextTick } from 'vue'
 import { debounceFunc } from '@/utils/common'
@@ -133,9 +133,9 @@ watch(
 onMounted(() => {
   nextTick(() => {
     linechart.value = echarts.init(chart.value)
-    console.log('io')
+
     initOptions()
-    console.log('io2')
+
     /**
      * @description: 只监听window会导致当侧边栏缩放时,dom大小变化但无法resize
      *              所以需要使用ovserver对整个dom进行监听

+ 2 - 2
src/hooks/useAnalysis.ts

@@ -7,14 +7,14 @@
  * @Description:
  *
  */
-import type { StaticReqConfig } from '@/types/dataAnalysis'
+import type { ReqConfig } from '@/types/dataAnalysis'
 
 export function useAnalysis() {
   /**
    * @description: 更新统计组件的请求参数
    * @return {*}
    */
-  const updateReqConfig = (config: StaticReqConfig, newVal: any) => {
+  const updateReqConfig = (config: ReqConfig, newVal: any) => {
     Object.keys(newVal).map((k) => {
       config.otherOptions[k] = newVal[k]
     })

+ 13 - 1
src/hooks/useRequest.ts

@@ -1,3 +1,12 @@
+/*
+ * @Author: fxs bjnsfxs@163.com
+ * @Date: 2024-08-20 17:24:06
+ * @LastEditors: fxs bjnsfxs@163.com
+ * @LastEditTime: 2024-08-29 16:43:13
+ * @FilePath: \Game-Backstage-Management-System\src\hooks\useRequest.ts
+ * @Description:
+ *
+ */
 import { ElMessage } from 'element-plus'
 import 'element-plus/theme-chalk/el-message.css'
 import 'element-plus/theme-chalk/el-message-box.css'
@@ -31,12 +40,15 @@ export function useRequest() {
     userSummary: `${baseIp}/user/summary`, //用户概览 -总览
     userMouthDistributionData: `${baseIp}/user/mouthDistributionData`, //用户概览 -30日趋势
     userTrendsOverview: `${baseIp}/user/userTrendsOverview`, //用户趋势 -总览
-    userDataTrades: `${baseIp}/user/dataTrades` //用户趋势 -数据趋势
+    userDataTrades: `${baseIp}/user/dataTrades`, //用户趋势 -数据趋势
+    userDataTradesDetail: `${baseIp}/user/dataTradesDetail`, //用户趋势 -数据趋势详情
+    userRemainDataBydDay: `${baseIp}/user/remainDataBydDay` //用户留存数据
   }
 
   const analysisResCode = (data: AxiosResponse, kind?: string): Promise<ResponseInfo> => {
     return new Promise((resolve, reject) => {
       let info = JSON.parse(JSON.stringify(data)) as ResponseInfo
+
       let type: MessageType = MessageType.Success
       let message = info.msg
       let kindText = kind === 'login' ? '登录' : '请求'

+ 0 - 6
src/stores/useDataAnalysis.ts

@@ -1,6 +0,0 @@
-import { reactive } from 'vue'
-import { defineStore } from 'pinia'
-
-export const useDataAnalysisStore = defineStore('dataAnalysisStore', () => {
-  return {}
-})

+ 36 - 11
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-29 11:32:11
+ * @LastEditTime: 2024-08-29 16:23:15
  * @FilePath: \Game-Backstage-Management-System\src\types\dataAnalysis.ts
  * @Description:用于dataAnalysis相关组件的type
  *
@@ -27,7 +27,7 @@ export interface DropDownInfo {
  *
  * @return {*}
  */
-export interface StaticReqConfig {
+export interface ReqConfig {
   url: string
   otherOptions: any
 }
@@ -44,7 +44,7 @@ export interface StaticField {
 // 其中如果配置了请求参数,那么会使用url去查询,然后赋值
 // 如果没有则直接使用fieldinfo里的value
 export interface StaticDataInfo {
-  requestConfig?: StaticReqConfig // 请求参数配置
+  requestConfig?: ReqConfig // 请求参数配置
   fieldsInfo: Array<StaticField> //字段信息
   titleClass?: string // 标题的样式
   valueClass?: string // 值的样式
@@ -68,18 +68,34 @@ export interface OptionsProps {
   seriesData: Array<any> // 数据
 }
 
+// 返回的数据中每个字段的分类信息
+export interface ResDataFieldInfo {
+  xAxis: string // x轴的刻度信息所在的字段
+  values: Array<string> // 值所在的字段
+}
+
+// 表格字段
+// key需要与上方的resDataField的values字段对应
+export interface TrendTableField {
+  [key: string]: string
+}
+
 // 时间趋势组件所需要的props
 export interface TemporalTrendProps {
-  needTab: boolean // 是否需要tab切换
-  selectExpressForm: number // 默认的表现形式,1为图表,2为表格
-  needChangeExpress: boolean // 是否需要切换表格/图表
-  type: number // 趋势组件的类型,1为小时段,2为日期统计
   tabInfo?: Array<TabInfo> // 用于切换的tab的信息
+
+  type: number // 趋势组件的类型,1为小时段,2为日期统计
+  needChangeExpress: boolean // 是否需要切换表格/图表
+  selectExpressForm: number // 默认的表现形式,1为图表,2为表格
+
   needTable: boolean // 是否需要表格
-  tableFieldsInfo?: any // 表格的字段信息
-  resDataFieldsInfo?: any // 返回的数据中有用的信息
-  requestConfig: StaticReqConfig // 请求参数配置,需要监听,一旦变化,需要重新获取数据
-  defaultActive?: string // 默认选中的tab
+  tableFieldsInfo: TrendTableField // 表格的字段信息
+
+  needCharts: boolean // 是否需要图表
+
+  resDataFieldsInfo: ResDataFieldInfo // 返回的数据中每个字段的分类信息
+  requestConfig: ReqConfig // 请求参数配置,需要监听,一旦变化,需要重新获取数据
+
   staticFields?: Array<StaticField> // 图表中统计组件的字段信息
   title: string // 上方显示的title
 }
@@ -90,3 +106,12 @@ export interface HeaderCardProps {
   defaultPf?: string // 默认选择的pf
   openDateSelect: boolean // 是否开启时间选择
 }
+
+// 趋势图组件需要的信息
+export interface TemporalTrendInfo {
+  dataReqConfig: ReqConfig // 请求的参数和配置
+  resDataField: ResDataFieldInfo // 返回数据中的字段信息
+  tabList?: Array<TabInfo> //表格数据
+  trendTableFields: TrendTableField // 表格的字段,同时也作为legend的一部分
+  chartsStaticField?: Array<StaticField> // 统计字段的信息
+}

+ 9 - 11
src/types/table.ts

@@ -1,3 +1,4 @@
+import type { ReqConfig } from './dataAnalysis'
 // 颜色类型
 export enum ColorType {
   DEFAULT = 'default',
@@ -66,21 +67,18 @@ export interface TableFieldInfo {
 
 // props的参数格式
 export interface PropsParams {
-  needRowindex: boolean // 是否需要行号
-  needAverage: boolean // 是否需要均值功能
-  needLeftTools: boolean // 是否需要左侧的工具栏
-  needRightTools: boolean // 是否需要右侧工具栏
-  openFilterQuery: boolean // 是否开启上方查询功能
-  openPageQuery: boolean // 是否开启分页查询
+  needRowindex?: boolean // 是否需要行号
+  needAverage?: boolean // 是否需要均值功能
+  needLeftTools?: boolean // 是否需要左侧的工具栏
+  needRightTools?: boolean // 是否需要右侧工具栏
+  openFilterQuery?: boolean // 是否开启上方查询功能
+  openPageQuery?: boolean // 是否开启分页查询
+
   dataList?: Array<any> // 表格数据,可以直接传入,也可以给请求地址来请求
   queryInfo?: Array<QueryInfo> // 上方查询功能所需要的信息
   paginationConfig: TablePaginationSetting // 表格分页的信息
   tableFieldsInfo: Array<TableFieldInfo> // 表格字段信息
-  requestConfig?: {
-    // 表格请求的配置
-    url: string
-    other: any
-  }
+  requestConfig?: ReqConfig
 }
 
 // 选择下拉框的信息格式

+ 163 - 83
src/views/Home/Analysis/KeepView.vue

@@ -2,102 +2,184 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-27 17:11:23
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-08-28 11:03:06
+ * @LastEditTime: 2024-08-29 17:23:51
  * @FilePath: \Game-Backstage-Management-System\src\views\Home\Analysis\KeepView.vue
  * @Description: 
  * 
 -->
 <script setup lang="ts">
-import { ref, reactive, onMounted } from 'vue'
+import { watch, reactive, onMounted } from 'vue'
 import Table from '@/components/Table.vue'
 import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
-import type { TablePaginationSetting } from '@/types/table'
-import type { HeaderCardProps } from '@/types/dataAnalysis'
+import axiosInstance from '@/utils/axios/axiosInstance'
+import type { TablePaginationSetting, TableFieldInfo } from '@/types/table'
+
+import type { ReqConfig, HeaderCardProps } from '@/types/dataAnalysis'
+import { resetTimeToMidnight } from '@/utils/common'
 import { useRequest } from '@/hooks/useRequest'
+import { useCommonStore } from '@/stores/useCommon'
+import { useAnalysis } from '@/hooks/useAnalysis'
+
+const { updateReqConfig } = useAnalysis()
+const { selectInfo } = useCommonStore()
 
 const { AllApi } = useRequest()
-// 配置请求参数
-const requestConfig = reactive({
-  url: AllApi.mockKeep,
-  other: {
-    appSecret: '6YJSuc50uJ18zj45'
-  }
-})
 
-// 配置分页数据
-const paginationConfig = reactive<TablePaginationSetting>({
-  limit: 20, // 每页展示个数
-  currentPage: 1, // 当前页码
-  total: 0, // 数据总数
-  pagesizeList: [20, 30], // 页数大小列表
-  loading: true, // 加载图标
-  hasLodingData: 0 // 已经加载的数据
+// 选择的信息
+const keepViewSelect = reactive({
+  pf: 'web'
 })
 
-// 字段信息
-const fieldsInfo = reactive([
-  {
-    name: 'date',
-    cnName: '日期',
-    isShow: true
-  },
-  {
-    name: 'userCount',
-    cnName: '用户数',
-    isShow: true
-  },
-  {
-    name: 'dayPlus1',
-    cnName: '+1日',
-    isShow: true
-  },
-  {
-    name: 'dayPlus2',
-    cnName: '+2日',
-    isShow: true
+// 数据详情表格信息
+const keepDataTableInfo = reactive<{
+  paginationConfig: TablePaginationSetting
+  requestConfig: ReqConfig
+  tableFieldsInfo: Array<TableFieldInfo>
+}>({
+  paginationConfig: {
+    limit: 15, // 每页展示个数
+    currentPage: 1, // 当前页码
+    total: 0, // 数据总数
+    pagesizeList: [15, 30], // 页数大小列表
+    loading: true, // 加载图标
+    hasLodingData: 0 // 已经加载的数据
   },
-  {
-    name: 'dayPlus3',
-    cnName: '+3日',
-    isShow: true
+  requestConfig: {
+    url: AllApi.userRemainDataBydDay,
+    otherOptions: {
+      pf: keepViewSelect.pf,
+      gid: selectInfo.gid,
+      startTime: resetTimeToMidnight(new Date()),
+      endTime: resetTimeToMidnight(new Date())
+    }
   },
-  {
-    name: 'dayPlus4',
-    cnName: '+4日',
-    isShow: true
-  },
-  {
-    name: 'dayPlus5',
-    cnName: '+5日',
-    isShow: true
-  },
-  {
-    name: 'dayPlus6',
-    cnName: '+6日',
-    isShow: true
-  },
-  {
-    name: 'dayPlus7',
-    cnName: '+7日',
-    isShow: true
-  },
-  {
-    name: 'dayPlus14',
-    cnName: '+14日',
-    isShow: true
-  },
-  {
-    name: 'dayPlus30',
-    cnName: '+30日',
-    isShow: true
-  }
-])
+  tableFieldsInfo: [
+    {
+      name: 'date',
+      cnName: '日期',
+      isShow: true
+    },
+    {
+      name: 'count',
+      cnName: '用户数',
+      isShow: true
+    },
+    {
+      name: '+1day',
+      cnName: '+1日',
+      isShow: true
+    },
+    {
+      name: '+2day',
+      cnName: '+2日',
+      isShow: true
+    },
+    {
+      name: '+3day',
+      cnName: '+3日',
+      isShow: true
+    },
+    {
+      name: '+4day',
+      cnName: '+4日',
+      isShow: true
+    },
+    {
+      name: '+5day',
+      cnName: '+5日',
+      isShow: true
+    },
+    {
+      name: '+6day',
+      cnName: '+6日',
+      isShow: true
+    },
+    {
+      name: '+7day',
+      cnName: '+7日',
+      isShow: true
+    }
+  ]
+})
+
+const keepTableData = reactive<Array<any>>([])
+
+/**
+ * @description: 选择的平台改变
+ * @param {*} pf  平台名
+ * @return {*}
+ */
+const changePf = (pf: string) => {
+  keepViewSelect.pf = pf
+}
+
+/**
+ * @description: 当日期改变,需要去更新三个组件的请求参数
+ * @param {*} date
+ * @return {*}
+ */
+const changeDate = (date: Array<Date>) => {
+  updateReqConfig(keepDataTableInfo.requestConfig, {
+    startTime: resetTimeToMidnight(date[0]),
+    endTime: resetTimeToMidnight(date[1])
+  })
+}
 
 const headerCardInfo = reactive<HeaderCardProps>({
   title: '留存分析',
   openDateSelect: true
 })
 
+/**
+ * @description: 获取detail表格的数据
+ * @return {*}
+ */
+const getTableData = () => {
+  axiosInstance
+    .post(keepDataTableInfo.requestConfig.url, {
+      ...keepDataTableInfo.requestConfig.otherOptions
+    })
+    .then((info) => {
+      let data = info.data
+      let newList = reactive<Array<any>>([])
+      for (const [key, val] of Object.entries(data)) {
+        // 为了编译通过,不做任何事
+        if (key) {
+        }
+        let nVal = val as Object
+        newList.push({
+          ...nVal
+        })
+      }
+      keepTableData.splice(0, keepTableData.length, ...newList)
+      keepDataTableInfo.paginationConfig.total = newList.length
+    })
+}
+
+/**
+ * @description: 监听pf和gid的变化,数据变化后立即重新请求所有相关数据
+ * @tip watch监听reactive的数据时,必须以getter形式,不然会警告
+ * @return {*}
+ */
+watch(
+  () => [keepViewSelect.pf, selectInfo.gid],
+  ([newPf, newGid]) => {
+    updateReqConfig(keepDataTableInfo.requestConfig, { pf: newPf, gid: newGid })
+  }
+)
+
+/**
+ * @description: 单独监听一下他的变化,去手动更新数据
+ * @return {*}
+ */
+watch(
+  () => keepDataTableInfo.requestConfig,
+  () => {
+    getTableData()
+  },
+  { deep: true }
+)
+
 onMounted(() => {})
 </script>
 <template>
@@ -106,19 +188,17 @@ onMounted(() => {})
       <HeaderCard
         :title="headerCardInfo.title"
         :open-date-select="headerCardInfo.openDateSelect"
+        :default-pf="keepViewSelect.pf"
+        @change-pf="changePf"
+        @change-date="changeDate"
       ></HeaderCard>
     </div>
     <div class="tableBox">
       <Table
-        :need-rowindex="true"
         :need-average="true"
-        :need-left-tools="false"
-        :need-right-tools="false"
-        :open-filter-query="false"
-        :open-page-query="false"
-        :pagination-config="paginationConfig"
-        :table-fields-info="fieldsInfo"
-        :request-config="requestConfig"
+        :pagination-config="keepDataTableInfo.paginationConfig"
+        :table-fields-info="keepDataTableInfo.tableFieldsInfo"
+        :data-list="keepTableData"
       ></Table>
     </div>
   </div>

+ 200 - 79
src/views/Home/Analysis/UserTrendView.vue

@@ -1,7 +1,9 @@
 <script setup lang="ts">
 import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
+import Table from '@/components/Table.vue'
 import { onMounted, reactive, watch, ref } from 'vue'
-import type { StaticField, TabInfo, StaticReqConfig } from '@/types/dataAnalysis'
+import type { StaticField, ReqConfig, TemporalTrendInfo } from '@/types/dataAnalysis'
+import type { TablePaginationSetting, TableFieldInfo } from '@/types/table'
 
 import StatisticText from '@/components/dataAnalysis/StatisticText.vue'
 import TemporalTrend from '@/components/dataAnalysis/TemporalTrend.vue'
@@ -9,6 +11,7 @@ import { useCommonStore } from '@/stores/useCommon'
 import { useRequest } from '@/hooks/useRequest'
 import { useAnalysis } from '@/hooks/useAnalysis'
 import { resetTimeToMidnight } from '@/utils/common'
+import axiosInstance from '@/utils/axios/axiosInstance'
 
 const { updateReqConfig } = useAnalysis()
 const { AllApi } = useRequest()
@@ -53,7 +56,7 @@ const userTrendStaticFieldInfo = reactive<Array<StaticField>>([
 ])
 
 // 总览请求参数的配置
-const userTrendDataReqConfig = reactive<StaticReqConfig>({
+const userTrendDataReqConfig = reactive<ReqConfig>({
   url: AllApi.userTrendsOverview,
   otherOptions: {
     pf: userTrendSelectInfo.pf,
@@ -63,74 +66,135 @@ const userTrendDataReqConfig = reactive<StaticReqConfig>({
   }
 })
 
-// 数据趋势请求参数配置
-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
+// 数据趋势组件所需要的信息
+const dataTrendInfo = reactive<TemporalTrendInfo>({
+  dataReqConfig: {
+    url: AllApi.userDataTrades,
+    otherOptions: {
+      pf: userTrendSelectInfo.pf,
+      gid: selectInfo.gid,
+      startTime: resetTimeToMidnight(new Date()),
+      endTime: resetTimeToMidnight(new Date())
+    }
   },
-  {
-    name: 'detailDatalyActiveUser',
-    tabTitle: '月活跃用户',
-    type: 4
+  tabList: [
+    {
+      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
+    }
+  ],
+  chartsStaticField: [
+    {
+      name: 'avg',
+      cnName: '均值',
+      value: ''
+    },
+    {
+      name: 'count',
+      cnName: '总数',
+      value: ''
+    }
+  ],
+  resDataField: {
+    xAxis: 'imeDistribution', // x轴的刻度信息所在的字段
+    values: ['imeDistribution'] // 值所在的字段
   },
-  {
-    name: 'launchCount',
-    tabTitle: '启动次数',
-    type: 5
-  },
-  {
-    name: 'dailyUsageTime',
-    tabTitle: '单日使用时长',
-    type: 6
+  trendTableFields: {
+    imeDistribution: '新增'
   }
-])
+})
 
-// 数据趋势统计数据字段信息
-const dataTrendChartsStaticFieldInfo = reactive<Array<StaticField>>([
-  {
-    name: 'avg',
-    cnName: '均值',
-    value: ''
+// 数据详情表格信息
+const detailDataTableInfo = reactive<{
+  paginationConfig: TablePaginationSetting
+  requestConfig: ReqConfig
+  tableFieldsInfo: Array<TableFieldInfo>
+}>({
+  paginationConfig: {
+    limit: 15, // 每页展示个数
+    currentPage: 1, // 当前页码
+    total: 0, // 数据总数
+    pagesizeList: [15, 30], // 页数大小列表
+    loading: true, // 加载图标
+    hasLodingData: 0 // 已经加载的数据
   },
-  {
-    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())
-  }
+  requestConfig: {
+    url: AllApi.userDataTradesDetail,
+    otherOptions: {
+      pf: userTrendSelectInfo.pf,
+      gid: selectInfo.gid,
+      startTime: resetTimeToMidnight(new Date()),
+      endTime: resetTimeToMidnight(new Date())
+    }
+  },
+  tableFieldsInfo: [
+    {
+      name: 'date',
+      cnName: '日期',
+      isShow: true
+    },
+    {
+      name: 'newUser',
+      cnName: '新增用户',
+      isShow: true
+    },
+    {
+      name: 'activeUser',
+      cnName: '日活跃用户',
+      isShow: true
+    },
+    {
+      name: 'activeUserWeek',
+      cnName: '周活跃用户',
+      isShow: true
+    },
+    {
+      name: 'activeUserMouth',
+      cnName: '月活跃用户',
+      isShow: true
+    },
+    {
+      name: 'activeStart',
+      cnName: '启动次数',
+      isShow: true
+    },
+    {
+      name: 'avgTime',
+      cnName: '平均使用时长',
+      isShow: true
+    }
+  ]
 })
 
+// detail表格的数据
+const detailDataTableData = reactive<Array<any>>([])
+
 /**
  * @description: 监听pf和gid的变化,数据变化后立即重新请求所有相关数据
  * @tip watch监听reactive的数据时,必须以getter形式,不然会警告
@@ -140,8 +204,8 @@ 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 })
+    updateReqConfig(dataTrendInfo.dataReqConfig, { pf: newPf, gid: newGid })
+    updateReqConfig(detailDataTableInfo.requestConfig, { pf: newPf, gid: newGid })
   }
 )
 
@@ -154,17 +218,64 @@ const changePf = (pf: string) => {
   userTrendSelectInfo.pf = pf
 }
 
+/**
+ * @description: 当日期改变,需要去更新三个组件的请求参数
+ * @param {*} date
+ * @return {*}
+ */
 const changeDate = (date: Array<Date>) => {
   updateReqConfig(userTrendDataReqConfig, {
     startTime: resetTimeToMidnight(date[0]),
     endTime: resetTimeToMidnight(date[1])
   })
-  updateReqConfig(detailDataReqConfig, {
+
+  updateReqConfig(dataTrendInfo.dataReqConfig, {
+    startTime: resetTimeToMidnight(date[0]),
+    endTime: resetTimeToMidnight(date[1])
+  })
+
+  updateReqConfig(detailDataTableInfo.requestConfig, {
     startTime: resetTimeToMidnight(date[0]),
     endTime: resetTimeToMidnight(date[1])
   })
 }
 
+/**
+ * @description: 获取detail表格的数据
+ * @return {*}
+ */
+const getDetailData = () => {
+  axiosInstance
+    .post(detailDataTableInfo.requestConfig.url, {
+      ...detailDataTableInfo.requestConfig.otherOptions
+    })
+    .then((info) => {
+      let data = info.data
+      let newList = reactive<Array<any>>([])
+      for (const [key, val] of Object.entries(data)) {
+        let nVal = val as Object
+        newList.push({
+          date: key,
+          ...nVal
+        })
+      }
+      detailDataTableData.splice(0, detailDataTableData.length, ...newList)
+      detailDataTableInfo.paginationConfig.total = newList.length
+    })
+}
+
+/**
+ * @description: 单独监听一下他的变化,去手动更新数据
+ * @return {*}
+ */
+watch(
+  () => detailDataTableInfo.requestConfig,
+  () => {
+    getDetailData()
+  },
+  { deep: true }
+)
+
 onMounted(() => {})
 </script>
 <template>
@@ -187,28 +298,32 @@ onMounted(() => {})
     </div>
     <div class="dataTrendBox">
       <TemporalTrend
+        :need-charts="true"
+        :table-fields-info="dataTrendInfo.trendTableFields"
+        :res-data-fields-info="dataTrendInfo.resDataField"
         :need-table="false"
         :need-tab="true"
         :select-express-form="1"
         :need-change-express="false"
-        :static-fields="dataTrendChartsStaticFieldInfo"
+        :static-fields="dataTrendInfo.chartsStaticField"
         :type="1"
-        :request-config="dataTrendReqConfig"
+        :request-config="dataTrendInfo.dataReqConfig"
         :title="'时段分布'"
-        :defaultActive="dataTrendTabList[0].name"
-        :tabInfo="dataTrendTabList"
+        :tabInfo="dataTrendInfo.tabList"
       ></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 class="boxHeader">
+        <span class="headerTitle">数据详情</span>
+      </div>
+      <el-divider />
+      <div class="detailTableBox">
+        <Table
+          :pagination-config="detailDataTableInfo.paginationConfig"
+          :table-fields-info="detailDataTableInfo.tableFieldsInfo"
+          :data-list="detailDataTableData"
+        ></Table>
+      </div>
     </div>
   </div>
 </template>
@@ -231,6 +346,12 @@ onMounted(() => {})
   width: 100%;
   padding: 0 24px;
 }
+
+.headerTitle {
+  font-size: 14px;
+  color: #1c2438;
+  font-weight: 600;
+}
 .header {
   padding: 0;
   box-shadow: none;

+ 2 - 2
src/views/Home/HomeView.vue

@@ -1,11 +1,11 @@
 <script setup lang="ts">
 import { RouterView } from 'vue-router'
-import { onMounted, reactive, ref } from 'vue'
+import { reactive, ref } from 'vue'
 import { ElMessage } from 'element-plus'
 import { getAllGameInfo } from '@/utils/table/table'
 import router from '@/router'
 import { getAssetsImageUrl } from '@/utils/common'
-import type { DropDownInfo, DropDownItem } from '@/types/dataAnalysis'
+import type { DropDownInfo } from '@/types/dataAnalysis'
 import DropDownSelection from '@/components/dataAnalysis/DropDownSelection.vue'
 import { useCommonStore } from '@/stores/useCommon'
 

+ 3 - 3
src/views/Home/InfoManage/GameManageView.vue

@@ -32,17 +32,17 @@ const gameDialogFormRef = ref<FormInstance>()
 // 配置请求参数
 const requestConfig = reactive({
   url: AllApi.getGameTable,
-  other: {
+  otherOptions: {
     appSecret: '6YJSuc50uJ18zj45'
   }
 })
 
 // 配置分页数据
 const paginationConfig = reactive<TablePaginationSetting>({
-  limit: 10, // 每页展示个数
+  limit: 15, // 每页展示个数
   currentPage: 1, // 当前页码
   total: 0, // 数据总数
-  pagesizeList: [10, 15], // 页数大小列表
+  pagesizeList: [15, 20], // 页数大小列表
   loading: true, // 加载图标
   hasLodingData: 0 // 已经加载的数据
 })

+ 2 - 2
src/views/Home/InfoManage/PlayerManageView.vue

@@ -45,7 +45,7 @@ const paginationConfig = reactive<TablePaginationSetting>({
   limit: 15, // 每页展示个数
   currentPage: 1, // 当前页码
   total: 0, // 数据总数
-  pagesizeList: [15, 20], // 页数大小列表
+  pagesizeList: [15, 30], // 页数大小列表
   loading: true, // 加载图标
   hasLodingData: 0 // 已经加载的数据
 })
@@ -53,7 +53,7 @@ const paginationConfig = reactive<TablePaginationSetting>({
 // 配置请求参数
 const requestConfig = reactive({
   url: AllApi.getUserTable,
-  other: {
+  otherOptions: {
     offset: 0,
     limit: paginationConfig.limit,
     gid: tableStore.playerQueryInfo.gid,

+ 119 - 120
src/views/Home/Overview/OverView.vue

@@ -1,15 +1,13 @@
 <script setup lang="ts">
 import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
 import { onMounted, reactive, watch, ref } from 'vue'
-import type { StaticField, TabInfo, OptionsProps, StaticReqConfig } from '@/types/dataAnalysis'
+import type { StaticField, ReqConfig, TemporalTrendInfo } from '@/types/dataAnalysis'
 
 import StatisticText from '@/components/dataAnalysis/StatisticText.vue'
 import TemporalTrend from '@/components/dataAnalysis/TemporalTrend.vue'
-import { formatDate, generateHourlyArray } from '@/utils/common'
 import { useCommonStore } from '@/stores/useCommon'
 import { useRequest } from '@/hooks/useRequest'
 import { useAnalysis } from '@/hooks/useAnalysis'
-import type { TableFieldInfo } from '@/types/table'
 
 const { updateReqConfig } = useAnalysis()
 const { AllApi } = useRequest()
@@ -49,7 +47,7 @@ const overViewStaticFieldInfo = reactive<Array<StaticField>>([
 ])
 
 // 总览请求参数的配置
-const overViewDataReqConfig = reactive<StaticReqConfig>({
+const overViewDataReqConfig = reactive<ReqConfig>({
   url: AllApi.userSummary,
   otherOptions: {
     pf: overViewSelectInfo.pf,
@@ -57,120 +55,117 @@ const overViewDataReqConfig = reactive<StaticReqConfig>({
   }
 })
 
-// 分时段组件请求参数配置
-const periodDataReqConfig = reactive<StaticReqConfig>({
-  url: AllApi.timeDistributionData,
-  otherOptions: {
-    pf: overViewSelectInfo.pf,
-    gid: selectInfo.gid
-  }
-})
-
-// 分时段组件据需要的tab信息
-const periodTabList = reactive<Array<TabInfo>>([
-  {
-    name: 'newUser',
-    tabTitle: '新增用户',
-    type: 1
-  },
-  {
-    name: 'activeUser',
-    tabTitle: '活跃用户',
-    type: 2
-  },
-  {
-    name: 'launchCount',
-    tabTitle: '启动次数',
-    type: 3
-  }
-])
-
-// 分时段统计数据字段信息
-const periodChartsStaticFieldInfo = reactive<Array<StaticField>>([
-  {
-    name: 'yesterdayCount',
-    cnName: '昨日',
-    value: ''
-  },
-  {
-    name: 'todayCount',
-    cnName: '今日',
-    value: ''
+// 分时段组件所需要的信息
+const periodInfo = reactive<TemporalTrendInfo>({
+  dataReqConfig: {
+    url: AllApi.timeDistributionData,
+    otherOptions: {
+      pf: overViewSelectInfo.pf,
+      gid: selectInfo.gid
+    }
   },
-  {
-    name: 'yesterdayThisTimeCount',
-    cnName: '昨日此时',
-    value: ''
-  }
-])
-
-// 返回数据中有用的字段
-const resDataField = {
-  xAxis: 'today', // x轴的刻度信息所在的字段
-  values: ['yesterday', 'today'] // 值所在的字段
-}
-
-// 表格字段
-// 除了索引字段,其他字段需要与上方的resDataField的values字段对应
-const tableFields = {
-  index: {
-    type: 1 // 索引字段, 0 没有索引字段 1 直接使用x轴的刻度作为信息
+  tabList: [
+    {
+      name: 'newUser',
+      tabTitle: '新增用户',
+      type: 1
+    },
+    {
+      name: 'activeUser',
+      tabTitle: '活跃用户',
+      type: 2
+    },
+    {
+      name: 'launchCount',
+      tabTitle: '启动次数',
+      type: 3
+    }
+  ],
+  chartsStaticField: [
+    {
+      name: 'yesterdayCount',
+      cnName: '昨日',
+      value: ''
+    },
+    {
+      name: 'todayCount',
+      cnName: '今日',
+      value: ''
+    },
+    {
+      name: 'yesterdayThisTimeCount',
+      cnName: '昨日此时',
+      value: ''
+    }
+  ],
+  resDataField: {
+    xAxis: 'today', // x轴的刻度信息所在的字段
+    values: ['yesterday', 'today'] // 值所在的字段
   },
-  today: '今日',
-  yesterday: '昨日'
-}
-
-// 一个月内组件请求参数配置
-const monthDataReqConfig = reactive<StaticReqConfig>({
-  url: AllApi.userMouthDistributionData,
-  otherOptions: {
-    pf: overViewSelectInfo.pf,
-    gid: selectInfo.gid
+  trendTableFields: {
+    index: '时间段',
+    today: '今日',
+    yesterday: '昨日'
   }
 })
 
-// 一个月内组件需要的tab信息
-const monthTabList = reactive<Array<TabInfo>>([
-  {
-    name: 'newUser',
-    tabTitle: '新增用户',
-    type: 1
-  },
-  {
-    name: 'activeUser',
-    tabTitle: '活跃用户',
-    type: 2
-  },
-  {
-    name: 'launchCount',
-    tabTitle: '启动次数',
-    type: 3
+// 30日趋势信息
+const monthInfo = reactive<TemporalTrendInfo>({
+  dataReqConfig: {
+    url: AllApi.userMouthDistributionData,
+    otherOptions: {
+      pf: overViewSelectInfo.pf,
+      gid: selectInfo.gid
+    }
   },
-  {
-    name: 'deviceDuration',
-    tabTitle: '单设备时长',
-    type: 4
-  },
-  {
-    name: 'retentionRate',
-    tabTitle: '留存率',
-    type: 5
-  }
-])
-
-// 一个月内统计数据字段信息
-const monthChartsStaticFieldInfo = reactive<Array<StaticField>>([
-  {
-    name: 'avg',
-    cnName: '平均值',
-    value: ''
+  tabList: [
+    {
+      name: 'newUser',
+      tabTitle: '新增用户',
+      type: 1
+    },
+    {
+      name: 'activeUser',
+      tabTitle: '活跃用户',
+      type: 2
+    },
+    {
+      name: 'launchCount',
+      tabTitle: '启动次数',
+      type: 3
+    },
+    {
+      name: 'deviceDuration',
+      tabTitle: '单设备时长',
+      type: 4
+    },
+    {
+      name: 'retentionRate',
+      tabTitle: '留存率',
+      type: 5
+    }
+  ],
+  chartsStaticField: [
+    {
+      name: 'avg',
+      cnName: '平均值',
+      value: ''
+    },
+    {
+      name: 'count',
+      cnName: '总数',
+      value: ''
+    }
+  ],
+  resDataField: {
+    xAxis: 'timeDistribution', // x轴的刻度信息所在的字段
+    values: ['timeDistribution'] // 值所在的字段
   },
-  {
-    name: 'count',
-    cnName: '总数',
-    value: ''
+  trendTableFields: {
+    index: '日期',
+    timeDistribution: '新增'
   }
-])
+})
 
 /**
  * @description: 监听pf和gid的变化,数据变化后立即重新请求所有相关数据
@@ -181,8 +176,8 @@ watch(
   () => [overViewSelectInfo.pf, selectInfo.gid],
   ([newPf, newGid]) => {
     updateReqConfig(overViewDataReqConfig, { pf: newPf, gid: newGid })
-    updateReqConfig(periodDataReqConfig, { pf: newPf, gid: newGid })
-    updateReqConfig(monthDataReqConfig, { pf: newPf, gid: newGid })
+    updateReqConfig(periodInfo.dataReqConfig, { pf: newPf, gid: newGid })
+    updateReqConfig(monthInfo.dataReqConfig, { pf: newPf, gid: newGid })
   }
 )
 
@@ -216,30 +211,34 @@ onMounted(() => {})
     </div>
     <div class="periodTrendBox">
       <TemporalTrend
+        :need-charts="true"
+        :table-fields-info="periodInfo.trendTableFields"
+        :res-data-fields-info="periodInfo.resDataField"
         :need-table="true"
         :need-tab="true"
         :select-express-form="1"
         :need-change-express="true"
-        :static-fields="periodChartsStaticFieldInfo"
+        :static-fields="periodInfo.chartsStaticField"
         :type="1"
-        :request-config="periodDataReqConfig"
+        :request-config="periodInfo.dataReqConfig"
         :title="'时段分布'"
-        :defaultActive="periodTabList[0].name"
-        :tabInfo="periodTabList"
+        :tabInfo="periodInfo.tabList"
       ></TemporalTrend>
     </div>
     <div class="oneMonthTrendBox">
       <TemporalTrend
+        :need-charts="true"
+        :table-fields-info="monthInfo.trendTableFields"
+        :res-data-fields-info="monthInfo.resDataField"
         :need-table="true"
         :need-tab="true"
         :select-express-form="1"
         :need-change-express="true"
-        :static-fields="monthChartsStaticFieldInfo"
+        :static-fields="monthInfo.chartsStaticField"
         :type="2"
-        :request-config="monthDataReqConfig"
+        :request-config="monthInfo.dataReqConfig"
         :title="'30日内趋势'"
-        :defaultActive="monthTabList[0].name"
-        :tabInfo="monthTabList"
+        :tabInfo="monthInfo.tabList"
       ></TemporalTrend>
     </div>
   </div>