upperClothTwo.vue 8.73 KB
<template>
	<!-- 整个页面容器 -->
	<div class="single-page-container">
		<!-- 顶部通栏:左-系统名 + 中-品牌 + 右-时间+下拉框 -->
		<div class="top-header">
			<!-- 左侧:系统标识区 -->
			<div class="header-left">
				<img src="../assets/img/logo.png" alt="系统图标" class="sys-icon" />
				<span class="sys-name">软控一体管理平台</span>
			</div>

			<!-- 中间:报警 -->
			<div class="header-center">
				<span class="brand-name">{{ sonData }}</span>
			</div>

			<!-- 右侧:时间 + 下拉选择器(保留时间,替换管理员/退出) -->
			<div class="header-right">
				<span class="info-item" id="current-time">{{ currentTime }}</span>
				<el-select v-model="selectedArea" clearable size="mini" class="area-selector" @change="handleAreaChange">
					<el-option v-for="item in areaOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
				</el-select>
			</div>
		</div>

		<!-- 左右分栏布局 -->
		<div class="layout-wrap">
			<!-- 左侧导航栏 -->
			<div class="left-nav">
				<ul class="nav-menu">
					<li class="menu-item" :class="{ active: currentActive === 'home' }" @click="switchContent('home')">
						<img src="../assets/img/当前任务.png" alt="任务" class="menu-icon" />
						当前任务
					</li>
					<li class="menu-item" :class="{ active: currentActive === 'device' }" @click="switchContent('device')">
						<img src="../assets/img/历史任务.png" alt="任务" class="menu-icon" />
						历史任务
					</li>
					<li class="menu-item" :class="{ active: currentActive === 'task' }" @click="switchContent('task')">
						<img src="../assets/img/设备状态.png" alt="任务" class="menu-icon" />
						设备状态
					</li>
					<li class="menu-item" :class="{ active: currentActive === 'about' }" @click="switchContent('about')">
						<img src="../assets/img/年.png" alt="任务" class="menu-icon" />
						今日摘要
					</li>
				</ul>
			</div>

			<!-- 右侧内容展示区:只有 pageReady 为 true 才渲染!! -->
			<div class="right-content" v-if="pageReady">
				<taskModule ref="taskModule" @send-data="getSonData" :userName="selectedArea" v-if="currentActive === 'home'" />
				<historyTask ref="historyTask" :userName="selectedArea" v-if="currentActive === 'device'" />
				<deviceStatus ref="deviceStatus" v-if="currentActive === 'task'" />
				<todaySummary ref="todaySummary" v-if="currentActive === 'about'" />
			</div>
		</div>
	</div>
</template>

<script>
import taskModule from '@/components/taskModel'
import historyTask from '@/components/historyTaskModule'
import deviceStatus from '@/components/deviceStatusModule'
import todaySummary from '@/components/todaySummary'

export default {
	name: 'SinglePageLayout',
	data() {
		return {
			baseUrlOffOne: 'http://127.0.0.1:6002/api/BulletinBoard/Mes/V1/ReadData1',
			baseUrlOnLineOne: window.appConfig.baseUrlintTotalConversion,
			sysData: {},
			currentActive: 'home',
			currentTime: '',
			selectedArea: '',
			areaOptions: [{ code: '', name: '全部' }],
			timeTimer: null,
			sonData: '',
			show: '',

			// 核心:控制页面是否准备好(接口加载完才变true)
			pageReady: false,
		}
	},
	components: {
		taskModule,
		historyTask,
		deviceStatus,
		todaySummary,
	},
	methods: {
		getData() {
			const opt = {
				urlSuffix: window.baseOnLineOrOff ? this.baseUrlOnLineOne : this.baseUrlOffOne,
				logTitle: '总转换接口',
				isUrlALL: true,
				headers: window.baseOnLineOrOff,
				header: window.baseOnLineOrOff,
				type: 'post',
				data: {
					requestMethod: 'post',
					requestUrl: '/api/cmc/getZones',
					requestService: 'WMS',
					requestBody: {
						zoneTypeList: ['L'],
					},
				},
			}
			const callBackFn = (res) => {
				if (!this.ajaxSuccessDataBefore(res, opt.logTitle)) return

				let temp = { code: '', name: '全部' }
				res.data.result.push(temp)

				// 赋值
				this.selectedArea = res.data.result[0].code
				this.areaOptions = res.data.result

				// ==============================================
				// 接口加载完成 ✅ 现在才允许渲染子页面
				// ==============================================
				this.pageReady = true
			}
			''.ajax(this, opt, callBackFn)
		},
		ajaxSuccessDataBefore(res, title) {
			if (!res || !res.data || res.data.result == null || res.data.result.length === 0) {
				this.sysData = []
				''.Log(`${title}无数据`, 'getData')
				return false
			}
			return true
		},
		getSonData(data) {
			this.sonData = data
		},
		switchContent(navKey) {
			this.currentActive = navKey
		},
		updateTime() {
			const now = new Date()
			const year = now.getFullYear()
			const month = String(now.getMonth() + 1).padStart(2, '0')
			const day = String(now.getDate()).padStart(2, '0')
			const hh = String(now.getHours()).padStart(2, '0')
			const mm = String(now.getMinutes()).padStart(2, '0')
			const ss = String(now.getSeconds()).padStart(2, '0')
			this.currentTime = `${year}/${month}/${day} ${hh}:${mm}:${ss}`
		},
		handleAreaChange(val) {
			const activePage = this.currentActive
			this.currentActive = ''
			this.$nextTick(() => {
				this.currentActive = activePage
			})
		},
		bindWheelScroll() {
			const container = document.querySelector('.device-management')
			if (!container) return
			container.addEventListener(
				'wheel',
				(e) => {
					const target = e.target
					const scrollEl = target.closest('.field-display-area, .right-top-box, .left-div, .parent-container')
					if (!scrollEl) return
					if (scrollEl.scrollWidth > scrollEl.clientWidth) {
						e.preventDefault()
						scrollEl.scrollLeft += e.deltaY * 1.5
					}
				},
				{ passive: false },
			)
		},
	},
	mounted() {
		// 先加载接口 → 接口成功后才会打开 pageReady → 渲染子组件
		this.getData()

		this.updateTime()
		this.bindWheelScroll()
		this.timeTimer = setInterval(() => {
			this.updateTime()
		}, 1000)
	},
	beforeDestroy() {
		clearInterval(this.timeTimer)
	},
}
</script>

