Преглед изворни кода

perf(CustomTable、): 优化界面显示

1.广告列表、用户行为的图表新增值切换功能,可在对数与原值之间切换
2.广告列表新增表格
3.修复无展开功能的表格也出现展开按钮的BUG
4.留存分析界面新增8,9,10日的数据
5.现在可根据传入数据决定是否显示展开行按钮
6.更新部分样式
7.优化vite打包,减小体积
fxs пре 1 месец
родитељ
комит
1a72f26ffb

+ 4 - 4
index.html

@@ -3,11 +3,11 @@
   <head>
     <meta charset="UTF-8" />
       <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-     <link rel="icon" href="/logoTest.svg" />
-<!--    <link rel="icon" href="/logo.svg" />-->
+<!--     <link rel="icon" href="/logoTest.svg" />-->
+    <link rel="icon" href="/logo.svg" />
 
-<!--    <title>淳皓游戏管理平台</title>-->
-     <title>测试库-游戏管理平台</title>
+    <title>淳皓游戏管理平台</title>
+<!--     <title>测试库-游戏管理平台</title>-->
   </head>
   <body>
     <div id="app"></div>

+ 6 - 0
src/assets/base.css

@@ -34,3 +34,9 @@ body {
   font-family: 'Helvetica Neue', 'Hiragino Sans GB', 'Segoe UI', 'Microsoft Yahei', '微软雅黑',
     Tahoma, Arial, STHeiti, sans-serif;
 }
+
+
+/*用于消除部分行的展开行图标*/
+.noneExpandIcon .el-table__expand-column .cell {
+  display: none !important;
+}

+ 13 - 15
src/components/table/CustomTable.vue

@@ -1,11 +1,3 @@
-<!--
- * @Author: fxs bjnsfxs@163.com
- * @Date: 2024-08-20 18:16:18
- * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-12-07
- * @Description: 
- * 
--->
 <script setup lang="ts">
 import type { PropsParams, TablePaginationSetting } from '@/types/table.ts'
 import type { ReqConfig } from '@/types/dataAnalysis.ts'
