| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- 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<TIME_TYPE>('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 () => (
- <div class={styles.homeStatistics} ref={homeStatisticsRef}>
- <div class={styles.homeHead}>
- <div class={styles.title}>
- <img src={icon1} />
- <span>浏览/购买</span>
- </div>
- <div class={styles.more} onClick={goDetail}>
- <span>详情</span>
- <img src={iconArrow} />
- </div>
- </div>
- <div class={styles.eChartSection}>
- <div class={styles.eChartTitle}>
- <div class={styles.left}>
- {statisticCounts.value.time && (
- <div class={styles.time}>{statisticCounts.value.time}</div>
- )}
- <div class={styles.twoItem}>
- <div class={styles.item} style="--color: #2DC7AA">
- <span class={styles.line}></span>
- <span class={styles.text}>浏览次数</span>
- <span class={styles.num}>
- {statisticCounts.value.browseCount}次
- </span>
- </div>
- <div class={styles.item} style="--color: #FF6079">
- <span class={styles.line}></span>
- <span class={styles.text}>购买次数</span>
- <span class={styles.num}>
- {statisticCounts.value.buyCount}次
- </span>
- </div>
- </div>
- </div>
- </div>
- <div class={styles.unit}>
- <div class={styles.unitText}>单位:次</div>
- <div class={styles.right}>
- <Popover
- v-model:show={popoverStatus.value}
- showArrow={false}
- placement="bottom-end"
- >
- {{
- default: () => (
- <div class={'select-time'}>
- <span
- onClick={() => onChangeTime('MONTH')}
- class={currentType.value === 'MONTH' ? 'active' : ''}
- >
- 本月
- </span>
- <span
- onClick={() => onChangeTime('THREE_MONTH')}
- class={
- currentType.value === 'THREE_MONTH' ? 'active' : ''
- }
- >
- 近三个月
- </span>
- <span
- onClick={() => onChangeTime('HALF_YEAR')}
- class={
- currentType.value === 'HALF_YEAR' ? 'active' : ''
- }
- >
- 近半年
- </span>
- <span
- onClick={() => onChangeTime('YEAR')}
- class={currentType.value === 'YEAR' ? 'active' : ''}
- >
- 近一年
- </span>
- </div>
- ),
- reference: () => (
- <div
- class={[
- styles.showItem,
- popoverStatus.value && styles.showItemActive
- ]}
- >
- <span>{searchText.value}</span>
- <img
- src={popoverStatus.value ? iconArrow11 : iconArrow1}
- />
- </div>
- )
- }}
- </Popover>
- </div>
- </div>
- <div class={styles.eChart}>
- <div id="eChart" style="width: 100%; height: 100%;"></div>
- </div>
- </div>
- </div>
- )
- }
- })
|