panhui 2 жил өмнө
parent
commit
cc620582b9
3 өөрчлөгдсөн 249 нэмэгдсэн , 5 устгасан
  1. 2 0
      package.json
  2. 222 5
      src/views/HomeView.vue
  3. 25 0
      yarn.lock

+ 2 - 0
package.json

@@ -10,10 +10,12 @@
     "format": "prettier --write src/"
   },
   "dependencies": {
+    "@vicons/fluent": "^0.12.0",
     "@vicons/tabler": "^0.12.0",
     "@vueuse/core": "^10.1.0",
     "axios": "^1.3.6",
     "date-fns": "^2.29.3",
+    "echarts": "^5.4.2",
     "element-plus": "^2.3.3",
     "pinia": "^2.0.32",
     "qs": "^6.11.1",

+ 222 - 5
src/views/HomeView.vue

@@ -1,11 +1,11 @@
 <template>
-    <el-main>
+    <el-main class="min-w-[700px]" ref="mainRef">
         <el-row :gutter="20">
-            <el-col :span="8" :xs="12" :sm="12" :md="8">
+            <el-col :span="8">
                 <el-card shadow="hover">
                     <div class="flex justify-between items-center">
-                        <el-icon size="60" color="#15A8AA">
-                            <user-circle />
+                        <el-icon size="60" color="#405CFF">
+                            <CalendarClock16Filled />
                         </el-icon>
                         <div class="flex flex-col items-end">
                             <span class="text-[#999] text-base">使用时长</span>
@@ -14,15 +14,232 @@
                     </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="#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-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>
 </template>
 <script setup>
-import { UserCircle } from '@vicons/tabler'
+import {
+    CalendarClock16Filled,
+    PersonAdd20Filled,
+    Chat24Filled,
+    DataArea20Filled,
+    DataTreemap20Filled
+} from '@vicons/fluent'
 import { useUserStore } from '@/stores/user'
 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 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>
+
+<style lang="less" scoped>
+.el-tabs {
+    --el-tabs-header-height: 60px;
+}
+</style>

+ 25 - 0
yarn.lock

@@ -294,6 +294,11 @@
   resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
   integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
 
+"@vicons/fluent@^0.12.0":
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/@vicons/fluent/-/fluent-0.12.0.tgz#7e9a39190114f7cb682a71dd166e7efec35e5e9c"
+  integrity sha512-ATCiqPuiJ6RI5GBlD3BIpZ9Xw4MsCA4RpI5oR6MCti4quS4mX1Gp6N74FCzw7lgOj+80rV4HMKhZTVInwimpVQ==
+
 "@vicons/tabler@^0.12.0":
   version "0.12.0"
   resolved "https://registry.npmmirror.com/@vicons/tabler/-/tabler-0.12.0.tgz#11924d2288e9346d47b44dd643ac20e72a32e089"
@@ -741,6 +746,14 @@ doctrine@^3.0.0:
   dependencies:
     esutils "^2.0.2"
 
+echarts@^5.4.2:
+  version "5.4.2"
+  resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.4.2.tgz#9f38781c9c6ae323e896956178f6956952c77a48"
+  integrity sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==
+  dependencies:
+    tslib "2.3.0"
+    zrender "5.4.3"
+
 electron-to-chromium@^1.4.284:
   version "1.4.369"
   resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.369.tgz#a98d838cdd79be4471cd04e9b4dffe891d037874"
@@ -1931,6 +1944,11 @@ ts-interface-checker@^0.1.9:
   resolved "https://registry.npmmirror.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
   integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
 
+tslib@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
+  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
+
 tslib@^2.3.0:
   version "2.5.0"
   resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
@@ -2122,3 +2140,10 @@ yocto-queue@^0.1.0:
   version "0.1.0"
   resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
   integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+zrender@5.4.3:
+  version "5.4.3"
+  resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.4.3.tgz#41ffaf835f3a3210224abd9d6964b48ff01e79f5"
+  integrity sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==
+  dependencies:
+    tslib "2.3.0"