@@ -82,7 +74,7 @@ const expandPageData = computed(() => {
 const activeExpandTablePageConfig = ref<string>('')
 
 // 查询表单的数据
-const queryFormData = reactive<{ [key: string]: any }>({})
+const queryFormData = ref<{ [key: string]: any }>({})
 
 // 分页数据
 const paginationConfig = reactive<TablePaginationSetting>({
@@ -215,7 +207,7 @@ const throttleGetData = throttleFunc(updateTableData, 1000)
  */
 const queryTableData = () => {
   if (props.openRemoteQuery && props.openRemoteReqData && props.requestConfig) {
-    reqConfig.otherOptions = { ...reqConfig.otherOptions, ...queryFormData }
+    reqConfig.otherOptions = { ...reqConfig.otherOptions, ...queryFormData.value }
     // 需要在查询前清除掉目前的数据,不然会导致之前缓存的数据混入
     //  比如第一页已经缓存了,在第二页重新查询,在切回第一页,还是显示查询前的数据,因为缓存没被清除
     tableData.splice(0, tableData.length)
@@ -227,7 +219,7 @@ const queryTableData = () => {
     if (props.dataList) {
       filteredTable = props.dataList.filter((item) => {
         let state = true
-        for (let [k, v] of Object.entries(queryFormData)) {
+        for (let [k, v] of Object.entries(queryFormData.value)) {
           // 模糊查询,看值是否跟表格中的数据匹配
           if (!fuzzySearch(v, item[k])) {
             state = false
@@ -434,7 +426,7 @@ const getTotal = () => {
 }
 
 const getFormQueryData = (): { [p: string]: any } => {
-  return markRaw(queryFormData)
+  return markRaw(queryFormData.value)
 }
 
 // 定义暴露出去的方法
@@ -529,6 +521,11 @@ const handleExpandSizeChange = (size: number) => {
   config.currentPage = 1
   config.limit = size
 }
+
+const handleRowClass = (row: any, _rowIndex: number): string => {
+  const hasOptions = row.row.haveOption
+  return hasOptions ? '' : 'noneExpandIcon'
+}
 </script>
 
 <template>
@@ -539,7 +536,7 @@ const handleExpandSizeChange = (size: number) => {
       </div>
       <div class="filterBody">
         <TableFilterForm
-          v-model:queryFormData="queryFormData"
+          v-model:query-form-data="queryFormData"
           :queryInfo="queryInfo"
           @query="throttleQueryTableData"
           ref="filterFormRef"
@@ -594,6 +591,7 @@ const handleExpandSizeChange = (size: number) => {
         @query="throttleGetData"
         @expand-change="handleExpand"
         table-layout="auto"
+        :row-class-name="handleRowClass"
       >
         <el-table-column
           v-if="props.needRowindex"
@@ -602,8 +600,8 @@ const handleExpandSizeChange = (size: number) => {
           type="index"
           :index="computedRowIndex"
         />
-        <el-table-column align="center" show-overflow-tooltip type="expand">
-          <template #default="rowInfo" v-if="props.needExpand">
+        <el-table-column align="center" show-overflow-tooltip type="expand" v-if="props.needExpand">
+          <template #default="rowInfo">
             <el-table :data="expandPageData">
               <template v-for="child in props.expandConfig?.expandField" :key="child.name">
                 <el-table-column

+ 0 - 1
src/components/table/TableFilterForm/FilterInput.vue

@@ -1,5 +1,4 @@
 <script setup lang="ts">
-import { withDefaults } from 'vue'
 import type { QueryInfo } from '@/types/table.ts'
 
 interface FilterInput {

+ 1 - 0
src/components/table/TableFilterForm/FilterSelect.vue

@@ -123,6 +123,7 @@ const handleCheckAll = () => {
       style="width: 120px"
       :multiple="item.type === FilterType.MULTI_SELECT"
       @change="selectChange"
+      :clearable="item.clearable"
     >
       <template #header v-if="item.type === FilterType.MULTI_SELECT">
         <el-checkbox

+ 1 - 0
src/components/table/TableFilterForm/TableFilterForm.vue

@@ -231,6 +231,7 @@ defineExpose({
           @input-enter-query="throttleQuery"
           :needTip="item.otherOption?.needTip ?? false"
           :tipText="item.otherOption?.tipText"
+          class="filterItem"
         ></FilterInput>
       </template>
 

+ 4 - 2
src/hooks/useTableChart.ts

@@ -35,7 +35,8 @@ export function useTableChart(
   filterInfo: Array<QueryInfo>,
   chartNeedFields: Array<string>,
   isPie: Ref<boolean>,
-  chartInstance: Ref<MChartType | null>
+  chartInstance: Ref<MChartType | null>,
+  isLog: Ref<boolean>
 ) {
   const chartInfo = ref<ChartInfo>({
     PieChart: [],
@@ -329,6 +330,7 @@ export function useTableChart(
 
   const barChartOptions = computed<EChartsOption>(() => {
     const barChartInfo = chartInfo.value.BarChart
+    const yType: any = isLog.value ? 'log' : 'value'
     return {
       tooltip: {
         trigger: 'axis',
@@ -350,7 +352,7 @@ export function useTableChart(
         }
       },
       yAxis: {
-        type: 'log',
+        type: yType,
         min: 1,
         axisLabel: {
           formatter: (value: number) => value.toLocaleString()

+ 4 - 2
src/hooks/useUserBehaviorChart.ts

@@ -25,7 +25,8 @@ export function useUserBehaviorChart(
   filterInfo: Array<QueryInfo>,
   chartNeedFields: Array<string>,
   isPie: Ref<boolean>,
-  chartInstance: Ref<MChartType | null>
+  chartInstance: Ref<MChartType | null>,
+  isLog: Ref<boolean>
 ) {
   const chartInfo = ref<ChartInfo>({
     PieChart: [],
@@ -197,6 +198,7 @@ export function useUserBehaviorChart(
 
   const barChartOptions = computed<EChartsOption>(() => {
     const barChartInfo = chartInfo.value.BarChart
+    const yType: any = isLog.value ? 'log' : 'value'
     return {
       xAxis: {
         type: 'category',
@@ -209,7 +211,7 @@ export function useUserBehaviorChart(
         }
       },
       yAxis: {
-        type: 'log',
+        type: yType,
         min: 1,
         axisLabel: {
           formatter: (value: number) => value.toLocaleString()

+ 1 - 0
src/types/table.ts

@@ -62,6 +62,7 @@ export interface QueryInfo {
   valueType?: ValueTypes
   otherOption?: any
   default?: any
+  clearable?: boolean
 }
 
 // 表格字段信息格式

+ 213 - 11
src/views/Home/AdvertisingData/AdvertisingList.vue

@@ -19,15 +19,24 @@ import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
 
 import { useRequest } from '@/hooks/useRequest'
 import { useCommonStore } from '@/stores/useCommon'
-import type { HeaderCardProps } from '@/types/dataAnalysis'
+import type { HeaderCardProps, ReqConfig } from '@/types/dataAnalysis'
 import { reactive, ref } from 'vue'
 
-import { FilterType, type QueryInfo, type SelectInfo } from '@/types/table'
+import {
+  FilterType,
+  type QueryInfo,
+  type SelectInfo,
+  type TableFieldInfo,
+  type TableToolsConfig
+} from '@/types/table'
 
 import TableFilterForm from '@/components/table/TableFilterForm/TableFilterForm.vue'
 import { useTableChart } from '@/hooks/useTableChart.ts'
 import { usePage } from '@/hooks/usePage.ts'
 import PieBorderRadius from '@/components/echarts/PieBorderRadius.vue'
+import { createDateRange, formatDate } from '@/utils/common'
+import { FieldSpecialEffectType, TextType } from '@/types/tableText.ts'
+import { useAnalysis } from '@/hooks/useAnalysis.ts'
 
 type MChartType = InstanceType<typeof PieBorderRadius>
 
@@ -35,6 +44,175 @@ const chartRef = ref<MChartType | null>(null)
 const { tempMultipleChoice, selectInfo } = useCommonStore()
 const { AllApi } = useRequest()
 
+const { updateReqConfig } = useAnalysis()
+
+// 分页设置
+const paginationConfig = reactive({
+  limit: 15, // 每页展示个数
+  currentPage: 1, // 当前页码
+  total: 0, // 数据总数
+  pageSizeList: [15, 30] // 页数大小列表
+})
+
+const tableFieldsInfo = reactive<Array<TableFieldInfo>>([
+  {
+    name: 'adsScene',
+    cnName: '广告场景',
+    isShow: true,
+    needSort: false
+  },
+  {
+    name: 'adsType',
+    cnName: '广告类型',
+    isShow: true,
+    needSort: false
+  },
+  {
+    name: 'adsState',
+    cnName: '广告状态',
+    isShow: true,
+    needSort: false,
+    specialEffect: {
+      type: FieldSpecialEffectType.TEXT,
+      otherInfo: {
+        translateMap: {
+          0: '未播放',
+          1: '未看完',
+          2: '已看完'
+        },
+        color: {
+          0: '#909399',
+          1: '#E6A23C',
+          2: '#67C23A'
+        },
+        textType: TextType.TEXT
+      }
+    }
+  },
+  {
+    name: 'openId',
+    cnName: '用户openID',
+    isShow: true,
+    needSort: false
+  },
+
+  {
+    name: 'date',
+    cnName: '日期',
+    isShow: true,
+    needSort: false,
+    specialEffect: {
+      type: FieldSpecialEffectType.CUSTOM,
+      otherInfo: {
+        render: formatDate
+      }
+    }
+  },
+  {
+    name: 'createdAt',
+    cnName: '创建时间',
+    isShow: true,
+    needSort: false
+  },
+  {
+    name: 'startTime',
+    cnName: '广告开始时间',
+    isShow: true,
+    needSort: false,
+    specialEffect: {
+      type: FieldSpecialEffectType.CUSTOM,
+      otherInfo: {
+        render: (val: string) => {
+          // 此格式为之前的数据,没有时间,需要特殊处理
+          if (val === '0001-01-01 00:00:00') {
+            return '无'
+          }
+          return val
+        }
+      }
+    }
+  },
+  {
+    name: 'adsId',
+    cnName: '广告ID',
+    isShow: false,
+    needSort: false
+  },
+  {
+    name: 'userId',
+    cnName: '用户ID',
+    isShow: false,
+    needSort: false
+  }
+])
+
+// 表格请求配置
+const requestConfig = reactive<ReqConfig>({
+  url: AllApi.userAdsDetail,
+  otherOptions: {
+    pf: selectInfo.pf,
+    gid: selectInfo.gid,
+    startTime: createDateRange(7)[0],
+    endTime: createDateRange(7)[1],
+    adsState: [0, 1, 2] // 默认选所有
+  }
+})
+
+const adStateOptions: Array<SelectInfo> = [
+  {
+    name: 'unPlay',
+    cnName: '未播放',
+    value: 0
+  },
+  {
+    name: 'unFinished',
+    cnName: '未看完',
+    value: 1
+  },
+  {
+    name: 'finished',
+    cnName: '已看完',
+    value: 2
+  }
+]
+
+// 查询字段设置
+const queryInfo = reactive<Array<QueryInfo>>([
+  {
+    name: 'adsState',
+    label: '广告状态',
+    type: FilterType.MULTI_SELECT,
+    placeholder: '请选择广告状态',
+    otherOption: adStateOptions,
+    default: [0, 1, 2],
+    supplementInfo: '此项全选与全不选均为查找所有'
+  },
+  {
+    name: 'adsType',
+    label: '广告类型',
+    type: FilterType.INPUT,
+    placeholder: '请输入广告类型',
+    otherOption: null,
+    default: ''
+  },
+  {
+    name: 'openId',
+    label: '用户openId',
+    type: FilterType.INPUT,
+    placeholder: '请输入用户openId',
+    otherOption: null,
+    default: ''
+  }
+])
+
+// 工具栏配置
+const tableToolsConfig: TableToolsConfig = {
+  add: false,
+  filterFields: true,
+  refresh: true,
+  download: true
+}
+
 const adTypeOptions: Array<SelectInfo> = [
   {
     name: 'Interstitial',
@@ -56,7 +234,8 @@ const filterInfo = reactive<Array<QueryInfo>>([
     type: FilterType.SELECT,
     placeholder: '请输入广告类型',
     otherOption: adTypeOptions,
-    default: ''
+    default: '',
+    clearable: true
   },
   {
     name: 'createTime',
@@ -121,7 +300,7 @@ const updateAllReq = (pf: string[], gid: string) => {
   queryFormData.value.gid = gid
   queryFormData.value.pf = pf
   updateChartData()
-  console.log('更新GID')
+  updateReqConfig(requestConfig, { pf, gid })
   // updateReqConfig(keepDataTableInfo.requestConfig, { pf, gid })
 }
 
@@ -129,6 +308,8 @@ const { watchPageChange } = usePage()
 
 const backupSelect = reactive([])
 
+const isLog = ref<boolean>(true)
+
 watchPageChange(() => [tempMultipleChoice.pf, selectInfo.gid], backupSelect, updateAllReq)
 
 const { updateChartData, chartOptions } = useTableChart(
@@ -137,7 +318,8 @@ const { updateChartData, chartOptions } = useTableChart(
   filterInfo,
   chartNeedFields,
   isPie,
-  chartRef
+  chartRef,
+  isLog
 )
 </script>
 
@@ -163,16 +345,35 @@ const { updateChartData, chartOptions } = useTableChart(
       <div class="chartContainer">
         <div class="chartContainer">
           <div class="chartsTools">
-            <el-radio-group class="formChangeRadioGroup" v-model="isPie" size="small">
-              <el-radio-button label="饼图" :value="true" />
-              <el-radio-button label="柱状图" :value="false" />
-            </el-radio-group>
+            <div class="chartVal">
+              <el-radio-group class="formChangeRadioGroup" v-model="isLog" size="small">
+                <el-radio-button label="对数" :value="true" />
+                <el-radio-button label="原值" :value="false" />
+              </el-radio-group>
+            </div>
+            <div class="chartForm">
+              <el-radio-group class="formChangeRadioGroup" v-model="isPie" size="small">
+                <el-radio-button label="饼图" :value="true" />
+                <el-radio-button label="柱状图" :value="false" />
+              </el-radio-group>
+            </div>
           </div>
+
           <div class="chartDisplay">
             <PieBorderRadius ref="chartRef" :options="chartOptions"></PieBorderRadius>
           </div>
         </div>
       </div>
+      <div class="adTableContent">
+        <CustomTable
+          :pagination-config="paginationConfig"
+          :table-fields-info="tableFieldsInfo"
+          :request-config="requestConfig"
+          :query-info="queryInfo"
+          :open-filter-query="true"
+          :tools="tableToolsConfig"
+        ></CustomTable>
+      </div>
     </div>
   </div>
 </template>
@@ -196,8 +397,9 @@ const { updateChartData, chartOptions } = useTableChart(
 
 .chartsTools {
   width: 100%;
-  position: relative;
+  /*position: relative;*/
   display: flex;
-  justify-content: flex-end;
+  justify-content: space-between;
+  /*justify-content: flex-end;*/
 }
 </style>

+ 19 - 0
src/views/Home/Analysis/KeepView.vue

@@ -111,6 +111,25 @@ const keepDataTableInfo = reactive<{
       needSort: false
     },
     {
+      name: '+8day',
+      cnName: '+8日',
+      isShow: true,
+      needSort: false
+    },
+    {
+      name: '+9day',
+      cnName: '+9日',
+      isShow: true,
+      needSort: false
+    },
+    {
+      name: '+10day',
+      cnName: '+10日',
+      isShow: true,
+      needSort: false
+    },
+
+    {
       name: '+14day',
       cnName: '+14日',
       isShow: true,

+ 18 - 7
src/views/Home/Analysis/UserBehavior.vue

@@ -194,6 +194,7 @@ const updateAllReq = (pf: string, gid: string) => {
   updateChartData()
   // updateReqConfig(keepDataTableInfo.requestConfig, { pf, gid })
 }
+const isLog = ref<boolean>(true)
 
 const { watchPageChange } = usePage()
 
@@ -207,7 +208,8 @@ const { updateChartData, chartOptions } = useUserBehaviorChart(
   filterInfo,
   chartNeedFields,
   isPie,
-  chartRef
+  chartRef,
+  isLog
 )
 </script>
 
@@ -228,10 +230,18 @@ const { updateChartData, chartOptions } = useUserBehaviorChart(
       <div class="chartContainer">
         <div class="chartContainer">
           <div class="chartsTools">
-            <el-radio-group class="formChangeRadioGroup" v-model="isPie" size="small">
-              <el-radio-button label="饼图" :value="true" />
-              <el-radio-button label="柱状图" :value="false" />
-            </el-radio-group>
+            <div class="chartVal">
+              <el-radio-group class="formChangeRadioGroup" v-model="isLog" size="small">
+                <el-radio-button label="对数" :value="true" />
+                <el-radio-button label="原值" :value="false" />
+              </el-radio-group>
+            </div>
+            <div class="chartForm">
+              <el-radio-group class="formChangeRadioGroup" v-model="isPie" size="small">
+                <el-radio-button label="饼图" :value="true" />
+                <el-radio-button label="柱状图" :value="false" />
+              </el-radio-group>
+            </div>
           </div>
           <div class="chartDisplay">
             <PieBorderRadius ref="chartRef" :options="chartOptions"></PieBorderRadius>
@@ -264,8 +274,9 @@ const { updateChartData, chartOptions } = useUserBehaviorChart(
 
 .chartsTools {
   width: 100%;
-  position: relative;
+  /*position: relative;*/
   display: flex;
-  justify-content: flex-end;
+  justify-content: space-between;
+  /*justify-content: flex-end;*/
 }
 </style>

+ 2 - 2
src/views/IndexView.vue

@@ -237,8 +237,8 @@ onMounted(() => {
       <div class="navBarBox">
         <div class="logoBox">
           <el-image :fit="'fill'" class="logoImg" :src="blobUrlInfo.logo"></el-image>
-          <span class="logoTitle">测试库</span>
-          <!--          <span class="logoTitle">淳皓科技</span>-->
+          <!--          <span class="logoTitle">测试库</span>-->
+          <span class="logoTitle">淳皓科技</span>
         </div>
 
         <div class="gameSelect">

+ 15 - 5
vite.config.ts

@@ -91,8 +91,15 @@ export default defineConfig(({ mode }) => {
     build: {
       rollupOptions: {
         output: {
-          manualChunks: {
-            echarts: ['echarts']
+          // manualChunks: {
+          //   echarts: ['echarts']
+          // },
+          manualChunks(id) {
+            if (id.includes('node_modules')) {
+              const parts = id.split('node_modules/')[1].split('/')
+              // 支持 scoped 包和普通包
+              return parts[0].startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0]
+            }
           },
           chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
           entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
@@ -110,9 +117,12 @@ export default defineConfig(({ mode }) => {
         verbose: true, // 默认即可
         disable: false, // 开启压缩(不禁用),默认即可
         deleteOriginFile: false, // 删除源文件
-        threshold: 5120, // 压缩前最小文件大小
-        algorithm: 'gzip', // 压缩算法
-        ext: '.gz' // 文件类型
+        // threshold: 5120, // 压缩前最小文件大小
+        // algorithm: 'gzip', // 压缩算法
+        // ext: '.gz' // 文件类型
+        algorithm: 'brotliCompress',
+        ext: '.br',
+        threshold: 10240 // 10KB 以上才压
       }),
       visualizer({ open: true }),
       AutoImport({