Parcourir la source

feat: 增加大屏框架结构

周玉环 il y a 3 jours
Parent
commit
da764c01d9
21 fichiers modifiés avec 906 ajouts et 25 suppressions
  1. 0 8
      xinkeaboard-admin/pnpm-lock.yaml
  2. BIN
      xinkeaboard-admin/src/assets/bigscreen/head.png
  3. BIN
      xinkeaboard-admin/src/assets/bigscreen/screen-bg.jpg
  4. 73 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/components/DataShow.js
  5. 23 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/components/PanelBlock.js
  6. 11 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/components/PanelNav.js
  7. 43 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/components/RadioButtonGroup.js
  8. 163 7
      xinkeaboard-admin/src/pages/sysset/bigscreen/index.js
  9. 99 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/index.less
  10. 43 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/layout/head/HeadContent.js
  11. 69 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/styles/data_show.less
  12. 31 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/styles/header_content.less
  13. 16 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/styles/panel_block.less
  14. 10 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/styles/panel_nav.less
  15. 37 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/styles/radio_button_group.less
  16. 6 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/theme.less
  17. 113 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/utils/getBarChartOptions.js
  18. 87 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/utils/getLineChartOptions.js
  19. 75 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/utils/getPieChartOptions.js
  20. 1 0
      xinkeaboard-admin/src/pages/sysset/bigscreen/utils/tableColumn.js
  21. 6 10
      xinkeaboard-admin/src/pages/sysset/models/bigscreen.js

+ 0 - 8
xinkeaboard-admin/pnpm-lock.yaml

@@ -252,9 +252,6 @@ importers:
       umi-plugin-react:
         specifier: ^1.2.0
         version: 1.15.9(@babel/core@7.28.0)(react-dom@16.14.0(react@16.14.0))(react-router@5.1.2(react@16.14.0))(react@16.14.0)(redbox-react@1.6.0(react-dom@16.14.0(react@16.14.0))(react@16.14.0))
-      vue-cli-plugin-style-resources-loader:
-        specifier: ^0.1.5
-        version: 0.1.5
     optionalDependencies:
       puppeteer:
         specifier: ^1.10.0
@@ -10193,9 +10190,6 @@ packages:
   vm-browserify@1.1.2:
     resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
 
-  vue-cli-plugin-style-resources-loader@0.1.5:
-    resolution: {integrity: sha512-LluhjWTZmpGl3tiXg51EciF+T70IN/9t6UvfmgluJBqxbrb6OV9i7L5lTd+OKtcTeghDkhcBmYhtTxxU4w/8sQ==}
-
   w3c-hr-time@1.0.2:
     resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
     deprecated: Use your platform's native performance.now() and performance.timeOrigin.
@@ -24570,8 +24564,6 @@ snapshots:
 
   vm-browserify@1.1.2: {}
 
-  vue-cli-plugin-style-resources-loader@0.1.5: {}
-
   w3c-hr-time@1.0.2:
     dependencies:
       browser-process-hrtime: 1.0.0

BIN
xinkeaboard-admin/src/assets/bigscreen/head.png


BIN
xinkeaboard-admin/src/assets/bigscreen/screen-bg.jpg


+ 73 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/components/DataShow.js

@@ -0,0 +1,73 @@
+import React from 'react';
+import styles from '../styles/data_show.less';
+
+class DataShow extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      animatedValues: [],
+    };
+  }
+
+  componentDidMount() {
+    this.startAnimation(this.props.options);
+  }
+
+  componentDidUpdate(prevProps) {
+    if (prevProps.options !== this.props.options) {
+      this.startAnimation(this.props.options);
+    }
+  }
+
+  startAnimation(data) {
+    this.setState({ animatedValues: data.map(() => 0) });
+
+    data.forEach((item, index) => {
+      this.animateNumber(item.value, 3000, 0, (val) => {
+        this.setState((prevState) => {
+          const newValues = [...prevState.animatedValues];
+          newValues[index] = val;
+          return { animatedValues: newValues };
+        });
+      });
+    });
+  }
+
+  animateNumber(target, duration = 2000, decimals = 0, onUpdate) {
+    const startTime = performance.now();
+
+    const step = (now) => {
+      const progress = Math.min((now - startTime) / duration, 1);
+      const current = +(progress * target).toFixed(decimals);
+      if (onUpdate) onUpdate(current);
+
+      if (progress < 1) {
+        requestAnimationFrame(step);
+      } else {
+        onUpdate(target);
+      }
+    };
+
+    requestAnimationFrame(step);
+  }
+
+  render() {
+    const { options } = this.props;
+    const { animatedValues } = this.state;
+
+    return (
+      <div className={styles.data_show}>
+        {options.map((item, index) => (
+          <div className={styles.dataCard} key={index}>
+            <div className={styles.data_value}>
+              {Number(animatedValues[index] || 0).toLocaleString()}
+            </div>
+            <div className={styles.data_label}>{item.label}</div>
+          </div>
+        ))}
+      </div>
+    );
+  }
+}
+
+export default DataShow;

