import { computed, defineComponent, nextTick, ref } from 'vue' import styles from './index.module.less' import icon1 from '../images/icon1.png' import iconArrow from '../images/icon-arrow.png' import iconArrow1 from '../images/icon-arrow1.png' import iconArrow11 from '../images/icon-arrow1-1.png' import { Popover } from 'vant' import * as echarts from 'echarts/core' import { LineChart // LineSeriesOption } from 'echarts/charts' // import { PieChart } from 'echarts/charts' import { TitleComponent, // 组件类型的定义后缀都为 ComponentOption // TitleComponentOption, TooltipComponent, // TooltipComponentOption, GridComponent, // 数据集组件 DatasetComponent, // DatasetComponentOption, // 内置数据转换器组件 (filter, sort) // TransformComponent, LegendComponent, ToolboxComponent, DataZoomComponent } from 'echarts/components' import { LabelLayout } from 'echarts/features' import { CanvasRenderer } from 'echarts/renderers' import request from '@/helpers/request' import dayjs from 'dayjs' import { listenerMessage, postMessage } from '@/helpers/native-message' import { browser } from '@/helpers/utils' import { useRouter } from 'vue-router' // 注册必须的组件 echarts.use([ TitleComponent, TooltipComponent, GridComponent, DatasetComponent, // TransformComponent, LabelLayout, // UniversalTransition, CanvasRenderer, // PieChart, ToolboxComponent, LegendComponent, DataZoomComponent, LineChart ]) const lineChartOption = ( xAxisData: any, seriesData: any, countMaxCount = 5 ) => { return { // title: { // text: '单位:次', // textStyle: { // color: '#777777', // fontSize: 13, // fontWeight: 400 // } // }, legend: { show: false }, emphasis: { lineStyle: { width: 2 } }, xAxis: { data: xAxisData, type: 'category', axisLine: { lineStyle: { color: '#8C8C8C' } }, lineStyle: { color: '#F2F2F2' }, boundaryGap: true, axisLabel: { // formatter: function (value, index) { // // 第一个和最后一个标签分别居左和居右显示 // if (index === 0) { // return '{left|' + value + '}' // } else if (index === xAxisData.length - 1) { // return '{right|' + value + '}' // } else { // return value // } // }, // rich: { // left: { // align: 'left' // }, // right: { // align: 'right' // } // } // align: 'left' } }, color: [ '#2DC7AA', '#FF6079' // '#2DC7AA', // '#FF602C', // '#91DD1C', // '#FFA92C', // '#BE7E2E', // '#1C96DD', // '#D22CFF', // '#FF3C3C', // '#1AEE3E', // '#00c9ff' ], series: [ { lineStyle: { width: 2 }, data: seriesData[0], symbol: 'circle', showSymbol: false, name: '浏览次数', type: 'line', emphasis: { lineStyle: { width: 2 } } }, { lineStyle: { width: 2 }, data: seriesData[1], symbol: 'circle', showSymbol: false, name: '购买次数', type: 'line', areaStyle: { color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [ { offset: 0, color: 'rgba(255, 96, 121, 0.23)' // 0% 处的颜色 }, { offset: 1, // 100% 处的颜色 color: 'rgba(255, 96, 121, 0)' } ] } }, emphasis: { lineStyle: { width: 2 } } } ], grid: { bottom: '3%', containLabel: true, left: '4%', right: '4%', top: '20' }, tooltip: { trigger: 'axis', position: function (point) { // 固定在顶部 return [point[0], '10%'] }, confine: true, formatter: function (params: any) { return params[0].name }, backgroundColor: '#FF6079', borderWidth: 0, borderRadius: 24, padding: [1, 4], textStyle: { color: '#FFFFFF', fontSize: 12 }, extraCssText: 'z-index: 2', axisPointer: { lineStyle: { color: '#FF6079' } } }, yAxis: { type: 'value', splitLine: { axisLine: { lineStyle: { color: '#F2F2F2' } }, lineStyle: { color: ['#f2f2f2'], type: 'dashed' } }, splitNumber: countMaxCount }, dataZoom: [{ type: 'inside', throttle: 100 }] // toolbox: { feature: { saveAsImage: { show: false } } } } } export type TIME_TYPE = 'MONTH' | 'THREE_MONTH' | 'HALF_YEAR' | 'YEAR' /** 获取时间范围 */ export const getTimeRange = (type: TIME_TYPE) => { if (type === 'MONTH') { return { startTime: dayjs().format('YYYY-MM') + '-01', endTime: dayjs().format('YYYY-MM-DD') } } else if (type === 'THREE_MONTH') { return { startTime: dayjs().subtract(3, 'month').format('YYYY-MM-DD'), endTime: dayjs().format('YYYY-MM-DD') } } else if (type === 'HALF_YEAR') { return { startTime: dayjs().subtract(6, 'month').format('YYYY-MM-DD'), endTime: dayjs().format('YYYY-MM-DD') } } else if (type === 'YEAR') { return { startTime: dayjs().subtract(1, 'year').format('YYYY-MM-DD'), endTime: dayjs().format('YYYY-MM-DD') } } } export default defineComponent({ name: 'HomeStatistics', setup() { const homeStatisticsRef = ref() const router = useRouter() const popoverStatus = ref(false) const currentType = ref('MONTH') const timeRange = ref(getTimeRange(currentType.value)) const statisticCounts = ref({ browseCount: 0, buyCount: 0, time: '' }) let myChart: echarts.ECharts nextTick(() => { myChart = echarts.init( document.getElementById('eChart') as HTMLDivElement ) getDetail() const round = homeStatisticsRef.value?.getBoundingClientRect() postMessage({ api: 'homeStatisticsHeight', content: { height: round.height || 300 } }) }) const searchText = computed(() => { const template = { MONTH: '本月', THREE_MONTH: '近三个月', HALF_YEAR: '近半年', YEAR: '近一年' } return template[currentType.value] }) const getDetail = async () => { try { const { data } = await request.post( '/api-teacher/home/courseExposure', { data: timeRange.value } ) const buy = data.buy || [] const exposure = data.exposure || [] const xAxisData: string[] = [] const exposureList: number[] = [] let maxCount = 0 // 最大人数 - 用记设置练习人数分割线 exposure.forEach((item: any, index: number) => { xAxisData.push(item.date) exposureList.push(item.exposureNum) if (maxCount < (item.exposureNum || 0)) { maxCount = item.exposureNum } if (exposure.length - 1 === index) { statisticCounts.value.browseCount = item.exposureNum statisticCounts.value.time = item.date } }) const buyList: number[] = [] buy.forEach((item: any, index: number) => { buyList.push(item.exposureNum) if (buy.length - 1 === index) { statisticCounts.value.buyCount = item.exposureNum } }) const yAxisData = [exposureList, buyList] const countMaxCount = maxCount >= 5 ? 5 : Math.max(maxCount, 1) myChart.clear() lineChartOption && myChart.setOption( lineChartOption(xAxisData, yAxisData, countMaxCount), true ) myChart.on('highlight', function (params: any) { const batch = params.batch || [] const options: any = myChart.getOption() batch.forEach((item: any) => { const batchIndex = item.dataIndex const browseCount = options.series[0].data[batchIndex] const buyCount = options.series[1].data[batchIndex] const time = options.xAxis[0].data[batchIndex] statisticCounts.value = { browseCount, buyCount, time } }) }) // 可能出现多个时,图表同时渲染,提示有问题 setTimeout(() => { const lastIndex = yAxisData[0].length - 1 myChart.dispatchAction({ type: 'showTip', seriesIndex: 0, // 系列索引 dataIndex: lastIndex // 数据索引 }) }, 0) } catch { // } } const onChangeTime = (type: TIME_TYPE) => { popoverStatus.value = false if (currentType.value === type) return currentType.value = type timeRange.value = getTimeRange(currentType.value) getDetail() } /** 跳转详情 */ const goDetail = () => { if (browser().isApp) { postMessage({ api: 'openWebView', content: { url: `${location.origin}/teacher/#/home-statistics-detail?currentType=${currentType.value}`, orientation: 1, isHideTitle: false } }) } else { router.push({ path: '/home-statistics-detail', query: { currentType: currentType.value } }) } } // 监听页面返回 listenerMessage('webViewOnResume', () => { getDetail() }) return () => (
浏览/购买
详情
{statisticCounts.value.time && (
{statisticCounts.value.time}
)}
浏览次数 {statisticCounts.value.browseCount}次
购买次数 {statisticCounts.value.buyCount}次
单位:次
{{ default: () => (
onChangeTime('MONTH')} class={currentType.value === 'MONTH' ? 'active' : ''} > 本月 onChangeTime('THREE_MONTH')} class={ currentType.value === 'THREE_MONTH' ? 'active' : '' } > 近三个月 onChangeTime('HALF_YEAR')} class={ currentType.value === 'HALF_YEAR' ? 'active' : '' } > 近半年 onChangeTime('YEAR')} class={currentType.value === 'YEAR' ? 'active' : ''} > 近一年
), reference: () => (
{searchText.value}
) }}
) } })