taskModule.vue 8.88 KB
<template>
	<div class="wms-ccs-container">
		<!-- <div class="header">
			<div class="wms-title">机加库区</div>
			<div class="status-lights">
				<div class="status-value big-value">{{ timeStr }}</div>
				<div class="status-item status-switch">
					<button class="search-btn green-btn">库区切换</button>
				</div>
			</div>
		</div> -->

		<div class="task-section">
			<div class="table-wrapper">
				<table class="task-table">
					<thead>
						<tr>
							<th>任务ID</th>
							<th>任务状态</th>
							<th>任务持续时间</th>
							<!-- <th>异常信息</th>
							<th>异常处理方案</th> -->
							<th>任务类型</th>
							<th>任务优先级</th>
							<th>巷道</th>
							<th>单据编码</th>
							<th>任务起始位置</th>
							<th>任务目标位置</th>
							<th>托盘编码</th>
							<th>任务执行顺序</th>
							<th>托盘当前位置</th>
							<th>执行设备ID</th>
							<th>设备状态</th>
							<th>设备运行模式</th>
							<th>设备当前位置</th>
							<!-- <th>任务阶段详情</th> -->
						</tr>
					</thead>
					<tbody>
						<tr
							v-for="(item, index) in taskList"
							:key="index"
							:class="{
								'green-text': item.taskDurationSeconds <= 10,
								'yellow-text': item.taskDurationSeconds > 10 && item.taskDurationSeconds < 60,
								'red-text': item.taskDurationSeconds >= 60,
							}"
							@click="progress(item)"
						>
							<td>{{ item.taskId }}</td>
							<td>{{ item.taskStatusDescription }}</td>
							<td>{{ item.taskDurationSecondsFormat }}</td>
							<!-- <td>{{ item.exceptionMessage }}</td>
							<td>{{ item.exceptionMessage }}</td> -->
							<td>{{ item.taskTypeDescription }}</td>
							<td>{{ item.taskPriority }}</td>
							<td>{{ item.roadway }}</td>
							<td>{{ item.orderCode }}</td>
							<td>{{ item.fromLocation }}</td>
							<td>{{ item.toLocation }}</td>
							<td>{{ item.containerCode }}</td>
							<td>{{ item.taskExecutionOrder }}</td>
							<td>{{ item.containerCurrentLocation }}</td>
							<td>{{ item.executionEquipmentId }}</td>
							<td>{{ item.equipmentStatusDescription }}</td>
							<td>{{ item.equipmentOperationMode }}</td>
							<td>{{ item.equipmentCurrentPosition }}</td>
							<!-- <td @click="drawer = true">操作</td> -->
						</tr>
					</tbody>
				</table>
			</div>
		</div>

		<el-dialog title="任务阶段查看" :visible.sync="drawer" width="75%" :before-close="handleClose">
			<el-steps finish-status="success" :active="temp + 1">
				<el-step v-for="(item, index) in deviceStatus" :key="index" :title="item.key" :description="item.value">
					<template v-slot:description>
						<el-button size="small">查看详情</el-button>
					</template>
				</el-step>
			</el-steps>
		</el-dialog>
	</div>
</template>

<script>
export default {
	data() {
		return {
			baseUrlOffOne: 'http://127.0.0.1:6002/api/BulletinBoard/Mes/V1/ReadData1',
			baseUrlOnLineOne: window.appConfig.baseUrlintTwo,
			sysData: {},
			timer: null,
			deviceStatus: [],
			taskList: [],
			drawer: false,
			direction: 'rtl',
			device: {},
			temp: 0,
		}
	},
	methods: {
		getAGVDataOne() {
			const opt = {
				urlSuffix: window.baseOnLineOrOff ? this.baseUrlOnLineOne : this.baseUrlOffTwo,
				logTitle: '任务列表',
				isUrlALL: true,
				headers: window.baseOnLineOrOff,
				header: window.baseOnLineOrOff,
				type: 'post',
			}
			const callBackFn = (res) => {
				if (!this.ajaxSuccessDataBefore(res, opt.logTitle)) return
				res.data.result.forEach((x) => {
					x.taskDurationSeconds = Number((x.taskDurationSeconds / 60).toFixed(2))
				})
				this.taskList = res.data.result
			}
			''.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
		},
		progress(item) {
			const taskStatusList = Object.entries(item.taskStatusTimestamps).map(([key, value]) => ({
				key: key,
				value: value,
			}))
			if (!taskStatusList.length) {
				this.temp = -1
				return
			}
			let lastValidIndex = -1
			taskStatusList.forEach((item, index) => {
				if (item.value !== null) {
					lastValidIndex = index
				}
			})
			this.temp = lastValidIndex
			this.deviceStatus = taskStatusList
			this.drawer = true
		},
		handleClose(done) {
			done()
		},
		intInterval: function() {
			setInterval(() => {
				this.getAGVDataOne()
			}, 2000)
		},
	},
	mounted() {
		this.getAGVDataOne()
		this.intInterval()
	},
}
</script>

