Jelajahi Sumber

用户分析静态页完成

htc 1 hari lalu
induk
melakukan
a9707ebbd6

TEMPAT SAMPAH
src/assets/images/agent/user_img1.png


TEMPAT SAMPAH
src/assets/images/agent/user_img2.png


TEMPAT SAMPAH
src/assets/images/agent/user_img3.png


TEMPAT SAMPAH
src/assets/images/agent/user_img4.png


TEMPAT SAMPAH
src/assets/images/agent/user_img5.png


TEMPAT SAMPAH
src/assets/images/agent/user_sex_nan.png


TEMPAT SAMPAH
src/assets/images/agent/user_sex_nv.png


+ 1 - 1
src/views/modules/statistics/order.vue

@@ -108,7 +108,7 @@
 </template>
 
 <script setup name="">
-  import * as echarts from "echarts";
+    import * as echarts from "echarts";
     import { ref, getCurrentInstance, onMounted } from 'vue'
     const { proxy } = getCurrentInstance();
     

+ 738 - 2
src/views/modules/statistics/userProfiling.vue

@@ -1,17 +1,753 @@
 <template>
     <div class="page">
-        <h3>用户分析</h3>
+        <div class="top adfac">
+            <div class="top-pre">
+                <div class="top-pre-num adfacjb">
+                    <div class="top-pre-num-l">
+                        <p>累计注册用户总数</p>
+                        <p class="n">{{ 24589 }}</p>
+                    </div>
+                    <div class="top-pre-num-r">
+                        <img src="@/assets/images/agent/user_img1.png">
+                    </div>
+                </div>
+                <div class="top-pre-text adfac">
+                    <div class="tn">较昨日&nbsp;{{ 23345 }}%&nbsp;<i class="el-icon-caret-bottom" style="color: #FD4F66;"></i></div>
+                </div>
+            </div>
+            <div class="top-pre">
+                <div class="top-pre-num adfacjb">
+                    <div class="top-pre-num-l">
+                        <p>今日新增用户总数</p>
+                        <p class="n">{{ 679 }}</p>
+                    </div>
+                    <div class="top-pre-num-r">
+                        <img src="@/assets/images/agent/user_img2.png">
+                    </div>
+                </div>
+                <div class="top-pre-text adfac">
+                    <div class="tn">较昨日&nbsp;{{ 345 }}%&nbsp;<i class="el-icon-caret-top" style="color: #33A7A7;"></i></div>
+                </div>
+            </div>
+            <div class="top-pre">
+                <div class="top-pre-num adfacjb">
+                    <div class="top-pre-num-l">
+                        <p>创衡运营邀请渠道</p>
+                        <p class="n">{{ 2458 }}</p>
+                    </div>
+                    <div class="top-pre-num-r">
+                        <img src="@/assets/images/agent/user_img3.png">
+                    </div>
+                </div>
+                <div class="top-pre-text adfac">
+                    <div class="tn">较昨日&nbsp;{{ 345 }}%&nbsp;<i class="el-icon-caret-top" style="color: #33A7A7;"></i></div>
+                </div>
+            </div>
+            <div class="top-pre">
+                <div class="top-pre-num adfacjb">
+                    <div class="top-pre-num-l">
+                        <p>用户推荐转发</p>
+                        <p class="n">{{ 7289 }}</p>
+                    </div>
+                    <div class="top-pre-num-r">
+                        <img src="@/assets/images/agent/user_img4.png">
+                    </div>
+                </div>
+                <div class="top-pre-text adfac">
+                    <div class="tn">较昨日&nbsp;{{ 345 }}%&nbsp;<i class="el-icon-caret-top" style="color: #33A7A7;"></i></div>
+                </div>
+            </div>
+            <div class="top-pre">
+                <div class="top-pre-num adfacjb">
+                    <div class="top-pre-num-l">
+                        <p>团队教练转发问卷任务</p>
+                        <p class="n">{{ 4589 }}</p>
+                    </div>
+                    <div class="top-pre-num-r">
+                        <img src="@/assets/images/agent/user_img5.png">
+                    </div>
+                </div>
+                <div class="top-pre-text adfac">
+                    <div class="tn">较昨日&nbsp;{{ 345 }}%&nbsp;<i class="el-icon-caret-bottom" style="color: #FD4F66;"></i></div>
+                </div>
+            </div>
+        </div>
+        <div class="middle adfacjb">
+            <div class="box box2 adffc">
+                <div class="date adfac">
+                    <div class="date-pre" :class="{'active':didx==1}" @click="changeDate(1)">本周</div>
+                    <div class="date-pre" :class="{'active':didx==2}" @click="changeDate(2)">本月</div>
+                    <el-select v-model="queryDate" placeholder="自定义时间" @change="changeCusDate" style="width: 167px;">
+                        <el-option label="近10天" value="10"></el-option>
+                    </el-select>
+                </div>
+                <div class="box-title">用户概览</div>
+                <div class="box-echart">
+                    <div ref="yhglRef" style="width: 100%; height: 100%;"></div>
+                </div>
+            </div>
+            <div class="box box1 adffc">
+                <div class="box-title">用户注册渠道</div>
+                <div class="box-echart adfac">
+                    <div class="box-echart-qd">
+                        <div ref="yhzcqdRef" style="width: 100%; height: 100%;"></div>
+                    </div>
+                    <div class="box-echart-type adfacjb">
+                        <div class="box-echart-type-pre" v-for="(item,index) in yhzcqdTypeList" :key="index">
+                            <div class="box-echart-type-pre-top adfac">
+                                <div class="circle" :style="{'background-color':item.color}"></div>
+                                <div class="text">{{ item.name }}</div>
+                            </div>
+                            <div class="box-echart-type-pre-num">{{ item.num }}</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="middle adfacjb">
+            <div class="box box2 adffc">
+                <div class="box-title">用户画像</div>
+                <div class="box-echart adfacjb">
+                    <div class="box-echart-half adffc">
+                        <div class="box-echart-half-title">性别比例</div>
+                        <div class="box-echart-half-tb">
+                            <div ref="yhhxRef" style="width: 100%; height: 100%;"></div>
+                        </div>
+                        <div class="box-echart-half-num adf">
+                            <div class="box-echart-half-num-pre adfacjc">
+                                <img src="@/assets/images/agent/user_sex_nan.png" alt="">
+                                <div class="box-echart-half-num-pre-info">
+                                    <p>男性</p>
+                                    <p class="num"><span>{{ 14589 }}</span>人</p>
+                                </div>
+                            </div>
+                            <div class="box-echart-half-num-pre adfacjc">
+                                <img src="@/assets/images/agent/user_sex_nv.png" alt="">
+                                <div class="box-echart-half-num-pre-info">
+                                    <p>女性</p>
+                                    <p class="num"><span>{{ 10000 }}</span>人</p>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="box-echart-half">
+                        <div class="box-echart-half-title">年龄分布</div>
+                        <div class="box-echart-half-boxs adfacjb">
+                            <div class="box-echart-half-boxs-box adfacjb">
+                                <div class="box-echart-half-boxs-box-l">
+                                    <p class="p1">{{ '22-28岁' }}</p>
+                                    <p class="p2">占比</p>
+                                    <p class="p3">{{ 38 }}%</p>
+                                </div>
+                                <div class="box-echart-half-boxs-box-r">
+                                    <div :ref="'nlfbRef'+1" style="width: 100%; height: 100%;"></div>
+                                </div>
+                            </div>
+                            <div class="box-echart-half-boxs-box adfacjb">
+                                <div class="box-echart-half-boxs-box-l">
+                                    <p class="p1">{{ '28-40岁' }}</p>
+                                    <p class="p2">占比</p>
+                                    <p class="p3">{{ 52 }}%</p>
+                                </div>
+                                <div class="box-echart-half-boxs-box-r">
+                                    <div :ref="'nlfbRef'+2" style="width: 100%; height: 100%;"></div>
+                                </div>
+                            </div>
+                            <div class="box-echart-half-boxs-box adfacjb">
+                                <div class="box-echart-half-boxs-box-l">
+                                    <p class="p1">{{ '40-50岁' }}</p>
+                                    <p class="p2">占比</p>
+                                    <p class="p3">{{ 7 }}%</p>
+                                </div>
+                                <div class="box-echart-half-boxs-box-r">
+                                    <div :ref="'nlfbRef'+3" style="width: 100%; height: 100%;"></div>
+                                </div>
+                            </div>
+                            <div class="box-echart-half-boxs-box adfacjb">
+                                <div class="box-echart-half-boxs-box-l">
+                                    <p class="p1">{{ '50-60岁' }}</p>
+                                    <p class="p2">占比</p>
+                                    <p class="p3">{{ 3 }}%</p>
+                                </div>
+                                <div class="box-echart-half-boxs-box-r">
+                                    <div :ref="'nlfbRef'+4" style="width: 100%; height: 100%;"></div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="box box1 adffc">
+                <div class="box-title">行业分布</div>
+                <div class="box-echart">
+                    <div class="list">
+                        <div class="list-item adfac" v-for="(item,index) in hyfbData" :key="index">
+                            <div class="list-item-name">{{ item.name }}</div>
+                            <div class="list-item-num">
+                                <div class="list-item-num-current" :style="{width:item.bl+'%'}"></div>
+                            </div>
+                            <div class="list-item-bl">{{ item.bl }}%</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
     </div>
 </template>
 
 <script setup name="">
