|
@@ -1,11 +1,11 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <el-main>
|
|
|
|
|
|
|
+ <el-main class="min-w-[700px]" ref="mainRef">
|
|
|
<el-row :gutter="20">
|
|
<el-row :gutter="20">
|
|
|
- <el-col :span="8" :xs="12" :sm="12" :md="8">
|
|
|
|
|
|
|
+ <el-col :span="8">
|
|
|
<el-card shadow="hover">
|
|
<el-card shadow="hover">
|
|
|
<div class="flex justify-between items-center">
|
|
<div class="flex justify-between items-center">
|
|
|
- <el-icon size="60" color="#15A8AA">
|
|
|
|
|
- <user-circle />
|
|
|
|
|
|
|
+ <el-icon size="60" color="#405CFF">
|
|
|
|
|
+ <CalendarClock16Filled />
|
|
|
</el-icon>
|
|
</el-icon>
|
|
|
<div class="flex flex-col items-end">
|
|
<div class="flex flex-col items-end">
|
|
|
<span class="text-[#999] text-base">使用时长</span>
|
|
<span class="text-[#999] text-base">使用时长</span>
|
|
@@ -14,15 +14,232 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-card shadow="hover">
|
|
|
|
|
+ <div class="flex justify-between items-center">
|
|
|
|
|
+ <el-icon size="60" color="#15A8AA">
|
|
|
|
|
+ <PersonAdd20Filled />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ <div class="flex flex-col items-end">
|
|
|
|
|
+ <span class="text-[#999] text-base">今日新增</span>
|
|
|
|
|
+ <span class="text-2xl font-bold mt-2">13 (人)</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-card shadow="hover">
|
|
|
|
|
+ <div class="flex justify-between items-center">
|
|
|
|
|
+ <el-icon size="60" color="#928EFB">
|
|
|
|
|
+ <Chat24Filled />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ <div class="flex flex-col items-end">
|
|
|
|
|
+ <span class="text-[#999] text-base">今日互动</span>
|
|
|
|
|
+ <span class="text-2xl font-bold mt-2">20 (次)</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <el-card shadow="hover" class="mt-5">
|
|
|
|
|
+ <div class="flex">
|
|
|
|
|
+ <el-tabs class="demo-tabs mt-5" v-model="activeName" tab-position="left">
|
|
|
|
|
+ <el-tab-pane name="user">
|
|
|
|
|
+ <template #label>
|
|
|
|
|
+ <div class="flex items-center py-4">
|
|
|
|
|
+ <el-icon size="24"><DataArea20Filled /></el-icon>
|
|
|
|
|
+ <span class="ml-1"> 人数统计 </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-tab-pane>
|
|
|
|
|
+ <el-tab-pane name="chat">
|
|
|
|
|
+ <template #label>
|
|
|
|
|
+ <div class="flex items-center py-4">
|
|
|
|
|
+ <el-icon size="24"><DataTreemap20Filled /></el-icon>
|
|
|
|
|
+ <span class="ml-1">互动统计</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template></el-tab-pane
|
|
|
|
|
+ >
|
|
|
|
|
+ </el-tabs>
|
|
|
|
|
+ <div id="chart" class="h-[500px] flex-1"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
</el-main>
|
|
</el-main>
|
|
|
</template>
|
|
</template>
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { UserCircle } from '@vicons/tabler'
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ CalendarClock16Filled,
|
|
|
|
|
+ PersonAdd20Filled,
|
|
|
|
|
+ Chat24Filled,
|
|
|
|
|
+ DataArea20Filled,
|
|
|
|
|
+ DataTreemap20Filled
|
|
|
|
|
+} from '@vicons/fluent'
|
|
|
import { useUserStore } from '@/stores/user'
|
|
import { useUserStore } from '@/stores/user'
|
|
|
import { differenceInCalendarDays } from 'date-fns'
|
|
import { differenceInCalendarDays } from 'date-fns'
|
|
|
|
|
+import { onMounted, watch, ref, nextTick } from 'vue'
|
|
|
|
|
+import { useDark, useToggle, useResizeObserver } from '@vueuse/core'
|
|
|
|
|
+import { http } from '@/plugins/http'
|
|
|
|
|
+
|
|
|
|
|
+const isDark = useDark({
|
|
|
|
|
+ storageKey: 'dark-mode-admin'
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+import * as echarts from 'echarts'
|
|
|
|
|
|
|
|
const { user } = useUserStore()
|
|
const { user } = useUserStore()
|
|
|
|
|
|
|
|
const time = differenceInCalendarDays(new Date(), new Date(user.createdAt))
|
|
const time = differenceInCalendarDays(new Date(), new Date(user.createdAt))
|
|
|
|
|
+
|
|
|
|
|
+watch(isDark, () => {
|
|
|
|
|
+ initChart()
|
|
|
|
|
+})
|
|
|
|
|
+const myChart = ref(null)
|
|
|
|
|
+
|
|
|
|
|
+const mainRef = ref(null)
|
|
|
|
|
+useResizeObserver(mainRef, () => {
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ initChart()
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
|
|
+const activeName = ref('user')
|
|
|
|
|
+
|
|
|
|
|
+watch(activeName, () => {
|
|
|
|
|
+ initChart()
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+function initChart() {
|
|
|
|
|
+ if (myChart.value) {
|
|
|
|
|
+ myChart.value.dispose()
|
|
|
|
|
+ myChart.value = null
|
|
|
|
|
+ }
|
|
|
|
|
+ var chartDom = document.getElementById('chart')
|
|
|
|
|
+ myChart.value = echarts.init(chartDom, isDark.value ? 'dark' : 'light')
|
|
|
|
|
+ var option
|
|
|
|
|
+
|
|
|
|
|
+ option = {
|
|
|
|
|
+ backgroundColor: isDark.value ? 'rgb(29, 30, 31)' : '#fff',
|
|
|
|
|
+ title: [
|
|
|
|
|
+ {
|
|
|
|
|
+ // text: '标题',
|
|
|
|
|
+ left: '2%'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ text: activeName.value === 'user' ? '全部用户' : '互动次数',
|
|
|
|
|
+ // subtext: userDatas.value.api + userDatas.value.user + '人',
|
|
|
|
|
+ subtext: activeName.value === 'user' ? 50 + '人' : 500 + '次',
|
|
|
|
|
+ textStyle: {
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ color: isDark.value ? '#fff' : '#000',
|
|
|
|
|
+ fontWeight: 'normal'
|
|
|
|
|
+ },
|
|
|
|
|
+ subtextStyle: {
|
|
|
|
|
+ fontSize: 28,
|
|
|
|
|
+ color: isDark.value ? '#fff' : '#000',
|
|
|
|
|
+ fontWeight: 'bold'
|
|
|
|
|
+ },
|
|
|
|
|
+ textAlign: 'center',
|
|
|
|
|
+ x: '50%',
|
|
|
|
|
+ y: '20%'
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ grid: [
|
|
|
|
|
+ {
|
|
|
|
|
+ top: '50%',
|
|
|
|
|
+ width: '100%',
|
|
|
|
|
+ left: 10,
|
|
|
|
|
+ containLabel: true
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ xAxis: { type: 'category', data: Object.keys(userDatas.value.week) },
|
|
|
|
|
+ yAxis: { gridIndex: 0 },
|
|
|
|
|
+ tooltip: [
|
|
|
|
|
+ {
|
|
|
|
|
+ trigger: 'item',
|
|
|
|
|
+ formatter: function (params) {
|
|
|
|
|
+ if (params.seriesType === 'pie') {
|
|
|
|
|
+ return `${params.seriesName} <br/>${params.name} : ${params.value}${
|
|
|
|
|
+ activeName.value === 'user' ? '人' : '次'
|
|
|
|
|
+ } (${params.percent}%)`
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return `${params.seriesName} <br/>${params.name} : ${params.value}${
|
|
|
|
|
+ activeName.value === 'user' ? '人' : '次'
|
|
|
|
|
+ } `
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ legend: {
|
|
|
|
|
+ left: 'center',
|
|
|
|
|
+ top: 'bottom',
|
|
|
|
|
+ data: ['注册用户', '内部用户']
|
|
|
|
|
+ },
|
|
|
|
|
+ toolbox: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ feature: {
|
|
|
|
|
+ mark: { show: true },
|
|
|
|
|
+ dataView: { show: true, readOnly: false },
|
|
|
|
|
+ restore: { show: true },
|
|
|
|
|
+ saveAsImage: { show: true }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ series: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '注册用户',
|
|
|
|
|
+ type: 'bar',
|
|
|
|
|
+ stack: 'one',
|
|
|
|
|
+ data: activeName.value === 'user' ? [5, 3, 2, 1, 6, 7, 4] : [30, 20, 13, 50, 21, 12, 30]
|
|
|
|
|
+ // data: Object.keys(userDatas.value.week).map((key) => {
|
|
|
|
|
+ // return userDatas.value.week[key].user
|
|
|
|
|
+ // })
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '内部用户',
|
|
|
|
|
+ type: 'bar',
|
|
|
|
|
+ stack: 'one',
|
|
|
|
|
+ data: activeName.value === 'user' ? [3, 4, 2, 4, 5, 6, 2] : [20, 12, 15, 16, 29, 39, 10]
|
|
|
|
|
+ // data: Object.keys(userDatas.value.week).map((key) => {
|
|
|
|
|
+ // return userDatas.value.week[key].api
|
|
|
|
|
+ // })
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'pie',
|
|
|
|
|
+ name: activeName.value === 'user' ? '用户人数' : '互动次数',
|
|
|
|
|
+ type: 'pie',
|
|
|
|
|
+ radius: ['20%', '40%'],
|
|
|
|
|
+ avoidLabelOverlap: false,
|
|
|
|
|
+ center: ['50%', '25%'],
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ borderRadius: 5
|
|
|
|
|
+ },
|
|
|
|
|
+ data: [
|
|
|
|
|
+ // { value: userDatas.value.user, name: '注册用户' },
|
|
|
|
|
+ // { value: userDatas.value.api, name: '内部用户' }
|
|
|
|
|
+ { value: activeName.value === 'user' ? 35 : 100, name: '注册用户' },
|
|
|
|
|
+ { value: activeName.value === 'user' ? 15 : 400, name: '内部用户' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ option && myChart.value.setOption(option)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const userDatas = ref({
|
|
|
|
|
+ today: 0
|
|
|
|
|
+})
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ http.get('/admin/users/getDatas', {
|
|
|
|
|
+ apiUserId: user.apiUserId
|
|
|
|
|
+ }).then((res) => {
|
|
|
|
|
+ userDatas.value = res
|
|
|
|
|
+ initChart()
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
</script>
|
|
</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="less" scoped>
|
|
|
|
|
+.el-tabs {
|
|
|
|
|
+ --el-tabs-header-height: 60px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|