<style scoped>
/* 全局基础样式 */
html,
body {
	height: 100%;
	margin: 0;
	padding: 0;
	overflow: hidden;
}
.wms-ccs-container {
	background-color: #000814;
	color: #e2e8f0;
	font-family: '微软雅黑', sans-serif;
	height: 94.5vh;
	width: 100%;
	display: flex;
	flex-direction: column;
	padding: 10px;
	box-sizing: border-box;
	background-image: linear-gradient(145deg, #00122e 0%, #000814 100%);
}
.wms-ccs-container * {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
.wms-title {
	width: 77%;
	font-size: 2.7vw;
	font-weight: bold;
	color: #ffffff;
	text-align: center;
	text-shadow: 0 0 8px rgba(0, 196, 255, 0.5);
}
.status-lights {
	width: 23%;
	display: flex;
	gap: 15px;
	align-items: center;
}
.status-item {
	display: flex;
	flex-direction: column;
	gap: 5px;
	align-items: center;
}
.status-value {
	font-size: 16px;
	color: #ffffff;
	font-weight: 500;
}
.big-value {
	font-size: 23px;
	font-weight: bold;
	color: #00ffd5;
	min-width: 180px;
	text-align: center;
}
.status-switch {
	margin-left: 20px;
}
.search-btn {
	background-color: #003554;
	border: 1px solid #00b4d8;
	color: #fff;
	padding: 6px 15px;
	border-radius: 4px;
	cursor: pointer;
	transition: all 0.2s;
}
.search-btn.green-btn {
	background-color: #00b42a;
	border-color: #00ff47;
}
.search-btn.green-btn:hover {
	background-color: #009a22;
	box-shadow: 0 0 8px rgba(0, 255, 71, 0.4);
}

/* 任务表格区域样式 */
.task-section {
	background-color: rgba(0, 20, 46, 0.8);
	border: 1px solid #00509d;
	border-radius: 8px;
	padding: 15px;
	/* margin-bottom: 15px; */
	flex: 1;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}
.table-wrapper {
	flex: 1;
	overflow-y: auto;
	overflow-x: auto;
}
.task-table {
	width: 100%;
	border-collapse: collapse;
	min-width: 1800px;
	background-color: rgba(0, 15, 38, 0.9);
	table-layout: fixed;
}
.task-table th {
	padding: 10px 5px;
	text-align: center;
	font-size: 13px;
	border: 1px solid #00509d;
	background-color: #003554;
	color: #00e5ff;
	font-weight: bold;
	position: sticky;
	top: 0;
	z-index: 1;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	height: 50px;
	line-height: 50px;
}
.task-table td {
	padding: 8px 5px;
	text-align: center;
	font-size: 13px;
	border: 1px solid #004080;
	white-space: normal;
	word-wrap: break-word;
	word-break: break-all;
	height: 50px;
	line-height: 1.6;
	max-height: 50px;
	overflow: hidden;
	text-overflow: ellipsis;
	display: table-cell;
	vertical-align: middle;
}
/* 表格列宽配置 */
.task-table th:nth-child(1),
.task-table th:nth-child(2),
.task-table th:nth-child(3),
.task-table th:nth-child(6),
.task-table th:nth-child(7),
.task-table th:nth-child(8),
.task-table th:nth-child(9),
.task-table th:nth-child(10),
.task-table th:nth-child(11),
.task-table th:nth-child(12),
.task-table th:nth-child(13),
.task-table th:nth-child(14),
.task-table th:nth-child(15),
.task-table th:nth-child(16),
.task-table th:nth-child(17),
.task-table th:nth-child(18),
.task-table th:nth-child(19),
.task-table td:nth-child(1),
.task-table td:nth-child(2),
.task-table td:nth-child(3),
.task-table td:nth-child(6),
.task-table td:nth-child(7),
.task-table td:nth-child(8),
.task-table td:nth-child(9),
.task-table td:nth-child(10),
.task-table td:nth-child(11),
.task-table td:nth-child(12),
.task-table td:nth-child(13),
.task-table td:nth-child(14),
.task-table td:nth-child(15),
.task-table td:nth-child(16),
.task-table td:nth-child(17),
.task-table td:nth-child(18),
.task-table td:nth-child(19) {
	width: 100px;
}
.task-table th:nth-child(4),
.task-table td:nth-child(4),
.task-table th:nth-child(5),
.task-table td:nth-child(5) {
	width: 200px;
}
/* 表格行hover效果 */
.task-table tr:hover {
	background-color: rgba(0, 80, 157, 0.3);
}

/* 任务时长文字颜色样式 */
.red-text {
	color: #ff2d55 !important;
}
.green-text {
	color: #00ff9d !important;
}
.yellow-text {
	color: #ffc107 !important;
}

/* 滚动条样式 */
.table-wrapper::-webkit-scrollbar {
	width: 8px;
	height: 8px;
}
.table-wrapper::-webkit-scrollbar-thumb {
	background-color: #0077b6;
	border-radius: 4px;
}
.table-wrapper::-webkit-scrollbar-track {
	background-color: #001e3c;
}

/* 精简响应式适配(仅保留当前模板相关元素) */
@media (max-width: 1200px) {
	.big-value {
		font-size: 14px;
		min-width: 160px;
	}
}
@media (max-width: 768px) {
	.big-value {
		font-size: 12px;
		min-width: 140px;
	}
	.status-switch {
		width: 100%;
		text-align: right;
	}
}
</style>