|
@@ -0,0 +1,182 @@
|
|
|
|
+<template>
|
|
|
|
+ <Card title="用户活跃度" :loading="loading">
|
|
|
|
+ <template #extra>
|
|
|
|
+ <condition type="2" @change="Search" :typeShow="true" @expor="handleExport" />
|
|
|
|
+ <!-- <div class="condition">
|
|
|
|
+ <div class="selct" style="display: inline-block;">
|
|
|
|
+ <span style="margin-right:15px">颗粒度</span>
|
|
|
|
+ <Select
|
|
|
|
+ v-model:value="value"
|
|
|
|
+ style="width: 100px;margin-right:30px"
|
|
|
|
+ placeholder="请选择颗粒度"
|
|
|
|
+ :options="options"
|
|
|
|
+ :defaultValue="1"
|
|
|
|
+ @change="handleChange"
|
|
|
|
+ ></Select>
|
|
|
|
+ </div>
|
|
|
|
+ <a-button type="primary" @click="handleExport">导出</a-button>
|
|
|
|
+ </div> -->
|
|
|
|
+ </template>
|
|
|
|
+ <div ref="chartRef" :style="{ height, width }"></div>
|
|
|
|
+ </Card>
|
|
|
|
+</template>
|
|
|
|
+<script lang="ts">
|
|
|
|
+ import { basicProps } from './props';
|
|
|
|
+ // import { dateUtil } from '/@/utils/dateUtil';
|
|
|
|
+ import { Card, Select } from 'ant-design-vue';
|
|
|
|
+ import type { SelectProps } from 'ant-design-vue';
|
|
|
|
+</script>
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
+ import { ref, Ref, watch, onMounted, reactive } from 'vue';
|
|
|
|
+ import { userTrend } from '/@/api/statistics/index';
|
|
|
|
+ import condition from './condition.vue';
|
|
|
|
+ // import type { dataItemType } from './props';
|
|
|
|
+ import { useECharts } from '/@/hooks/web/useECharts';
|
|
|
|
+ import { exportElsxFile, } from '/@/utils/file/download';
|
|
|
|
+ const props = defineProps({
|
|
|
|
+ loading: Boolean,
|
|
|
|
+ ...basicProps,
|
|
|
|
+ });
|
|
|
|
+ const value = ref(1);
|
|
|
|
+ const SearchData = reactive({
|
|
|
|
+ startTime: '',
|
|
|
|
+ endTime: '',
|
|
|
|
+ dataType: 2,
|
|
|
|
+ type: 2,
|
|
|
|
+ });
|
|
|
|
+ const options = ref<SelectProps['options']>([
|
|
|
|
+ {
|
|
|
|
+ value: 1,
|
|
|
|
+ label: '日',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ value: 2,
|
|
|
|
+ label: '周',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ value: 3,
|
|
|
|
+ label: '月',
|
|
|
|
+ },
|
|
|
|
+ ]);
|
|
|
|
+ const viewStaticsData = ref<number[]>([]);
|
|
|
|
+ const shareStaticsData = ref<number[]>([]);
|
|
|
|
+ const yixStringData = ref<string[]>([]);
|
|
|
|
+ const maxSize = ref(0);
|
|
|
|
+ const chartRef = ref<HTMLDivElement | null>(null);
|
|
|
|
+ const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
|
|
|
+ onMounted(() => {
|
|
|
|
+ getAddUser();
|
|
|
|
+ });
|
|
|
|
+ function handleChange(val){
|
|
|
|
+ console.log('handleChange',val)
|
|
|
|
+ SearchData.value = val
|
|
|
|
+ getAddUser()
|
|
|
|
+ }
|
|
|
|
+ function Search(val) {
|
|
|
|
+ const { startTime, endTime, dataType, type } = val;
|
|
|
|
+ console.log('params', val);
|
|
|
|
+ SearchData.startTime = startTime;
|
|
|
|
+ SearchData.endTime = endTime;
|
|
|
|
+ // SearchData.dataType = type;
|
|
|
|
+ SearchData.type = dataType;
|
|
|
|
+ getAddUser();
|
|
|
|
+ }
|
|
|
|
+ function handleExport(){
|
|
|
|
+ console.log('props',props.propsData)
|
|
|
|
+ let hader = ['日期', '数量']
|
|
|
|
+ let data = yixStringData.value.map((ele,index) => {
|
|
|
|
+ return {
|
|
|
|
+ '日期':ele,
|
|
|
|
+ '数量':viewStaticsData.value && viewStaticsData.value[index] || 0,
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ exportElsxFile(hader,data,'用户趋势')
|
|
|
|
+}
|
|
|
|
+ async function getAddUser() {
|
|
|
|
+ let xdata = [], yData=[]
|
|
|
|
+ const data = await userTrend(SearchData);
|
|
|
|
+ data.map(ele => {
|
|
|
|
+ xdata.push(ele.groupKey)
|
|
|
|
+ yData.push(ele.count)
|
|
|
|
+ })
|
|
|
|
+ yixStringData.value = xdata
|
|
|
|
+ viewStaticsData.value = yData
|
|
|
|
+ handlesetOptions()
|
|
|
|
+ }
|
|
|
|
+ function handlesetOptions() {
|
|
|
|
+ setOptions({
|
|
|
|
+ tooltip: {
|
|
|
|
+ trigger: 'axis',
|
|
|
|
+ axisPointer: {
|
|
|
|
+ lineStyle: {
|
|
|
|
+ width: 1,
|
|
|
|
+ color: '#019680',
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ legend: {
|
|
|
|
+ orient: 'horizontal',
|
|
|
|
+ bottom: 0,
|
|
|
|
+ },
|
|
|
|
+ // grid: { left: '2%', right: '2%', top: '10%', bottom: '10%', containLabel: true },
|
|
|
|
+ xAxis: {
|
|
|
|
+ type: 'category',
|
|
|
|
+ // data: [...new Array(30)].map((_item, index) => `${index + 1}日`),
|
|
|
|
+ data: yixStringData.value,
|
|
|
|
+ },
|
|
|
|
+ yAxis: {
|
|
|
|
+ type: 'value',
|
|
|
|
+ // max: maxSize.value,
|
|
|
|
+ splitNumber: 4,
|
|
|
|
+ },
|
|
|
|
+ series: [
|
|
|
|
+ {
|
|
|
|
+ data: viewStaticsData.value,
|
|
|
|
+ type: 'line',
|
|
|
|
+ itemStyle: { color: '#38a0ff' },
|
|
|
|
+ // barMaxWidth: 80,
|
|
|
|
+ name: '用户趋势',
|
|
|
|
+ },
|
|
|
|
+ // {
|
|
|
|
+ // data: shareStaticsData.value,
|
|
|
|
+ // type: 'line',
|
|
|
|
+ // itemStyle: { color: '#4cca73' },
|
|
|
|
+ // // barMaxWidth: 80,
|
|
|
|
+ // name: '用户分享数',
|
|
|
|
+ // },
|
|
|
|
+ ],
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ // props.viewStatics,
|
|
|
|
+ watch(
|
|
|
|
+ // () => [props.viewStatics, props.shareStatics],
|
|
|
|
+ // ([data1, data2]) => {
|
|
|
|
+ () => props.loading,
|
|
|
|
+ () => {
|
|
|
|
+ console.log('viewStatics-data');
|
|
|
|
+ // viewStaticsData.value = data1.reduce<number[]>(
|
|
|
|
+ // (prev: number[], current) => prev.concat(Number(current.amount)),
|
|
|
|
+ // [],
|
|
|
|
+ // );
|
|
|
|
+
|
|
|
|
+ // yixStringData.value = data1.reduce<string[]>(
|
|
|
|
+ // (prev: string[], current) => prev.concat(current.date),
|
|
|
|
+ // [],
|
|
|
|
+ // );
|
|
|
|
+ // shareStaticsData.value = data2.reduce<number[]>(
|
|
|
|
+ // (prev: number[], current) => prev.concat(Number(current.amount)),
|
|
|
|
+ // [],
|
|
|
|
+ // );
|
|
|
|
+
|
|
|
|
+ const maxNumber = Math.max(...viewStaticsData.value.concat(shareStaticsData.value));
|
|
|
|
+ const pow = Math.pow(10, maxNumber.toString().length - 1);
|
|
|
|
+ maxSize.value = maxNumber > 10 ? Math.floor(maxNumber / 10) * 10 + pow * 2 : 10;
|
|
|
|
+ console.log('maxSize', maxSize.value);
|
|
|
|
+ handlesetOptions();
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ immediate: true,
|
|
|
|
+ deep: true,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+</script>
|