<style scoped>
/* 全局页面样式 */
.single-page-container {
	width: 100vw;
	height: 100dvh;
	margin: 0;
	padding: 0;
	overflow: hidden;
	font-family: '微软雅黑', sans-serif;
	display: flex;
	flex-direction: column;
}

/* 顶部通栏样式 */
.top-header {
	width: 100%;
	height: 2.5vw;
	background: linear-gradient(to right, #1f2937, #374151);
	color: #e5e7eb;
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 0 0.6vw;
	box-sizing: border-box;
	border-bottom: 0vw solid #4b5563;
	box-shadow: 0 0.1vw 0.3vw rgba(0, 0, 0, 0.4);
	z-index: 10;
}

/* 左侧:系统图标+名称 */
.header-left {
	display: flex;
	align-items: center;
	gap: 0.6vw;
}
.sys-icon {
	width: 9.5vw;
	height: 1.3vw;
}
.sys-name {
	font-size: 1.2vw;
	font-weight: 600;
	color: #ffffff;
	line-height: 1.2vw;
}

/* 中间:品牌标识 */
.header-center {
	width: 50vw;
	font-size: 1vw;
	font-weight: bold;
	color: red;
	letter-spacing: 0.2vw;
	display: flex;
	align-items: center;
	justify-content: center;
}

/* 右侧:时间+下拉框容器 */
.header-right {
	display: flex;
	align-items: center;
	gap: 0.6vw;
	font-size: 0.8vw;
	color: #d1d5db;
}
.info-item {
	display: inline-block;
}

/* 下拉框样式 */
.area-selector {
	width: 10vw;
}
::v-deep .el-input--mini {
	font-size: 1vw;
}
::v-deep .el-input--mini .el-input__inner {
	line-height: 1.9vw !important;
	padding: 0 0.4vw !important;
}
.area-selector ::v-deep .el-input__inner {
	background-color: #374151 !important;
	border: 0.05vw solid #4b5563 !important;
	color: #e5e7eb !important;
	height: 1.6vw;
	font-size: 0.7vw;
}
::v-deep .el-input__inner {
	padding: 0 16px !important;
	border-radius: 0.4vw !important;
}
::v-deep .el-input__icon {
	height: 100% !important;
	width: 1vw !important;
	font-size: 0.8vw !important;
	line-height: 1.6vw !important;
}
::v-deep .el-select-dropdown__list {
	padding: 10px 0 !important;
}
::v-deep .el-input__suffix {
	right: 0.4vw !important;
}

/* 左右分栏布局 */
.layout-wrap {
	display: flex;
	width: 100%;
	height: calc(100% - 2.5vw);
}

/* 左侧导航栏样式 */
.left-nav {
	width: 7vw;
	height: 100%;
	background-color: #2c3e50;
	color: #ffffff;
	box-shadow: 0.2vw 0 0.5vw rgba(0, 0, 0, 0.1);
}

.nav-menu {
	list-style: none;
	padding: 0;
	margin: 0;
}

.menu-item {
	padding: 1vw 1vw 1vw 0.5vw;
	font-size: 0.8vw;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background-color 0.2s ease;
	border-left: 0.3vw solid transparent;
}

.menu-item.active {
	background-color: #34495e;
	border-left-color: #00c6ff;
	color: #ffffff;
	font-weight: 500;
}

.menu-item:hover:not(.active) {
	background-color: #4a6583;
}
.menu-icon {
	width: 0.95vw;
	height: 0.95vw;
	object-fit: contain;
}

/* 右侧内容展示区 */
.right-content {
	flex: 1;
	height: 100%;
	background-color: #1c2c3b;
	overflow: hidden;
	box-sizing: border-box;
}
</style>