| | |
| | | |
| | | <!-- 顶部标题栏 --> |
| | | <div class="dashboard-header"> |
| | | <div class="factory-name">PSI 数据分析</div> |
| | | <div class="factory-name">进销存数据面板</div> |
| | | </div> |
| | | |
| | | <!-- 主要内容区域 --> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue' |
| | | import autofit from 'autofit.js' |
| | | import LeftBottom from './components/left-bottom.vue' |
| | | import CenterCenter from './components/center-center.vue' |
| | |
| | | |
| | | // 用户store |
| | | const userStore = useUserStore() |
| | | |
| | | /** 与 dataDashboard 共用注入名,子组件(含复用的 right-top/right-bottom)每分钟刷新 */ |
| | | const DASHBOARD_REFRESH_MS = 60 * 1000 |
| | | const dataDashboardRefreshTick = ref(0) |
| | | provide('dataDashboardRefreshTick', dataDashboardRefreshTick) |
| | | let dashboardPollTimer = null |
| | | |
| | | // 计算缩放比例 |
| | | const calculateScale = () => { |
| | |
| | | window.addEventListener('fullscreenchange', handleFullscreenChange) |
| | | window.addEventListener('webkitfullscreenchange', handleFullscreenChange) |
| | | window.addEventListener('MSFullscreenChange', handleFullscreenChange) |
| | | |
| | | dashboardPollTimer = setInterval(() => { |
| | | dataDashboardRefreshTick.value++ |
| | | }, DASHBOARD_REFRESH_MS) |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (dashboardPollTimer) { |
| | | clearInterval(dashboardPollTimer) |
| | | dashboardPollTimer = null |
| | | } |
| | | window.removeEventListener('resize', handleResize) |
| | | window.removeEventListener('fullscreenchange', handleFullscreenChange) |
| | | window.removeEventListener('webkitfullscreenchange', handleFullscreenChange) |
| | |
| | | justify-content: center; |
| | | background-color: #000; |
| | | overflow: hidden; |
| | | position: relative; |
| | | } |
| | | |
| | | /* 动态网格背景 */ |
| | | .scale-container::before { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: 0; |
| | | background-image: |
| | | linear-gradient(rgba(0, 212, 255, 0.03) 1px, transparent 1px), |
| | | linear-gradient(90deg, rgba(0, 212, 255, 0.03) 1px, transparent 1px); |
| | | background-size: 50px 50px; |
| | | animation: gridMove 20s linear infinite; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes gridMove { |
| | | 0% { transform: translate(0, 0); } |
| | | 100% { transform: translate(50px, 50px); } |
| | | } |
| | | |
| | | /* 内部内容区域 - 固定设计尺寸 */ |
| | |
| | | color: #FFFFFF; |
| | | top: 16px; |
| | | position: absolute; |
| | | animation: titleGlow 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleGlow { |
| | | 0%, 100% { text-shadow: 0 0 20px rgba(0, 212, 255, 0.3); } |
| | | 50% { text-shadow: 0 0 40px rgba(0, 212, 255, 0.6), 0 0 60px rgba(0, 212, 255, 0.3); } |
| | | } |
| | | |
| | | .fullscreen-btn { |
| | |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .left-panel { |
| | | animation: slideInLeft 0.8s ease-out; |
| | | } |
| | | |
| | | .right-panel { |
| | | animation: slideInRight 0.8s ease-out; |
| | | } |
| | | |
| | | .center-panel { |
| | | animation: slideInUp 0.8s ease-out; |
| | | } |
| | | |
| | | @keyframes slideInLeft { |
| | | from { opacity: 0; transform: translateX(-50px); } |
| | | to { opacity: 1; transform: translateX(0); } |
| | | } |
| | | |
| | | @keyframes slideInRight { |
| | | from { opacity: 0; transform: translateX(50px); } |
| | | to { opacity: 1; transform: translateX(0); } |
| | | } |
| | | |
| | | @keyframes slideInUp { |
| | | from { opacity: 0; transform: translateY(30px); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | flex: 1; |