Pārlūkot izejas kodu

refactor(用户行为和广告列表页面): 更新用户行为和广告列表的数据表现形式

fxs 8 mēneši atpakaļ
vecāks
revīzija
e60b173104

+ 3 - 3
.env

@@ -1,8 +1,8 @@
 # 开发
-#VITE_API_URL_DEV="http://192.168.1.139:8000"
-VITE_API_URL_DEV='http://service.ichunhao.cn'
+VITE_API_URL_DEV="http://192.168.1.139:8000"
+#VITE_API_URL_DEV='http://server.ichunhao.cn'
 # 测试服和本地开发
 #VITE_API_URL_TEST='http://server.ichunhao.cn'
-VITE_API_URL_TEST='http://service.ichunhao.cn'
+VITE_API_URL_TEST="http://192.168.1.139:8000"
 # 线上
 VITE_API_URL_PRODUCT='http://service.ichunhao.cn'

+ 12 - 24
src/components/echarts/PieBorderRadius.vue

@@ -1,12 +1,12 @@
 <script setup lang="ts">
 // 图表Ref
-import { nextTick, onMounted, ref, watch } from 'vue'
+import { markRaw, nextTick, onMounted, ref, watch } from 'vue'
 import echarts from '@/components/echarts/index.ts'
 import { debounceFunc } from '@/utils/common'
 import type { EChartsOption } from 'echarts/types/dist/shared'
 
 interface PieProps {
-  options: EChartsOption
+  options: EChartsOption | null
 }
 
 const props = withDefaults(defineProps<PieProps>(), {})