-    import { ref, getCurrentInstance } from 'vue'
+    import * as echarts from "echarts";
+    import { ref, getCurrentInstance, onMounted } from 'vue'
     const { proxy } = getCurrentInstance();
     
+    const didx = ref(1)
+    const queryDate = ref('')
+    const yhglRef = ref(null)
+    const yhzcqdRef = ref(null)
+    const yhhxRef = ref(null)
+    const hyfbData = ref([])
+    const nlfbRef1 = ref(null)
+    const nlfbRef2 = ref(null)
+    const nlfbRef3 = ref(null)
+    const nlfbRef4 = ref(null)
+    const yhzcqdTypeList = ref([])
+
+    const changeDate = (idx) => {
+        didx.value = idx
+    }
+
+    const changeCusDate = () => {
+        didx.value = ''
+    }
+
+    const initYhglEchart = () => {
+        const chart = echarts.init(yhglRef.value)
+        let option = {
+            color: ['#01A79C','#0177B3'],
+            xAxis: {
+                type: 'category',
+                boundaryGap: false,
+                data: ['11-01', '11-02', '11-03', '11-04', '11-05', '11-06', '11-07']
+            },
+            yAxis: {
+                type: 'value'
+            },
+            grid: {
+                left: '1%',
+                right: '1%',
+                top: '20%',
+                bottom: '1%',
+                containLabel: true
+            },
+            legend: {
+                data: ['新增用户', '累计用户'],
+                top:'3%',
+                left:'1%'
+            },
+            tooltip: {
+                trigger: 'axis',
+                axisPointer: {
+                type: 'cross',
+                label: {
+                    backgroundColor: '#6a7985'
+                }
+                }
+            },
+            series: [
+                {
+                name:'新增用户',
+                data: [30,170,30,80,50,160,20],
+                type: 'line',
+                smooth: true,
+                lineStyle: {
+                    width: 4,
+                },
+                showSymbol: false,
+                },
+                {
+                name:'累计用户',
+                data: [200,90,130,90,220,60,80],
+                type: 'line',
+                smooth: true,
+                lineStyle: {
+                    width: 4,
+                },
+                showSymbol: false,
+                }
+            ]
+        }
+        chart.setOption(option)
+    }
+
+    const initHyfbData = () => {
+        hyfbData.value = [
+            {name:'IT/互联网',num:3623},
+            {name:'金融语专业服务',num:2311},
+            {name:'制造与工业',num:1523},
+            {name:'医疗保健与生命科学',num:965},
+            {name:'消费品与零售',num:623},
+            {name:'文化、媒体与教育',num:311},
+            {name:'能源、资源与公共事业',num:223},
+            {name:'政府与非营利组织',num:123},
+            {name:'其他',num:111}
+        ]
+        let sum = hyfbData.value.reduce((total,item)=>{return total+item.num},0)
+        hyfbData.value.forEach(item=>{
+            item.bl = (item.num/sum*100).toFixed(2)
+        })
+    }
+
+    const initYhhxEchart = () => {
+        const data = [
+            { name: '男',  value: '58' },
+            { name: '女', value: '42' }
+        ]
+        const chart = echarts.init(yhhxRef.value)
+        let option = {
+            color: [
+                new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#33A7A7' },
+                    { offset: 1, color: '#06C6BF' },
+                ]),
+                '#FFDF73'
+            ],
+            tooltip: {
+                trigger: 'item',
+                backgroundColor: 'rgba(3,50,86,0.8)',
+                textStyle: {
+                    fontSize: 16,
+                    color: '#ffffff',
+                },
+                formatter: (params) => {
+                    return params.name + ': ' + params.value + '%'
+                }
+            },
+            series: [
+                {
+                    type: 'pie',
+                    roseType: 'radius',
+                    radius: ['50%', '95%'],
+                    center: ['50%', '50%'],
+                    data: data,
+                    itemStyle: {
+                        borderWidth: 2
+                    },
+                    labelLine: {
+                        length: 0
+                    },
+                    label: {
+                        formatter: (params) => {
+                            return '{name|' + params.name + ': }{value|' + params.value + '%}'
+                        },
+                        rich: {
+                            name: {
+                            fontSize: 14,
+                            color: '#002846',
+                            },
+                            value: {
+                            fontSize: 32,
+                            color: '#002846',
+                            },
+                        }
+                    }
+                }
+            ]
+        }
+        chart.setOption(option)
+    }
+
+    const initNlfbEcharts = () => {
+        let refs = [nlfbRef1.value,nlfbRef2.value,nlfbRef3.value,nlfbRef4.value]
+        let arr = [
+            {color:'#FFDF73',data:[{value:38},{value:62}]},
+            {color:'#35CBCA',data:[{value:52},{value:62}]},
+            {color:'#3AA1FF',data:[{value:7},{value:62}]},
+            {color:'#F3637C',data:[{value:3},{value:62}]}
+        ]
+        arr.forEach((item,index)=>{
+            initNlfbEchart(item.color,item.data,refs[index])
+        })
+    }
+
+    const initYhzcqdData = () => {
+        yhzcqdTypeList.value = [
+            {color:'#009191',name:'创衡运营邀请渠道',num:8928},
+            {color:'#35CBCA',name:'用户搜索注册',num:10233},
+            {color:'#7CC5C5',name:'用户推荐转发',num:7344},
+            {color:'#FBD438',name:'团队教练转发问卷任务',num:10987}
+        ]
+        let data = yhzcqdTypeList.value.map(d=>({name:d.name,value:d.num}))
+        let sum = data.reduce((total,item)=>{return total+item.value},0)
+        const chart = echarts.init(yhzcqdRef.value)
+        let option = {
+            color: ['#009191','#35CBCA','#7CC5C5','#FBD438'],
+            grid: {
+                left: 20,
+                right: 20,
+                bottom: 10,
+                top: 10,
+                containLabel: true
+            },
+            title: {
+                show: true,
+                text: '{a|'+sum+'}\n{b|注册总数}',
+                x: '34%',
+                y: '46%',
+                textStyle: {
+                    rich: {
+                        a: {
+                            align: 'center',
+                            fontSize: 28,
+                            fontWeight:'bold',
+                            color: '#002846',
+                            padding: [0, 0, 10, 0],
+                        },
+                        b: {
+                            align: 'center',
+                            fontSize: 14,
+                            color: '#667E90'
+                        },
+                    },
+                }
+            },
+            tooltip: {
+                trigger: 'item',
+                formatter: '{b}:{c}({d}%)'
+            },
+            series: [{
+                type: 'pie',
+                startAngle: 90,
+                radius: ['50%', '90%'],
+                center: ['50%', '53%'],
+                hoverAnimation: false,
+                roseType: 'radius',
+                data,
+                label: {
+                    show: false
+                },
+                labelLine: {
+                    show: false
+                }
+            }]
+        }
+        chart.setOption(option)
+    }
+
+    const initNlfbEchart = (color,data,ref) => {
+        const chart = echarts.init(ref)
+        let option = {
+            color:[color,'#F1F2F6'],
+            series: [
+                {
+                    type: 'pie',
+                    radius: ['40%', '70%'],
+                    padAngle: 3,
+                    itemStyle: {
+                        borderRadius: 5
+                    },
+                    labelLine: {
+                        show: false
+                    },
+                    data
+                }
+            ]
+        }
+        chart.setOption(option)
+    }
+
+    onMounted(()=>{
+        initYhglEchart()
+        initHyfbData()
+        initYhzcqdData()
+        initYhhxEchart()
+        initNlfbEcharts()
+        proxy.$nextTick(()=>{
+            
+        })
+    })
 </script>
 
 <style scoped lang="scss">
     .page{
         padding: 16px;
+        .top{
+            justify-content: space-between;
+            &-pre{
+                width: calc(20% - 9.6px);
+                background: #FFFFFF;
+                box-shadow: 0px 2px 12px 0px rgba(0,0,0,0.06);
+                border-radius: 6px;
+                padding: 24px 20px;
+                box-sizing: border-box;
+                &-num{
+                    &-l{
+                        p{
+                            font-family: PingFangSC, PingFang SC;
+                            font-weight: 400;
+                            font-size: 14px;
+                            color: #335368;
+                            line-height: 14px;
+                            &.n{
+                                font-family: DINAlternate, DINAlternate;
+                                font-weight: bold;
+                                font-size: 28px;
+                                color: #002846;
+                                line-height: 28px;
+                                margin-top: 16px;
+                            }
+                        }
+                    }
+                    &-r{
+                        img{
+                            width: 60px;
+                            height: 60px;
+                        }
+                    }
+                }
+                &-text{
+                    margin-top: 16px;
+                    .tn{
+                        width: 100%;
+                        font-family: PingFangSC, PingFang SC;
+                        font-weight: 400;
+                        font-size: 14px;
+                        color: #667E90;
+                        line-height: 14px;
+
+                    }
+                }
+            }
+        }
+        
+        .box{
+            background: #FFFFFF;
+            box-shadow: 0px 2px 12px 0px rgba(0,0,0,0.06);
+            border-radius: 6px;
+            padding: 20px;
+            box-sizing: border-box;
+            height: 420px;
+            position: relative;
+            &.box1{
+                width: calc(100% / 5 * 2 - 6px);
+            }
+            &.box2{
+                width: calc(100% / 5 * 3 - 6px);
+            }
+        }
+        
+        .box-title{
+            font-family: PingFang-SC, PingFang-SC;
+            font-weight: bold;
+            font-size: 16px;
+            color: #002846;
+            line-height: 16px;
+        }
+        .box-echart{
+            flex: 1;
+            margin-top: 10px;
+            overflow-y: auto;
+
+            &-half{
+                width: 50%;
+                height: 100%;
+                &-title{
+                    padding-left: 7px;
+                    margin-top: 10px;
+                    font-family: PingFangSC, PingFang SC;
+                    font-weight: 400;
+                    font-size: 14px;
+                    color: #002846;
+                    line-height: 14px;
+                    position: relative;
+                    &::before{
+                        content: '';
+                        width: 3px;
+                        height: 14px;
+                        background: #33A7A7;
+                        position: absolute;
+                        left: 0;
+                        top: 50%;
+                        transform: translateY(-50%);
+                    }
+                }
+                &-tb{
+                    flex: 1;
+                }
+                &-num{
+                    margin-top: 60px;
+                    padding-bottom: 30px;
+                    &-pre{
+                        width: 50%;
+                        img{
+                            width: 43px;
+                            height: 43px;
+                        }
+                        &-info{
+                            margin-left: 12px;
+                            p{
+                                font-family: PingFangSC, PingFang SC;
+                                font-weight: 400;
+                                font-size: 14px;
+                                color: #667E90;
+                                line-height: 14px;
+                                &.num{
+                                    margin-top: 6px;
+                                    span{
+                                        font-family: D-DINCondensed, D-DINCondensed;
+                                        font-weight: bold;
+                                        font-size: 24px;
+                                        color: #002846;
+                                        line-height: 24px;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                &-boxs{
+                    flex-wrap: wrap;
+                    &-box{
+                        width: calc(50% - 18px);
+                        background: #FCFCFE;
+                        border-radius: 6px;
+                        padding: 24px 20px;
+                        box-sizing: border-box;
+                        margin-top: 15px;
+                        &-l{
+                            padding-right: 20px;
+                            .p1{
+                                font-family: PingFangSC, PingFang SC;
+                                font-weight: 400;
+                                font-size: 14px;
+                                color: #002846;
+                                line-height: 14px;
+                            }
+                            .p2{
+                                font-family: PingFangSC, PingFang SC;
+                                font-weight: 400;
+                                font-size: 14px;
+                                color: #99A9B5;
+                                line-height: 14px;
+                                margin-top: 16px;
+                            }
+                            .p3{
+                                font-family: D-DINCondensed, D-DINCondensed;
+                                font-weight: bold;
+                                font-size: 32px;
+                                color: #002846;
+                                line-height: 32px;
+                                margin-top: 8px;
+                            }
+                        }
+                    }
+                }
+            }
+
+            &-qd{
+                width: 290px;
+                height: 100%;
+
+            }
+            &-type{
+                flex: 1;
+                margin-top: -80px;
+                flex-wrap: wrap;
+                &-pre{
+                    width: 50%;
+                    margin-top: 80px;
+                    &-top{
+                        .circle{
+                            width: 8px;
+                            height: 8px;
+                            border-radius: 50%;
+                        }
+                        .text{
+                            font-family: PingFangSC, PingFang SC;
+                            font-weight: 400;
+                            font-size: 14px;
+                            color: #667E90;
+                            line-height: 16px;
+                            margin-left: 8px;
+                        }
+                    }
+                    &-num{
+                        margin: 16px 0 0 12px;
+                        font-family: D-DINCondensed, D-DINCondensed;
+                        font-weight: bold;
+                        font-size: 24px;
+                        color: #002846;
+                        line-height: 24px;
+                    }
+                }
+            }
+        }
+
+        .middle{
+            margin-top: 16px;
+        }
+        
+        .date{
+            position: absolute;
+            top: 42px;
+            right: 20px;
+            &-pre{
+                width: 54px;
+                height: 40px;
+                border-radius: 6px;
+                border: 1px solid #DDE0E6;
+                font-family: PingFangSC, PingFang SC;
+                font-weight: 400;
+                font-size: 14px;
+                color: #335368;
+                line-height: 40px;
+                text-align: center;
+                margin-right: 16px;
+                cursor: pointer;
+                &.active{
+                    background: rgba(51,167,167,0.08);
+                    border-radius: 6px;
+                    border: 1px solid #33A7A7;
+                    color: #009191;
+                }
+            }
+        }
+
+        .list{
+            &-item{
+                margin-top: 19px;
+                &-name{
+                    width: 158px;
+                    padding-right: 18px;
+                    box-sizing: border-box;
+                    font-family: PingFangSC, PingFang SC;
+                    font-weight: 400;
+                    font-size: 14px;
+                    color: #33536B;
+                    line-height: 20px;
+                    text-align: right;
+                }
+                &-num{
+                    flex: 1;
+                    height: 8px;
+                    background: #F3F4FA;
+                    position: relative;
+                    &-current{
+                        height: 8px;
+                        background: #4CB2B2;
+                    }
+                }
+                &-bl{
+                    width: 82px;
+                    padding-left: 16px;
+                    box-sizing: border-box;
+                    font-family: PingFangSC, PingFang SC;
+                    font-weight: 400;
+                    font-size: 14px;
+                    color: #536387;
+                    line-height: 20px;
+                    text-align: left;
+                }
+            }
+        }
     }
 </style>