|
@@ -0,0 +1,732 @@
|
|
|
|
|
+<!-- 异常停泊区管理 - 深色科技风格 -->
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="delivery-page">
|
|
|
|
|
+ <!-- 背景层 -->
|
|
|
|
|
+ <div class="bg-layer" :style="{ backgroundImage: `url(${bgImg})` }" />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 顶部标题区域 -->
|
|
|
|
|
+ <div class="header-section">
|
|
|
|
|
+ <button class="back-btn" @click="$router.push('/home')">
|
|
|
|
|
+ <i class="fas fa-arrow-left" />
|
|
|
|
|
+ <span>返回</span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <h1 class="page-title">异常停泊区管理</h1>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 主内容区域 -->
|
|
|
|
|
+ <main class="main-content">
|
|
|
|
|
+ <div class="stations-grid">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="station in stations" :key="station.positionNo" class="station-card"
|
|
|
|
|
+ :class="getStationClass(station)" @click="openStation(station)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="card-header">
|
|
|
|
|
+ <div class="card-title">{{ station.positionName }}</div>
|
|
|
|
|
+ <span class="status-badge" :class="getStatusClass(station.positionStatus)">
|
|
|
|
|
+ {{ station.positionStatus }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 卡片内容 -->
|
|
|
|
|
+ <div class="card-content">
|
|
|
|
|
+ <!-- 占用状态 - 显示物料图标 -->
|
|
|
|
|
+ <div v-if="station.positionStatus === '已占用'" class="material-display">
|
|
|
|
|
+ <div class="material-image">
|
|
|
|
|
+ <i class="fas fa-car" style="font-size: 60px; color: #fff;" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 空闲状态 -->
|
|
|
|
|
+ <div v-else class="empty-state">
|
|
|
|
|
+ <i class="fas fa-inbox" />
|
|
|
|
|
+ <span>暂无物料车</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </main>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 确认取走弹窗 - 科技感风格 -->
|
|
|
|
|
+ <div v-if="visible" class="tech-modal-overlay" @click.self="cancelTask">
|
|
|
|
|
+ <div class="tech-modal">
|
|
|
|
|
+ <div class="modal-content-row">
|
|
|
|
|
+ <div class="modal-text">
|
|
|
|
|
+ <h3>人工核对</h3>
|
|
|
|
|
+ <p>您是否已检查<span class="highlight">【{{ positionName }}】</span>的工装/设备,<br />确认无误并准备取走料车?</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="modal-icon">
|
|
|
|
|
+ <div class="icon-box">
|
|
|
|
|
+ <i class="fas fa-dolly" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- RFID记录详细信息 -->
|
|
|
|
|
+ <div v-if="selectedStation && selectedStation.agvRfidRecordLogResponseList" class="rfid-details">
|
|
|
|
|
+ <h4 class="details-title">RFID校验记录</h4>
|
|
|
|
|
+ <div v-if="selectedStation && selectedStation.positionEndNo" class="endpoint-info">
|
|
|
|
|
+ <h3>料车目标终点货位:</h3>
|
|
|
|
|
+ <span class="endpoint-value">{{ selectedStation.positionEndNo }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="record-list">
|
|
|
|
|
+ <div v-for="(record, index) in selectedStation.agvRfidRecordLogResponseList" :key="index" class="record-item">
|
|
|
|
|
+ <div class="record-header">
|
|
|
|
|
+ <span class="record-index">闸机第{{ record.countExecute }}次校验</span>
|
|
|
|
|
+ <span class="record-time">{{ record.requestTime }}</span>
|
|
|
|
|
+ <span class="record-status" :class="record.success ? 'success' : 'failed'">
|
|
|
|
|
+ {{ record.success ? '成功' : '失败' }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="record-message">
|
|
|
|
|
+ <i class="fas fa-info-circle" />
|
|
|
|
|
+ <span>{{ record.message }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- RFID设备信息 -->
|
|
|
|
|
+ <div v-if="record.rfidInventoryResponseList && record.rfidInventoryResponseList.length > 0" class="inventory-section">
|
|
|
|
|
+ <h5>RFID读取的设备:</h5>
|
|
|
|
|
+ <div class="inventory-list">
|
|
|
|
|
+ <div v-for="(item, idx) in record.rfidInventoryResponseList" :key="idx" class="inventory-item">
|
|
|
|
|
+ <span class="inventory-no">{{ item.inventoryNo }}</span>
|
|
|
|
|
+ <span class="inventory-name">{{ item.inventoryName }}</span>
|
|
|
|
|
+ <span class="inventory-box">{{ item.feedBoxName }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 校验设备信息 -->
|
|
|
|
|
+ <div v-if="record.checkInventoryResponseList && record.checkInventoryResponseList.length > 0" class="check-section">
|
|
|
|
|
+ <h5>需要校验的设备:</h5>
|
|
|
|
|
+ <div class="inventory-list">
|
|
|
|
|
+ <div v-for="(item, idx) in record.checkInventoryResponseList" :key="idx" class="inventory-item">
|
|
|
|
|
+ <span class="inventory-no">{{ item.inventoryNo }}</span>
|
|
|
|
|
+ <span class="inventory-name">{{ item.inventoryName }}</span>
|
|
|
|
|
+ <span class="inventory-box">{{ item.feedBoxName }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="modal-footer">
|
|
|
|
|
+ <button class="modal-btn cancel-btn" @click="cancelTask">取消</button>
|
|
|
|
|
+ <button class="modal-btn confirm-btn" @click="takeAway">确认取走</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- Loading -->
|
|
|
|
|
+ <div v-if="loading" class="loading-overlay">
|
|
|
|
|
+ <div class="loading-dots">
|
|
|
|
|
+ <div class="dot" />
|
|
|
|
|
+ <div class="dot" />
|
|
|
|
|
+ <div class="dot" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="loading-text">加载中...</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, onMounted } from 'vue';
|
|
|
|
|
+import { showNotify } from 'vant';
|
|
|
|
|
+import { getLocatorAbnormalAreaStatus, takeAwayAbnormalCar } from '../api/agv.js';
|
|
|
|
|
+
|
|
|
|
|
+// 图片资源
|
|
|
|
|
+import bgImg from '../assets/images/bj.png';
|
|
|
|
|
+
|
|
|
|
|
+// 加载状态
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+// 还料位数据
|
|
|
|
|
+const stations = ref([]);
|
|
|
|
|
+
|
|
|
|
|
+const visible = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+const positionName = ref('');
|
|
|
|
|
+const positionNo = ref('');
|
|
|
|
|
+const taskId = ref('');
|
|
|
|
|
+const selectedStation = ref(null);
|
|
|
|
|
+
|
|
|
|
|
+// 获取卡片样式类
|
|
|
|
|
+const getStationClass = station => {
|
|
|
|
|
+ if (station.positionStatus === '已占用') return 'station-occupied';
|
|
|
|
|
+ if (station.positionStatus === '空闲中') return 'station-idle';
|
|
|
|
|
+ if (station.positionStatus === '待入库') return 'station-pending';
|
|
|
|
|
+ return '';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 获取状态徽章类
|
|
|
|
|
+const getStatusClass = status => {
|
|
|
|
|
+ if (status === '已占用') return 'status-danger';
|
|
|
|
|
+ if (status === '空闲中') return 'status-success';
|
|
|
|
|
+ if (status === '待入库') return 'status-warning';
|
|
|
|
|
+ return '';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 打开弹窗
|
|
|
|
|
+const openStation = station => {
|
|
|
|
|
+ if (station.positionStatus === '空闲中' || station.positionStatus === '待入库') {
|
|
|
|
|
+ showNotify({ type: 'danger', message: '请选择占用中的异常停泊区' });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ visible.value = true;
|
|
|
|
|
+ positionName.value = station.positionName;
|
|
|
|
|
+ positionNo.value = station.positionNo;
|
|
|
|
|
+ taskId.value = station.taskId;
|
|
|
|
|
+ selectedStation.value = station;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 根据还料货位和料车编号生成归还单和调度任务
|
|
|
|
|
+const takeAway = async () => {
|
|
|
|
|
+
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ positionNo: positionNo.value,
|
|
|
|
|
+ taskId: taskId.value,
|
|
|
|
|
+ };
|
|
|
|
|
+ const res = await takeAwayAbnormalCar(params);
|
|
|
|
|
+ if (res.errorCode === 0) {
|
|
|
|
|
+ showNotify({ type: 'success', message: '料车取走成功' });
|
|
|
|
|
+ visible.value = false;
|
|
|
|
|
+ selectedStation.value = null;
|
|
|
|
|
+ await getStations();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showNotify({ type: 'danger', message: res.errorMessage || '料车取走失败' });
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('料车取走失败:', error);
|
|
|
|
|
+ showNotify({ type: 'danger', message: '料车取走失败' });
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 取消任务
|
|
|
|
|
+const cancelTask = () => {
|
|
|
|
|
+ visible.value = false;
|
|
|
|
|
+ selectedStation.value = null;
|
|
|
|
|
+};
|
|
|
|
|
+// 获取还料位数据
|
|
|
|
|
+const getStations = async () => {
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getLocatorAbnormalAreaStatus();
|
|
|
|
|
+ if (res.errorCode === 0) {
|
|
|
|
|
+ if (res.datas && res.datas.length > 0) {
|
|
|
|
|
+ stations.value = res.datas;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ stations.value = [];
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showNotify({ type: 'danger', message: res.errorMessage });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取异常停泊区货位数据失败:', error);
|
|
|
|
|
+ showNotify({ type: 'danger', message: '获取异常停泊区货位数据失败' });
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ getStations();
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+/* ========== 基础样式 ========== */
|
|
|
|
|
+.delivery-page {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ font-family: 'Microsoft YaHei', sans-serif;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 背景层 */
|
|
|
|
|
+.bg-layer {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ background-color: #041c3d;
|
|
|
|
|
+ background-size: cover;
|
|
|
|
|
+ background-position: center;
|
|
|
|
|
+ z-index: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 主内容区域 ========== */
|
|
|
|
|
+.main-content {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ padding: 20px 30px;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 网格布局 */
|
|
|
|
|
+.stations-grid {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 卡片样式 ========== */
|
|
|
|
|
+.station-card {
|
|
|
|
|
+ background: rgba(9, 61, 140, 0.6);
|
|
|
|
|
+ border: 1px solid #049FD8;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ min-height: 280px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.station-card:hover {
|
|
|
|
|
+ transform: translateY(-4px);
|
|
|
|
|
+ box-shadow: 0 0 25px rgba(4, 159, 216, 0.4);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.station-occupied {
|
|
|
|
|
+ border-color: #ef4444;
|
|
|
|
|
+ background: rgba(239, 68, 68, 0.15);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.station-idle {
|
|
|
|
|
+ border-color: #10b981;
|
|
|
|
|
+ background: rgba(16, 185, 129, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.station-pending {
|
|
|
|
|
+ border-color: #f59e0b;
|
|
|
|
|
+ background: rgba(245, 158, 11, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 卡片头部 */
|
|
|
|
|
+.card-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ padding-bottom: 15px;
|
|
|
|
|
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.card-title {
|
|
|
|
|
+ font-size: 20px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 状态徽章 */
|
|
|
|
|
+.status-badge {
|
|
|
|
|
+ padding: 6px 14px;
|
|
|
|
|
+ border-radius: 20px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 卡片内容 */
|
|
|
|
|
+.card-content {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.status-success {
|
|
|
|
|
+ background: rgba(16, 185, 129, 0.2);
|
|
|
|
|
+ color: #34d399;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.status-danger {
|
|
|
|
|
+ background: rgba(239, 68, 68, 0.2);
|
|
|
|
|
+ color: #f87171;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.status-warning {
|
|
|
|
|
+ background: rgba(245, 158, 11, 0.2);
|
|
|
|
|
+ color: #fbbf24;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 物料显示区域 */
|
|
|
|
|
+.material-display {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.material-image {
|
|
|
|
|
+ width: 150px;
|
|
|
|
|
+ height: 150px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.material-image img {
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ max-height: 100%;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ filter: brightness(0) invert(1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 空状态 */
|
|
|
|
|
+.empty-state {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ color: #7ec8ff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-state i {
|
|
|
|
|
+ font-size: 48px;
|
|
|
|
|
+ opacity: 0.5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-state span {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 科技感弹窗样式 ========== */
|
|
|
|
|
+.tech-modal-overlay {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ background: rgba(4, 28, 61, 0.9);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ z-index: 2000;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.tech-modal {
|
|
|
|
|
+ background: linear-gradient(135deg, #0a3d6d 0%, #041c3d 100%);
|
|
|
|
|
+ border: 1px solid #049FD8;
|
|
|
|
|
+ border-radius: 16px;
|
|
|
|
|
+ width: 90%;
|
|
|
|
|
+ max-width: 500px;
|
|
|
|
|
+ box-shadow: 0 0 40px rgba(4, 159, 216, 0.3);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-content-row {
|
|
|
|
|
+ padding: 30px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 30px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-text {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.endpoint-info {
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.endpoint-info h3 {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ display: inline;
|
|
|
|
|
+ margin-right: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.endpoint-info .endpoint-value {
|
|
|
|
|
+ color: #00bfff;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ display: inline;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-text h3 {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ margin: 0 0 12px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-text p {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #7ec8ff;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ line-height: 1.6;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-text .highlight {
|
|
|
|
|
+ color: #00bfff;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-icon {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.icon-box {
|
|
|
|
|
+ width: 80px;
|
|
|
|
|
+ height: 80px;
|
|
|
|
|
+ background: linear-gradient(135deg, #1e90ff 0%, #00bfff 100%);
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 36px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ box-shadow: 0 10px 30px rgba(0, 191, 255, 0.3);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-footer {
|
|
|
|
|
+ padding: 20px 30px 30px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.modal-btn {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ padding: 14px 0;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cancel-btn {
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+ border: 1px solid #2a7fff;
|
|
|
|
|
+ color: #7ec8ff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cancel-btn:hover {
|
|
|
|
|
+ background: rgba(42, 127, 255, 0.2);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.confirm-btn {
|
|
|
|
|
+ background: linear-gradient(90deg, #1e90ff 0%, #00bfff 100%);
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.confirm-btn:hover {
|
|
|
|
|
+ box-shadow: 0 0 20px rgba(30, 144, 255, 0.5);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== RFID详细信息样式 ========== */
|
|
|
|
|
+.rfid-details {
|
|
|
|
|
+ padding: 0 30px 20px;
|
|
|
|
|
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
+ margin-top: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.details-title {
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ margin: 0 0 15px 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.details-title::before {
|
|
|
|
|
+ content: '';
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 4px;
|
|
|
|
|
+ height: 20px;
|
|
|
|
|
+ background: linear-gradient(135deg, #1e90ff 0%, #00bfff 100%);
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-list {
|
|
|
|
|
+ max-height: 300px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-item {
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-index {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #00bfff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-time {
|
|
|
|
|
+ color: #7ec8ff;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-status {
|
|
|
|
|
+ padding: 4px 12px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-status.success {
|
|
|
|
|
+ background: rgba(16, 185, 129, 0.2);
|
|
|
|
|
+ color: #34d399;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-status.failed {
|
|
|
|
|
+ background: rgba(239, 68, 68, 0.2);
|
|
|
|
|
+ color: #f87171;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-message {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ color: #7ec8ff;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-message i {
|
|
|
|
|
+ color: #00bfff;
|
|
|
|
|
+ margin-top: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-section, .check-section {
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ padding-top: 12px;
|
|
|
|
|
+ border-top: 1px dashed rgba(255, 255, 255, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-section h5, .check-section h5 {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ margin: 0 0 8px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-list {
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.03);
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ padding: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 6px 8px;
|
|
|
|
|
+ margin-bottom: 4px;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-item:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-no {
|
|
|
|
|
+ color: #00bfff;
|
|
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
|
|
+ flex: 2;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-name {
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ flex: 3;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-box {
|
|
|
|
|
+ color: #7ec8ff;
|
|
|
|
|
+ flex: 2;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 滚动条样式 */
|
|
|
|
|
+.record-list::-webkit-scrollbar {
|
|
|
|
|
+ width: 6px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-list::-webkit-scrollbar-track {
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-list::-webkit-scrollbar-thumb {
|
|
|
|
|
+ background: rgba(0, 191, 255, 0.3);
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.record-list::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
+ background: rgba(0, 191, 255, 0.5);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 响应式 - 横屏 ========== */
|
|
|
|
|
+@media screen and (orientation: landscape) {
|
|
|
|
|
+ .header-section {
|
|
|
|
|
+ padding: 10px 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .page-title {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .main-content {
|
|
|
|
|
+ padding: 10px 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .station-card {
|
|
|
|
|
+ min-height: 200px;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .rfid-details {
|
|
|
|
|
+ padding: 0 20px 15px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-content-row {
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-footer {
|
|
|
|
|
+ padding: 15px 20px 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|