@@ -23,30 +23,18 @@ const changeSize = () => {
 }
 
 const initOptions = () => {
-  let options = props.options
-  const series = options.series
-  let hasData = true
-  if (!series) {
-    hasData = false
-  } else if (Array.isArray(props.options.series)) {
-    if (props.options.series.length === 0) hasData = false
-  } else if (Object.keys(series).length === 0) {
-    hasData = false
-  }
-  if (!hasData) {
-    options = {
-      title: {
-        text: '暂无数据',
-        left: 'center',
-        top: 'center',
-        textStyle: {
-          fontSize: 16,
-          fontWeight: 'normal'
-        }
+  const defaultOptions = {
+    title: {
+      text: '暂无数据',
+      left: 'center',
+      top: 'center',
+      textStyle: {
+        fontSize: 16,
+        fontWeight: 'normal'
       }
     }
   }
-
+  let options = props.options ?? defaultOptions
   pieChart.value?.setOption(options, true)
 }
 
@@ -66,7 +54,7 @@ onMounted(() => {
     return
   }
   // 开始的时候,不要去直接初始化,先展示加载状态,等到数据加载完状态改变,再去设置
-  pieChart.value = echarts.init(chart.value)
+  pieChart.value = markRaw(echarts.init(chart.value))
 
   nextTick(() => {
     initOptions()

+ 19 - 3
src/components/table/CustomTable.vue

@@ -15,7 +15,17 @@ import { fuzzySearch, throttleFunc } from '@/utils/common'
 
 import { useTable } from '@/hooks/useTable.ts'
 import { useRequest } from '@/hooks/useRequest.ts'
-import { computed, type ComputedRef, nextTick, onMounted, reactive, ref, toRaw, watch } from 'vue'
+import {
+  computed,
+  type ComputedRef,
+  markRaw,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  toRaw,
+  watch
+} from 'vue'
 
 import TableFilterForm from '@/components/table/TableFilterForm/TableFilterForm.vue'
 import axiosInstance from '@/utils/axios/axiosInstance.ts'
@@ -183,6 +193,7 @@ const queryTableData = () => {
     //  比如第一页已经缓存了,在第二页重新查询,在切回第一页,还是显示查询前的数据,因为缓存没被清除
     tableData.splice(0, tableData.length)
     updateTableData()
+    console.log(reqConfig.otherOptions)
   } else {
     let filteredTable: any[]
     // 过滤出来所有符合formData数据的条件
@@ -395,13 +406,18 @@ const getTotal = () => {
   return props.totalFunc(tableData, paginationConfig.total)
 }
 
+const getFormQueryData = (): { [p: string]: any } => {
+  return markRaw(queryFormData)
+}
+
 // 定义暴露出去的方法
 defineExpose({
   updateTableData,
   resetTableData,
   deleteRow,
   downLoadTable,
-  outGetTableData
+  outGetTableData,
+  getFormQueryData
 })
 
 onMounted(() => {
@@ -598,7 +614,7 @@ onMounted(() => {
 }
 
 .filterItem {
-  width: 20%;
+  /*width: 20%;*/
   display: flex;
   align-items: center;
 }

+ 36 - 19
src/components/table/TableFilterForm/FilterInput.vue

@@ -1,11 +1,17 @@
 <script setup lang="ts">
+import { withDefaults } from 'vue'
 import type { QueryInfo } from '@/types/table.ts'
 
 interface FilterInput {
   itemInfo: QueryInfo
+  needTip?: boolean
+  tipText?: string
 }
 
-defineProps<FilterInput>()
+withDefaults(defineProps<FilterInput>(), {
+  needTip: false,
+  tipText: ''
+})
 
 const model = defineModel<any>()
 
@@ -21,23 +27,34 @@ const enterQuery = () => {
 
 <template>
   <!-- 所有的input查询框 -->
-  <el-form-item @keyup.enter="enterQuery" v-bind="$attrs" class="filterItem">
-    <el-input
-      v-if="itemInfo.valueType !== 'int'"
-      clearable
-      :placeholder="itemInfo.placeholder"
-      v-model="model"
-      class="inputW180"
-    />
-    <el-input
-      v-else
-      clearable
-      :placeholder="itemInfo.placeholder"
-      type="number"
-      v-model.number="model"
-      class="inputW180"
-    />
-  </el-form-item>
+  <div class="inputItem">
+    <el-form-item @keyup.enter="enterQuery" v-bind="$attrs" class="filterItem">
+      <el-input
+        v-if="itemInfo.valueType !== 'int'"
+        clearable
+        :placeholder="itemInfo.placeholder"
+        v-model="model"
+        class="inputW180"
+      />
+      <el-input
+        v-else
+        clearable
+        :placeholder="itemInfo.placeholder"
+        type="number"
+        v-model.number="model"
+        class="inputW180"
+      />
+      <div class="inputTip">
+        <el-tooltip effect="dark" :content="tipText" placement="top" v-if="needTip">
+          <el-icon><QuestionFilled /></el-icon>
+        </el-tooltip>
+      </div>
+    </el-form-item>
+  </div>
 </template>
 
-<style scoped></style>
+<style scoped>
+.inputTip {
+  margin-left: 10px;
+}
+</style>

+ 4 - 2
src/components/table/TableFilterForm/TableFilterForm.vue

@@ -175,6 +175,8 @@ defineExpose({
           :label="item.label"
           v-model="queryFormData[item.name]"
           @input-enter-query="throttleQuery"
+          :needTip="item.otherOption?.needTip ?? false"
+          :tipText="item.otherOption?.tipText"
         ></FilterInput>
       </template>
 
@@ -200,7 +202,7 @@ defineExpose({
       >
         <el-date-picker
           v-model="queryFormData[item.name]"
-          type="date"
+          :type="item.otherOption.dataRange ? 'daterange' : 'date'"
           :value-format="item.otherOption.valueFormat"
           :placeholder="item.placeholder"
           clearable
@@ -277,7 +279,7 @@ defineExpose({
 }
 
 .filterItem {
-  width: 20%;
+  width: 350px;
   display: flex;
   align-items: center;
 }

+ 4 - 2
src/hooks/useRequest.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 17:24:06
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-11-29
+ * @LastEditTime: 2025-04-07
  * @Description:
  *
  */
@@ -42,6 +42,7 @@ export function useRequest() {
     userDataTradesDetail: `/user/dataTradesDetail`, //用户趋势 -数据趋势详情
     userRemainDataBydDay: `/user/remainDataBydDay`, //用户留存数据
     userBehaviorList: `/user/behaviorList`, // 用户行为
+    userBehaviorPieChart: `/user/behaviorListCake`, // 用户行为饼图数据
     userAdRelatedList: `/user/adRelatedList`, // 广告用户数据
 
     // 事件相关
@@ -69,7 +70,8 @@ export function useRequest() {
     // 广告数据
     userAdsOverview: `/user/userAdsOverview`, // 用户广告数据总览
     userAdsDaily: `/user/userAdsDaily`, // 广告每日数据曲线
-    userAdsDetail: `/user/userAdsDetail` // 广告数据列表
+    userAdsDetail: `/user/userAdsDetail`, // 广告数据列表
+    adListChart: `/user/userAdsCake` // 广告列表图表数据
   }
 
   /**

+ 177 - 0
src/hooks/useTableChart.ts

@@ -0,0 +1,177 @@
+import { computed, type Ref, ref } from 'vue'
+import type { EChartsOption } from 'echarts/types/dist/shared'
+import axiosInstance from '@/utils/axios/axiosInstance.ts'
+import type { ResponseInfo } from '@/types/res.ts'
+import type { QueryInfo } from '@/types/table.ts'
+
+interface BarChartInfo {
+  labelList: string[]
+  valueList: any[]
+}
+
+interface ChartInfo {
+  PieChart: Array<{
+    name: string
+    value: number
+  }>
+  BarChart: BarChartInfo
+}
+
+export function useTableChart(
+  url: string,
+  queryFormData: Ref<any>,
+  filterInfo: Array<QueryInfo>,
+  chartNeedFields: Array<string>,
+  isPie: Ref<boolean>
+) {
+  const pieChartOptions = computed<EChartsOption>(() => {
+    return {
+      tooltip: {
+        trigger: 'item'
+      },
+      legend: {
+        top: '5%',
+        left: 'center'
+      },
+      series: [
+        {
+          name: '',
+          type: 'pie',
+          radius: ['40%', '70%'],
+          avoidLabelOverlap: false,
+          itemStyle: {
+            borderRadius: 10,
+            borderColor: '#fff',
+            borderWidth: 2
+          },
+          label: {
+            show: false,
+            position: 'center'
+          },
+          emphasis: {
+            label: {
+              show: true,
+              fontSize: 40,
+              fontWeight: 'bold'
+            }
+          },
+          labelLine: {
+            show: false
+          },
+          data: chartInfo.value.PieChart
+        }
+      ]
+    }
+  })
+
+  const barChartOptions = computed<EChartsOption>(() => {
+    const barChartInfo = chartInfo.value.BarChart
+    return {
+      xAxis: {
+        type: 'category',
+        data: barChartInfo.labelList
+      },
+      yAxis: {
+        type: 'value'
+      },
+      series: [
+        {
+          data: barChartInfo.valueList,
+          type: 'bar'
+        }
+      ]
+    }
+  })
+
+  const chartInfo = ref<ChartInfo>({
+    PieChart: [],
+    BarChart: {
+      labelList: [],
+      valueList: []
+    }
+  })
+
+  const updateChartData = async () => {
+    // 如果没有筛选,则提示.根据chartNeedFields来
+    if (chartNeedFields.length > 0) {
+      const hasFilter = chartNeedFields.every((item) => {
+        return queryFormData.value[item] === ''
+      })
+      if (hasFilter) {
+        // ElMessage.warning('请选择筛选条件')
+        const tip = filterInfo
+          .filter((item) => {
+            return chartNeedFields.includes(item.name as any)
+          })
+          .map((item) => {
+            return item.label
+          })
+          .join(',')
+        ElMessage.warning(`${tip}请至少输入一个筛选条件`)
+        return
+      }
+    }
+
+    const params = {} as any
+    Object.assign(params, queryFormData.value)
+    // TODO 时间范围问题
+    if (queryFormData.value.createTime) {
+      params.createTime = queryFormData.value.createTime
+        .map((item: any) => {
+          // 日期转时间戳
+          return new Date(item).getTime().toString()
+        })
+        .join(',')
+    }
+
+    const res = (await axiosInstance.post(url, params)) as ResponseInfo
+    if (res.code !== 0) {
+      ElMessage.error('获取数据失败')
+      return
+    }
+
+    const data = res.data as Array<{
+      name: string
+      count: number
+    }> | null
+    if (!data) {
+      chartInfo.value.PieChart = []
+      chartInfo.value.BarChart = {
+        labelList: [],
+        valueList: []
+      }
+    } else {
+      const isAllZero = data.every((item) => item.count === 0)
+      if (isAllZero) {
+        chartInfo.value.PieChart = []
+        chartInfo.value.BarChart = {
+          labelList: [],
+          valueList: []
+        }
+        return
+      }
+      chartInfo.value.PieChart = data.map((item) => {
+        return {
+          name: item.name,
+          value: item.count
+        }
+      })
+      chartInfo.value.BarChart = {
+        labelList: data.map((item) => item.name),
+        valueList: data.map((item) => item.count)
+      }
+    }
+  }
+
+  const chartOptions = computed(() => {
+    const pieChartInfo = chartInfo.value.PieChart.length ?? null
+    const barChartInfo = chartInfo.value.BarChart.valueList.length ?? null
+    if (!pieChartInfo && !barChartInfo) return null
+    return isPie.value ? pieChartOptions.value : barChartOptions.value
+  })
+
+  return {
+    updateChartData,
+    chartOptions
+  }
+}

+ 97 - 212
src/views/Home/AdvertisingData/AdvertisingList.vue

@@ -15,242 +15,94 @@
  * 
 -->
 <script setup lang="ts">
-import CustomTable from '@/components/table/CustomTable.vue'
 import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
 
 import { useRequest } from '@/hooks/useRequest'
 import { useCommonStore } from '@/stores/useCommon'
-import type { HeaderCardProps, ReqConfig } from '@/types/dataAnalysis'
-import { reactive } from 'vue'
-import { createDateRange, resetTimeToMidnight } from '@/utils/common'
-import { useAnalysis } from '@/hooks/useAnalysis'
-import { usePage } from '@/hooks/usePage'
-import {
-  FilterType,
-  type QueryInfo,
-  type SelectInfo,
-  type TableFieldInfo,
-  type TableToolsConfig
-} from '@/types/table'
-import { FieldSpecialEffectType, TextType } from '@/types/tableText'
-import { formatDate } from '@/utils/common'
-import Table from '@/components/table/CustomTable.vue'
+import type { HeaderCardProps } from '@/types/dataAnalysis'
+import { reactive, ref } from 'vue'
 
-const { selectInfo } = useCommonStore()
-const { AllApi } = useRequest()
-const { updateReqConfig } = useAnalysis()
-
-const { watchPageChange } = usePage()
+import { FilterType, type QueryInfo, type SelectInfo } from '@/types/table'
 
-// 表格请求配置
-const requestConfig = reactive<ReqConfig>({
-  url: `http://service.ichunhao.cn${AllApi.userAdsDetail}`,
-  otherOptions: {
-    pf: selectInfo.pf,
-    gid: selectInfo.gid,
-    startTime: createDateRange(7)[0],
-    endTime: createDateRange(7)[1],
-    adsState: [0, 1, 2] // 默认选所有
-  }
-})
+import TableFilterForm from '@/components/table/TableFilterForm/TableFilterForm.vue'
+import { useTableChart } from '@/hooks/useTableChart.ts'
 
-// 分页设置
-const paginationConfig = reactive({
-  limit: 15, // 每页展示个数
-  currentPage: 1, // 当前页码
-  total: 0, // 数据总数
-  pageSizeList: [15, 30] // 页数大小列表
-})
-
-// 工具栏配置
-const tableToolsConfig: TableToolsConfig = {
-  add: false,
-  filterFields: true,
-  refresh: true,
-  download: true
-}
-
-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 { tempMultipleChoice } = useCommonStore()
+const { AllApi } = useRequest()
 
-const adStateOptions: Array<SelectInfo> = [
-  {
-    name: 'unPlay',
-    cnName: '未播放',
-    value: 0
-  },
+const adTypeOptions: Array<SelectInfo> = [
   {
-    name: 'unFinished',
-    cnName: '未看完',
-    value: 1
+    name: 'Interstitial',
+    cnName: '插屏广告',
+    value: 'Interstitial'
   },
   {
-    name: 'finished',
-    cnName: '已看完',
-    value: 2
+    name: 'Rewarded',
+    cnName: '普通广告',
+    value: 'Rewarded'
   }
 ]
 
 // 查询字段设置
-const queryInfo = reactive<Array<QueryInfo>>([
-  {
-    name: 'adsState',
-    label: '广告状态',
-    type: FilterType.MULTI_SELECT,
-    placeholder: '请选择广告状态',
-    otherOption: adStateOptions,
-    default: [0, 1, 2],
-    supplementInfo: '此项全选与全不选均为查找所有'
-  },
+const filterInfo = reactive<Array<QueryInfo>>([
   {
     name: 'adsType',
     label: '广告类型',
-    type: FilterType.INPUT,
+    type: FilterType.SELECT,
     placeholder: '请输入广告类型',
-    otherOption: null,
+    otherOption: adTypeOptions,
     default: ''
   },
   {
-    name: 'openId',
-    label: '用户openId',
-    type: FilterType.INPUT,
-    placeholder: '请输入用户openId',
-    otherOption: null,
-    default: ''
+    name: 'createTime',
+    label: '创建时间',
+    type: FilterType.DATE,
+    placeholder: '选择日期',
+    otherOption: {
+      dataRange: true
+    }
   }
 ])
 
 const headerCardInfo: HeaderCardProps = {
   // title: '广告数据(正式服数据)',
   title: '广告数据',
-  openDateSelect: true
+  openDateSelect: false
 }
 
-/**
- * 更新请求配置
- * @param {*} date 新的日期
- */
-const changeDate = (date: Array<Date>) => {
-  updateReqConfig(requestConfig, {
-    startTime: resetTimeToMidnight(date[0]),
-    endTime: resetTimeToMidnight(date[1])
-  })
-}
+interface ChartQuery {
+  /** 游戏ID */
+  gid: string
 
-/**
- * 更新选择
- * @param {*} pf  新pf
- * @param {*} gid 新gid
- */
-const updateSelect = (pf: string, gid: string) => {
-  updateReqConfig(requestConfig, { pf, gid })
+  /** 渠道 */
+  pf: string[]
+
+  /** 广告类型 */
+  adsType: string
+
+  /** 创建时间范围,数组形式,例如 ['2024-01-01', '2024-01-31'] */
+  createTime: [string, string]
 }
 
-const backupSelect = reactive([])
+const queryFormData = ref<ChartQuery>({
+  gid: tempMultipleChoice.gid,
+  pf: tempMultipleChoice.pf,
+  adsType: 'Interstitial ',
+  createTime: ['', '']
+})
+
+const chartNeedFields: string[] = []
 
-watchPageChange(() => [selectInfo.pf, selectInfo.gid], backupSelect, updateSelect)
+const isPie = ref(true)
+const isRadioPf = ref(false)
 
-/**
- * 获取合计数据
- * @param _data 当前页表格数据,如果不是远程分页查询,则是全部数据
- * @param total 表格总数
- * @param needOther 是否需要自定义其他内容,为false则只返回数据总条数
- * @returns 合计数据数组
- */
-const getSummary = (_data: any, total: number, needOther = false) => {
-  if (!needOther) return [total + '条数据']
-  // 如需其他内容则在此处补充
-  return []
-}
+const { updateChartData, chartOptions } = useTableChart(
+  AllApi.adListChart,
+  queryFormData,
+  filterInfo,
+  chartNeedFields,
+  isPie
+)
 </script>
 
 <template>
@@ -260,20 +112,41 @@ const getSummary = (_data: any, total: number, needOther = false) => {
       <HeaderCard
         :title="headerCardInfo.title"
         :open-date-select="headerCardInfo.openDateSelect"
-        @change-date="changeDate"
+        :is-radio="isRadioPf"
       ></HeaderCard>
     </div>
     <div class="adTableContent">
-      <CustomTable
-        :pagination-config="paginationConfig"
-        :table-fields-info="tableFieldsInfo"
-        :request-config="requestConfig"
-        :query-info="queryInfo"
-        :open-filter-query="true"
-        :tools="tableToolsConfig"
-        :need-total="true"
-        :total-func="getSummary"
-      ></CustomTable>
+      <div class="filterContainer">
+        <TableFilterForm
+          v-model:queryFormData="queryFormData"
+          :queryInfo="filterInfo"
+          @query="updateChartData"
+          ref="filterFormRef"
+        ></TableFilterForm>
+      </div>
+      <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>
+          <div class="chartDisplay">
+            <PieBorderRadius :options="chartOptions"></PieBorderRadius>
+          </div>
+        </div>
+      </div>
+      <!--      <CustomTable-->
+      <!--        :pagination-config="paginationConfig"-->
+      <!--        :table-fields-info="tableFieldsInfo"-->
+      <!--        :request-config="requestConfig"-->
+      <!--        :query-info="filterInfo"-->
+      <!--        :open-filter-query="true"-->
+      <!--        :tools="tableToolsConfig"-->
+      <!--        :need-total="true"-->
+      <!--        :total-func="getSummary"-->
+      <!--      ></CustomTable>-->
     </div>
   </div>
 </template>
@@ -289,4 +162,16 @@ const getSummary = (_data: any, total: number, needOther = false) => {
 .adTableContent {
   padding: 0 24px;
 }
+
+.chartContainer {
+  width: 100%;
+  position: relative;
+}
+
+.chartsTools {
+  width: 100%;
+  position: relative;
+  display: flex;
+  justify-content: flex-end;
+}
 </style>

+ 96 - 307
src/views/Home/Analysis/UserBehavior.vue

@@ -7,50 +7,67 @@
  * 
 -->
 <script setup lang="ts">
-import type { HeaderCardProps, ReqConfig } from '@/types/dataAnalysis'
-import type {
-  QueryInfo,
-  SelectInfo,
-  TableFieldInfo,
-  TablePaginationSetting,
-  TableToolsConfig
-} from '@/types/table'
+import type { HeaderCardProps } from '@/types/dataAnalysis'
+import type { QueryInfo, SelectInfo } from '@/types/table'
 import { FilterType } from '@/types/table'
-import { CustomFilterValueType } from '@/types/customFilter'
 
-import { computed, reactive, ref } from 'vue'
+import { ref } from 'vue'
 import { useRequest } from '@/hooks/useRequest'
-import { useAnalysis } from '@/hooks/useAnalysis'
+
 import { useCommonStore } from '@/stores/useCommon'
-import { formatTimestamp } from '@/utils/common'
-import { formatDate } from '@/utils/common'
-import { usePage } from '@/hooks/usePage'
 
-import Table from '@/components/table/CustomTable.vue'
-import { FieldSpecialEffectType, TagType, TextType } from '@/types/tableText'
-import type { EChartsOption } from 'echarts/types/dist/shared'
+import TableFilterForm from '@/components/table/TableFilterForm/TableFilterForm.vue'
+import { useTableChart } from '@/hooks/useTableChart.ts'
 
-type TableType = InstanceType<typeof Table>
+interface ChartQuery {
+  /** 游戏ID */
+  gid: string
 
-const { AllApi } = useRequest()
-const { selectInfo } = useCommonStore()
-const { updateReqConfig } = useAnalysis()
-const { watchPageChange } = usePage()
+  /** 渠道 */
+  pf: string
 
-const isSinglePf = ref(true)
+  /** 是否已经上报,'true' | 'false' */
+  activeStatus: boolean
 
-const behaviourTable = ref<TableType>()
+  /** 是否已经转化,'true' | 'false' */
+  conversionStatus: boolean
 
-// 表格请求配置
-const requestConfig = reactive<ReqConfig>({
-  // url: 'http://192.168.1.139:8000/user/behaviorList',
-  url: AllApi.userBehaviorList,
-  otherOptions: {
-    pf: 'tt',
-    gid: selectInfo.gid
-  }
+  /** 总在线时长范围字符串,比如 '0:100,300:1000' */
+  totalDuration: string
+
+  /** 总广告观看次数范围字符串,比如 '0:100,300:1000' */
+  totalAdReqCount: string
+
+  /** 广告看完次数范围字符串,比如 '0:100,300:1000' */
+  totalAdEposedCount: string
+
+  /** 创建时间范围,数组形式,例如 ['2024-01-01', '2024-01-31'] */
+  createTime: [string, string]
+}
+
+const { AllApi } = useRequest()
+const { selectInfo } = useCommonStore()
+
+const isPie = ref(true)
+
+const queryFormData = ref<ChartQuery>({
+  gid: selectInfo.gid,
+  pf: selectInfo.pf[0],
+  activeStatus: false,
+  conversionStatus: false,
+  totalDuration: '',
+  totalAdReqCount: '',
+  totalAdEposedCount: '',
+  createTime: ['', '']
 })
 
+// 图表需要的筛选字段
+const chartNeedFields: Array<keyof ChartQuery> = [
+  'totalDuration',
+  'totalAdReqCount',
+  'totalAdEposedCount'
+]
+
 // 上报状态
 const uploadStateSelect: Array<SelectInfo> = [
   {
@@ -91,12 +108,12 @@ const conversionStateSelect: Array<SelectInfo> = [
 
 // 事件表格的上方查询字段信息
 const filterInfo: Array<QueryInfo> = [
-  {
-    name: 'openId',
-    label: 'OpenId',
-    type: FilterType.INPUT,
-    placeholder: '输入OpenId'
-  },
+  // {
+  //   name: 'openId',
+  //   label: 'OpenId',
+  //   type: FilterType.INPUT,
+  //   placeholder: '输入OpenId'
+  // },
   {
     name: 'activeStatus',
     label: '上报状态',
@@ -116,281 +133,59 @@ const filterInfo: Array<QueryInfo> = [
   {
     name: 'createTime',
     label: '创建时间',
-    type: FilterType.CUSTOM,
+    type: FilterType.DATE,
     placeholder: '选择日期',
     otherOption: {
-      customFilterValueType: CustomFilterValueType.DATEPICKER,
-      valueFormat: 'X'
+      dataRange: true
     }
   },
   {
     name: 'totalDuration',
     label: '总在线时长',
-    type: FilterType.CUSTOM,
+    type: FilterType.INPUT,
     placeholder: '请输入筛选时长',
-    default: 0,
+    default: '',
     otherOption: {
-      customFilterValueType: CustomFilterValueType.INPUT,
-      valueFormat: (val: any) => {
-        if (val === '') return val
-        return parseInt(val)
-      },
-      valueValid: (val: any) => {
-        return !isNaN(val)
-      }
+      needTip: true,
+      tipText: '使用逗号分隔,如:100,400。那么将筛选0-100,100-400,400-∞'
     }
   },
   {
     name: 'totalAdReqCount',
     label: '总广告观看次数',
-    type: FilterType.CUSTOM,
+    type: FilterType.INPUT,
     placeholder: '总广告观看次数',
-    default: 0,
+    default: '',
     otherOption: {
-      customFilterValueType: CustomFilterValueType.INPUT,
-      valueFormat: (val: any) => {
-        if (val === '') return val
-        return parseInt(val)
-      },
-      valueValid: (val: any) => {
-        return !isNaN(val)
-      }
+      needTip: true,
+      tipText: '使用逗号分隔,如:100,400。那么将筛选0-100,100-400,400-∞'
     }
   },
   {
     name: 'totalAdEposedCount',
     label: '广告看完次数',
-    type: FilterType.CUSTOM,
+    type: FilterType.INPUT,
     placeholder: '广告看完次数',
-    default: 0,
+    default: '',
     otherOption: {
-      customFilterValueType: CustomFilterValueType.INPUT,
-      valueFormat: (val: any) => {
-        if (val === '') return val
-        return parseInt(val)
-      },
-      valueValid: (val: any) => {
-        return !isNaN(val)
-      }
+      needTip: true,
+      tipText: '使用逗号分隔,如:100,400。那么将筛选0-100,100-400,400-∞'
     }
   }
 ]
 
-// 表格分页设置
-const pagingConfig = reactive<TablePaginationSetting>({
-  limit: 20,
-  currentPage: 1,
-  total: 0,
-  pageSizeList: [20, 30]
-})
-
-// 工具栏配置
-const tableToolsConfig: TableToolsConfig = {
-  add: false,
-  filterFields: true,
-  refresh: true,
-  download: false
-}
-
-// 表格字段信息
-const tableFieldsInfo = reactive<Array<TableFieldInfo>>([
-  {
-    name: 'openId',
-    cnName: 'OpenId',
-    isShow: true,
-    needSort: false
-  },
-  {
-    name: 'totalDuration',
-    cnName: '总时长',
-    isShow: true,
-    needSort: false
-  },
-  {
-    name: 'totalAdReqCount',
-    cnName: '总广告观看次数',
-    isShow: true,
-    needSort: false
-  },
-  {
-    name: 'totalAdEposedCount',
-    cnName: '广告看完次数',
-    isShow: true,
-    needSort: false
-  },
-  {
-    name: 'createDate',
-    cnName: '创建日期',
-    isShow: true,
-    needSort: false,
-    specialEffect: {
-      type: FieldSpecialEffectType.CUSTOM,
-      otherInfo: {
-        render: formatDate
-      }
-    }
-  },
-  {
-    name: 'createTime',
-    cnName: '创建时间',
-    isShow: true,
-    needSort: false,
-    specialEffect: {
-      type: FieldSpecialEffectType.CUSTOM,
-      otherInfo: {
-        render: formatTimestamp
-      }
-    }
-  },
-  {
-    name: 'startNum',
-    cnName: '启动次数',
-    isShow: true,
-    needSort: false
-  },
-  {
-    name: 'activeStatus',
-    cnName: '是否激活',
-    isShow: true,
-    needSort: false,
-    specialEffect: {
-      type: FieldSpecialEffectType.TEXT,
-      otherInfo: {
-        translateMap: ['是', '否'],
-        tagType: [TagType.SUCCESS, TagType.DANGER],
-        textType: TextType.TAG
-      }
-    }
-  },
-  {
-    name: 'conversionStatus',
-    cnName: '是否转化',
-    isShow: true,
-    needSort: false,
-    specialEffect: {
-      type: FieldSpecialEffectType.TEXT,
-      otherInfo: {
-        translateMap: ['是', '否'],
-        tagType: [TagType.SUCCESS, TagType.DANGER],
-        textType: TextType.TAG
-      }
-    }
-  },
-  {
-    name: 'remainData',
-    cnName: '留存数据',
-    isShow: false,
-    needSort: false,
-    specialEffect: {
-      type: FieldSpecialEffectType.CUSTOM,
-      otherInfo: {
-        render: (val: any) => {
-          if (!val) return '无'
-          return val
-        }
-      }
-    }
-  }
-])
-
 const headerCardInfo: HeaderCardProps = {
   title: '用户行为',
   openDateSelect: false
 }
 
-/**
- * 更新所有请求配置
- * @param {*} pf  新pf
- * @param {*} gid 新gid
- */
-const updateAllReq = (pf: string, gid: string) => {
-  pf = isSinglePf.value ? pf[0] : pf
-  updateReqConfig(requestConfig, { pf, gid })
-}
-
-const backupSelect = reactive([]) // 保存选择数据
-
-watchPageChange(() => [selectInfo.pf, selectInfo.gid], backupSelect, updateAllReq)
-
-/**
- * 获取合计数据
- * @param _data 当前页表格数据,如果不是远程分页查询,则是全部数据
- * @param total 表格总数
- * @param needOther 是否需要自定义其他内容,为false则只返回数据总条数
- * @returns 合计数据数组
- */
-const getSummary = (_data: any, total: number, needOther = false) => {
-  if (!needOther) return [total + '条数据']
-  // 如需其他内容则在此处补充
-  return []
-}
-
-const pieChartOptions: EChartsOption = {
-  tooltip: {
-    trigger: 'item'
-  },
-  legend: {
-    top: '5%',
-    left: 'center'
-  },
-  series: [
-    {
-      name: 'Access From',
-      type: 'pie',
-      radius: ['40%', '70%'],
-      avoidLabelOverlap: false,
-      itemStyle: {
-        borderRadius: 10,
-        borderColor: '#fff',
-        borderWidth: 2
-      },
-      label: {
-        show: false,
-        position: 'center'
-      },
-      emphasis: {
-        label: {
-          show: true,
-          fontSize: 40,
-          fontWeight: 'bold'
-        }
-      },
-      labelLine: {
-        show: false
-      },
-      data: [
-        { value: 1048, name: 'Search Engine' },
-        { value: 735, name: 'Direct' },
-        { value: 580, name: 'Email' },
-        { value: 484, name: 'Union Ads' },
-        { value: 300, name: 'Video Ads' }
-      ]
-    }
-  ]
-}
-
-const barChartOptions: EChartsOption = {
-  xAxis: {
-    type: 'category',
-    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-  },
-  yAxis: {
-    type: 'value'
-  },
-  series: [
-    {
-      data: [120, 200, 150, 80, 70, 110, 130],
-      type: 'bar'
-    }
-  ]
-}
-
-const isPie = ref(false)
-
-const chartOptions = computed(() => {
-  console.log(isPie.value)
-  return isPie.value ? pieChartOptions : barChartOptions
-})
+const { updateChartData, chartOptions } = useTableChart(
+  AllApi.userBehaviorPieChart,
+  queryFormData,
+  filterInfo,
+  chartNeedFields,
+  isPie
+)
 </script>
 
 <template>
@@ -399,33 +194,27 @@ const chartOptions = computed(() => {
       <HeaderCard :title="headerCardInfo.title"></HeaderCard>
     </div>
     <div class="tableBox">
-      <Table
-        ref="behaviourTable"
-        :request-config="requestConfig"
-        :query-info="filterInfo"
-        :pagination-config="pagingConfig"
-        :table-fields-info="tableFieldsInfo"
-        :open-remote-query="true"
-        :open-page-query="true"
-        :open-filter-query="true"
-        :tools="tableToolsConfig"
-        :need-total="true"
-        :total-func="getSummary"
-      >
-        <template #chart>
-          <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>
-            <div class="chartDisplay">
-              <PieBorderRadius :options="chartOptions"></PieBorderRadius>
-            </div>
+      <div class="filterContainer">
+        <TableFilterForm
+          v-model:queryFormData="queryFormData"
+          :queryInfo="filterInfo"
+          @query="updateChartData"
+          ref="filterFormRef"
+        ></TableFilterForm>
+      </div>
+      <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>
+          <div class="chartDisplay">
+            <PieBorderRadius :options="chartOptions"></PieBorderRadius>
           </div>
-        </template>
-      </Table>
+        </div>
+      </div>
     </div>
   </div>
 </template>