|
|
@@ -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>
|