index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. <template>
  2. <div class="dashboard-container">
  3. <!-- 顶部横幅 -->
  4. <div class="banner">
  5. <div class="banner-content">
  6. <h1>时空门户</h1>
  7. <p>时空门户是一个集数据采集、分析、展示于一体的综合性平台,为用户提供全面的设备监控和数据分析服务</p>
  8. <button class="enter-btn">进入系统</button>
  9. </div>
  10. </div>
  11. <!-- 平台数据统计 -->
  12. <div class="stats-section">
  13. <div class="stats-grid">
  14. <div class="stat-card card-1">
  15. <div class="stat-number">1,248</div>
  16. <div class="stat-label">在线设备数</div>
  17. </div>
  18. <div class="stat-card card-2">
  19. <div class="stat-number">86</div>
  20. <div class="stat-label">重大隐患统计</div>
  21. </div>
  22. <div class="stat-card card-3">
  23. <div class="stat-number">24,586</div>
  24. <div class="stat-label">隐患排查人员</div>
  25. </div>
  26. </div>
  27. </div>
  28. <!-- 数据概览 -->
  29. <div class="data-overview">
  30. <div class="overview-header">
  31. <h2>数据概览</h2>
  32. <div class="time-tabs">
  33. <div class="tab active">今日</div>
  34. <div class="tab">本周</div>
  35. <div class="tab">本月</div>
  36. <div class="tab">本年</div>
  37. </div>
  38. </div>
  39. <div class="charts-grid">
  40. <!-- 设备统计柱状图 -->
  41. <div class="chart-card">
  42. <div class="chart-title">设备统计</div>
  43. <div ref="deviceChart" class="chart-container"></div>
  44. </div>
  45. <!-- 设备状态分布饼图 -->
  46. <div class="chart-card">
  47. <div class="chart-title">设备状态分布</div>
  48. <div ref="statusChart" class="chart-container"></div>
  49. </div>
  50. <!-- 用户活跃度分析折线图 -->
  51. <div class="chart-card">
  52. <div class="chart-title">用户活跃度分析</div>
  53. <div ref="activityChart" class="chart-container"></div>
  54. </div>
  55. <!-- 数据量柱状图 -->
  56. <div class="chart-card">
  57. <div class="chart-title">数据量</div>
  58. <div ref="dataVolumeChart" class="chart-container"></div>
  59. </div>
  60. </div>
  61. </div>
  62. <!-- 设备综合分析比较 -->
  63. <div class="comparison-section">
  64. <div class="chart-card full-width">
  65. <div class="chart-title">设备综合分析比较</div>
  66. <div ref="comparisonChart" class="chart-container"></div>
  67. </div>
  68. </div>
  69. <!-- 功能演示 -->
  70. <div class="demo-section">
  71. <h2>功能演示</h2>
  72. <div class="demo-grid">
  73. <div class="demo-card">
  74. <div class="demo-thumbnail">
  75. <div class="play-btn">▶</div>
  76. </div>
  77. <div class="demo-title">设备监控演示</div>
  78. </div>
  79. <div class="demo-card">
  80. <div class="demo-thumbnail">
  81. <div class="play-btn">▶</div>
  82. </div>
  83. <div class="demo-title">数据分析演示</div>
  84. </div>
  85. <div class="demo-card">
  86. <div class="demo-thumbnail">
  87. <div class="play-btn">▶</div>
  88. </div>
  89. <div class="demo-title">隐患排查演示</div>
  90. </div>
  91. </div>
  92. </div>
  93. </div>
  94. </template>
  95. <script>
  96. import * as echarts from 'echarts'
  97. export default {
  98. name: 'SpatialTemporalPortal',
  99. data() {
  100. return {
  101. deviceChart: null,
  102. statusChart: null,
  103. activityChart: null,
  104. dataVolumeChart: null,
  105. comparisonChart: null
  106. }
  107. },
  108. mounted() {
  109. this.initCharts()
  110. window.addEventListener('resize', this.handleResize)
  111. },
  112. beforeUnmount() {
  113. window.removeEventListener('resize', this.handleResize)
  114. this.destroyCharts()
  115. },
  116. methods: {
  117. initCharts() {
  118. this.initDeviceChart()
  119. this.initStatusChart()
  120. this.initActivityChart()
  121. this.initDataVolumeChart()
  122. this.initComparisonChart()
  123. },
  124. initDeviceChart() {
  125. this.deviceChart = echarts.init(this.$refs.deviceChart)
  126. const option = {
  127. tooltip: {
  128. trigger: 'axis',
  129. backgroundColor: 'rgba(0, 25, 50, 0.8)',
  130. borderColor: '#1E90FF',
  131. textStyle: {
  132. color: '#fff'
  133. }
  134. },
  135. grid: {
  136. left: '3%',
  137. right: '4%',
  138. bottom: '3%',
  139. containLabel: true
  140. },
  141. xAxis: {
  142. type: 'category',
  143. data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
  144. axisLabel: {
  145. color: '#a3b6c7'
  146. },
  147. axisLine: {
  148. lineStyle: {
  149. color: '#1E90FF'
  150. }
  151. }
  152. },
  153. yAxis: {
  154. type: 'value',
  155. axisLabel: {
  156. color: '#a3b6c7'
  157. },
  158. axisLine: {
  159. lineStyle: {
  160. color: '#1E90FF'
  161. }
  162. },
  163. splitLine: {
  164. lineStyle: {
  165. color: 'rgba(30, 144, 255, 0.2)'
  166. }
  167. }
  168. },
  169. series: [
  170. {
  171. data: [120, 200, 150, 80, 70, 110],
  172. type: 'bar',
  173. barWidth: '60%',
  174. itemStyle: {
  175. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  176. { offset: 0, color: '#1E90FF' },
  177. { offset: 1, color: '#00BFFF' }
  178. ])
  179. }
  180. }
  181. ]
  182. }
  183. this.deviceChart.setOption(option)
  184. },
  185. initStatusChart() {
  186. this.statusChart = echarts.init(this.$refs.statusChart)
  187. const option = {
  188. tooltip: {
  189. trigger: 'item',
  190. backgroundColor: 'rgba(0, 25, 50, 0.8)',
  191. borderColor: '#1E90FF',
  192. textStyle: {
  193. color: '#fff'
  194. }
  195. },
  196. legend: {
  197. orient: 'horizontal',
  198. bottom: 0,
  199. textStyle: {
  200. color: '#a3b6c7'
  201. }
  202. },
  203. series: [
  204. {
  205. name: '设备状态',
  206. type: 'pie',
  207. radius: ['40%', '70%'],
  208. avoidLabelOverlap: false,
  209. itemStyle: {
  210. borderRadius: 10,
  211. borderColor: '#0A192F',
  212. borderWidth: 2
  213. },
  214. label: {
  215. show: false,
  216. position: 'center'
  217. },
  218. emphasis: {
  219. label: {
  220. show: true,
  221. fontSize: 20,
  222. fontWeight: 'bold',
  223. color: '#fff'
  224. }
  225. },
  226. labelLine: {
  227. show: false
  228. },
  229. data: [
  230. { value: 400, name: '正常', itemStyle: { color: '#52C41A' } },
  231. { value: 300, name: '警告', itemStyle: { color: '#FAAD14' } },
  232. { value: 200, name: '异常', itemStyle: { color: '#F5222D' } },
  233. { value: 100, name: '离线', itemStyle: { color: '#8C8C8C' } }
  234. ]
  235. }
  236. ]
  237. }
  238. this.statusChart.setOption(option)
  239. },
  240. initActivityChart() {
  241. this.activityChart = echarts.init(this.$refs.activityChart)
  242. const option = {
  243. tooltip: {
  244. trigger: 'axis',
  245. backgroundColor: 'rgba(0, 25, 50, 0.8)',
  246. borderColor: '#1E90FF',
  247. textStyle: {
  248. color: '#fff'
  249. }
  250. },
  251. grid: {
  252. left: '3%',
  253. right: '4%',
  254. bottom: '3%',
  255. containLabel: true
  256. },
  257. xAxis: {
  258. type: 'category',
  259. boundaryGap: false,
  260. data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
  261. axisLabel: {
  262. color: '#a3b6c7'
  263. },
  264. axisLine: {
  265. lineStyle: {
  266. color: '#1E90FF'
  267. }
  268. }
  269. },
  270. yAxis: {
  271. type: 'value',
  272. axisLabel: {
  273. color: '#a3b6c7'
  274. },
  275. axisLine: {
  276. lineStyle: {
  277. color: '#1E90FF'
  278. }
  279. },
  280. splitLine: {
  281. lineStyle: {
  282. color: 'rgba(30, 144, 255, 0.2)'
  283. }
  284. }
  285. },
  286. series: [
  287. {
  288. name: '活跃度',
  289. type: 'line',
  290. stack: 'Total',
  291. smooth: true,
  292. lineStyle: {
  293. color: '#1E90FF'
  294. },
  295. areaStyle: {
  296. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  297. { offset: 0, color: 'rgba(30, 144, 255, 0.6)' },
  298. { offset: 1, color: 'rgba(30, 144, 255, 0.1)' }
  299. ])
  300. },
  301. emphasis: {
  302. focus: 'series'
  303. },
  304. data: [120, 132, 101, 134, 90, 230]
  305. }
  306. ]
  307. }
  308. this.activityChart.setOption(option)
  309. },
  310. initDataVolumeChart() {
  311. this.dataVolumeChart = echarts.init(this.$refs.dataVolumeChart)
  312. const option = {
  313. tooltip: {
  314. trigger: 'axis',
  315. backgroundColor: 'rgba(0, 25, 50, 0.8)',
  316. borderColor: '#1E90FF',
  317. textStyle: {
  318. color: '#fff'
  319. }
  320. },
  321. grid: {
  322. left: '3%',
  323. right: '4%',
  324. bottom: '3%',
  325. containLabel: true
  326. },
  327. xAxis: {
  328. type: 'category',
  329. data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
  330. axisLabel: {
  331. color: '#a3b6c7'
  332. },
  333. axisLine: {
  334. lineStyle: {
  335. color: '#1E90FF'
  336. }
  337. }
  338. },
  339. yAxis: {
  340. type: 'value',
  341. axisLabel: {
  342. color: '#a3b6c7'
  343. },
  344. axisLine: {
  345. lineStyle: {
  346. color: '#1E90FF'
  347. }
  348. },
  349. splitLine: {
  350. lineStyle: {
  351. color: 'rgba(30, 144, 255, 0.2)'
  352. }
  353. }
  354. },
  355. series: [
  356. {
  357. data: [1200, 2000, 1500, 800, 700, 1100, 1300],
  358. type: 'bar',
  359. barWidth: '60%',
  360. itemStyle: {
  361. color: '#FF7F50'
  362. }
  363. }
  364. ]
  365. }
  366. this.dataVolumeChart.setOption(option)
  367. },
  368. initComparisonChart() {
  369. this.comparisonChart = echarts.init(this.$refs.comparisonChart)
  370. const option = {
  371. tooltip: {
  372. trigger: 'axis',
  373. backgroundColor: 'rgba(0, 25, 50, 0.8)',
  374. borderColor: '#1E90FF',
  375. textStyle: {
  376. color: '#fff'
  377. }
  378. },
  379. legend: {
  380. data: ['设备A', '设备B', '设备C'],
  381. textStyle: {
  382. color: '#a3b6c7'
  383. }
  384. },
  385. grid: {
  386. left: '3%',
  387. right: '4%',
  388. bottom: '3%',
  389. containLabel: true
  390. },
  391. xAxis: {
  392. type: 'category',
  393. boundaryGap: false,
  394. data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
  395. axisLabel: {
  396. color: '#a3b6c7'
  397. },
  398. axisLine: {
  399. lineStyle: {
  400. color: '#1E90FF'
  401. }
  402. }
  403. },
  404. yAxis: {
  405. type: 'value',
  406. axisLabel: {
  407. color: '#a3b6c7'
  408. },
  409. axisLine: {
  410. lineStyle: {
  411. color: '#1E90FF'
  412. }
  413. },
  414. splitLine: {
  415. lineStyle: {
  416. color: 'rgba(30, 144, 255, 0.2)'
  417. }
  418. }
  419. },
  420. series: [
  421. {
  422. name: '设备A',
  423. type: 'line',
  424. stack: 'Total',
  425. smooth: true,
  426. lineStyle: {
  427. color: '#1E90FF'
  428. },
  429. areaStyle: {
  430. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  431. { offset: 0, color: 'rgba(30, 144, 255, 0.6)' },
  432. { offset: 1, color: 'rgba(30, 144, 255, 0.1)' }
  433. ])
  434. },
  435. data: [120, 132, 101, 134, 90, 230]
  436. },
  437. {
  438. name: '设备B',
  439. type: 'line',
  440. stack: 'Total',
  441. smooth: true,
  442. lineStyle: {
  443. color: '#52C41A'
  444. },
  445. areaStyle: {
  446. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  447. { offset: 0, color: 'rgba(82, 196, 26, 0.6)' },
  448. { offset: 1, color: 'rgba(82, 196, 26, 0.1)' }
  449. ])
  450. },
  451. data: [220, 182, 191, 234, 290, 330]
  452. },
  453. {
  454. name: '设备C',
  455. type: 'line',
  456. stack: 'Total',
  457. smooth: true,
  458. lineStyle: {
  459. color: '#FF7F50'
  460. },
  461. areaStyle: {
  462. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  463. { offset: 0, color: 'rgba(255, 127, 80, 0.6)' },
  464. { offset: 1, color: 'rgba(255, 127, 80, 0.1)' }
  465. ])
  466. },
  467. data: [150, 232, 201, 154, 190, 330]
  468. }
  469. ]
  470. }
  471. this.comparisonChart.setOption(option)
  472. },
  473. handleResize() {
  474. if (this.deviceChart) this.deviceChart.resize()
  475. if (this.statusChart) this.statusChart.resize()
  476. if (this.activityChart) this.activityChart.resize()
  477. if (this.dataVolumeChart) this.dataVolumeChart.resize()
  478. if (this.comparisonChart) this.comparisonChart.resize()
  479. },
  480. destroyCharts() {
  481. if (this.deviceChart) {
  482. this.deviceChart.dispose()
  483. this.deviceChart = null
  484. }
  485. if (this.statusChart) {
  486. this.statusChart.dispose()
  487. this.statusChart = null
  488. }
  489. if (this.activityChart) {
  490. this.activityChart.dispose()
  491. this.activityChart = null
  492. }
  493. if (this.dataVolumeChart) {
  494. this.dataVolumeChart.dispose()
  495. this.dataVolumeChart = null
  496. }
  497. if (this.comparisonChart) {
  498. this.comparisonChart.dispose()
  499. this.comparisonChart = null
  500. }
  501. }
  502. }
  503. }
  504. </script>
  505. <style lang="less" scoped>
  506. .dashboard-container {
  507. background-color: #0A192F;
  508. min-height: 100vh;
  509. color: #fff;
  510. }
  511. /* 顶部横幅 */
  512. .banner {
  513. position: relative;
  514. height: 500px;
  515. background: url('@/assets/images/common/home-bg1.png') center/cover no-repeat;
  516. display: flex;
  517. align-items: center;
  518. justify-content: flex-end;
  519. padding-right: 10%;
  520. &::before {
  521. content: '';
  522. position: absolute;
  523. top: 0;
  524. left: 0;
  525. right: 0;
  526. bottom: 0;
  527. background: linear-gradient(to right, rgba(10, 25, 47, 0.9), rgba(10, 25, 47, 0.7));
  528. }
  529. .banner-content {
  530. position: relative;
  531. max-width: 600px;
  532. text-align: left;
  533. padding: 0 20px;
  534. h1 {
  535. font-size: 42px;
  536. font-weight: bold;
  537. margin-bottom: 20px;
  538. color: #fff;
  539. }
  540. p {
  541. font-size: 14px;
  542. line-height: 1.8;
  543. margin-bottom: 30px;
  544. color: #a3b6c7;
  545. }
  546. .enter-btn {
  547. background-color: transparent;
  548. color: #409eff;
  549. border: 1px solid #409eff;
  550. padding: 8px 30px;
  551. font-size: 16px;
  552. border-radius: 20px;
  553. cursor: pointer;
  554. transition: all 0.3s ease;
  555. &:hover {
  556. background-color: #409eff;
  557. color: #fff;
  558. transform: translateY(-2px);
  559. }
  560. }
  561. }
  562. }
  563. /* 平台数据统计 */
  564. .stats-section {
  565. padding: 40px 20px;
  566. .stats-grid {
  567. display: flex;
  568. justify-content: center;
  569. gap: 30px;
  570. flex-wrap: wrap;
  571. .stat-card {
  572. width: 300px;
  573. height: 150px;
  574. border-radius: 12px;
  575. padding: 20px;
  576. display: flex;
  577. flex-direction: column;
  578. justify-content: center;
  579. align-items: center;
  580. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  581. transition: transform 0.3s ease;
  582. &:hover {
  583. transform: translateY(-5px);
  584. }
  585. .stat-number {
  586. font-size: 36px;
  587. font-weight: bold;
  588. margin-bottom: 10px;
  589. color: #fff;
  590. }
  591. .stat-label {
  592. font-size: 16px;
  593. color: rgba(255, 255, 255, 0.8);
  594. }
  595. }
  596. .card-1 {
  597. background: linear-gradient(135deg, #1E90FF 0%, #00BFFF 100%);
  598. }
  599. .card-2 {
  600. background: linear-gradient(135deg, #52C41A 0%, #95DE64 100%);
  601. }
  602. .card-3 {
  603. background: linear-gradient(135deg, #9370DB 0%, #BA55D3 100%);
  604. }
  605. }
  606. }
  607. /* 数据概览 */
  608. .data-overview {
  609. padding: 0 20px 40px;
  610. .overview-header {
  611. display: flex;
  612. justify-content: space-between;
  613. align-items: center;
  614. margin-bottom: 30px;
  615. h2 {
  616. font-size: 24px;
  617. color: #fff;
  618. margin: 0;
  619. }
  620. .time-tabs {
  621. display: flex;
  622. gap: 20px;
  623. .tab {
  624. padding: 8px 16px;
  625. cursor: pointer;
  626. color: #a3b6c7;
  627. border-radius: 20px;
  628. transition: all 0.3s ease;
  629. &:hover {
  630. color: #409eff;
  631. }
  632. &.active {
  633. background-color: #409eff;
  634. color: #fff;
  635. }
  636. }
  637. }
  638. }
  639. .charts-grid {
  640. display: grid;
  641. grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  642. gap: 30px;
  643. .chart-card {
  644. background-color: rgba(30, 41, 59, 0.6);
  645. border-radius: 12px;
  646. padding: 20px;
  647. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  648. .chart-title {
  649. font-size: 18px;
  650. color: #fff;
  651. margin-bottom: 20px;
  652. text-align: center;
  653. }
  654. .chart-container {
  655. height: 300px;
  656. width: 100%;
  657. }
  658. }
  659. }
  660. }
  661. /* 设备综合分析比较 */
  662. .comparison-section {
  663. padding: 0 20px 40px;
  664. .chart-card {
  665. background-color: rgba(30, 41, 59, 0.6);
  666. border-radius: 12px;
  667. padding: 20px;
  668. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  669. &.full-width {
  670. max-width: 100%;
  671. }
  672. .chart-title {
  673. font-size: 18px;
  674. color: #fff;
  675. margin-bottom: 20px;
  676. text-align: center;
  677. }
  678. .chart-container {
  679. height: 400px;
  680. width: 100%;
  681. }
  682. }
  683. }
  684. /* 功能演示 */
  685. .demo-section {
  686. padding: 0 20px 40px;
  687. h2 {
  688. font-size: 24px;
  689. color: #fff;
  690. margin-bottom: 30px;
  691. text-align: center;
  692. }
  693. .demo-grid {
  694. display: flex;
  695. justify-content: center;
  696. gap: 30px;
  697. flex-wrap: wrap;
  698. .demo-card {
  699. width: 350px;
  700. background-color: rgba(30, 41, 59, 0.6);
  701. border-radius: 12px;
  702. overflow: hidden;
  703. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  704. transition: transform 0.3s ease;
  705. &:hover {
  706. transform: translateY(-5px);
  707. }
  708. .demo-thumbnail {
  709. height: 200px;
  710. background-color: #1E90FF;
  711. position: relative;
  712. display: flex;
  713. justify-content: center;
  714. align-items: center;
  715. .play-btn {
  716. width: 60px;
  717. height: 60px;
  718. border-radius: 50%;
  719. background-color: rgba(255, 255, 255, 0.8);
  720. color: #1E90FF;
  721. font-size: 30px;
  722. display: flex;
  723. justify-content: center;
  724. align-items: center;
  725. cursor: pointer;
  726. transition: all 0.3s ease;
  727. &:hover {
  728. background-color: #fff;
  729. transform: scale(1.1);
  730. }
  731. }
  732. }
  733. .demo-title {
  734. padding: 15px;
  735. font-size: 16px;
  736. color: #fff;
  737. text-align: center;
  738. }
  739. }
  740. }
  741. }
  742. /* 响应式设计 */
  743. @media (max-width: 768px) {
  744. .banner {
  745. padding-right: 5%;
  746. .banner-content {
  747. h1 {
  748. font-size: 32px;
  749. }
  750. }
  751. }
  752. .stats-section {
  753. .stats-grid {
  754. gap: 20px;
  755. .stat-card {
  756. width: 100%;
  757. max-width: 300px;
  758. }
  759. }
  760. }
  761. .data-overview {
  762. .overview-header {
  763. flex-direction: column;
  764. gap: 20px;
  765. h2 {
  766. text-align: center;
  767. }
  768. }
  769. .charts-grid {
  770. grid-template-columns: 1fr;
  771. .chart-card {
  772. .chart-container {
  773. height: 250px;
  774. }
  775. }
  776. }
  777. }
  778. .comparison-section {
  779. .chart-card {
  780. .chart-container {
  781. height: 300px;
  782. }
  783. }
  784. }
  785. .demo-section {
  786. .demo-grid {
  787. gap: 20px;
  788. .demo-card {
  789. width: 100%;
  790. max-width: 350px;
  791. }
  792. }
  793. }
  794. }
  795. </style>