play.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. <template>
  2. <div class="play-dashboard-root">
  3. <div class="play-dashboard-page">
  4. <el-container class="play-dashboard-container" style="height: 100vh">
  5. <el-header style="height: auto; padding: 20px;">
  6. <el-card shadow="hover" class="header-card">
  7. <el-row justify="end" align="middle">
  8. <el-col :span="19" style="text-align: right">
  9. <el-radio-group v-model="timeRadio" size="small" @change="handleDateRangeChange"
  10. class="time-radio-group">
  11. <el-radio-button label="近7天" value="week"/>
  12. <el-radio-button label="近30天" value="month"/>
  13. <el-radio-button label="自定义" value="diy"/>
  14. </el-radio-group>
  15. </el-col>
  16. <el-col :span="5" style="text-align: right">
  17. <el-date-picker v-model="dateRange" type="daterange" @change="handleDateRangeChange"
  18. range-separator="-"
  19. start-placeholder="开始日期"
  20. :disabled="diyFlag" :clearable="false" end-placeholder="结束日期"
  21. style="margin-left: 10px; margin-right: 30px"/>
  22. </el-col>
  23. </el-row>
  24. </el-card>
  25. </el-header>
  26. <el-main style="padding: 0 20px;">
  27. <el-row :gutter="20">
  28. <el-col :span="12">
  29. <el-card shadow="never" class="stat-card-large">
  30. <el-row :gutter="20">
  31. <el-col :span="8">
  32. <div class="stat-content">
  33. <p class="stat-label">总内容量</p>
  34. <h2 class="stat-number primary">{{ totalNum }}</h2>
  35. </div>
  36. </el-col>
  37. <el-col :span="16">
  38. <div ref="createLine" class="chart-small"></div>
  39. </el-col>
  40. </el-row>
  41. </el-card>
  42. </el-col>
  43. <el-col :span="6">
  44. <el-card shadow="never" class="stat-card">
  45. <p class="stat-label">图片素材</p>
  46. <h2 class="stat-number warning">{{ imageNum }}</h2>
  47. </el-card>
  48. </el-col>
  49. <el-col :span="6">
  50. <el-card shadow="never" class="stat-card">
  51. <p class="stat-label">视频素材</p>
  52. <h2 class="stat-number success">{{ videoNum }}</h2>
  53. </el-card>
  54. </el-col>
  55. </el-row>
  56. <el-row :gutter="20" class="margin-top-20">
  57. <el-col :span="18">
  58. <el-row :gutter="20">
  59. <el-col :span="8">
  60. <el-card shadow="never">
  61. <h3 class="chart-title">内容占比</h3>
  62. <div ref="typePie" class="chart-placeholder"></div>
  63. </el-card>
  64. </el-col>
  65. <el-col :span="8">
  66. <el-card shadow="never">
  67. <h3 class="chart-title">类型占比</h3>
  68. <div ref="tagPie" class="chart-placeholder"></div>
  69. </el-card>
  70. </el-col>
  71. <el-col :span="8">
  72. <el-card shadow="never">
  73. <h3 class="chart-title">素材统计</h3>
  74. <div ref="typeAndTag" class="chart-placeholder"></div>
  75. </el-card>
  76. </el-col>
  77. </el-row>
  78. <el-row :gutter="20" class="margin-top-20">
  79. <el-col :span="12">
  80. <el-card shadow="never" class="disk-card">
  81. <h3 class="chart-title">空间使用情况</h3>
  82. <div class="disk-info">
  83. <p>已用空间</p>
  84. <h2>{{ diskUsed }} GB / {{ diskTotal }} GB</h2>
  85. </div>
  86. <div class="disk-progress">
  87. <el-row align="middle">
  88. <el-col :span="3">
  89. <h3 class="progress-label">图片:</h3>
  90. </el-col>
  91. <el-col :span="21">
  92. <el-progress :text-inside="true" :stroke-width="22" :percentage="diskImage"
  93. color="#E6A23C" />
  94. </el-col>
  95. </el-row>
  96. </div>
  97. <div class="disk-progress">
  98. <el-row align="middle">
  99. <el-col :span="3">
  100. <h3 class="progress-label">视频:</h3>
  101. </el-col>
  102. <el-col :span="21">
  103. <el-progress :text-inside="true" :stroke-width="22" :percentage="diskVideo"
  104. color="#67C23A" />
  105. </el-col>
  106. </el-row>
  107. </div>
  108. </el-card>
  109. </el-col>
  110. <el-col :span="12">
  111. <el-card shadow="never">
  112. <h3 class="chart-title">播放时长统计</h3>
  113. <div ref="onlineTimeLine" class="chart-placeholder"></div>
  114. </el-card>
  115. </el-col>
  116. </el-row>
  117. </el-col>
  118. <el-col :span="6">
  119. <el-card shadow="never" class="top5-card">
  120. <div>
  121. <el-row :gutter="20" align="middle" class="top5-header">
  122. <el-col :span="12">
  123. <h3 class="chart-title">内容 TOP 5</h3>
  124. </el-col>
  125. <el-col :span="12">
  126. <el-select v-model="topType" @change="getPlayTop" placeholder="Select" style="margin-right: 10px">
  127. <el-option label="播放次数" value="1" />
  128. <el-option label="播放时长" value="2" />
  129. </el-select>
  130. </el-col>
  131. </el-row>
  132. </div>
  133. <div class="top-stats">
  134. <el-row :gutter="20" align="bottom">
  135. <el-col :span="12">
  136. <h4>图片</h4>
  137. </el-col>
  138. <el-col :span="12" class="text-right">
  139. <h3 class="top-stat-number">{{ imageTopNum }}</h3>
  140. </el-col>
  141. </el-row>
  142. </div>
  143. <div ref="playImageTop" class="chart-placeholder"></div>
  144. <div class="top-stats">
  145. <el-row :gutter="20" align="bottom">
  146. <el-col :span="12">
  147. <h4>视频</h4>
  148. </el-col>
  149. <el-col :span="12" class="text-right">
  150. <h3 class="top-stat-number">{{ videoTopNum }}</h3>
  151. </el-col>
  152. </el-row>
  153. </div>
  154. <div ref="playVideoTop" class="chart-placeholder"></div>
  155. </el-card>
  156. </el-col>
  157. </el-row>
  158. </el-main>
  159. </el-container>
  160. </div>
  161. </div>
  162. </template>
  163. <style>
  164. /* Global styles to ensure full height and remove default margins */
  165. html,
  166. body,
  167. #app {
  168. height: 100%;
  169. margin: 0;
  170. padding: 0;
  171. background-color: #f0f2f5;
  172. /* Set a background for the whole page */
  173. }
  174. .play-dashboard-root {
  175. height: 100vh;
  176. overflow-y: auto;
  177. }
  178. .play-dashboard-page {
  179. height: 100%;
  180. }
  181. /* Overriding Element Plus container styles for proper layout */
  182. .play-dashboard-container {
  183. height: 100%;
  184. flex-direction: column !important;
  185. display: flex !important;
  186. }
  187. .el-main.scrollable-main {
  188. height: 100%;
  189. overflow-y: auto;
  190. padding: 20px;
  191. }
  192. /* Overrides for nested layout components if they exist */
  193. .play-dashboard-page .navbar-fixed-full {
  194. position: static !important;
  195. }
  196. .play-dashboard-page .app-wrapper,
  197. .play-dashboard-page .layout-body,
  198. .play-dashboard-page .main-container {
  199. height: auto !important;
  200. min-height: auto !important;
  201. overflow: visible !important;
  202. display: block !important;
  203. margin-top: 0 !important;
  204. }
  205. </style>
  206. <style scoped>
  207. /* Main Content Area */
  208. .main-content {
  209. padding: 20px;
  210. background-color: #f0f2f5;
  211. }
  212. .play-dashboard-header {
  213. margin-bottom: 20px;
  214. height: 50px;
  215. }
  216. /* Header Card */
  217. .header-card {
  218. border-radius: 8px;
  219. border: none;
  220. }
  221. .text-right {
  222. text-align: right;
  223. }
  224. .date-picker {
  225. margin-left: 10px;
  226. }
  227. /* General Card Styling */
  228. .el-card {
  229. border-radius: 12px;
  230. border: none;
  231. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
  232. height: 100%;
  233. }
  234. /* Statistic Cards */
  235. .stat-card,
  236. .stat-card-large {
  237. text-align: center;
  238. display: flex;
  239. flex-direction: column;
  240. justify-content: center;
  241. padding: 20px;
  242. }
  243. .stat-card-large {
  244. text-align: left;
  245. }
  246. .stat-content {
  247. text-align: center;
  248. }
  249. .stat-label {
  250. font-size: 14px;
  251. color: #606266;
  252. margin: 0 0 10px 0;
  253. font-weight: bold;
  254. }
  255. .stat-number {
  256. font-size: 36px;
  257. font-weight: bold;
  258. margin: 0;
  259. line-height: 1.2;
  260. }
  261. .primary {
  262. color: #409EFF;
  263. }
  264. .success {
  265. color: #67C23A;
  266. }
  267. .warning {
  268. color: #E6A23C;
  269. }
  270. .danger {
  271. color: #F56C6C;
  272. }
  273. /* Chart Styling */
  274. .chart-title {
  275. font-size: 16px;
  276. font-weight: 600;
  277. color: #303133;
  278. margin-bottom: 20px;
  279. padding-left: 10px;
  280. }
  281. .chart-small {
  282. height: 120px;
  283. }
  284. .chart-placeholder {
  285. height: 230px;
  286. }
  287. .margin-top-20 {
  288. margin-top: 20px;
  289. }
  290. /* Disk Usage Card */
  291. .disk-card {
  292. height: 300px;
  293. }
  294. .disk-info {
  295. text-align: center;
  296. margin: 10px 0;
  297. }
  298. .disk-info p {
  299. color: #606266;
  300. margin: 0;
  301. }
  302. .disk-info h2 {
  303. font-size: 28px;
  304. font-weight: bold;
  305. color: #303133;
  306. margin-top: 8px;
  307. }
  308. .disk-progress {
  309. margin-top: 25px;
  310. padding: 0 15px;
  311. }
  312. .progress-label {
  313. font-size: 14px;
  314. font-weight: normal;
  315. color: #606266;
  316. }
  317. :deep(.el-progress-bar__inner) {
  318. border-radius: 100px;
  319. }
  320. :deep(.el-progress-bar__outer) {
  321. border-radius: 100px;
  322. }
  323. /* Top 5 Card */
  324. .top5-card {
  325. height: 605px; /* Allow height to adjust to content */
  326. }
  327. .top5-header {
  328. margin-bottom: 20px;
  329. }
  330. .top-stats {
  331. margin-top: 15px;
  332. padding: 0 10px;
  333. }
  334. .top-stats h4 {
  335. font-size: 16px;
  336. font-weight: 500;
  337. color: #606266;
  338. margin: 0;
  339. }
  340. .top-stat-number {
  341. color: #303133;
  342. font-weight: bold;
  343. margin: 0;
  344. }
  345. </style>
  346. <script setup lang="ts">
  347. import * as echarts from 'echarts';
  348. import {onMounted, onUnmounted, ref} from 'vue';
  349. import {
  350. diskUse,
  351. fileStatistics,
  352. fileStatisticsByTag,
  353. numLine,
  354. statisticsByTypeAndTag
  355. } from '@/api/smsb/source/minioData';
  356. import {playTopStatistics, sumOnlineTimeLine} from '@/api/smsb/source/play_record';
  357. // ECharts instances
  358. let onlineTimeLineInstance: echarts.ECharts | null = null;
  359. let playImageTopInstance: echarts.ECharts | null = null;
  360. let playVideoTopInstance: echarts.ECharts | null = null;
  361. let typeAndTagInstance: echarts.ECharts | null = null;
  362. let tagPieInstance: echarts.ECharts | null = null;
  363. let createLineInstance: echarts.ECharts | null = null;
  364. let typePieInstance: echarts.ECharts | null = null;
  365. // ECharts Color Palette
  366. const colorPalette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
  367. onUnmounted(() => {
  368. // Dispose all echarts instances on component unmount
  369. onlineTimeLineInstance?.dispose();
  370. playImageTopInstance?.dispose();
  371. playVideoTopInstance?.dispose();
  372. typeAndTagInstance?.dispose();
  373. tagPieInstance?.dispose();
  374. createLineInstance?.dispose();
  375. typePieInstance?.dispose();
  376. });
  377. // Reactive state variables
  378. const timeRadio = ref('week');
  379. const dateRange = ref<[Date, Date]>([new Date(), new Date()]);
  380. const diyFlag = ref(true);
  381. const totalNum = ref(0);
  382. const imageNum = ref(0);
  383. const videoNum = ref(0);
  384. const imageTopNum = ref(0);
  385. const videoTopNum = ref(0);
  386. const diskUsed = ref('0');
  387. const diskTotal = ref('0');
  388. const diskImage = ref(0);
  389. const diskVideo = ref(0);
  390. const topType = ref('1');
  391. // Template refs for chart containers
  392. const createLine = ref<HTMLElement>();
  393. const typePie = ref<HTMLElement>();
  394. const tagPie = ref<HTMLElement>();
  395. const typeAndTag = ref<HTMLElement>();
  396. const playImageTop = ref<HTMLElement>();
  397. const playVideoTop = ref<HTMLElement>();
  398. const onlineTimeLine = ref<HTMLElement>();
  399. // Helper function to format date
  400. const formatDate = (date: Date): string => {
  401. const year = date.getFullYear();
  402. const month = String(date.getMonth() + 1).padStart(2, '0');
  403. const day = String(date.getDate()).padStart(2, '0');
  404. return `${year}-${month}-${day}`;
  405. };
  406. // Set initial date range to the last 7 days
  407. const setInitialDateRange = () => {
  408. const endDate = new Date();
  409. const startDate = new Date();
  410. startDate.setDate(endDate.getDate() - 6); // Inclusive of the start day
  411. dateRange.value = [startDate, endDate];
  412. };
  413. const getDiskUse = async () => {
  414. try {
  415. const res = await diskUse();
  416. diskTotal.value = (res.data.total / 1024 / 1024).toFixed(2);
  417. diskUsed.value = (res.data.used / 1024 / 1024).toFixed(2); // Keep consistent decimal places
  418. diskImage.value = parseFloat(((res.data.imageUse / res.data.total) * 100).toFixed(2));
  419. diskVideo.value = parseFloat(((res.data.videoUse / res.data.total) * 100).toFixed(2));
  420. } catch (error) {
  421. console.error('Error fetching disk usage:', error);
  422. }
  423. };
  424. const getOnlineTimeLine = async () => {
  425. if (!onlineTimeLine.value) return;
  426. try {
  427. const params = {
  428. startTime: formatDate(dateRange.value[0]),
  429. endTime: formatDate(dateRange.value[1])
  430. };
  431. const res = await sumOnlineTimeLine(params);
  432. onlineTimeLineInstance = echarts.init(onlineTimeLine.value, 'macaroons');
  433. onlineTimeLineInstance.setOption({
  434. color: ['#80FFA5', '#00DDFF'],
  435. tooltip: { trigger: 'axis' },
  436. legend: { data: ['图片', '视频'], textStyle: { color: '#606266' } },
  437. grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
  438. xAxis: {
  439. type: 'category',
  440. boundaryGap: false,
  441. data: res.data.timeList,
  442. axisLine: { lineStyle: { color: '#DCDFE6' } },
  443. axisLabel: { color: '#909399' }
  444. },
  445. yAxis: {
  446. type: 'value',
  447. axisLine: { show: true, lineStyle: { color: '#DCDFE6' } },
  448. axisLabel: { color: '#909399' },
  449. splitLine: { lineStyle: { color: '#E4E7ED', type: 'dashed' } }
  450. },
  451. series: [
  452. {
  453. name: '图片',
  454. type: 'line',
  455. smooth: true,
  456. data: res.data.imageNumberList,
  457. areaStyle: {
  458. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(128, 255, 165, 0.5)' }, { offset: 1, color: 'rgba(128, 255, 165, 0)' }])
  459. }
  460. },
  461. {
  462. name: '视频',
  463. type: 'line',
  464. smooth: true,
  465. data: res.data.videoNumberList,
  466. areaStyle: {
  467. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(0, 221, 255, 0.5)' }, { offset: 1, color: 'rgba(0, 221, 255, 0)' }])
  468. }
  469. }
  470. ]
  471. });
  472. } catch (error) {
  473. console.error('Error fetching online time line:', error);
  474. }
  475. };
  476. const getPlayTop = async () => {
  477. if (!playImageTop.value || !playVideoTop.value) return;
  478. try {
  479. const params = {
  480. startTime: formatDate(dateRange.value[0]),
  481. endTime: formatDate(dateRange.value[1]),
  482. type: topType.value
  483. };
  484. const res = await playTopStatistics(params);
  485. imageTopNum.value = res.data.imageNum;
  486. videoTopNum.value = res.data.videoNum;
  487. // 文本截取函数
  488. const truncateText = (text: string, maxLength: number = 15): string => {
  489. if (!text) return '';
  490. return text.length > maxLength ? text.substring(0, maxLength) + '...' : text;
  491. };
  492. // Image Top Chart
  493. playImageTopInstance = echarts.init(playImageTop.value, 'macaroons');
  494. playImageTopInstance.setOption({
  495. tooltip: {
  496. trigger: 'axis',
  497. axisPointer: { type: 'shadow' },
  498. formatter: (params) => {
  499. const param = params[0];
  500. return `${param.name}<br/>${param.seriesName}: ${param.value}`;
  501. }
  502. },
  503. grid: { left: '3%', right: '10%', bottom: '3%', containLabel: true },
  504. xAxis: { type: 'value', boundaryGap: [0, 0.01], show: false },
  505. yAxis: {
  506. type: 'category',
  507. data: res.data.imageList,
  508. axisLabel: {
  509. color: '#606266',
  510. formatter: (value) => truncateText(value, 5) // 限制y轴标签最多显示5个字符
  511. }
  512. },
  513. series: [{
  514. type: 'bar',
  515. data: res.data.imageNumberList,
  516. itemStyle: { color: '#E6A23C', borderRadius: [0, 5, 5, 0] },
  517. label: {
  518. show: false // 如果需要在柱子上显示数值可以设为true
  519. }
  520. }]
  521. });
  522. // Video Top Chart
  523. playVideoTopInstance = echarts.init(playVideoTop.value, 'macaroons');
  524. playVideoTopInstance.setOption({
  525. tooltip: {
  526. trigger: 'axis',
  527. axisPointer: { type: 'shadow' },
  528. formatter: (params) => {
  529. const param = params[0];
  530. return `${param.name}<br/>${param.seriesName}: ${param.value}`;
  531. }
  532. },
  533. grid: { left: '3%', right: '10%', bottom: '3%', containLabel: true },
  534. xAxis: { type: 'value', boundaryGap: [0, 0.01], show: false },
  535. yAxis: {
  536. type: 'category',
  537. data: res.data.videoList,
  538. axisLabel: {
  539. color: '#606266',
  540. formatter: (value) => truncateText(value, 5) // 限制y轴标签最多显示5个字符
  541. }
  542. },
  543. series: [{
  544. type: 'bar',
  545. data: res.data.videoNumberList,
  546. itemStyle: { color: '#67C23A', borderRadius: [0, 5, 5, 0] },
  547. label: {
  548. show: false // 如果需要在柱子上显示数值可以设为true
  549. }
  550. }]
  551. });
  552. } catch (error) {
  553. console.error('Error fetching play top statistics:', error);
  554. }
  555. };
  556. const getNumByTypeAndTag = async () => {
  557. if (!typeAndTag.value) return;
  558. try {
  559. const res = await statisticsByTypeAndTag();
  560. typeAndTagInstance = echarts.init(typeAndTag.value, 'macaroons');
  561. typeAndTagInstance.setOption({
  562. color: colorPalette,
  563. legend: { textStyle: { color: '#606266' } },
  564. tooltip: {},
  565. dataset: {
  566. source: [['product', '广告', '公益', '宣传'], ['图片'].concat(res.data.imageTagList), ['视频'].concat(res.data.videoTagList)]
  567. },
  568. xAxis: { type: 'category', axisLabel: { color: '#909399' } },
  569. yAxis: { axisLabel: { color: '#909399' }, splitLine: { lineStyle: { color: '#E4E7ED', type: 'dashed' } } },
  570. series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
  571. });
  572. } catch (error) {
  573. console.error('Error fetching statistics by type and tag:', error);
  574. }
  575. };
  576. const getNumByTag = async () => {
  577. if (!tagPie.value) return;
  578. try {
  579. const res = await fileStatisticsByTag();
  580. tagPieInstance = echarts.init(tagPie.value, 'macaroons');
  581. tagPieInstance.setOption({
  582. color: ['#fac858', '#91cc75', '#73c0de'],
  583. tooltip: { trigger: 'item', formatter: '{b} : {c} ({d}%)' },
  584. legend: { orient: 'vertical', left: 'left', textStyle: { color: '#606266' } },
  585. series: [
  586. {
  587. name: '类型占比',
  588. type: 'pie',
  589. radius: ['40%', '65%'],
  590. avoidLabelOverlap: false,
  591. label: { show: false, position: 'center' },
  592. emphasis: { label: { show: true, fontSize: '20', fontWeight: 'bold' } },
  593. data: [
  594. { value: res.data.ggNum, name: '广告' },
  595. { value: res.data.gyNum, name: '公益' },
  596. { value: res.data.xcNum, name: '宣传' }
  597. ]
  598. }
  599. ]
  600. });
  601. } catch (error) {
  602. console.error('Error fetching statistics by tag:', error);
  603. }
  604. };
  605. const getNumAndLine = async () => {
  606. try {
  607. const params = {
  608. startTime: formatDate(dateRange.value[0]),
  609. endTime: formatDate(dateRange.value[1])
  610. };
  611. const res = await fileStatistics();
  612. totalNum.value = res.data.totalNum;
  613. imageNum.value = res.data.imageNum;
  614. videoNum.value = res.data.videoNum;
  615. if (createLine.value) {
  616. const lineRes = await numLine(params);
  617. createLineInstance = echarts.init(createLine.value, 'macaroons');
  618. createLineInstance.setOption({
  619. tooltip: { trigger: 'axis' },
  620. grid: { left: '0', right: '0', bottom: '0', top: '10%', containLabel: false },
  621. xAxis: { type: 'category', boundaryGap: false, data: lineRes.data.timeList, show: false },
  622. yAxis: { type: 'value', show: false },
  623. series: [{
  624. name: '内容量',
  625. type: 'line',
  626. smooth: true,
  627. symbol: 'none',
  628. lineStyle: { color: '#409EFF', width: 2 },
  629. areaStyle: {
  630. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(64, 158, 255, 0.3)' }, { offset: 1, color: 'rgba(64, 158, 255, 0)' }])
  631. },
  632. data: lineRes.data.numberList
  633. }]
  634. });
  635. }
  636. if (typePie.value) {
  637. typePieInstance = echarts.init(typePie.value, 'macaroons');
  638. typePieInstance.setOption({
  639. color: ['#E6A23C', '#67C23A'],
  640. tooltip: { trigger: 'item', formatter: '{b} : {c} ({d}%)' },
  641. legend: { orient: 'vertical', left: 'left', textStyle: { color: '#606266' } },
  642. series: [{
  643. name: '内容占比',
  644. type: 'pie',
  645. radius: ['40%', '65%'],
  646. avoidLabelOverlap: false,
  647. label: { show: false, position: 'center' },
  648. emphasis: { label: { show: true, fontSize: '20', fontWeight: 'bold' } },
  649. data: [
  650. { value: res.data.imageNum, name: '图片' },
  651. { value: res.data.videoNum, name: '视频' }
  652. ],
  653. }]
  654. });
  655. }
  656. } catch (error) {
  657. console.error('Error fetching number and line data:', error);
  658. }
  659. };
  660. const handleDateRangeChange = () => {
  661. const rangeType = timeRadio.value;
  662. const endDate = new Date();
  663. const startDate = new Date();
  664. if (rangeType === 'week') {
  665. startDate.setDate(endDate.getDate() - 6);
  666. dateRange.value = [startDate, endDate];
  667. diyFlag.value = true;
  668. } else if (rangeType === 'month') {
  669. startDate.setMonth(endDate.getMonth() - 1);
  670. dateRange.value = [startDate, endDate];
  671. diyFlag.value = true;
  672. } else if (rangeType === 'diy') {
  673. diyFlag.value = false;
  674. return; // Don't refetch until user selects a new DIY range
  675. }
  676. // Refetch data for the new date range
  677. fetchAllData();
  678. };
  679. const fetchAllData = () => {
  680. getNumAndLine();
  681. getPlayTop();
  682. getOnlineTimeLine();
  683. }
  684. onMounted(() => {
  685. setInitialDateRange();
  686. // Initial data fetch
  687. getNumByTag();
  688. getNumByTypeAndTag();
  689. getDiskUse();
  690. fetchAllData();
  691. // Resize charts on window resize
  692. const resizeHandler = () => {
  693. onlineTimeLineInstance?.resize();
  694. playImageTopInstance?.resize();
  695. playVideoTopInstance?.resize();
  696. typeAndTagInstance?.resize();
  697. tagPieInstance?.resize();
  698. createLineInstance?.resize();
  699. typePieInstance?.resize();
  700. };
  701. window.addEventListener('resize', resizeHandler);
  702. onUnmounted(() => {
  703. window.removeEventListener('resize', resizeHandler);
  704. });
  705. });
  706. </script>