dataTendency.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. <template>
  2. <div v-loading="loading">
  3. <MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
  4. <div style="height: 350px;" ref="chartRef"></div>
  5. </div>
  6. </template>
  7. <script lang="ts" setup>
  8. import { ref,onMounted, onBeforeUnmount, Ref, unref, watch, computed } from 'vue'
  9. import * as echarts from 'echarts'
  10. import { spCampaignMetricsEnum } from '/@/views/adManage/utils/enum.js'
  11. import MetricsCards from '/@/components/MetricsCards/index.vue'
  12. import XEUtils from 'xe-utils'
  13. import { buildChartOpt, parseQueryParams } from '/@/views/adManage/utils/tools.js'
  14. defineOptions({
  15. name: "DataTendencyChart"
  16. })
  17. interface Props {
  18. fetchCard: Function,
  19. fetchLine: Function,
  20. fetchLineMonth?: Function,
  21. fetchLineWeek?: Function,
  22. query: {[key: string]: any},
  23. initMetric?: ShowMetric[],
  24. metricEnum?: {[key: string]: string}[]
  25. }
  26. const props = withDefaults(defineProps<Props>(), {
  27. initMetric: () => [
  28. {metric: 'Impression', color: '#0085ff', 'label': '曝光量'},
  29. {metric: 'Click', color: '#3fd4cf', 'label': '点击量'},
  30. {metric: 'Spend', color: '#ff9500', 'label': '花费'},
  31. ],
  32. metricEnum: () => spCampaignMetricsEnum
  33. })
  34. const metrics = ref(props.initMetric)
  35. // const shopInfo = useShopInfo()
  36. // const publicData = usePublicData()
  37. // const { dateRange } = storeToRefs(publicData)
  38. const metricsItems: Ref<MetricData[]> = ref([])
  39. let chartObj:any
  40. const chartRef = ref()
  41. const statDim = ref('day')
  42. const option: any = {
  43. dataset: {
  44. source: []
  45. },
  46. tooltip: {
  47. trigger: 'axis',
  48. axisPointer: {
  49. label: {
  50. backgroundColor: '#6a7985'
  51. }
  52. }
  53. },
  54. legend: {
  55. selected: {}, // 控制显隐
  56. show: false
  57. },
  58. grid: {
  59. top: 50, right: 150, bottom: 30, left: 65,
  60. },
  61. xAxis: {
  62. type: 'category'
  63. },
  64. yAxis: [
  65. {
  66. id: 0,
  67. type: 'value',
  68. name: '',
  69. splitLine: {
  70. show: true // 设置显示分割线
  71. },
  72. axisLine: {
  73. show: true,
  74. lineStyle: { color: '' }
  75. },
  76. show: true
  77. },
  78. {
  79. id: 1,
  80. type: 'value',
  81. name: '',
  82. position: 'right',
  83. splitLine: {
  84. show: false
  85. },
  86. axisLine: {
  87. show: true,
  88. lineStyle: {
  89. color: ''
  90. }
  91. },
  92. show: true
  93. },
  94. {
  95. id: 2,
  96. type: 'value',
  97. position: 'right',
  98. offset: 90,
  99. name: '',
  100. splitLine: {
  101. show: false
  102. },
  103. axisLine: {
  104. show: true,
  105. lineStyle: {
  106. color: ''
  107. }
  108. },
  109. show: true
  110. }
  111. ],
  112. series: [
  113. {
  114. id: 0,
  115. name: '',
  116. type: 'bar',
  117. encode: {
  118. x: 'Name',
  119. y: ''
  120. },
  121. barWidth: '20px',
  122. yAxisIndex: 0,
  123. itemStyle: {
  124. color: '',
  125. borderRadius: [6, 6, 6, 6],
  126. }
  127. },
  128. {
  129. id: 1,
  130. name: '',
  131. type: 'line',
  132. encode: {
  133. x: 'Name',
  134. y: ''
  135. },
  136. symbolSize: 6,
  137. symbol: 'circle',
  138. smooth: true,
  139. yAxisIndex: 1,
  140. itemStyle: {
  141. // color: '#ff9500',
  142. // borderColor: '#ff9500'
  143. },
  144. areaStyle: {
  145. // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  146. // { offset: 0, color: '#3fd4cf53' },
  147. // { offset: 1, color: '#3fd4cf03' },
  148. // ]),
  149. },
  150. emphasis: {
  151. focus:'series'
  152. }
  153. },
  154. {
  155. id: 2,
  156. name: '',
  157. type: 'line',
  158. encode: {
  159. x: 'Name',
  160. y: ''
  161. },
  162. symbolSize: 6,
  163. symbol: 'circle',
  164. smooth: true,
  165. yAxisIndex: 2,
  166. itemStyle: {},
  167. areaStyle: {},
  168. emphasis: {
  169. focus:'series'
  170. }
  171. }
  172. ]
  173. }
  174. const loading = ref(true)
  175. const queryParams = computed(() => parseQueryParams(props.query))
  176. onMounted(() => {
  177. getMetricsItems()
  178. addResize()
  179. // initLine()
  180. setTimeout(() => { initLine() }, 0)
  181. })
  182. onBeforeUnmount(() => {
  183. if(chartObj) {
  184. chartObj.dispose()
  185. chartObj = null
  186. }
  187. removeResize()
  188. })
  189. const initLine = async () => {
  190. chartObj = echarts.init(chartRef.value)
  191. const items = await getDataset()
  192. option.dataset.source = items
  193. XEUtils.arrayEach(option.series, (info:any, index) => {
  194. const color = metrics.value[index].color
  195. info.name = metrics.value[index].label
  196. info.encode.y = metrics.value[index].metric
  197. if (info.type === 'bar') {
  198. info.itemStyle.color = color
  199. } else {
  200. info.itemStyle = { color: color, borderColor: color }
  201. info.areaStyle = {
  202. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  203. { offset: 0, color: color + '53' },
  204. { offset: 1, color: color + '03' },
  205. ])
  206. }
  207. }
  208. })
  209. XEUtils.arrayEach(option.yAxis, (info:any, index) => {
  210. info.name = metrics.value[index].label
  211. info.axisLine.lineStyle.color = metrics.value[index].color
  212. })
  213. XEUtils.arrayEach(props.metricEnum, info => {
  214. option.legend.selected[info.label] = false
  215. })
  216. for(const info of metrics.value) {
  217. option.legend.selected[info.label] = true
  218. }
  219. // console.log(option)
  220. chartObj.setOption(option)
  221. loading.value = false
  222. }
  223. const getDataset = async () => {
  224. if (statDim.value === 'week') {
  225. if (props.fetchLineWeek) {
  226. const resp = await props.fetchLineWeek(queryParams.value)
  227. return resp.data
  228. }
  229. } else if (statDim.value === 'month') {
  230. if (props.fetchLineMonth) {
  231. const resp = await props.fetchLineMonth(queryParams.value)
  232. return resp.data
  233. }
  234. } else {
  235. const resp = await props.fetchLine(queryParams.value)
  236. return resp.data
  237. }
  238. }
  239. const getMetricsItems = async () => {
  240. const resp = await props.fetchCard(queryParams.value)
  241. const data = resp.data
  242. metricsItems.value.length = 0
  243. XEUtils.arrayEach(props.metricEnum, info => {
  244. const tmp:MetricData = {
  245. label: info.label,
  246. value: info.value,
  247. metricVal: data[info.value],
  248. gapVal: data[`gap${info.value}`],
  249. preVal: data[`prev${info.value}`],
  250. }
  251. metricsItems.value.push(tmp)
  252. })
  253. }
  254. const changeMetric = () => {
  255. const opt = buildChartOpt(option, metrics.value)
  256. chartObj.setOption(opt)
  257. }
  258. const changeStatDim = async () => {
  259. loading.value = true
  260. let source = await getDataset()
  261. if (source.length > 0) {
  262. chartObj.setOption({dataset: {source: source}})
  263. }
  264. loading.value = false
  265. }
  266. watch(
  267. props.query,
  268. async () => {
  269. // console.log("------watch-----queryParams", props.query)
  270. loading.value = true
  271. await getMetricsItems()
  272. const items = await getDataset()
  273. const opt = { dataset: { source: items } }
  274. chartObj.setOption(opt)
  275. loading.value = false
  276. }
  277. )
  278. const resizeChart = () => { chartObj.resize() }
  279. const addResize = () => { window.addEventListener('resize', resizeChart) }
  280. const removeResize = () => { window.removeEventListener('resize', resizeChart) }
  281. </script>
  282. <style scoped>
  283. .metrics-cards {
  284. display: flex;
  285. justify-content: space-between;
  286. align-items: flex-start;
  287. gap: 12px;
  288. width: 100%;
  289. }
  290. .chart-button-group {
  291. display: flex;
  292. justify-content: flex-end;
  293. margin-top: 5px;
  294. }
  295. </style>