|
|
@@ -1,162 +1,307 @@
|
|
|
<template>
|
|
|
- <el-container>
|
|
|
- <el-header>
|
|
|
- <el-card shadow="hover" style="margin-top: 10px">
|
|
|
- <el-row justify="end" align="middle">
|
|
|
- <el-col :span="19" style="text-align: right">
|
|
|
- <el-radio-group v-model="timeRadio" size="small" @change="handleDateRangeChange">
|
|
|
- <!-- <el-radio-button label="今日" value="today" />-->
|
|
|
- <el-radio-button label="近7天" value="week" />
|
|
|
- <el-radio-button label="近30天" value="month" />
|
|
|
- </el-radio-group>
|
|
|
- </el-col>
|
|
|
- <el-col :span="5" style="text-align: right">
|
|
|
- <el-date-picker v-model="dateRange" type="daterange" range-separator="-" start-placeholder="开始日期"
|
|
|
- end-placeholder="结束日期" style="margin-left: 10px; margin-right: 30px" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-card>
|
|
|
- </el-header>
|
|
|
-
|
|
|
- <el-main style="margin-top: 20px">
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <el-card shadow="hover" class="stat-card">
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="8">
|
|
|
- <h2 style="color: green; font-size: 30px">{{ totalNum }}</h2>
|
|
|
- <p class="success">总内容量</p>
|
|
|
+ <div class="play-dashboard-page">
|
|
|
+ <el-container>
|
|
|
+ <el-main class="scrollable-main main-content">
|
|
|
+ <div class="play-dashboard-header">
|
|
|
+ <el-card shadow="hover" class="header-card">
|
|
|
+ <el-row justify="end" align="middle">
|
|
|
+ <el-col :span="19" class="text-right">
|
|
|
+ <el-radio-group v-model="timeRadio" size="small" @change="handleDateRangeChange">
|
|
|
+ <el-radio-button label="近7天" value="week" />
|
|
|
+ <el-radio-button label="近30天" value="month" />
|
|
|
+ </el-radio-group>
|
|
|
</el-col>
|
|
|
- <el-col :span="16">
|
|
|
- <div ref="createLine" style="height: 150px"></div>
|
|
|
+ <el-col :span="5" class="text-right">
|
|
|
+ <el-date-picker v-model="dateRange" type="daterange" range-separator="-" start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期" class="date-picker" />
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</el-card>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <el-card shadow="hover" class="stat-card">
|
|
|
- <h2 style="color: orange; font-size: 30px">{{ imageNum }}</h2>
|
|
|
- <p class="warning">图片素材</p>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <el-card shadow="hover" class="stat-card">
|
|
|
- <h2 style="color: green; font-size: 30px">{{ videoNum }}</h2>
|
|
|
- <p class="success">视频素材</p>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="20" style="margin-top: 20px">
|
|
|
- <el-col :span="18">
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="8">
|
|
|
- <el-card shadow="hover">
|
|
|
- <h3>内容占比</h3>
|
|
|
- <div ref="typePie" class="chart-placeholder"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- <el-col :span="8">
|
|
|
- <el-card shadow="hover">
|
|
|
- <h3>类型占比</h3>
|
|
|
- <div ref="tagPie" class="chart-placeholder"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- <el-col :span="8">
|
|
|
- <el-card shadow="hover">
|
|
|
- <h3>素材统计</h3>
|
|
|
- <div ref="typeAndTag" class="chart-placeholder"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-row :gutter="20" style="margin-top: 20px">
|
|
|
- <el-col :span="12">
|
|
|
- <el-card shadow="hover" style="height: 330px">
|
|
|
- <h3>空间使用情况</h3>
|
|
|
- <div style="margin-top: 50px">
|
|
|
- <h2>已用空间:{{ diskUsed }}GB/{{ diskTotal }}GB</h2>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="disk-progress">
|
|
|
- <el-row>
|
|
|
- <el-col :span="2">
|
|
|
- <h3>图片:</h3>
|
|
|
- </el-col>
|
|
|
- <el-col :span="22">
|
|
|
- <el-progress :text-inside="true" :stroke-width="26" :percentage="diskImage" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- <div class="disk-progress">
|
|
|
- <el-row>
|
|
|
- <el-col :span="2">
|
|
|
- <h3>视频:</h3>
|
|
|
- </el-col>
|
|
|
- <el-col :span="22">
|
|
|
- <el-progress :text-inside="true" :stroke-width="26" status="success" :percentage="diskVideo" />
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-card shadow="hover">
|
|
|
- <h3>播放时长统计</h3>
|
|
|
- <div ref="onlineTimeLine" class="chart-placeholder"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <el-card shadow="hover">
|
|
|
- <div>
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <h3>内容TOP5</h3>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-select v-model="topType" @change="topTypeSelectChange">
|
|
|
- <el-option label="播放次数" value="1" />
|
|
|
- <el-option label="播放时长" value="2" />
|
|
|
- </el-select>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="4">
|
|
|
- <h3>图片</h3>
|
|
|
- </el-col>
|
|
|
- <el-col :span="4">
|
|
|
- <h3>{{ imageTopNum }}</h3>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- <div ref="playImageTop" class="chart-placeholder"></div>
|
|
|
- <div>
|
|
|
+ </div>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card shadow="hover" class="stat-card">
|
|
|
<el-row :gutter="20">
|
|
|
- <el-col :span="4">
|
|
|
- <h3>视频</h3>
|
|
|
+ <el-col :span="8">
|
|
|
+ <h2 class="stat-number success">{{ totalNum }}</h2>
|
|
|
+ <p class="success">总内容量</p>
|
|
|
</el-col>
|
|
|
- <el-col :span="4">
|
|
|
- <h3>{{ videoTopNum }}</h3>
|
|
|
+ <el-col :span="16">
|
|
|
+ <div ref="createLine" class="chart-small"></div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
- </div>
|
|
|
- <div ref="playVideoTop" class="chart-placeholder"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-main>
|
|
|
- </el-container>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="hover" class="stat-card">
|
|
|
+ <h2 class="stat-number warning">{{ imageNum }}</h2>
|
|
|
+ <p class="warning">图片素材</p>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="hover" class="stat-card">
|
|
|
+ <h2 class="stat-number success">{{ videoNum }}</h2>
|
|
|
+ <p class="success">视频素材</p>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row :gutter="20" class="margin-top-20">
|
|
|
+ <el-col :span="18">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <h3>内容占比</h3>
|
|
|
+ <div ref="typePie" class="chart-placeholder"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <h3>类型占比</h3>
|
|
|
+ <div ref="tagPie" class="chart-placeholder"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <h3>素材统计</h3>
|
|
|
+ <div ref="typeAndTag" class="chart-placeholder"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row :gutter="20" class="margin-top-20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card shadow="hover" class="disk-card">
|
|
|
+ <h3>空间使用情况</h3>
|
|
|
+ <div class="disk-info">
|
|
|
+ <h2>已用空间:{{ diskUsed }}GB/{{ diskTotal }}GB</h2>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="disk-progress">
|
|
|
+ <el-row align="middle">
|
|
|
+ <el-col :span="3">
|
|
|
+ <h3>图片:</h3>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="21">
|
|
|
+ <el-progress :text-inside="true" :stroke-width="26" :percentage="diskImage" />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div class="disk-progress">
|
|
|
+ <el-row align="middle">
|
|
|
+ <el-col :span="3">
|
|
|
+ <h3>视频:</h3>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="21">
|
|
|
+ <el-progress :text-inside="true" :stroke-width="26" status="success" :percentage="diskVideo" />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <h3>播放时长统计</h3>
|
|
|
+ <div ref="onlineTimeLine" class="chart-placeholder"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <div>
|
|
|
+ <el-row :gutter="20" align="middle">
|
|
|
+ <el-col :span="12">
|
|
|
+ <h3>内容TOP5</h3>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-select v-model="topType" @change="getPlayTop">
|
|
|
+ <el-option label="播放次数" value="1" />
|
|
|
+ <el-option label="播放时长" value="2" />
|
|
|
+ </el-select>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div class="top-stats">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <h3>图片</h3>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <h3>{{ imageTopNum }}</h3>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div ref="playImageTop" class="chart-placeholder"></div>
|
|
|
+ <div class="top-stats">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <h3>视频</h3>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <h3>{{ videoTopNum }}</h3>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div ref="playVideoTop" class="chart-placeholder"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-main>
|
|
|
+ </el-container>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
+<style>
|
|
|
+html,
|
|
|
+body,
|
|
|
+#app {
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.play-dashboard-page {
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.el-container {
|
|
|
+ height: 100%;
|
|
|
+ flex-direction: column !important;
|
|
|
+ display: flex !important;
|
|
|
+}
|
|
|
+
|
|
|
+.el-main.main-content {
|
|
|
+ height: 100%;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-bottom: 70px;
|
|
|
+ /* 避免内容被底部元素遮挡,可根据实际调整 */
|
|
|
+}
|
|
|
+
|
|
|
+.play-dashboard-header {
|
|
|
+ margin-top: 0;
|
|
|
+ /* width: 98%; */
|
|
|
+ /* margin-left: 1%; */
|
|
|
+ /* margin-right: 1%; */
|
|
|
+ align-self: stretch;
|
|
|
+}
|
|
|
+
|
|
|
+.play-dashboard-page .navbar-fixed-full {
|
|
|
+ position: static !important;
|
|
|
+}
|
|
|
+
|
|
|
+.play-dashboard-page .app-wrapper,
|
|
|
+.play-dashboard-page .layout-body,
|
|
|
+.play-dashboard-page .main-container {
|
|
|
+ height: auto !important;
|
|
|
+ min-height: auto !important;
|
|
|
+ overflow: visible !important;
|
|
|
+ display: block !important;
|
|
|
+}
|
|
|
+
|
|
|
+.play-dashboard-page .layout-body,
|
|
|
+.play-dashboard-page .main-container {
|
|
|
+ height: auto !important;
|
|
|
+ min-height: auto !important;
|
|
|
+ overflow: visible !important;
|
|
|
+}
|
|
|
+
|
|
|
+.play-dashboard-page .layout-body {
|
|
|
+ margin-top: 0 !important;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.el-container {
|
|
|
+ min-height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.navbar-fixed-full) {
|
|
|
+ position: static !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.layout-body) {
|
|
|
+ margin-top: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.header-card {
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.text-right {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.date-picker {
|
|
|
+ margin-left: 10px;
|
|
|
+ margin-right: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.main-content {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card {
|
|
|
+ text-align: center;
|
|
|
+ height: 170px;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-number {
|
|
|
+ font-size: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.success {
|
|
|
+ color: green;
|
|
|
+}
|
|
|
+
|
|
|
+.danger {
|
|
|
+ color: red;
|
|
|
+}
|
|
|
+
|
|
|
+.warning {
|
|
|
+ color: orange;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-small {
|
|
|
+ height: 150px;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-placeholder {
|
|
|
+ height: 250px;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.margin-top-20 {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.disk-card {
|
|
|
+ height: 330px;
|
|
|
+}
|
|
|
+
|
|
|
+.disk-info {
|
|
|
+ margin-top: 50px;
|
|
|
+}
|
|
|
+
|
|
|
+.disk-progress {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.disk-progress .el-progress--line {
|
|
|
+ margin-bottom: 15px;
|
|
|
+ max-width: 100%;
|
|
|
+ /* Adjust as needed */
|
|
|
+}
|
|
|
+
|
|
|
+.top-stats {
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
<script setup lang="ts">
|
|
|
import * as echarts from 'echarts';
|
|
|
import { diskUse, fileStatistics, fileStatisticsByTag, numLine, statisticsByTypeAndTag } from '@/api/smsb/source/minioData';
|
|
|
import { playTopStatistics, sumOnlineTimeLine } from '@/api/smsb/source/play_record';
|
|
|
+import { ref, onMounted } from 'vue'; // Import ref and onMounted
|
|
|
|
|
|
const timeRadio = ref('week');
|
|
|
-const dateRange = ref(['2025-01-01', '2025-01-01']);
|
|
|
+const dateRange = ref<[string, string]>(['', '']); // Explicitly type dateRange
|
|
|
const totalNum = ref(0);
|
|
|
const imageNum = ref(0);
|
|
|
const videoNum = ref(0);
|
|
|
@@ -175,297 +320,262 @@ const diskTotal = ref();
|
|
|
const diskImage = ref();
|
|
|
const diskVideo = ref();
|
|
|
|
|
|
+// Helper function to format date
|
|
|
+const formatDate = (date: Date): string => {
|
|
|
+ const year = date.getFullYear();
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
+ const day = String(date.getDate()).padStart(2, '0');
|
|
|
+ return `${year}-${month}-${day}`;
|
|
|
+};
|
|
|
+
|
|
|
+// Set initial date range to the last 7 days
|
|
|
+const setInitialDateRange = () => {
|
|
|
+ const today = new Date();
|
|
|
+ const startDate = new Date();
|
|
|
+ startDate.setDate(today.getDate() - 7);
|
|
|
+ dateRange.value = [formatDate(startDate), formatDate(today)];
|
|
|
+};
|
|
|
+
|
|
|
const getDiskUse = async () => {
|
|
|
- const res = await diskUse();
|
|
|
- diskTotal.value = res.data.total / 1024 / 1024;
|
|
|
- diskUsed.value = (res.data.used / 1024 / 1024).toFixed(3);
|
|
|
- diskImage.value = ((res.data.imageUse / res.data.total) * 100).toFixed(2);
|
|
|
- diskVideo.value = ((res.data.videoUse / res.data.total) * 100).toFixed(2);
|
|
|
+ try {
|
|
|
+ const res = await diskUse();
|
|
|
+ diskTotal.value = (res.data.total / 1024 / 1024).toFixed(2); // Format to 2 decimal places
|
|
|
+ diskUsed.value = (res.data.used / 1024 / 1024).toFixed(3);
|
|
|
+ diskImage.value = ((res.data.imageUse / res.data.total) * 100).toFixed(2);
|
|
|
+ diskVideo.value = ((res.data.videoUse / res.data.total) * 100).toFixed(2);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching disk usage:', error);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const getOnlineTimeLine = async () => {
|
|
|
- const params = {
|
|
|
- startTime: dateRange.value[0],
|
|
|
- endTime: dateRange.value[1]
|
|
|
- };
|
|
|
- const res = await sumOnlineTimeLine(params);
|
|
|
-
|
|
|
- const alarmLevelInstance = echarts.init(onlineTimeLine.value, 'macaroons');
|
|
|
- alarmLevelInstance.setOption({
|
|
|
- title: {
|
|
|
- text: ''
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'axis'
|
|
|
- },
|
|
|
- legend: {
|
|
|
- data: ['图片', '视频']
|
|
|
- },
|
|
|
- grid: {
|
|
|
- left: '3%',
|
|
|
- right: '4%',
|
|
|
- bottom: '3%',
|
|
|
- containLabel: true
|
|
|
- },
|
|
|
- toolbox: {
|
|
|
- feature: {
|
|
|
- saveAsImage: {}
|
|
|
- }
|
|
|
- },
|
|
|
- xAxis: {
|
|
|
- type: 'category',
|
|
|
- boundaryGap: false,
|
|
|
- data: res.data.timeList
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- type: 'value'
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '图片',
|
|
|
- type: 'line',
|
|
|
- stack: 'Total',
|
|
|
- data: res.data.imageNumberList
|
|
|
- },
|
|
|
- {
|
|
|
- name: '视频',
|
|
|
- type: 'line',
|
|
|
- stack: 'Total',
|
|
|
- data: res.data.videoNumberList
|
|
|
- }
|
|
|
- ]
|
|
|
- });
|
|
|
-};
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ startTime: dateRange.value[0],
|
|
|
+ endTime: dateRange.value[1]
|
|
|
+ };
|
|
|
+ const res = await sumOnlineTimeLine(params);
|
|
|
|
|
|
-const topTypeSelectChange = () => {
|
|
|
- getPlayTop();
|
|
|
+ const alarmLevelInstance = echarts.init(onlineTimeLine.value, 'macaroons');
|
|
|
+ alarmLevelInstance.setOption({
|
|
|
+ title: { text: '' },
|
|
|
+ tooltip: { trigger: 'axis' },
|
|
|
+ legend: { data: ['图片', '视频'] },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ toolbox: { feature: { saveAsImage: {} } },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ boundaryGap: false,
|
|
|
+ data: res.data.timeList
|
|
|
+ },
|
|
|
+ yAxis: { type: 'value' },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '图片',
|
|
|
+ type: 'line',
|
|
|
+ stack: 'Total',
|
|
|
+ data: res.data.imageNumberList
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '视频',
|
|
|
+ type: 'line',
|
|
|
+ stack: 'Total',
|
|
|
+ data: res.data.videoNumberList
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching online time line:', error);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const getPlayTop = async () => {
|
|
|
- const params = {
|
|
|
- startTime: dateRange.value[0],
|
|
|
- endTime: dateRange.value[1],
|
|
|
- type: topType.value
|
|
|
- };
|
|
|
- const res = await playTopStatistics(params);
|
|
|
- imageTopNum.value = res.data.imageNum;
|
|
|
- videoTopNum.value = res.data.videoNum;
|
|
|
- const playImageTopInstance = echarts.init(playImageTop.value, 'macaroons');
|
|
|
- playImageTopInstance.setOption({
|
|
|
- title: {
|
|
|
- text: ''
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'axis',
|
|
|
- axisPointer: {
|
|
|
- type: 'shadow'
|
|
|
- }
|
|
|
- },
|
|
|
- legend: {},
|
|
|
- grid: {
|
|
|
- left: '3%',
|
|
|
- right: '4%',
|
|
|
- bottom: '3%',
|
|
|
- containLabel: true
|
|
|
- },
|
|
|
- xAxis: {
|
|
|
- type: 'value',
|
|
|
- boundaryGap: [0, 0.01]
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- type: 'category',
|
|
|
- data: res.data.imageList
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '',
|
|
|
- type: 'bar',
|
|
|
- data: res.data.imageNumberList
|
|
|
- }
|
|
|
- ]
|
|
|
- });
|
|
|
- const playVideoTopInstance = echarts.init(playVideoTop.value, 'macaroons');
|
|
|
- playVideoTopInstance.setOption({
|
|
|
- title: {
|
|
|
- text: ''
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'axis',
|
|
|
- axisPointer: {
|
|
|
- type: 'shadow'
|
|
|
- }
|
|
|
- },
|
|
|
- legend: {},
|
|
|
- grid: {
|
|
|
- left: '3%',
|
|
|
- right: '4%',
|
|
|
- bottom: '3%',
|
|
|
- containLabel: true
|
|
|
- },
|
|
|
- xAxis: {
|
|
|
- type: 'value',
|
|
|
- boundaryGap: [0, 0.01]
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- type: 'category',
|
|
|
- data: res.data.videoList
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '',
|
|
|
- type: 'bar',
|
|
|
- data: res.data.videoNumberList
|
|
|
- }
|
|
|
- ]
|
|
|
- });
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ startTime: dateRange.value[0],
|
|
|
+ endTime: dateRange.value[1],
|
|
|
+ type: topType.value
|
|
|
+ };
|
|
|
+ const res = await playTopStatistics(params);
|
|
|
+ imageTopNum.value = res.data.imageNum;
|
|
|
+ videoTopNum.value = res.data.videoNum;
|
|
|
+
|
|
|
+ const playImageTopInstance = echarts.init(playImageTop.value, 'macaroons');
|
|
|
+ playImageTopInstance.setOption({
|
|
|
+ title: { text: '' },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: { type: 'shadow' }
|
|
|
+ },
|
|
|
+ legend: {},
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: { type: 'value', boundaryGap: [0, 0.01] },
|
|
|
+ yAxis: { type: 'category', data: res.data.imageList },
|
|
|
+ series: [{ name: '', type: 'bar', data: res.data.imageNumberList }]
|
|
|
+ });
|
|
|
+
|
|
|
+ const playVideoTopInstance = echarts.init(playVideoTop.value, 'macaroons');
|
|
|
+ playVideoTopInstance.setOption({
|
|
|
+ title: { text: '' },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: { type: 'shadow' }
|
|
|
+ },
|
|
|
+ legend: {},
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: { type: 'value', boundaryGap: [0, 0.01] },
|
|
|
+ yAxis: { type: 'category', data: res.data.videoList },
|
|
|
+ series: [{ name: '', type: 'bar', data: res.data.videoNumberList }]
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching play top statistics:', error);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const getNumByTypeAndTag = async () => {
|
|
|
- const res = await statisticsByTypeAndTag();
|
|
|
- const imageTagList = res.data.imageTagList;
|
|
|
- const videoTagList = res.data.videoTagList;
|
|
|
- const typeAndTagInstance = echarts.init(typeAndTag.value, 'macaroons');
|
|
|
- typeAndTagInstance.setOption({
|
|
|
- legend: {},
|
|
|
- tooltip: {},
|
|
|
- dataset: {
|
|
|
- source: [['product', '广告', '公益', '视频'], ['图片'].concat(imageTagList), ['视频'].concat(videoTagList)]
|
|
|
- },
|
|
|
- xAxis: { type: 'category' },
|
|
|
- yAxis: {},
|
|
|
- series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
|
|
|
- });
|
|
|
+ try {
|
|
|
+ const res = await statisticsByTypeAndTag();
|
|
|
+ const imageTagList = res.data.imageTagList;
|
|
|
+ const videoTagList = res.data.videoTagList;
|
|
|
+ const typeAndTagInstance = echarts.init(typeAndTag.value, 'macaroons');
|
|
|
+ typeAndTagInstance.setOption({
|
|
|
+ legend: {},
|
|
|
+ tooltip: {},
|
|
|
+ dataset: {
|
|
|
+ source: [['product', '广告', '公益', '宣传'], ['图片'].concat(imageTagList), ['视频'].concat(videoTagList)] // Changed '视频' to '宣传' based on pie chart data
|
|
|
+ },
|
|
|
+ xAxis: { type: 'category' },
|
|
|
+ yAxis: {},
|
|
|
+ series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching statistics by type and tag:', error);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const getNumByTag = async () => {
|
|
|
- const res = await fileStatisticsByTag();
|
|
|
- const tagPieInstance = echarts.init(tagPie.value, 'macaroons');
|
|
|
- tagPieInstance.setOption({
|
|
|
- title: {
|
|
|
- text: '',
|
|
|
- subtext: '',
|
|
|
- left: 'center'
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'item'
|
|
|
- },
|
|
|
- legend: {
|
|
|
- orient: 'vertical',
|
|
|
- left: 'left'
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '内容占比',
|
|
|
- type: 'pie',
|
|
|
- radius: '65%',
|
|
|
- data: [
|
|
|
- { value: (res.data.ggNum / res.data.totalNum) * 100, name: '广告' },
|
|
|
- { value: (res.data.gyNum / res.data.totalNum) * 100, name: '公益' },
|
|
|
- { value: (res.data.xcNum / res.data.totalNum) * 100, name: '宣传' }
|
|
|
- ],
|
|
|
- emphasis: {
|
|
|
- itemStyle: {
|
|
|
- shadowBlur: 10,
|
|
|
- shadowOffsetX: 0,
|
|
|
- shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
|
+ try {
|
|
|
+ const res = await fileStatisticsByTag();
|
|
|
+ const tagPieInstance = echarts.init(tagPie.value, 'macaroons');
|
|
|
+ tagPieInstance.setOption({
|
|
|
+ title: { text: '', subtext: '', left: 'center' },
|
|
|
+ tooltip: { trigger: 'item' },
|
|
|
+ legend: { orient: 'vertical', left: 'left' },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '内容占比',
|
|
|
+ type: 'pie',
|
|
|
+ radius: '65%',
|
|
|
+ data: [
|
|
|
+ { value: ((res.data.ggNum / res.data.totalNum) * 100).toFixed(2), name: '广告' }, // Format to 2 decimal places
|
|
|
+ { value: ((res.data.gyNum / res.data.totalNum) * 100).toFixed(2), name: '公益' },
|
|
|
+ { value: ((res.data.xcNum / res.data.totalNum) * 100).toFixed(2), name: '宣传' }
|
|
|
+ ],
|
|
|
+ emphasis: {
|
|
|
+ itemStyle: {
|
|
|
+ shadowBlur: 10,
|
|
|
+ shadowOffsetX: 0,
|
|
|
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- ]
|
|
|
- });
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching statistics by tag:', error);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const getNumAndLine = async () => {
|
|
|
- const params = {
|
|
|
- startTime: dateRange.value[0],
|
|
|
- endTime: dateRange.value[1]
|
|
|
- };
|
|
|
- const res = await fileStatistics();
|
|
|
- totalNum.value = res.data.totalNum;
|
|
|
- imageNum.value = res.data.imageNum;
|
|
|
- videoNum.value = res.data.videoNum;
|
|
|
- const lineRes = await numLine(params);
|
|
|
- const createLineInstance = echarts.init(createLine.value, 'macaroons');
|
|
|
- createLineInstance.setOption({
|
|
|
- title: {
|
|
|
- text: ''
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'axis'
|
|
|
- },
|
|
|
- legend: {
|
|
|
- data: ['']
|
|
|
- },
|
|
|
- grid: {
|
|
|
- left: '3%',
|
|
|
- right: '4%',
|
|
|
- bottom: '3%',
|
|
|
- containLabel: true
|
|
|
- },
|
|
|
- toolbox: {
|
|
|
- feature: {
|
|
|
- saveAsImage: {}
|
|
|
- }
|
|
|
- },
|
|
|
- xAxis: {
|
|
|
- type: 'category',
|
|
|
- boundaryGap: false,
|
|
|
- data: lineRes.data.timeList
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- type: 'value'
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '',
|
|
|
- type: 'line',
|
|
|
- stack: 'Total',
|
|
|
- data: lineRes.data.numberList
|
|
|
- }
|
|
|
- ]
|
|
|
- });
|
|
|
- const typePieInstance = echarts.init(typePie.value, 'macaroons');
|
|
|
- typePieInstance.setOption({
|
|
|
- title: {
|
|
|
- text: '',
|
|
|
- subtext: '',
|
|
|
- left: 'center'
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'item'
|
|
|
- },
|
|
|
- legend: {
|
|
|
- orient: 'vertical',
|
|
|
- left: 'left'
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '内容占比',
|
|
|
- type: 'pie',
|
|
|
- radius: '65%',
|
|
|
- data: [
|
|
|
- { value: (res.data.imageNum / res.data.totalNum) * 100, name: '图片' },
|
|
|
- { value: (res.data.videoNum / res.data.totalNum) * 100, name: '视频' }
|
|
|
- ],
|
|
|
- emphasis: {
|
|
|
- itemStyle: {
|
|
|
- shadowBlur: 10,
|
|
|
- shadowOffsetX: 0,
|
|
|
- shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ startTime: dateRange.value[0],
|
|
|
+ endTime: dateRange.value[1]
|
|
|
+ };
|
|
|
+ const res = await fileStatistics();
|
|
|
+ totalNum.value = res.data.totalNum;
|
|
|
+ imageNum.value = res.data.imageNum;
|
|
|
+ videoNum.value = res.data.videoNum;
|
|
|
+
|
|
|
+ const lineRes = await numLine(params);
|
|
|
+ const createLineInstance = echarts.init(createLine.value, 'macaroons');
|
|
|
+ createLineInstance.setOption({
|
|
|
+ title: { text: '' },
|
|
|
+ tooltip: { trigger: 'axis' },
|
|
|
+ legend: { data: [''] },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ toolbox: { feature: { saveAsImage: {} } },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ boundaryGap: false,
|
|
|
+ data: lineRes.data.timeList
|
|
|
+ },
|
|
|
+ yAxis: { type: 'value' },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '',
|
|
|
+ type: 'line',
|
|
|
+ stack: 'Total',
|
|
|
+ data: lineRes.data.numberList
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ });
|
|
|
+
|
|
|
+ const typePieInstance = echarts.init(typePie.value, 'macaroons');
|
|
|
+ typePieInstance.setOption({
|
|
|
+ title: { text: '', subtext: '', left: 'center' },
|
|
|
+ tooltip: { trigger: 'item' },
|
|
|
+ legend: { orient: 'vertical', left: 'left' },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '内容占比',
|
|
|
+ type: 'pie',
|
|
|
+ radius: '65%',
|
|
|
+ data: [
|
|
|
+ { value: ((res.data.imageNum / res.data.totalNum) * 100).toFixed(2), name: '图片' }, // Format to 2 decimal places
|
|
|
+ { value: ((res.data.videoNum / res.data.totalNum) * 100).toFixed(2), name: '视频' }
|
|
|
+ ],
|
|
|
+ emphasis: {
|
|
|
+ itemStyle: {
|
|
|
+ shadowBlur: 10,
|
|
|
+ shadowOffsetX: 0,
|
|
|
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- ]
|
|
|
- });
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching number and line data:', error);
|
|
|
+ }
|
|
|
};
|
|
|
+
|
|
|
const handleDateRangeChange = () => {
|
|
|
const rangeType = timeRadio.value;
|
|
|
const today = new Date();
|
|
|
const startDate = new Date();
|
|
|
const endDate = new Date();
|
|
|
switch (rangeType) {
|
|
|
- case 'today':
|
|
|
- break;
|
|
|
case 'week':
|
|
|
startDate.setDate(today.getDate() - 7);
|
|
|
break;
|
|
|
@@ -473,6 +583,14 @@ const handleDateRangeChange = () => {
|
|
|
startDate.setMonth(today.getMonth() - 1);
|
|
|
break;
|
|
|
default:
|
|
|
+ // Handle custom date range from date picker
|
|
|
+ if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
|
|
|
+ // Date picker value is already set, no need to calculate
|
|
|
+ getNumAndLine();
|
|
|
+ getPlayTop();
|
|
|
+ getOnlineTimeLine();
|
|
|
+ return;
|
|
|
+ }
|
|
|
throw new Error('Invalid range type');
|
|
|
}
|
|
|
dateRange.value = [formatDate(startDate), formatDate(endDate)];
|
|
|
@@ -480,55 +598,20 @@ const handleDateRangeChange = () => {
|
|
|
getPlayTop();
|
|
|
getOnlineTimeLine();
|
|
|
};
|
|
|
-const formatDate = (date: Date) => {
|
|
|
- const year = date.getFullYear();
|
|
|
- const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
- const day = String(date.getDate()).padStart(2, '0');
|
|
|
- return `${year}-${month}-${day}`;
|
|
|
-};
|
|
|
+
|
|
|
+// Watch for changes in dateRange and trigger data fetching
|
|
|
+watch(dateRange, (newDateRange, oldDateRange) => {
|
|
|
+ if (newDateRange && newDateRange[0] && newDateRange[1] && (newDateRange[0] !== oldDateRange?.[0] || newDateRange[1] !== oldDateRange?.[1])) {
|
|
|
+ getNumAndLine();
|
|
|
+ getPlayTop();
|
|
|
+ getOnlineTimeLine();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
- handleDateRangeChange();
|
|
|
- getNumAndLine();
|
|
|
+ setInitialDateRange(); // Set initial date range on mount
|
|
|
getNumByTag();
|
|
|
getNumByTypeAndTag();
|
|
|
- getPlayTop();
|
|
|
- getOnlineTimeLine();
|
|
|
getDiskUse();
|
|
|
});
|
|
|
</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.stat-card {
|
|
|
- text-align: center;
|
|
|
- height: 170px;
|
|
|
-}
|
|
|
-
|
|
|
-.number {
|
|
|
- font-size: 24px;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
-.success {
|
|
|
- color: green;
|
|
|
-}
|
|
|
-
|
|
|
-.danger {
|
|
|
- color: red;
|
|
|
-}
|
|
|
-
|
|
|
-.warning {
|
|
|
- color: orange;
|
|
|
-}
|
|
|
-
|
|
|
-.chart-placeholder {
|
|
|
- height: 250px;
|
|
|
- /*background: #f5f5f5;*/
|
|
|
- border-radius: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.disk-progress .el-progress--line {
|
|
|
- margin-bottom: 15px;
|
|
|
- max-width: 600px;
|
|
|
- margin-top: 50px;
|
|
|
-}
|
|
|
-</style>
|