+ 23 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/components/PanelBlock.js

@@ -0,0 +1,23 @@
+import React from "react";
+import PanelNav from "./PanelNav";
+import styles from "../styles/panel_block.less";
+
+class PanelBlock extends React.Component {
+  render() {
+    const { title, height, children } = this.props;
+
+    const style = {
+      height: height || undefined,
+      flex: height ? "unset" : 1,
+    };
+
+    return (
+      <div className={`${styles.panel} ${styles.block}`} style={style}>
+        {title && <PanelNav title={title} />}
+        {children}
+      </div>
+    );
+  }
+}
+
+export default PanelBlock;

+ 11 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/components/PanelNav.js

@@ -0,0 +1,11 @@
+import React from 'react';
+import styles from '../styles/panel_nav.less';
+
+class PanelNav extends React.Component {
+  render() {
+    const { title } = this.props;
+    return <div className={styles.panel_nav}>{title}</div>;
+  }
+}
+
+export default PanelNav;

+ 43 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/components/RadioButtonGroup.js

@@ -0,0 +1,43 @@
+import React from 'react';
+import styles from './index.module.less';
+
+class RadioButtonGroup extends React.Component {
+  static defaultProps = {
+    options: [
+      { label: '日', value: 'day' },
+      { label: '月', value: 'month' },
+      { label: '年', value: 'year' },
+    ],
+    value: 'day',
+    onChange: () => {},
+  };
+
+  handleSelect = (val) => {
+    const { value, onChange } = this.props;
+    if (val !== value) {
+      onChange(val);
+    }
+  };
+
+  render() {
+    const { options, value } = this.props;
+
+    return (
+      <div className={styles.screenRadioGroup}>
+        {options.map((item, index) => (
+          <div
+            key={index}
+            className={`${styles.customRadioButton} ${
+              value === item.value ? styles.checked : ''
+            }`}
+            onClick={() => this.handleSelect(item.value)}
+          >
+            {item.label}
+          </div>
+        ))}
+      </div>
+    );
+  }
+}
+
+export default RadioButtonGroup;

+ 163 - 7
xinkeaboard-admin/src/pages/sysset/bigscreen/index.js

@@ -1,15 +1,171 @@
-import React, { Component } from "react";
-import { connect } from "dva/index";
+import React from "react";
+import styles from "./index.less";
+import PanelBlock from "./components/PanelBlock";
+import HeaderContent from "./layout/head/HeadContent";
 
