|
@@ -0,0 +1,479 @@
|
|
|
+import {
|
|
|
+ defineComponent,
|
|
|
+ nextTick,
|
|
|
+ onMounted,
|
|
|
+ PropType,
|
|
|
+ reactive,
|
|
|
+ ref,
|
|
|
+ shallowReactive,
|
|
|
+ watch
|
|
|
+} 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 * 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 { Button, DatetimePicker, Popup } from 'vant'
|
|
|
+import { formatterDatePicker } from '@/helpers/utils'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { getTimeRange, TIME_TYPE } from '../../home-statistics'
|
|
|
+
|
|
|
+// 注册必须的组件
|
|
|
+echarts.use([
|
|
|
+ TitleComponent,
|
|
|
+ TooltipComponent,
|
|
|
+ GridComponent,
|
|
|
+ DatasetComponent,
|
|
|
+ // TransformComponent,
|
|
|
+ LabelLayout,
|
|
|
+ // UniversalTransition,
|
|
|
+ CanvasRenderer,
|
|
|
+ // PieChart,
|
|
|
+ ToolboxComponent,
|
|
|
+ LegendComponent,
|
|
|
+ DataZoomComponent,
|
|
|
+ LineChart
|
|
|
+])
|
|
|
+
|
|
|
+const lineChartOption = (xAxisData: any, seriesData: any) => {
|
|
|
+ return {
|
|
|
+ title: {
|
|
|
+ text: '单位:次',
|
|
|
+ textStyle: {
|
|
|
+ color: '#777777',
|
|
|
+ fontSize: 13,
|
|
|
+ fontWeight: 400
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: { show: false },
|
|
|
+ emphasis: { lineStyle: { width: 2 } },
|
|
|
+ xAxis: {
|
|
|
+ boundaryGap: false,
|
|
|
+ data: xAxisData,
|
|
|
+ type: 'category',
|
|
|
+ axisLine: { lineStyle: { color: '#8C8C8C' } },
|
|
|
+ lineStyle: { color: '#F2F2F2' }
|
|
|
+ },
|
|
|
+ color: [
|
|
|
+ '#2DC7AA',
|
|
|
+ '#FF6079'
|
|
|
+ // '#2DC7AA',
|
|
|
+ // '#FF602C',
|
|
|
+ // '#91DD1C',
|
|
|
+ // '#FFA92C',
|
|
|
+ // '#BE7E2E',
|
|
|
+ // '#1C96DD',
|
|
|
+ // '#D22CFF',
|
|
|
+ // '#FF3C3C',
|
|
|
+ // '#1AEE3E',
|
|
|
+ // '#00c9ff'
|
|
|
+ ],
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ lineStyle: { width: 1 },
|
|
|
+ data: seriesData[0],
|
|
|
+ symbol: 'circle',
|
|
|
+ name: '浏览次数',
|
|
|
+ type: 'line',
|
|
|
+ emphasis: { lineStyle: { width: 1 } }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ lineStyle: { width: 1 },
|
|
|
+ data: seriesData[1],
|
|
|
+ symbol: 'circle',
|
|
|
+ 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: 1 } }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ grid: {
|
|
|
+ bottom: '3%',
|
|
|
+ containLabel: true,
|
|
|
+ left: '3%',
|
|
|
+ right: '5%',
|
|
|
+ top: '40'
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ confine: true,
|
|
|
+ formatter: function (params: any) {
|
|
|
+ return params[0].name
|
|
|
+ },
|
|
|
+ backgroundColor: '#FF6079',
|
|
|
+ borderWidth: 0,
|
|
|
+ borderRadius: 24,
|
|
|
+ padding: [1, 4],
|
|
|
+ textStyle: {
|
|
|
+ color: '#FFFFFF',
|
|
|
+ fontSize: 12
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ splitLine: {
|
|
|
+ axisLine: { lineStyle: { color: '#8C8C8C' } },
|
|
|
+ lineStyle: { color: ['#f2f2f2'], type: 'dashed' }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ dataZoom: [{ type: 'inside', throttle: 100 }],
|
|
|
+ toolbox: { feature: { saveAsImage: { show: false } } }
|
|
|
+ }
|
|
|
+}
|
|
|
+export default defineComponent({
|
|
|
+ name: 'eChats-model',
|
|
|
+ props: {
|
|
|
+ obj: {
|
|
|
+ type: Object,
|
|
|
+ default: () => ({})
|
|
|
+ },
|
|
|
+ currentType: {
|
|
|
+ type: String as PropType<TIME_TYPE>,
|
|
|
+ default: 'MONTH'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ emits: ['confirm'],
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const chartId = 'eChart' + Date.now()
|
|
|
+ const statisticCounts = ref({
|
|
|
+ browseCount: 0,
|
|
|
+ buyCount: 0
|
|
|
+ })
|
|
|
+ const currentType = ref<TIME_TYPE>(props.currentType)
|
|
|
+ const timeRange = getTimeRange(currentType.value)
|
|
|
+ const searchStatus = ref(false)
|
|
|
+ const forms = reactive({
|
|
|
+ loading: false,
|
|
|
+ dataShow: true,
|
|
|
+ subjectId: '' as any, // 选择的声部
|
|
|
+ subjectList: [] as any,
|
|
|
+ startTimeStatus: false,
|
|
|
+ endTimeMinDate: new Date(),
|
|
|
+ endTimeMaxDate: dayjs(new Date()).add(1, 'year').toDate(),
|
|
|
+ endTimeStatus: false,
|
|
|
+ startTime: new Date(timeRange?.startTime || ''),
|
|
|
+ startTimeStr: timeRange?.startTime || '',
|
|
|
+ endTime: new Date(timeRange?.endTime || ''),
|
|
|
+ endTimeStr: timeRange?.endTime || ''
|
|
|
+ })
|
|
|
+ const showTimeRange = shallowReactive({
|
|
|
+ startTime: timeRange?.startTime || '',
|
|
|
+ endTime: timeRange?.endTime || ''
|
|
|
+ })
|
|
|
+ let myChart: echarts.ECharts
|
|
|
+
|
|
|
+ const _initData = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ statisticCounts.value.browseCount = props.obj.browseCount || 0
|
|
|
+ statisticCounts.value.buyCount = props.obj.buyCount || 0
|
|
|
+ myChart.clear()
|
|
|
+ lineChartOption &&
|
|
|
+ myChart.setOption(
|
|
|
+ lineChartOption(props.obj.xAxisData, props.obj.yAxisData)
|
|
|
+ )
|
|
|
+ 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]
|
|
|
+ statisticCounts.value = {
|
|
|
+ browseCount,
|
|
|
+ buyCount
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ nextTick(() => {
|
|
|
+ myChart = echarts.init(document.getElementById(chartId) as HTMLDivElement)
|
|
|
+ _initData()
|
|
|
+ })
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => props.obj,
|
|
|
+ () => {
|
|
|
+ _initData()
|
|
|
+ },
|
|
|
+ {
|
|
|
+ deep: true
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => props.currentType,
|
|
|
+ () => {
|
|
|
+ currentType.value = props.currentType
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ const onChangeTime = (type: TIME_TYPE) => {
|
|
|
+ if (currentType.value === type) return
|
|
|
+ currentType.value = type
|
|
|
+ resetTime(type)
|
|
|
+ // emit('confirm', currentType.value)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化
|
|
|
+ const resetTime = (type: TIME_TYPE) => {
|
|
|
+ const timeRang = getTimeRange(type)
|
|
|
+
|
|
|
+ forms.startTime = new Date(timeRang?.startTime || '')
|
|
|
+ forms.startTimeStr = timeRang?.startTime || ''
|
|
|
+ forms.endTimeMinDate = dayjs(timeRang?.startTime || '').toDate()
|
|
|
+ forms.endTimeMaxDate = dayjs(timeRang?.startTime || '')
|
|
|
+ .add(1, 'year')
|
|
|
+ .toDate()
|
|
|
+ forms.endTime = new Date(timeRang?.endTime || '')
|
|
|
+ forms.endTimeStr = timeRang?.endTime || ''
|
|
|
+ }
|
|
|
+
|
|
|
+ return () => (
|
|
|
+ <div class={styles.eChartSection}>
|
|
|
+ <div class={styles.homeHead}>
|
|
|
+ <div class={styles.title}>
|
|
|
+ <img src={icon1} />
|
|
|
+ <span>浏览/购买</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class={styles.right}>
|
|
|
+ <div
|
|
|
+ class={[
|
|
|
+ styles.showItem,
|
|
|
+ searchStatus.value && styles.showItemActive
|
|
|
+ ]}
|
|
|
+ onClick={() => (searchStatus.value = true)}
|
|
|
+ >
|
|
|
+ <span>
|
|
|
+ {showTimeRange.startTime}~{showTimeRange.endTime}
|
|
|
+ </span>
|
|
|
+ <img src={searchStatus.value ? iconArrow11 : iconArrow1} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={styles.eChartTitle}>
|
|
|
+ <div class={styles.left}>
|
|
|
+ <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 class={styles.eChart}>
|
|
|
+ <div id={chartId} style="width: 100%; height: 100%;"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <Popup
|
|
|
+ v-model:show={searchStatus.value}
|
|
|
+ closeable
|
|
|
+ round
|
|
|
+ position="bottom"
|
|
|
+ teleport="body"
|
|
|
+ >
|
|
|
+ <div class={styles.popupContainer}>
|
|
|
+ <div class={styles.popupTitle}>筛选</div>
|
|
|
+
|
|
|
+ <div class={styles.popupSearchList}>
|
|
|
+ <div class={styles.popupSection}>
|
|
|
+ <div class={styles.title}>
|
|
|
+ <span>时间</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class={styles.timeCount}>
|
|
|
+ <p
|
|
|
+ onClick={() => onChangeTime('MONTH')}
|
|
|
+ class={currentType.value === 'MONTH' ? styles.active : ''}
|
|
|
+ >
|
|
|
+ 本月
|
|
|
+ </p>
|
|
|
+ <p
|
|
|
+ onClick={() => onChangeTime('THREE_MONTH')}
|
|
|
+ class={
|
|
|
+ currentType.value === 'THREE_MONTH' ? styles.active : ''
|
|
|
+ }
|
|
|
+ >
|
|
|
+ 近三个月
|
|
|
+ </p>
|
|
|
+ <p
|
|
|
+ onClick={() => onChangeTime('HALF_YEAR')}
|
|
|
+ class={
|
|
|
+ currentType.value === 'HALF_YEAR' ? styles.active : ''
|
|
|
+ }
|
|
|
+ >
|
|
|
+ 近半年
|
|
|
+ </p>
|
|
|
+ <p
|
|
|
+ onClick={() => onChangeTime('YEAR')}
|
|
|
+ class={currentType.value === 'YEAR' ? styles.active : ''}
|
|
|
+ >
|
|
|
+ 近一年
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class={styles.timeRang}>
|
|
|
+ <p
|
|
|
+ class={[
|
|
|
+ styles.timeInput,
|
|
|
+ forms.startTimeStr && styles.hasValue
|
|
|
+ ]}
|
|
|
+ onClick={() => (forms.startTimeStatus = true)}
|
|
|
+ >
|
|
|
+ {forms.startTimeStr || '起始时间'}
|
|
|
+ </p>
|
|
|
+ <p class={styles.timeUnit}></p>
|
|
|
+ <p
|
|
|
+ class={[
|
|
|
+ styles.timeInput,
|
|
|
+ forms.endTimeStr && styles.hasValue
|
|
|
+ ]}
|
|
|
+ onClick={() => (forms.endTimeStatus = true)}
|
|
|
+ >
|
|
|
+ {forms.endTimeStr || '终止时间'}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class={styles.popupBottom}>
|
|
|
+ <Button
|
|
|
+ round
|
|
|
+ block
|
|
|
+ type="default"
|
|
|
+ onClick={() => {
|
|
|
+ currentType.value = props.currentType
|
|
|
+ resetTime(props.currentType)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 重置
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ round
|
|
|
+ block
|
|
|
+ type="primary"
|
|
|
+ onClick={() => {
|
|
|
+ emit('confirm', {
|
|
|
+ startTime: forms.startTimeStr,
|
|
|
+ endTime: forms.endTimeStr
|
|
|
+ })
|
|
|
+ // 显示的时间
|
|
|
+ showTimeRange.startTime = forms.startTimeStr
|
|
|
+ showTimeRange.endTime = forms.endTimeStr
|
|
|
+ searchStatus.value = false
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 确定
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Popup>
|
|
|
+
|
|
|
+ {/* 开始日期 */}
|
|
|
+ <Popup
|
|
|
+ v-model:show={forms.startTimeStatus}
|
|
|
+ position="bottom"
|
|
|
+ round
|
|
|
+ class={'popupBottomSearch'}
|
|
|
+ teleport={'body'}
|
|
|
+ >
|
|
|
+ <DatetimePicker
|
|
|
+ v-model={forms.startTime}
|
|
|
+ type="date"
|
|
|
+ formatter={formatterDatePicker}
|
|
|
+ onCancel={() => (forms.startTimeStatus = false)}
|
|
|
+ onConfirm={(val: any) => {
|
|
|
+ forms.startTime = val
|
|
|
+ forms.startTimeStr = dayjs(val).format('YYYY-MM-DD')
|
|
|
+ forms.startTimeStatus = false
|
|
|
+ forms.endTime = null as any
|
|
|
+ forms.endTimeStr = ''
|
|
|
+ forms.endTimeMinDate = dayjs(val || new Date()).toDate()
|
|
|
+ forms.endTimeMaxDate = dayjs(val || new Date())
|
|
|
+ .add(1, 'year')
|
|
|
+ .toDate()
|
|
|
+ currentType.value = '' as any
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Popup>
|
|
|
+ {/* 结束日期 */}
|
|
|
+ <Popup
|
|
|
+ v-model:show={forms.endTimeStatus}
|
|
|
+ position="bottom"
|
|
|
+ round
|
|
|
+ class={'popupBottomSearch'}
|
|
|
+ teleport={'body'}
|
|
|
+ >
|
|
|
+ <DatetimePicker
|
|
|
+ v-model={forms.endTime}
|
|
|
+ type="date"
|
|
|
+ minDate={forms.endTimeMinDate}
|
|
|
+ maxDate={forms.endTimeMaxDate}
|
|
|
+ formatter={formatterDatePicker}
|
|
|
+ onCancel={() => (forms.endTimeStatus = false)}
|
|
|
+ onConfirm={(val: any) => {
|
|
|
+ forms.endTime = val
|
|
|
+ forms.endTimeStatus = false
|
|
|
+ forms.endTimeStr = dayjs(val).format('YYYY-MM-DD')
|
|
|
+ currentType.value = '' as any
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Popup>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+})
|