|
@@ -1,15 +1,26 @@
|
|
|
<script setup lang="ts">
|
|
|
import type { ResponseInfo } from '@/types/axios'
|
|
|
-import type { AllOptionsVal } from '@/types/HomeTypes'
|
|
|
-import type { DateOptionVal, overviewAdvertisingData } from '@/types/HomeTypes'
|
|
|
+
|
|
|
+import {
|
|
|
+ type BaseOption,
|
|
|
+ type CSelectLegend,
|
|
|
+ CSelectType,
|
|
|
+ type DateOptionVal,
|
|
|
+ type overviewAdvertisingData,
|
|
|
+} from '@/types/HomeTypes'
|
|
|
import type { BaseMenu } from '@/types/Promotion/Menu'
|
|
|
import type {
|
|
|
HomeAnalysisChartData,
|
|
|
LegendInfo,
|
|
|
+ ProductAnalysisRes,
|
|
|
+ ProjectRes,
|
|
|
} from '@/types/echarts/homeAnalysisChart'
|
|
|
-import type { AnalysisSelectInfo } from '@/hooks/HomeSelect/useAnalysisSelect'
|
|
|
+import type {
|
|
|
+ AnalysisSelectInfo,
|
|
|
+ LegendSelectInfo,
|
|
|
+} from '@/hooks/HomeSelect/useAnalysisSelect'
|
|
|
|
|
|
-import { computed, reactive, ref, watch } from 'vue'
|
|
|
+import { computed, reactive, ref } from 'vue'
|
|
|
import { useRequest } from '@/hooks/useRequest'
|
|
|
import { useHomeSelect } from '@/hooks/HomeSelect/useHomeSelect'
|
|
|
|
|
@@ -17,20 +28,72 @@ import Menu from '@/components/navigation/Menu.vue'
|
|
|
import CSelect from '@/components/form/CSelect.vue'
|
|
|
import HomeAnalysisLine from '@/components/echarts/HomeAnalysisLine.vue'
|
|
|
import axiosInstance from '@/utils/axios/axiosInstance'
|
|
|
-import AnimationNumber from '@/components/animationNumber/AnimationNumber.vue'
|
|
|
|
|
|
import '@/assets/css/statistic.css'
|
|
|
import type { AxiosRequestConfig } from 'axios'
|
|
|
+import StatisticCard from '@/components/statisticCard/StatisticCard.vue'
|
|
|
+import { convertToTimestampInSeconds } from '@/utils/common' // 主页所有数据的返回格式
|
|
|
+
|
|
|
+// 主页所有数据的返回格式
|
|
|
+interface HomeResInfo {
|
|
|
+ overview: {
|
|
|
+ data: overviewAdvertisingData[]
|
|
|
+ indicator: Array<BaseOption>
|
|
|
+ media: Array<BaseOption>
|
|
|
+ }
|
|
|
+ product: {}
|
|
|
+ project: {}
|
|
|
+}
|
|
|
|
|
|
const { AllApi } = useRequest()
|
|
|
|
|
|
-const {
|
|
|
- overviewSelectInfo,
|
|
|
- projctAnalySeleInfo,
|
|
|
- productAnalySeleInfo,
|
|
|
- legendSelectInfo,
|
|
|
- leftToolsSelectInfo,
|
|
|
-} = useHomeSelect()
|
|
|
+const { overviewSelectInfo, projctAnalySeleInfo, productAnalySeleInfo } =
|
|
|
+ useHomeSelect()
|
|
|
+
|
|
|
+let chartReqcontroller: AbortController | null = null // 请求控制器,用于取消请求
|
|
|
+let chartReqList: Array<string> = [] // 表格的请求列表,暂时只存了url,可以存其他的
|
|
|
+
|
|
|
+const createDateRange = (day: number): [Date, Date] => {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * day)
|
|
|
+ return [start, end]
|
|
|
+}
|
|
|
+
|
|
|
+// 快速选择日期
|
|
|
+const shortcuts = [
|
|
|
+ {
|
|
|
+ text: '上一周',
|
|
|
+ value: () => createDateRange(7),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '上个月',
|
|
|
+ value: () => createDateRange(30),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '近三个月',
|
|
|
+ value: () => createDateRange(90),
|
|
|
+ },
|
|
|
+]
|
|
|
+// 选择的日期
|
|
|
+const selectDate = ref<[Date, Date]>(shortcuts[0].value())
|
|
|
+
|
|
|
+/**
|
|
|
+ * 禁用日期
|
|
|
+ * @param time 时间
|
|
|
+ */
|
|
|
+const disableDate = (time: Date) => {
|
|
|
+ return time.getTime() > Date.now()
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 日期变化,重新请求总览数据
|
|
|
+ */
|
|
|
+const dateChange = () => {
|
|
|
+ // changeDateRange(val)
|
|
|
+
|
|
|
+ getOverviewData()
|
|
|
+}
|
|
|
|
|
|
// 总览数据的自定义指标最多选择个数
|
|
|
const maxSelectOverviewIndicator = 6
|
|
@@ -66,7 +129,9 @@ const overviewDataConfig: {
|
|
|
} = {
|
|
|
url: AllApi.mockOverview,
|
|
|
config: {
|
|
|
- params: {},
|
|
|
+ params: {
|
|
|
+ overview: {},
|
|
|
+ },
|
|
|
},
|
|
|
}
|
|
|
|
|
@@ -102,7 +167,16 @@ const chartLoading = ref<boolean>(true)
|
|
|
// 图表数据
|
|
|
const chartData = reactive<Array<HomeAnalysisChartData>>([])
|
|
|
|
|
|
+// legend信息
|
|
|
+const legendInfo: {
|
|
|
+ [key: string]: LegendSelectInfo
|
|
|
+} = reactive({
|
|
|
+ projAnalysis: {},
|
|
|
+ productAnalysis: {},
|
|
|
+})
|
|
|
+
|
|
|
/**
|
|
|
+ * @deprecated
|
|
|
* @description: (暂时废弃,因为会导致更换指标的时候,数组的变化导致数据重新执行动画)
|
|
|
* 根据已选择自定义指标动态的加入广告数据概况
|
|
|
* @return {*}
|
|
@@ -149,14 +223,58 @@ const changeChartSelect = () => {
|
|
|
* @param {*} newMenu 新的菜单值
|
|
|
* @return {*}
|
|
|
*/
|
|
|
-const analysisiMenuChange = (newMenu: string) => {
|
|
|
+const analysisMenuChange = (newMenu: string) => {
|
|
|
analysisiMenuActive.value = newMenu
|
|
|
|
|
|
getChartData()
|
|
|
}
|
|
|
|
|
|
-let chartReqcontroller: AbortController | null = null // 请求控制器,用于取消请求
|
|
|
-let chartReqList: Array<string> = [] // 表格的请求列表,暂时只存了url,可以存其他的
|
|
|
+/**
|
|
|
+ * 根据返回的legend创建legend信息
|
|
|
+ * @param data
|
|
|
+ */
|
|
|
+const createLegendInfo = (data: ProjectRes | ProductAnalysisRes) => {
|
|
|
+ const legends = data.legend
|
|
|
+ // 2种颜色
|
|
|
+ const colorList = [
|
|
|
+ '#00e070',
|
|
|
+ '#1495eb',
|
|
|
+ '#993333', // Dark Red
|
|
|
+ '#FFD700', // Bright Yellow
|
|
|
+ '#FF00FF', // Magenta
|
|
|
+ '#FFA500', // Orange
|
|
|
+ '#800080', // Dark Purple
|
|
|
+ '#A52A2A', // Brown
|
|
|
+ '#FF4500', // Orange Red
|
|
|
+ '#FF6347', // Tomato
|
|
|
+ '#B22222', // Firebrick
|
|
|
+ '#FF1493', // Deep Pink
|
|
|
+ ]
|
|
|
+ let count = 0
|
|
|
+ for (const [k, v] of Object.entries(legends)) {
|
|
|
+ const legendItem: CSelectLegend = {
|
|
|
+ type: CSelectType.RadioLegend,
|
|
|
+ name: k,
|
|
|
+ value: v[0].value,
|
|
|
+ label: v[0].label,
|
|
|
+ options: v,
|
|
|
+ color: colorList[count++ % colorList.length],
|
|
|
+ }
|
|
|
+ legendInfo[analysisiMenuActive.value][k] = legendItem
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 根据返回的数据解析出图表数据
|
|
|
+ * @param res
|
|
|
+ */
|
|
|
+const analysisResChartData = (res: ResponseInfo) => {
|
|
|
+ const resInfo =
|
|
|
+ analysisiMenuActive.value === 'projAnalysis'
|
|
|
+ ? (res.data as ProjectRes)
|
|
|
+ : (res.data as ProductAnalysisRes)
|
|
|
+ return resInfo
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* @description: 获取图表数据
|
|
@@ -172,8 +290,10 @@ const getChartData = async () => {
|
|
|
config.signal = chartReqcontroller.signal
|
|
|
chartLoading.value = true
|
|
|
const res = (await axiosInstance.get(url, config)) as ResponseInfo
|
|
|
+ const data = analysisResChartData(res) // 解析出图表数据
|
|
|
+ createLegendInfo(data) // 创建对应的legend信息
|
|
|
if (res.code !== 0) throw new Error('获取图表数据失败')
|
|
|
- chartData.splice(0, chartData.length, ...res.data)
|
|
|
+ chartData.splice(0, chartData.length, ...data.data)
|
|
|
} catch (err) {
|
|
|
console.log(err)
|
|
|
} finally {
|
|
@@ -190,65 +310,38 @@ const getChartData = async () => {
|
|
|
*/
|
|
|
const analysisLegendInfo = computed<Array<LegendInfo>>(() => {
|
|
|
let result: Array<LegendInfo> = []
|
|
|
- for (let [_k, v] of Object.entries(
|
|
|
- legendSelectInfo[analysisiMenuActive.value],
|
|
|
- )) {
|
|
|
+ for (let [_k, v] of Object.entries(legendInfo[analysisiMenuActive.value])) {
|
|
|
result.push({
|
|
|
value: v.value,
|
|
|
- color: v.color!,
|
|
|
- cnName: v.CnName,
|
|
|
+ color: v.color,
|
|
|
+ cnName: v.label,
|
|
|
})
|
|
|
}
|
|
|
return result
|
|
|
})
|
|
|
|
|
|
-// const lengendInfo = reactive<Array<LegendInfo>>([])
|
|
|
-
|
|
|
-// const initLegend = ()=>{
|
|
|
-// for (let [_k, v] of Object.entries(
|
|
|
-// legendSelectInfo[analysisiMenuActive.value],
|
|
|
-// )) {
|
|
|
-// lengendInfo.push({
|
|
|
-// value: v.value,
|
|
|
-// color: v.color!,
|
|
|
-// cnName: v.CnName,
|
|
|
-// })
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// initLegend();
|
|
|
-
|
|
|
-// const changeLengend = (newval: any, name: string) => {
|
|
|
-// console.log(newval, name)
|
|
|
-// console.log(legendSelectInfo)
|
|
|
-// console.log(analysisLegendInfo.value)
|
|
|
-// if(legendSelectInfo[analysisiMenuActive.value])
|
|
|
-// }
|
|
|
-
|
|
|
/**
|
|
|
* @description: 创建新的自定义指标选择框的值
|
|
|
* @param {*} data 返回的数据
|
|
|
* @return {*}
|
|
|
*/
|
|
|
-const createIndicatorSelectInfo = (data: Array<overviewAdvertisingData>) => {
|
|
|
- let options = data.map(item => {
|
|
|
- return {
|
|
|
- value: item.name,
|
|
|
- label: item.title,
|
|
|
- }
|
|
|
- })
|
|
|
- // 形成新的值,也就是把所有的name都取出来
|
|
|
- let values = data.slice(0, maxSelectOverviewIndicator).map(item => item.name)
|
|
|
-
|
|
|
- // 更新自定义指标选项
|
|
|
- let overviewOptions = overviewSelectInfo.customIndicatorSelect.options
|
|
|
- overviewOptions.splice(0, overviewOptions.length, ...options)
|
|
|
-
|
|
|
- // 更新值
|
|
|
+const createIndicatorSelectInfo = (options: BaseOption[]) => {
|
|
|
+ let values = options
|
|
|
+ .slice(0, maxSelectOverviewIndicator)
|
|
|
+ .map(item => item.value)
|
|
|
+ overviewSelectInfo.customIndicatorSelect.options = options
|
|
|
let overviewValues = overviewSelectInfo.customIndicatorSelect.value
|
|
|
overviewValues.splice(0, overviewValues.length, ...values)
|
|
|
}
|
|
|
|
|
|
+const createMediaSelectInfo = (options: BaseOption[]) => {
|
|
|
+ overviewSelectInfo.mediaSelect.options = options
|
|
|
+ const originValue = overviewSelectInfo.mediaSelect.value
|
|
|
+ if (!options.find(item => item.value === originValue)) {
|
|
|
+ overviewSelectInfo.mediaSelect.value = options[0].value
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* @description: 创建广告数据概况请求参数
|
|
|
* @return {*}
|
|
@@ -256,18 +349,17 @@ const createIndicatorSelectInfo = (data: Array<overviewAdvertisingData>) => {
|
|
|
const createOverviewReqParams = () => {
|
|
|
let result: { [key: string]: any } = {}
|
|
|
for (let [k, v] of Object.entries(overviewSelectInfo)) {
|
|
|
- // 除了自定义指标,另外两个选择框的值就作为请求参数
|
|
|
+ // 将媒体字段的值加入
|
|
|
if (k !== 'customIndicatorSelect') {
|
|
|
- if (v.name === 'date') {
|
|
|
- // date选择框需要单独处理一下
|
|
|
- result['startTime'] = v.value.startTime
|
|
|
- result['endTime'] = v.value.endTime
|
|
|
- } else {
|
|
|
- result[v.name] = v.value
|
|
|
- }
|
|
|
+ result[v.name] = v.value
|
|
|
}
|
|
|
}
|
|
|
- overviewDataConfig.config.params = result
|
|
|
+ // indicator暂时不传
|
|
|
+ result['indicator'] = []
|
|
|
+ // 转秒级时间戳
|
|
|
+ result['start_time'] = convertToTimestampInSeconds(selectDate.value[0])
|
|
|
+ result['end_time'] = convertToTimestampInSeconds(selectDate.value[0])
|
|
|
+ overviewDataConfig.config.params.overview = result
|
|
|
}
|
|
|
|
|
|
let overviewReqcontroller: AbortController | null = null // 请求控制器,用于取消请求
|
|
@@ -285,12 +377,16 @@ const getOverviewData = async () => {
|
|
|
overviewReqList.push(url) // 添加到请求列表
|
|
|
overviewReqcontroller && overviewReqcontroller.abort() // 取消上一次请求
|
|
|
overviewReqcontroller = new AbortController()
|
|
|
- config.signal = overviewReqcontroller.signal
|
|
|
+ // config.signal = overviewReqcontroller.signal
|
|
|
|
|
|
- let res = (await axiosInstance.get(url, config)) as ResponseInfo
|
|
|
+ let res = (await axiosInstance.post(url, config.params)) as ResponseInfo
|
|
|
if (res.code !== 0) throw new Error('获取广告数据概况失败')
|
|
|
- let data = res.data as Array<overviewAdvertisingData>
|
|
|
- createIndicatorSelectInfo(data) // 根据返回的数据去更新自定义指标选项和值
|
|
|
+ const resData = res.data as HomeResInfo
|
|
|
+ let data = resData.overview.data
|
|
|
+ const indicator = resData.overview.indicator
|
|
|
+ const media = resData.overview.media
|
|
|
+ createIndicatorSelectInfo(indicator) // 根据返回的数据去更新自定义指标选项和值
|
|
|
+ createMediaSelectInfo(media)
|
|
|
overviewAdvertisingData.splice(0, overviewAdvertisingData.length, ...data)
|
|
|
} catch (err: any) {
|
|
|
console.log(err)
|
|
@@ -314,13 +410,16 @@ const getOverviewData = async () => {
|
|
|
const changeOverviewSelect = (_newSelect: any, name: string) => {
|
|
|
if (name === 'customIndicator') {
|
|
|
// console.log(_newSelect)
|
|
|
-
|
|
|
return
|
|
|
}
|
|
|
|
|
|
getOverviewData()
|
|
|
}
|
|
|
-import StatisticCard from '@/components/statisticCard/StatisticCard.vue'
|
|
|
+
|
|
|
+const changeLegend = () => {
|
|
|
+ getChartData()
|
|
|
+}
|
|
|
+
|
|
|
getChartData()
|
|
|
getOverviewData()
|
|
|
</script>
|
|
@@ -333,7 +432,26 @@ getOverviewData()
|
|
|
<span class="overviewTitle">广告数据概况</span>
|
|
|
<span class="getDetail">查看详情</span>
|
|
|
</div>
|
|
|
- <div class="overviewFilterBox">
|
|
|
+ <div
|
|
|
+ class="overviewFilterBox"
|
|
|
+ style="display: flex; align-items: center"
|
|
|
+ >
|
|
|
+ <div style="margin-right: 10px">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="selectDate"
|
|
|
+ :disabled-date="disableDate"
|
|
|
+ :unlink-panels="false"
|
|
|
+ @change="dateChange"
|
|
|
+ type="daterange"
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="Start date"
|
|
|
+ end-placeholder="End date"
|
|
|
+ :shortcuts="shortcuts"
|
|
|
+ :size="'default'"
|
|
|
+ >
|
|
|
+ </el-date-picker>
|
|
|
+ </div>
|
|
|
+
|
|
|
<CSelect
|
|
|
:multiple-limit="maxSelectOverviewIndicator"
|
|
|
size="default"
|
|
@@ -388,7 +506,7 @@ getOverviewData()
|
|
|
mode="horizontal"
|
|
|
default-active="projAnalysis"
|
|
|
:menu-list="dataAnalysisMenuList"
|
|
|
- @active-change="analysisiMenuChange"
|
|
|
+ @active-change="analysisMenuChange"
|
|
|
></Menu>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -402,23 +520,13 @@ getOverviewData()
|
|
|
></CSelect>
|
|
|
</div>
|
|
|
<div class="chartBoxTools">
|
|
|
- <div
|
|
|
- class="dataTools"
|
|
|
- v-if="analysisiMenuActive === 'productAnalysis'"
|
|
|
- >
|
|
|
- <div class="dataToolItem"></div>
|
|
|
- <div class="dataToolItem">
|
|
|
- <CSelect
|
|
|
- class="dataSource"
|
|
|
- :select-info="leftToolsSelectInfo"
|
|
|
- ></CSelect>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <!-- :select-info="legendSelectInfo[analysisiMenuActive]"-->
|
|
|
<div class="legendTools">
|
|
|
<CSelect
|
|
|
:select-style="`width:100px;margin-right:15px;`"
|
|
|
size="small"
|
|
|
- :select-info="legendSelectInfo[analysisiMenuActive]"
|
|
|
+ :select-info="legendInfo[analysisiMenuActive]"
|
|
|
+ @change-select="changeLegend"
|
|
|
></CSelect>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -443,6 +551,7 @@ getOverviewData()
|
|
|
.homeContainer {
|
|
|
padding-top: 3vh;
|
|
|
}
|
|
|
+
|
|
|
.advertisingDataOverview {
|
|
|
width: 1320px;
|
|
|
margin: 0 auto;
|