-@connect(({ bigscreen }) => ({
-  bigscreen,
-}))
-export default class BigScreen extends Component {
+class BigScreen extends React.Component {
   constructor(props) {
     super(props);
+    this.state = {
+      isFullScreen: false,
+      startTime: performance.now(),
+    };
+    this.resizeHandler = null;
+    this.timer = null;
+    this.htmlOverflow = null;
+    this.bodyOverflow = null;
   }
 
+  componentDidMount() {
+    this.setScale();
+    window.addEventListener("resize", this.debounceSetScale);
+
+    this.showRenderTime();
+    this.htmlOverflow = document.documentElement.style.overflow;
+    this.bodyOverflow = document.body.style.overflow;
+
+    document.documentElement.style.overflow = "hidden";
+    document.body.style.overflow = "hidden";
+
+    // 全屏事件监听
+    [
+      "fullscreenchange",
+      "webkitfullscreenchange",
+      "mozfullscreenchange",
+      "MSFullscreenChange",
+    ].forEach((event) =>
+      document.addEventListener(event, this.onFullScreenChange)
+    );
+  }
+
+  componentWillUnmount() {
+    window.removeEventListener("resize", this.debounceSetScale);
+
+    document.documentElement.style.overflow = this.htmlOverflow || "";
+    document.body.style.overflow = this.bodyOverflow || "";
+
+    [
+      "fullscreenchange",
+      "webkitfullscreenchange",
+      "mozfullscreenchange",
+      "MSFullscreenChange",
+    ].forEach((event) =>
+      document.removeEventListener(event, this.onFullScreenChange)
+    );
+  }
+
+  // 全屏切换
+  toggleFullScreen = () => {
+    const elem = document.querySelector(`.${styles.screenWrapper}`);
+    if (!this.state.isFullScreen) {
+      if (elem.requestFullscreen) elem.requestFullscreen();
+      else if (elem.webkitRequestFullscreen) elem.webkitRequestFullscreen();
+      else if (elem.mozRequestFullScreen) elem.mozRequestFullScreen();
+      else if (elem.msRequestFullscreen) elem.msRequestFullscreen();
+    } else {
+      if (document.exitFullscreen) document.exitFullscreen();
+      else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
+      else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
+      else if (document.msExitFullscreen) document.msExitFullscreen();
+    }
+  };
+
+  onFullScreenChange = () => {
+    this.setState({
+      isFullScreen: !!(
+        document.fullscreenElement ||
+        document.webkitFullscreenElement ||
+        document.mozFullScreenElement ||
+        document.msFullscreenElement
+      ),
+    });
+  };
+
+  debounceSetScale = () => {
+    clearTimeout(this.resizeHandler);
+    this.resizeHandler = setTimeout(() => {
+      this.setScale();
+    }, 200);
+  };
+
+  setScale = () => {
+    const baseWidth = 3840;
+    const baseHeight = 2160;
+    const wrapper = document.querySelector(`.${styles.screenWrapper}`);
+    const ww = wrapper ? wrapper.clientWidth : window.innerWidth;
+    const wh = wrapper ? wrapper.clientHeight : window.innerHeight;
+    const scale = Math.min(ww / baseWidth, wh / baseHeight);
+
+    const screenContainer = document.querySelector(
+      `.${styles.screenContainer}`
+    );
+    if (screenContainer) {
+      screenContainer.style.transform = `scale(${scale}) translate(-50%, -50%)`;
+      screenContainer.style.transformOrigin = "0 0";
+      screenContainer.style.left = "50%";
+      screenContainer.style.top = "50%";
+      screenContainer.style.margin = "0";
+    }
+  };
+
+  showRenderTime = () => {
+    const timeUsed = (performance.now() - this.state.startTime).toFixed(2);
+    console.log(`页面渲染完成耗时:${timeUsed} ms`);
+  };
+
   render() {
-    return "sdsdd";
+    const { isFullScreen } = this.state;
+
+    return (
+      <div className={styles.screenWrapper}>
+        <button
+          className={styles.fullscreenBtn}
+          onClick={this.toggleFullScreen}
+        >
+          {isFullScreen ? "退出全屏" : "全屏"}
+        </button>
+        <div className={styles.screenContainer}>
+          {/* 顶部 */}
+          <div className={styles.headPanel}>
+            <HeaderContent />
+          </div>
+          <div className={styles.contentPanel}>
+            {/* 左侧 */}
+            <div className={styles.contentPanelLeft}>
+              {/* <PanelBlock height="200px" /> */}
+              <PanelBlock />
+              <PanelBlock />
+              <PanelBlock height="500px" />
+            </div>
+
+            {/* 中间 */}
+            <div className={styles.contentPanelCenter}>
+              <div className={styles.contentPanelCenterTop}>
+                <PanelBlock />
+              </div>
+              <div className={styles.contentPanelCenterMiddle}>
+                <PanelBlock />
+              </div>
+              <div className={styles.contentPanelCenterBottom}>
+                <PanelBlock />
+                <PanelBlock />
+              </div>
+            </div>
+
+            {/* 右侧 */}
+            <div className={styles.contentPanelRight}>
+              <div className={styles.contentPanelRightTop}>
+                <PanelBlock />
+              </div>
+              <div className={styles.contentPanelRightBottom}>
+                <PanelBlock />
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    );
   }
 }
+
+export default BigScreen;

+ 99 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/index.less

@@ -0,0 +1,99 @@
+@import "./theme.less";
+.screenWrapper {
+  width: 100%;
+  height: calc(100vh - 60px);
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  position: relative;
+  background: url("../../../assets/bigscreen/screen-bg.jpg") no-repeat center center;
+  background-size: cover;
+
+  .fullscreenBtn {
+    position: absolute;
+    top: 0;
+    right: 0;
+    z-index: 10000;
+    background: rgba(0, 0, 0, 0.7);
+    color: #00ff88;
+    border: none;
+    border-radius: 4px;
+    padding: 8px 18px;
+    font-size: 16px;
+    cursor: pointer;
+    transition: background 0.2s;
+
+    &:hover {
+      background: rgba(0, 0, 0, 0.9);
+    }
+  }
+}
+
+.screenContainer {
+  width: 3840px;
+  height: 2160px;
+  padding: 24px;
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  overflow: hidden;
+  gap: @gap-size;
+  position: absolute;
+  left: 0;
+  top: 0;
+}
+
+.headPanel {
+  height: 200px;
+  gap: @gap-size;
+}
+
+.contentPanel {
+  display: flex;
+  flex: 1;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  gap: @gap-size;
+
+  &Left,
+  &Center,
+  &Right {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+  }
+
+  &Left {
+    width: 25%;
+  }
+
+  &Center {
+    width: 50%;
+    &Top {
+      width: 100%;
+      height: 20%;
+    }
+    &Middle {
+      width: 100%;
+      height: 50%;
+    }
+    &Bottom {
+      display: flex;
+      justify-content: space-between;
+      width: 100%;
+      height: 30%;
+    }
+  }
+
+  &Right {
+    width: 25%;
+    &Top {
+      height: 50%;
+    }
+
+    &Bottom {
+      height: 50%;
+    }
+  }
+}

+ 43 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/layout/head/HeadContent.js

@@ -0,0 +1,43 @@
+import React from "react";
+import { connect } from "dva";
+import styles from "../../styles/header_content.less";
+
+class HeaderContent extends React.Component {
+  componentDidMount() {
+    this.updateTime();
+    this.timeInterval = setInterval(this.updateTime, 1000);
+    // this.props.dispatch({ type: 'header/fetchWeather' });
+  }
+
+  componentWillUnmount() {
+    clearInterval(this.timeInterval);
+  }
+
+  updateTime = () => {
+    const now = new Date();
+    const pad = (n) => n.toString().padStart(2, "0");
+    const currentTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(
+      now.getDate()
+    )} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(
+      now.getSeconds()
+    )}`;
+    this.setState({ currentTime });
+  };
+
+  state = {
+    currentTime: "",
+  };
+
+  render() {
+    const { currentTime } = this.state;
+    const { weatherData } = this.props;
+    return (
+      <div className={styles.headerContent}>
+        <div className={styles.headerContentTitle}>这是一个大屏</div>
+        <div className={styles.headerContentTime}>{currentTime}</div>
+      </div>
+    );
+  }
+}
+
+export default connect(() => ({}))(HeaderContent);

+ 69 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/styles/data_show.less

@@ -0,0 +1,69 @@
+@import '../theme.less';
+
+.data_show {
+  display: flex;
+  justify-content: space-between;
+  gap: @gap-size;
+  border-radius: 20px;
+}
+
+.data_card {
+  flex: 1;
+  background: rgba(20, 40, 80, 0.85);
+  border: 2px solid rgba(0, 255, 255, 0.25);
+  border-radius: 16px;
+  padding: 25px 0;
+  text-align: center;
+  position: relative;
+  overflow: hidden;
+  transition: transform 0.2s, box-shadow 0.2s;
+  cursor: pointer;
+}
+
+.data_card::before {
+  content: '';
+  position: absolute;
+  top: -50%;
+  left: -50%;
+  width: 200%;
+  height: 200%;
+  background: radial-gradient(circle, rgba(0, 255, 255, 0.15) 0%, transparent 70%);
+  z-index: 0;
+  pointer-events: none;
+  animation: shine 3s linear infinite;
+}
+
+.data_card:hover {
+  transform: translateY(-8px) scale(1.04);
+}
+
+.data_value {
+  color: #00fff7;
+  font-size: @font-title-sub;
+  font-weight: bold;
+  letter-spacing: 3px;
+  margin-bottom: 12px;
+  text-shadow: 0 0 12px #00fff7, 0 0 24px #0ff;
+  position: relative;
+  z-index: 1;
+  animation: glow 2s ease-in-out infinite alternate;
+}
+
+@keyframes glow {
+  from {
+    text-shadow: 0 0 12px #00fff7, 0 0 24px #0ff;
+  }
+  to {
+    text-shadow: 0 0 24px #00fff7, 0 0 48px #0ff;
+  }
+}
+
+.data_label {
+  color: #fff;
+  font-weight: bold;
+  font-size: @font-body;
+  letter-spacing: 2px;
+  opacity: 0.85;
+  position: relative;
+  z-index: 1;
+}

+ 31 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/styles/header_content.less

@@ -0,0 +1,31 @@
+@import '../theme.less';
+
+.headerContent {
+  background-image: url("../../../../assets/bigscreen/head.png");
+  background-repeat: no-repeat;
+  background-size: cover;
+  background-position: center;
+  text-align: center;
+  font-size: @font-title-main;
+  position: relative;
+
+  .headerContentTitle {
+    line-height: 200px;
+    font-size: @font-title-main;
+    font-weight: bold;
+    color: #00c6ff;
+    text-shadow: 0 2px 8px rgba(0, 198, 255, 0.3);
+  }
+
+  .headerContentTime {
+    position: absolute;
+    bottom: 0px;
+    right: 100px;
+    font-size: @font-title-sub;
+    background: linear-gradient(90deg, #00c6ff, #0072ff);
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    background-clip: text;
+    color: transparent;
+  }
+}

+ 16 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/styles/panel_block.less

@@ -0,0 +1,16 @@
+.panel {
+  border-radius: 28px;
+  width: 100%;
+  font-size: 40px;
+  letter-spacing: 1px;
+}
+
+.block {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  height: 100%;
+  box-sizing: border-box;
+  margin-top: 10px;
+  border: 1px solid red;
+}

+ 10 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/styles/panel_nav.less

@@ -0,0 +1,10 @@
+
+@import '../theme.less';
+
+.panel_nav {
+  font-size: @font-title-sub;
+  font-weight: bold;
+  color: #00c6ff;
+  margin-bottom: 10px;
+  text-shadow: 0 2px 8px rgba(30, 200, 255, 0.2);
+}

+ 37 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/styles/radio_button_group.less

@@ -0,0 +1,37 @@
+.screenRadioGroup {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-top: 20px;
+}
+
+.customRadioButton {
+  width: 100px;
+  height: 50px;
+  line-height: 50px;
+  text-align: center;
+  font-size: 30px;
+  color: #fff;
+  background-color: #1a1a1a;
+  border: 1px solid #4fd2dd;
+  border-right: none;
+  cursor: pointer;
+  user-select: none;
+  transition: background 0.2s, border 0.2s;
+
+  &:hover {
+    background-color: #333;
+    border-color: #4fd2dd;
+  }
+}
+
+.checked {
+  background-color: #4fd2dd;
+  color: #fff;
+  border-color: #4fd2dd;
+}
+
+.customRadioButton:last-child {
+  margin-right: 0;
+  border-right: 1px solid #4fd2dd;
+}

+ 6 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/theme.less

@@ -0,0 +1,6 @@
+@font-title-main: 72px; /* 主标题(H1),建议60~80px */
+@font-title-sub: 42px; /* 副标题(H2/H3),建议36~48px */
+@font-body: 32px; /* 普通正文/数据,建议28~36px */
+@font-label: 20px; /* 次要说明、标签,建议18~24px */
+@font-helper: 16px; /* 辅助性单位、备注,建议≥16px */
+@gap-size: 25px;

+ 113 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/utils/getBarChartOptions.js

@@ -0,0 +1,113 @@
+export default function ({ xAxisData, seriesData }) {
+  return {
+    backgroundColor: "transparent",
+    xAxis: {
+      type: "category",
+      data: xAxisData,
+      axisLabel: {
+        fontSize: 22,
+        color: "#4fd2dd",
+        fontWeight: "bold",
+        shadowColor: "#000",
+        shadowBlur: 4,
+      },
+      axisLine: {
+        lineStyle: {
+          color: "#4fd2dd",
+          width: 2,
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: "value",
+      axisLabel: {
+        fontSize: 22,
+        color: "#4fd2dd",
+        fontWeight: "bold",
+        shadowColor: "#000",
+        shadowBlur: 4,
+      },
+      splitLine: {
+        lineStyle: {
+          color: "rgba(79,210,221,0.2)",
+          type: "dashed",
+        },
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: "#4fd2dd",
+          width: 2,
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      interval: 50,
+    },
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(34,34,34,0.95)",
+      borderColor: "#4fd2dd",
+      borderWidth: 2,
+      textStyle: { color: "#fff", fontSize: 26, fontWeight: "bold" },
+      axisPointer: {
+        type: "shadow",
+        shadowStyle: {
+          color: "rgba(79,210,221,0.15)",
+        },
+      },
+    },
+    grid: {
+      left: "4%",
+      right: "4%",
+      bottom: "8%",
+      top: "10%",
+      containLabel: true,
+    },
+    series: [
+      {
+        data: seriesData,
+        type: "bar",
+        barWidth: 28,
+        itemStyle: {
+          color: {
+            type: "linear",
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              { offset: 0, color: "#4fd2dd" },
+              { offset: 1, color: "#235fa7" },
+            ],
+          },
+          shadowColor: "#4fd2dd",
+          shadowBlur: 10,
+          borderRadius: [8, 8, 0, 0],
+        },
+        emphasis: {
+          itemStyle: {
+            color: "#fff",
+            borderColor: "#4fd2dd",
+            borderWidth: 3,
+            shadowColor: "#4fd2dd",
+            shadowBlur: 20,
+          },
+        },
+        label: {
+          show: true,
+          position: "top",
+          color: "#fff",
+          fontSize: 20,
+          fontWeight: "bold",
+          shadowColor: "#4fd2dd",
+          shadowBlur: 6,
+        },
+      },
+    ],
+  };
+}

+ 87 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/utils/getLineChartOptions.js

@@ -0,0 +1,87 @@
+export default function ({ xAxisData, seriesData }, $echarts) {
+  return {
+    xAxis: {
+      type: "category",
+      data: xAxisData,
+      axisLine: { lineStyle: { color: "#00ffe7", width: 2 } },
+      axisLabel: {
+        color: "#00ffe7",
+        fontSize: 22,
+        fontWeight: "bold",
+        shadowColor: "#00ffe7",
+        shadowBlur: 10,
+      },
+      splitLine: { show: false },
+    },
+    yAxis: {
+      type: "value",
+      axisLine: { lineStyle: { color: "#00ffe7", width: 2 } },
+      axisLabel: {
+        color: "#00ffe7",
+        fontSize: 22,
+        fontWeight: "bold",
+        shadowColor: "#00ffe7",
+        shadowBlur: 10,
+      },
+      splitLine: { lineStyle: { color: "rgba(0,255,231,0.1)" } },
+    },
+    series: [
+      {
+        data: seriesData,
+        type: "line",
+        smooth: true,
+        symbol: "circle",
+        symbolSize: 16,
+        lineStyle: {
+          color: {
+            type: "linear",
+            x: 0,
+            y: 0,
+            x2: 1,
+            y2: 0,
+            colorStops: [
+              { offset: 0, color: "#00ffe7" },
+              { offset: 1, color: "#0078ff" },
+            ],
+          },
+          width: 5,
+          shadowColor: "#00ffe7",
+          shadowBlur: 20,
+        },
+        itemStyle: {
+          color: "#00ffe7",
+          borderColor: "#fff",
+          borderWidth: 4,
+          shadowColor: "#00ffe7",
+          shadowBlur: 10,
+        },
+        areaStyle: {
+          color: new $echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "rgba(0,255,231,0.5)" },
+            { offset: 1, color: "rgba(0,120,255,0.1)" },
+          ]),
+        },
+      },
+    ],
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(0,34,51,0.9)",
+      borderColor: "#00ffe7",
+      borderWidth: 2,
+      textStyle: { color: "#00ffe7", fontSize: 26, fontWeight: "bold" },
+      axisPointer: {
+        lineStyle: {
+          color: "#00ffe7",
+          width: 3,
+          type: "dashed",
+        },
+      },
+    },
+    grid: {
+      left: "3%",
+      right: "4%",
+      bottom: "3%",
+      containLabel: true,
+    },
+  };
+}

+ 75 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/utils/getPieChartOptions.js

@@ -0,0 +1,75 @@
+export default function ({ seriesData }) {
+  return {
+    tooltip: {
+      trigger: "item",
+      backgroundColor: "rgba(0,0,0,0.8)",
+      borderColor: "#00ffe7",
+      textStyle: {
+        color: "#fff",
+        fontSize: 25,
+      },
+    },
+    legend: {
+      show: false, // 隐藏左侧标签列表
+    },
+    series: [
+      {
+        name: "Access From",
+        type: "pie",
+        radius: ["40%", "70%"],
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 10,
+          borderColor: "#222",
+          borderWidth: 4,
+          // shadowBlur: 20,
+          // shadowColor: "rgba(0,255,231,0.5)",
+        },
+        label: {
+          position: "outside",
+          show: true,
+          fontSize: 20,
+          color: "#fff",
+          fontWeight: "bold",
+          textShadowColor: "#00ffe7",
+          textShadowBlur: 10,
+          overflow: "break", // 支持换行
+          width: 100, // 设置宽度以便换行生效,可根据实际调整
+          formatter: function (params) {
+            // 自动换行
+            const maxLength = 8; // 每行最大字符数,可根据需要调整
+            let name = params.name;
+            let result = "";
+            while (name.length > maxLength) {
+              result += name.substring(0, maxLength) + "\n";
+              name = name.substring(maxLength);
+            }
+            result += name;
+            return result;
+          },
+        },
+        labelLine: {
+          length: 10,
+          length2: 10,
+          lineStyle: {
+            color: "#00ffe7",
+            width: 3,
+          },
+        },
+        data: seriesData,
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 30,
+            shadowOffsetX: 0,
+            shadowColor: "rgba(0,255,231,0.8)",
+          },
+          label: {
+            fontSize: 24,
+            color: "#00ffe7",
+            fontWeight: "bolder",
+          },
+        },
+      },
+    ],
+  };
+}

+ 1 - 0
xinkeaboard-admin/src/pages/sysset/bigscreen/utils/tableColumn.js

@@ -0,0 +1 @@
+export default {};

+ 6 - 10
xinkeaboard-admin/src/models/bigscreen.js → xinkeaboard-admin/src/pages/sysset/models/bigscreen.js

@@ -1,10 +1,8 @@
-import { sldCommonService } from '@/utils/utils';
+import { sldCommonService } from "@/utils/utils";
 export default {
-  namespace: 'bigscreen',
+  namespace: "bigscreen",
 
-  state: {
-    
-  },
+  state: {},
 
   effects: {
     // *change_manager_pwd({ payload, callback }, { call }) {
@@ -13,16 +11,14 @@ export default {
     // },
   },
 
-  reducers: {
-    
-  },
+  reducers: {},
 
   subscriptions: {
     setup({ history }) {
       // Subscribe history(url) change, trigger `load` action if pathname is `/`
       return history.listen(({ pathname, search }) => {
-        if (typeof window.ga !== 'undefined') {
-          window.ga('send', 'pageview', pathname + search);
+        if (typeof window.ga !== "undefined") {
+          window.ga("send", "pageview", pathname + search);
         }
       });
     },