| | |
| | | <view class="button-right" @click="ejected()"></view> |
| | | <!-- 主视图 --> |
| | | <view class="main"> |
| | | <view class="mian-item"> |
| | | <view class="mian-item-box"> |
| | | <view class="main-item"> |
| | | <view class="main-item-box"> |
| | | <y-box> |
| | | <view class="box-item"> |
| | | <text class="item-title">智能大屏显示系统</text> |
| | |
| | | <text class="item-title">仓库数据</text> |
| | | <text class="item-subTitle">warehouse data</text> |
| | | <view class="img-box"> |
| | | <view style="width: 100%; display: flex" v-for="(item, i) in locList" :key="i"> |
| | | <view style="display: flex; justify-content: center; align-items: center; width: 48%; font-size: 1.3vw">物料码: {{ item.matnr }}</view> |
| | | <view style="display: flex; justify-content: center; align-items: center; width: 48%; font-size: 1.3vw">数量: {{ item.matnrCount }}</view> |
| | | <view class="data-row" v-for="(item, i) in locList" :key="i"> |
| | | <view class="data-cell data-text">物料码: {{ item.matnr }}</view> |
| | | <view class="data-cell data-text-lg">数量: {{ item.matnrCount }}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | </y-box> |
| | | </view> |
| | | </view> |
| | | <view class="mian-item"> |
| | | <view class="mian-item-box"> |
| | | <view class="main-item"> |
| | | <view class="main-item-box"> |
| | | <view style="width: 100%; height: 100%"> |
| | | <view style="height: 35%"> |
| | | <!-- 折线图 --> |
| | |
| | | :echartsApp="true" |
| | | /> |
| | | </view> |
| | | <view> |
| | | <view class="stat-panel"> |
| | | <view class="flex-row sub-info"> |
| | | <image src="../../static/g1.png" mode="aspectFit"></image> |
| | | <view style="width: 8vw; height: 4vw; line-height: 4vw">在库</view> |
| | | <view style="width: 8vw; height: 4vw; line-height: 4vw; font-size: 2vw"> |
| | | {{ baseInfo.stockCount }} |
| | | </view> |
| | | <view class="stat-label">在库</view> |
| | | <view class="stat-label data-text-lg">{{ baseInfo.stockCount }}</view> |
| | | </view> |
| | | <view class="flex-row sub-info" style="margin-top: 2vh"> |
| | | <view class="flex-row sub-info"> |
| | | <image src="../../static/f1.png" mode="aspectFit"></image> |
| | | <view style="width: 8vw; height: 4vw; line-height: 4vw">空库</view> |
| | | <view style="width: 8vw; height: 4vw; line-height: 4vw; font-size: 2vw"> |
| | | {{ baseInfo.emptyCount }} |
| | | </view> |
| | | <view class="stat-label">空库</view> |
| | | <view class="stat-label data-text-lg">{{ baseInfo.emptyCount }}</view> |
| | | </view> |
| | | <view class="flex-row sub-info" style="margin-top: 2vh"> |
| | | <view class="flex-row sub-info"> |
| | | <image src="../../static/e1.png" mode="aspectFit"></image> |
| | | <view style="width: 8vw; height: 4vw; line-height: 4vw">锁定</view> |
| | | <view style="width: 8vw; height: 4vw; line-height: 4vw; font-size: 2vw"> |
| | | {{ baseInfo.noneCount }} |
| | | </view> |
| | | <view class="stat-label">锁定</view> |
| | | <view class="stat-label data-text-lg">{{ baseInfo.noneCount }}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | </template> |
| | | <script> |
| | | import WebSocketUtil from './uniWebSocket'; |
| | | |
| | | // 任务类型常量映射 |
| | | const IO_TYPE_MAP = { |
| | | 101: '全板出库', |
| | | 103: '拣料出库', |
| | | 107: '盘点出库', |
| | | 1: '入库', |
| | | 10: '空托入库', |
| | | 110: '空托出库', |
| | | 104: '并板出库', |
| | | 54: '并板入库' |
| | | }; |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | // 视图状态 |
| | | homeViewShow: true, |
| | | infoViewShow: false, |
| | | errorInfoViewShow: false, |
| | | homeMode: [], |
| | | infoMode: [], |
| | | errorInfoMode: [], |
| | | |
| | | // 基础信息 |
| | | baseInfo: { |
| | | xDistance: 1, |
| | | yDistance: 2, |
| | |
| | | emptyCount: '', |
| | | noneCount: '' |
| | | }, |
| | | |
| | | // 图表数据 |
| | | chartsData: { |
| | | Line: { |
| | | categories: [], |
| | | series: [] |
| | | }, |
| | | Pie: { |
| | | series: [ |
| | | { |
| | | data: [] |
| | | } |
| | | ] |
| | | } |
| | | Line: { categories: [], series: [] }, |
| | | Pie: { series: [{ data: [] }] } |
| | | }, |
| | | |
| | | // 动画与图表 |
| | | duration: 300, |
| | | calendar: '', |
| | | ringOpts: {}, |
| | | chartsDataLine1: {}, |
| | | chartsDataPie2: {}, |
| | | |
| | | // 配置弹窗 |
| | | ejectShow: false, |
| | | |
| | | // 服务器配置 |
| | | baseIP: '', |
| | | basePort: '', |
| | | baseLedId: '', |
| | | baseUrl: '', |
| | | wmsUrl: '', |
| | | wmsPort: '', |
| | | getConfigUrl: 'http://127.0.0.1:8088/wcs/monitor/getIpConfig', |
| | | |
| | | // 任务信息 |
| | | infoType: 0, |
| | | infoText: { |
| | | title: '', |
| | |
| | | barcode: '' |
| | | }, |
| | | swiperList: [], |
| | | |
| | | // 连接状态 |
| | | timeOut: false, |
| | | times: 0, |
| | | socketClient: null, |
| | | socketUrl: '', |
| | | |
| | | // 日期时间 |
| | | currDate: '', |
| | | locList: [], |
| | | oldHours: '', |
| | | oldMin: '', |
| | | socketClient: null, |
| | | |
| | | // 版本更新 |
| | | version: '', |
| | | socketUrl: '', |
| | | msgType: 'success', |
| | | filename: '', |
| | | dialogContent: '', |
| | | wmsUrl: '', |
| | | wmsPort: '', |
| | | |
| | | // 视图切换控制 |
| | | switchDebounceTimer: null, |
| | | viewSwitchInProgress: false, |
| | | getConfigUrl:"http://127.0.0.1:8088/wcs/monitor/getIpConfig" |
| | | |
| | | // 定时器ID(用于清理) |
| | | refreshTimerId: null, |
| | | restartTimerId: null, |
| | | gcTimerId: null |
| | | }; |
| | | }, |
| | | onShow() { |
| | |
| | | plus.navigator.setFullscreen(true); |
| | | // #endif |
| | | this.getVersion(); |
| | | |
| | | }, |
| | | |
| | | mounted() { |
| | | let that = this; |
| | | const BaseIP = uni.getStorageSync('BaseIp'); |
| | | const BaseLedId = uni.getStorageSync('BaseLedId'); |
| | | const BasePort = uni.getStorageSync('BasePort'); |
| | | const BaseCrnId = uni.getStorageSync('BaseCrnId'); |
| | | const PROJ = uni.getStorageSync('UPROJ'); |
| | | const WMSURL = uni.getStorageSync('wmsUrl'); |
| | | const WMSPORT = uni.getStorageSync('wmsPort'); |
| | | that.baseUrl = PROJ; |
| | | that.baseIP = BaseIP; |
| | | that.baseLedId = BaseLedId; |
| | | that.basePort = BasePort; |
| | | that.baseCrnId = BaseCrnId; |
| | | that.wmsUrl = WMSURL; |
| | | that.wmsPort = WMSPORT; |
| | | // 使用统一的配置初始化方法 |
| | | this.initConfig(); |
| | | }, |
| | | |
| | | created() { |
| | | let that = this; |
| | | const BaseIP = uni.getStorageSync('BaseIp'); |
| | | const BaseLedId = uni.getStorageSync('BaseLedId'); |
| | | const BasePort = uni.getStorageSync('BasePort'); |
| | | const BaseCrnId = uni.getStorageSync('BaseCrnId'); |
| | | const PROJ = uni.getStorageSync('UPROJ'); |
| | | const WMSURL = uni.getStorageSync('wmsUrl'); |
| | | const WMSPORT = uni.getStorageSync('wmsPort'); |
| | | that.baseUrl = PROJ; |
| | | that.baseIP = BaseIP; |
| | | that.baseLedId = BaseLedId; |
| | | that.basePort = BasePort; |
| | | that.baseCrnId = BaseCrnId; |
| | | that.wmsUrl = WMSURL; |
| | | that.wmsPort = WMSPORT; |
| | | |
| | | that.getIPConfig(); |
| | | |
| | | that.uniWebSocket(); |
| | | // that.webSockerInit() |
| | | // 初始化配置并建立连接 |
| | | this.initConfig(); |
| | | this.getIPConfig(); |
| | | this.uniWebSocket(); |
| | | }, |
| | | |
| | | onLoad() { |
| | | setInterval(() => { |
| | | // 数据刷新定时器(每秒) |
| | | this.refreshTimerId = setInterval(() => { |
| | | this.getServerData(); |
| | | this.controller(); |
| | | }, 1000); |
| | | |
| | | setInterval(() => { |
| | | // 应用重启定时器(每4小时) |
| | | this.restartTimerId = setInterval(() => { |
| | | setTimeout(() => { |
| | | plus.runtime.restart(); |
| | | }, 100); |
| | | }, 1000 * 60 * 60 * 4); |
| | | |
| | | // 每小时触发一次垃圾回收 |
| | | const memoryCleanerId = setInterval(() => { |
| | | // 垃圾回收定时器(每5分钟) |
| | | this.gcTimerId = setInterval(() => { |
| | | // #ifdef APP-PLUS |
| | | if (plus.os.name.toLowerCase() === 'android') { |
| | | // 强制触发 GC |
| | | plus.android.importClass('java.lang.System'); |
| | | plus.android.invoke('java.lang.System', 'gc'); |
| | | console.log('手动触发 GC'); |
| | | } |
| | | // 清理不再需要的大型数据对象 |
| | | // #endif |
| | | // 清理大型数据对象 |
| | | if (this.oldData && this.oldData.length > 100) { |
| | | this.oldData = []; |
| | | } |
| | | }, 30000 * 10); // 每小时执行一次 |
| | | |
| | | |
| | | }, 30000 * 10); |
| | | }, |
| | | |
| | | // 组件卸载时清理资源 |
| | | onUnload() { |
| | | // 清理所有定时器 |
| | | if (this.refreshTimerId) { |
| | | clearInterval(this.refreshTimerId); |
| | | this.refreshTimerId = null; |
| | | } |
| | | if (this.restartTimerId) { |
| | | clearInterval(this.restartTimerId); |
| | | this.restartTimerId = null; |
| | | } |
| | | if (this.gcTimerId) { |
| | | clearInterval(this.gcTimerId); |
| | | this.gcTimerId = null; |
| | | } |
| | | if (this.switchDebounceTimer) { |
| | | clearTimeout(this.switchDebounceTimer); |
| | | this.switchDebounceTimer = null; |
| | | } |
| | | |
| | | // 关闭 WebSocket 连接 |
| | | if (this.socketClient) { |
| | | this.socketClient.close(); |
| | | this.socketClient = null; |
| | | } |
| | | }, |
| | | |
| | | methods: { |
| | | getIPConfig(){ |
| | | const that = this |
| | | |
| | | console.log(that.baseIP) |
| | | uni.request({ |
| | | url: that.getConfigUrl, |
| | | method:'GET', |
| | | success(result) { |
| | | console.log(result) |
| | | const res = result.data |
| | | uni.setStorageSync('BaseIp', res.data.ledIp); |
| | | uni.setStorageSync('BaseLedId', res.data.ledId); |
| | | uni.setStorageSync('BasePort', res.data.ledPort); |
| | | uni.setStorageSync('UPROJ', res.data.ledUrl); |
| | | |
| | | // 统一的配置初始化方法 |
| | | initConfig() { |
| | | this.baseIP = uni.getStorageSync('BaseIp') || ''; |
| | | this.baseLedId = uni.getStorageSync('BaseLedId') || ''; |
| | | this.basePort = uni.getStorageSync('BasePort') || ''; |
| | | this.baseCrnId = uni.getStorageSync('BaseCrnId') || ''; |
| | | this.baseUrl = uni.getStorageSync('UPROJ') || ''; |
| | | this.wmsUrl = uni.getStorageSync('wmsUrl') || ''; |
| | | this.wmsPort = uni.getStorageSync('wmsPort') || ''; |
| | | }, |
| | | |
| | | // 获取IP配置(带错误处理) |
| | | getIPConfig() { |
| | | const that = this; |
| | | uni.request({ |
| | | url: that.getConfigUrl, |
| | | method: 'GET', |
| | | timeout: 5000, |
| | | success(result) { |
| | | if (result.data && result.data.data) { |
| | | const configData = result.data.data; |
| | | uni.setStorageSync('BaseIp', configData.ledIp || ''); |
| | | uni.setStorageSync('BaseLedId', configData.ledId || ''); |
| | | uni.setStorageSync('BasePort', configData.ledPort || ''); |
| | | uni.setStorageSync('UPROJ', configData.ledUrl || ''); |
| | | console.log('IP配置获取成功'); |
| | | } |
| | | }); |
| | | |
| | | |
| | | }, |
| | | fail(err) { |
| | | console.error('获取IP配置失败:', err); |
| | | // 使用本地存储的配置作为后备 |
| | | } |
| | | }); |
| | | }, |
| | | uniWebSocket() { |
| | | let that = this; |
| | |
| | | that.baseInfo.used = data.used; |
| | | that.baseInfo.usedPr = data.usedPr; |
| | | |
| | | that.chartsData.Line.categories = [ |
| | | that.getDateFormat(-11), |
| | | that.getDateFormat(-10), |
| | | that.getDateFormat(-9), |
| | | that.getDateFormat(-8), |
| | | that.getDateFormat(-7), |
| | | that.getDateFormat(-6), |
| | | that.getDateFormat(-5), |
| | | that.getDateFormat(-4), |
| | | that.getDateFormat(-3), |
| | | that.getDateFormat(-2), |
| | | that.getDateFormat(-1), |
| | | that.getDateFormat(0) |
| | | ]; |
| | | that.chartsData.Line.categories = that.generateDateCategories(-11, 0); |
| | | that.chartsData.Line.series = data.rows; |
| | | that.calendar = data.year + '年' + data.month + '月' + data.day + '日 ' + data.hour + ':' + data.minute + ':' + data.second + ' ' + data.week; |
| | | that.currDate = data.year + '/' + data.month + '/' + data.day; |
| | |
| | | that.infoType = 0; |
| | | } |
| | | } else if (data.type === 'task') { |
| | | if (data.taskList && data.taskList !== '' && data.taskList.length != 0) { |
| | | if (that.infoType == 2 || that.infoType == 3) { |
| | | return; |
| | | } |
| | | // infoType1:只有拣料等信息 |
| | | that.infoType = 1; |
| | | if (data.taskList[0].ioType === 101) { |
| | | that.infoText.title = '全板出库'; |
| | | } else if (data.taskList[0].ioType === 103) { |
| | | that.infoText.title = '拣料出库'; |
| | | } else if (data.taskList[0].ioType === 107) { |
| | | that.infoText.title = '盘点出库'; |
| | | } else if (data.taskList[0].ioType === 1) { |
| | | that.infoText.title = '入库'; |
| | | } else if (data.taskList[0].ioType === 10) { |
| | | that.infoText.title = '空托入库'; |
| | | } else if (data.taskList[0].ioType === 110) { |
| | | that.infoText.title = '空托出库'; |
| | | } else if (data.taskList[0].ioType === 104) { |
| | | that.infoText.title = '并板出库'; |
| | | } else if (data.taskList[0].ioType === 54) { |
| | | that.infoText.title = '并板入库'; |
| | | }else { |
| | | that.infoText.title = data.taskList[0].title; |
| | | } |
| | | that.infoText.barcode = data.taskList[0].barcode; |
| | | that.infoText.workNo = data.taskList[0].workNo; |
| | | that.infoText.sourceLocNo = data.taskList[0].sourceLocNo; |
| | | that.infoText.staNo = data.taskList[0].staNo; |
| | | that.swiperList = data.taskList[0].matDtos; |
| | | }else if(data.type === 'NoData'){ |
| | | that.infoType = 0; |
| | | } |
| | | else { |
| | | if (that.infoType == 2 || that.infoType == 3) { |
| | | return; |
| | | } |
| | | that.infoType = 0; |
| | | } |
| | | this.handleTaskData(data); |
| | | } else if (data.type === 'NoData') { |
| | | that.infoType = 0; |
| | | } |
| | | }, |
| | | |
| | | // 处理任务数据(使用常量映射简化逻辑) |
| | | handleTaskData(data) { |
| | | // 无任务列表时 |
| | | if (!data.taskList || data.taskList.length === 0) { |
| | | // 异常信息优先级更高,不切换 |
| | | if (this.infoType === 2 || this.infoType === 3) { |
| | | return; |
| | | } |
| | | this.infoType = 0; |
| | | return; |
| | | } |
| | | |
| | | // 异常信息优先级更高,不切换到任务视图 |
| | | if (this.infoType === 2 || this.infoType === 3) { |
| | | return; |
| | | } |
| | | |
| | | const task = data.taskList[0]; |
| | | this.infoType = 1; |
| | | |
| | | // 使用常量映射获取任务类型名称 |
| | | this.infoText.title = IO_TYPE_MAP[task.ioType] || task.title || '任务'; |
| | | this.infoText.barcode = task.barcode || ''; |
| | | this.infoText.workNo = task.workNo || ''; |
| | | this.infoText.sourceLocNo = task.sourceLocNo || ''; |
| | | this.infoText.staNo = task.staNo || ''; |
| | | this.swiperList = task.matDtos || []; |
| | | }, |
| | | |
| | | // 生成日期分类数组(性能优化) |
| | | generateDateCategories(startOffset, endOffset) { |
| | | const categories = []; |
| | | const baseDate = new Date(this.currDate); |
| | | for (let i = startOffset; i <= endOffset; i++) { |
| | | const date = new Date(baseDate); |
| | | date.setDate(date.getDate() + i); |
| | | categories.push(`${date.getMonth() + 1}-${date.getDate()}`); |
| | | } |
| | | return categories; |
| | | }, |
| | | |
| | | getDateFormat(value) { |
| | | var date = new Date(this.currDate); // 获取当前时间 |
| | | date.setDate(date.getDate() + value); // 设置天数 -1 天 |
| | | var m = date.getMonth() + 1; |
| | | var d = date.getDate(); |
| | | var newDate = m + '-' + d; |
| | | return newDate; |
| | | const date = new Date(this.currDate); |
| | | date.setDate(date.getDate() + value); |
| | | return `${date.getMonth() + 1}-${date.getDate()}`; |
| | | }, |
| | | |
| | | getServerData() { |
| | | this.chartsDataLine1 = JSON.parse(JSON.stringify(this.chartsData.Line)); |
| | | this.chartsDataPie2 = JSON.parse(JSON.stringify(this.chartsData.Pie)); |
| | | // 使用展开运算符浅拷贝(性能优于 JSON 深拷贝) |
| | | this.chartsDataLine1 = { ...this.chartsData.Line }; |
| | | this.chartsDataPie2 = { ...this.chartsData.Pie }; |
| | | }, |
| | | // 控制器 |
| | | controller() { |
| | |
| | | } |
| | | }, |
| | | |
| | | showHomeView() { |
| | | this.infoViewShow = false; |
| | | this.errorInfoViewShow = false; |
| | | this.infoMode = ['fade', 'slide-bottom']; |
| | | this.errorInfoMode = ['fade', 'slide-bottom']; |
| | | // 统一的视图切换方法 |
| | | switchToView(viewType) { |
| | | const transitionMode = ['fade', 'slide-bottom']; |
| | | |
| | | // 根据目标视图隐藏其他视图 |
| | | if (viewType !== 'home') { |
| | | this.homeViewShow = false; |
| | | this.homeMode = transitionMode; |
| | | } |
| | | if (viewType !== 'info') { |
| | | this.infoViewShow = false; |
| | | this.infoMode = transitionMode; |
| | | } |
| | | if (viewType !== 'error') { |
| | | this.errorInfoViewShow = false; |
| | | this.errorInfoMode = transitionMode; |
| | | } |
| | | |
| | | // 延迟显示目标视图 |
| | | setTimeout(() => { |
| | | this.homeViewShow = true; |
| | | this.homeMode = ['fade', 'slide-bottom']; |
| | | switch(viewType) { |
| | | case 'home': |
| | | this.homeViewShow = true; |
| | | this.homeMode = transitionMode; |
| | | break; |
| | | case 'info': |
| | | this.infoViewShow = true; |
| | | this.infoMode = transitionMode; |
| | | break; |
| | | case 'error': |
| | | this.errorInfoViewShow = true; |
| | | this.errorInfoMode = transitionMode; |
| | | break; |
| | | } |
| | | }, this.duration); |
| | | }, |
| | | |
| | | showHomeView() { |
| | | this.switchToView('home'); |
| | | }, |
| | | |
| | | showInfoView() { |
| | | this.homeViewShow = false; |
| | | this.errorInfoViewShow = false; |
| | | this.homeMode = ['fade', 'slide-bottom']; |
| | | this.errorInfoMode = ['fade', 'slide-bottom']; |
| | | setTimeout(() => { |
| | | this.infoViewShow = true; |
| | | this.infoMode = ['fade', 'slide-bottom']; |
| | | }, this.duration); |
| | | this.switchToView('info'); |
| | | }, |
| | | |
| | | showErrorView() { |
| | | this.homeViewShow = false; |
| | | this.infoViewShow = false; |
| | | this.homeMode = ['fade', 'slide-bottom']; |
| | | this.infoMode = ['fade', 'slide-bottom']; |
| | | setTimeout(() => { |
| | | this.errorInfoViewShow = true; |
| | | this.errorInfoMode = ['fade', 'slide-bottom']; |
| | | }, this.duration); |
| | | this.switchToView('error'); |
| | | }, |
| | | // 配置 |
| | | ejected() { |
| | |
| | | that.getUpdateVersion(); |
| | | }, 100); |
| | | }, |
| | | // 校验版本 |
| | | // 校验版本(增强错误处理) |
| | | getUpdateVersion() { |
| | | let that = this; |
| | | let type = 1; |
| | | if (that.baseUrl == 'http://undefined:undefined/undefined') { |
| | | const that = this; |
| | | const type = 1; |
| | | |
| | | // 配置验证 |
| | | if (!that.baseIP || !that.wmsPort || !that.wmsUrl) { |
| | | console.log('版本检查跳过:配置不完整'); |
| | | return; |
| | | } |
| | | const wms = 'http://' + that.baseIP + ':' + that.wmsPort + '/' + that.wmsUrl; |
| | | console.log(wms); |
| | | let url = wms + '/appVersion/checkUpdate/' + that.version + '/' + type; |
| | | |
| | | const wmsBaseUrl = `http://${that.baseIP}:${that.wmsPort}/${that.wmsUrl}`; |
| | | const url = `${wmsBaseUrl}/appVersion/checkUpdate/${that.version}/${type}`; |
| | | |
| | | uni.request({ |
| | | url: url, |
| | | method: 'GET', |
| | | success(res) { |
| | | console.log(res); |
| | | var res = res.data; |
| | | if (res.data) { |
| | | timeout: 10000, |
| | | success(result) { |
| | | const res = result.data; |
| | | if (res && res.data) { |
| | | that.filename = res.data.path; |
| | | that.dialogContent = '发现新版本:' + res.data.version + ', 是否立即更新'; |
| | | that.dialogContent = `发现新版本: ${res.data.version}, 是否立即更新`; |
| | | that.$refs.upVersion.open(); |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.msg, |
| | | icon: 'none', |
| | | position: 'top' |
| | | }); |
| | | } |
| | | }, |
| | | fail(err) { |
| | | console.error('版本检查失败:', err); |
| | | } |
| | | }); |
| | | }, |
| | |
| | | <style> |
| | | @import url('home.css'); |
| | | |
| | | /* 列 */ |
| | | /* ========== 工具类 ========== */ |
| | | .flex-col { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | /* 行 */ |
| | | .flex-row { |
| | | display: flex; |
| | | flex-direction: row; |
| | | } |
| | | |
| | | .flex-full { |
| | | width: 100%; |
| | | display: flex; |
| | | } |
| | | |
| | | .flex-center { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | |
| | | /* 数据文本样式 */ |
| | | .data-text { |
| | | font-size: 1.3vw; |
| | | color: rgba(255, 255, 255, 0.9); |
| | | } |
| | | |
| | | .data-text-lg { |
| | | font-size: 2vw; |
| | | font-weight: 600; |
| | | color: #00d4ff; |
| | | } |
| | | |
| | | .data-text-xl { |
| | | font-size: 3vw; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .stat-label { |
| | | width: 8vw; |
| | | height: 4vw; |
| | | line-height: 4vw; |
| | | } |
| | | |
| | | /* 数据行列表 */ |
| | | .data-row { |
| | | width: 100%; |
| | | display: flex; |
| | | padding: 0.5vw 0; |
| | | border-bottom: 1px solid rgba(0, 212, 255, 0.1); |
| | | transition: background 0.2s ease; |
| | | } |
| | | |
| | | .data-row:hover { |
| | | background: rgba(0, 212, 255, 0.05); |
| | | } |
| | | |
| | | .data-cell { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | width: 48%; |
| | | } |
| | | |
| | | /* 统计面板 */ |
| | | .stat-panel { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 1.5vh; |
| | | } |
| | | |
| | | /* ========== 容器 ========== */ |
| | | .container { |
| | | width: 100vw; |
| | | min-height: 100vh; |
| | | background-color: #00163e; |
| | | background: linear-gradient(135deg, #00163e 0%, #001a4d 50%, #00163e 100%); |
| | | color: #fff; |
| | | text-align: center; |
| | | } |
| | | |
| | | /* 主视图 */ |
| | | /* ========== 主视图 ========== */ |
| | | .home-view { |
| | | width: 100vw; |
| | | min-height: 100vh; |
| | | background-image: url(../../static/background.png); |
| | | background-size: 100vw 100vh; |
| | | background-position: center; |
| | | } |
| | | |
| | | .home-right { |
| | | width: 50vw; |
| | | height: 89vh; |
| | | /* background-color: cadetblue; */ |
| | | } |
| | | |
| | | .home-right-box { |
| | |
| | | height: 98%; |
| | | } |
| | | |
| | | /* ========== 头部标题 ========== */ |
| | | .head { |
| | | width: 100vw; |
| | | height: 11vh; |
| | |
| | | align-items: center; |
| | | justify-content: center; |
| | | transform: scale(0.7); |
| | | background: linear-gradient(180deg, rgba(0, 212, 255, 0.1) 0%, transparent 100%); |
| | | text-shadow: 0 0 20px rgba(0, 212, 255, 0.5); |
| | | letter-spacing: 0.5vw; |
| | | } |
| | | |
| | | /* ========== 时间工具栏 ========== */ |
| | | .time-tools { |
| | | position: absolute; |
| | | right: 2%; |
| | | top: 2%; |
| | | font-size: 1vw; |
| | | transform: scale(0.8); |
| | | color: rgba(255, 255, 255, 0.8); |
| | | text-shadow: 0 0 10px rgba(0, 212, 255, 0.3); |
| | | } |
| | | |
| | | /* ========== 装饰按钮 ========== */ |
| | | .button-left { |
| | | position: absolute; |
| | | background-image: url(../../static/right.png); |
| | |
| | | width: 13.5%; |
| | | height: 8.5%; |
| | | transform: scaleX(-1); |
| | | opacity: 0.9; |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | |
| | | .button-left:hover, |
| | | .button-right:hover { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .button-right { |
| | |
| | | left: 65%; |
| | | width: 13.5%; |
| | | height: 8.5%; |
| | | opacity: 0.9; |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | |
| | | /* ========== 仓库数据列表 ========== */ |
| | | .img-box { |
| | | height: 23vw; |
| | | width: 100%; |
| | | /* background-color: #666666; */ |
| | | display: flex; |
| | | flex-direction: row; |
| | | justify-content: flex-start; |
| | | flex-wrap: wrap; |
| | | font-size: 1vw; |
| | | overflow-y: auto; |
| | | padding: 0.5vw; |
| | | } |
| | | |
| | | .img-box::-webkit-scrollbar { |
| | | width: 4px; |
| | | } |
| | | |
| | | .img-box::-webkit-scrollbar-thumb { |
| | | background: rgba(0, 212, 255, 0.5); |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | .item-img { |
| | |
| | | margin-top: 5%; |
| | | display: flex; |
| | | flex-direction: row; |
| | | /* background-color: #00ffff; */ |
| | | justify-content: flex-start; |
| | | align-items: flex-start; |
| | | } |
| | |
| | | width: 5vw; |
| | | } |
| | | |
| | | /* ========== 进度条(增强版)========== */ |
| | | .progressBar { |
| | | margin-top: 9%; |
| | | /* width: 100%; */ |
| | | height: 20%; |
| | | background-color: #233751; |
| | | background: linear-gradient(90deg, #233751 0%, #1a2a3d 100%); |
| | | border-radius: 5vw; |
| | | overflow: hidden; |
| | | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); |
| | | position: relative; |
| | | } |
| | | |
| | | .progress { |
| | | /* width: 90%; */ |
| | | height: 100%; |
| | | background-color: #ff5722; |
| | | max-width: 100%; |
| | | background: linear-gradient(90deg, #ff9800 0%, #ff5722 50%, #f44336 100%); |
| | | border-radius: 5vw; |
| | | transition: width 0.5s ease-out; |
| | | position: relative; |
| | | } |
| | | |
| | | .progress::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: linear-gradient(180deg, rgba(255, 255, 255, 0.3) 0%, transparent 50%); |
| | | border-radius: 5vw; |
| | | } |
| | | |
| | | /* ========== 图表区域 ========== */ |
| | | .charts-box { |
| | | width: 80%; |
| | | height: 24vh; |
| | |
| | | .charts-box-ring { |
| | | width: 60%; |
| | | height: 24vh; |
| | | /* background-color: #00ffff; */ |
| | | } |
| | | |
| | | /* ========== 库存统计信息 ========== */ |
| | | .sub-info { |
| | | font-size: 1.5vw; |
| | | padding: 0.5vw 1vw; |
| | | border-radius: 0.5vw; |
| | | background: rgba(0, 212, 255, 0.05); |
| | | transition: background 0.3s ease; |
| | | } |
| | | |
| | | .sub-info:hover { |
| | | background: rgba(0, 212, 255, 0.1); |
| | | } |
| | | |
| | | .sub-info image { |
| | | width: 3.5vw; |
| | | height: 3.5vw; |
| | | margin-right: 0.5vw; |
| | | } |
| | | |
| | | /* 共用 */ |
| | | /* ========== 共用 ========== */ |
| | | .main { |
| | | width: 100vw; |
| | | height: 88vh; |
| | |
| | | display: flex; |
| | | } |
| | | |
| | | .mian-item { |
| | | .main-item { |
| | | width: 50%; |
| | | height: 100%; |
| | | display: flex; |
| | |
| | | justify-content: center; |
| | | } |
| | | |
| | | .mian-item-box { |
| | | .main-item-box { |
| | | width: 98%; |
| | | height: 98%; |
| | | } |