|
|
@@ -1,161 +1,201 @@
|
|
|
-<!-- 主页 -->
|
|
|
+<!-- 智能仓储管理系统 - 大屏首页 (1080x1920 竖屏优化,支持其他设备滚动) -->
|
|
|
<template>
|
|
|
- <div class="bg-gray-50 min-h-screen">
|
|
|
- <!-- 顶部信息栏 -->
|
|
|
- <PageHeader :show-back="false" />
|
|
|
-
|
|
|
- <!-- 主内容区域 -->
|
|
|
- <main class="container mx-auto px-6 py-12 pb-40">
|
|
|
- <div class="text-center mb-16">
|
|
|
- <h1 class="text-4xl font-bold text-gray-800 mb-4">智能仓储管理系统</h1>
|
|
|
- <p class="text-xl text-gray-600 max-w-2xl mx-auto">高效管理物料流转,实时监控库存状态,优化仓储作业流程</p>
|
|
|
+ <div class="home-page">
|
|
|
+ <!-- 背景 -->
|
|
|
+ <div class="bg-layer" :style="{ backgroundImage: `url(${bgImg})` }" />
|
|
|
+
|
|
|
+ <!-- 飞机图片 - 作为背景层 -->
|
|
|
+ <div class="airplane-layer">
|
|
|
+ <img :src="airplaneImg" alt="飞机模型" class="airplane-img" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 顶部标题区域 - 全宽 -->
|
|
|
+ <div class="header-section">
|
|
|
+ <img :src="headerImg" alt="" class="header-bg" />
|
|
|
+ <h1 class="title">智能仓储管理系统</h1>
|
|
|
+ <!-- 左侧用户信息 -->
|
|
|
+ <div class="user-badge">
|
|
|
+ <i class="fas fa-user user-icon" />
|
|
|
+ <span class="username">{{ username }}</span>
|
|
|
</div>
|
|
|
+ <!-- 右侧操作按钮 -->
|
|
|
+ <div class="header-actions">
|
|
|
+ <div ref="settingsDropdown" class="settings-dropdown">
|
|
|
+ <button class="icon-btn" @click="toggleSettings">
|
|
|
+ <img :src="settingsIcon" alt="设置" class="settings-icon" />
|
|
|
+ </button>
|
|
|
+ <div v-if="showSettings" class="dropdown-menu">
|
|
|
+ <div class="dropdown-item" @click="goToFingerprintEnroll">
|
|
|
+ <i class="fas fa-fingerprint mr-2" />
|
|
|
+ <span>指纹录入</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="isOut" class="dropdown-item" @click="toggleMenu">
|
|
|
+ <i class="fas fa-menu mr-2" />
|
|
|
+ <span>内侧菜单</span>
|
|
|
+ </div>
|
|
|
+ <div v-else class="dropdown-item" @click="toggleMenu">
|
|
|
+ <i class="fas fa-menu mr-2" />
|
|
|
+ <span>外侧菜单</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <button class="exit-btn" @click="handleLogout">退出</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- 数据概览卡片 -->
|
|
|
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-16">
|
|
|
+ <!-- 页面内容容器 -->
|
|
|
+ <div class="page-container">
|
|
|
+ <!-- 统计卡片区域 -->
|
|
|
+ <div class="stats-section">
|
|
|
<div
|
|
|
- v-for="stat in statistics" :key="stat.title" class="bg-white rounded-xl shadow-md p-6 border-l-4"
|
|
|
- :class="getStatColorClasses(stat.color, 'border')"
|
|
|
+ v-for="stat in statistics" :key="stat.title" class="stat-card"
|
|
|
+ :style="{ backgroundImage: `url(${stat.bg})` }"
|
|
|
>
|
|
|
- <div class="flex justify-between items-start">
|
|
|
- <div>
|
|
|
- <p class="text-gray-500 text-sm">{{ stat.title }}</p>
|
|
|
- <p class="text-3xl font-bold mt-2">{{ stat.value }}</p>
|
|
|
+ <div class="stat-info">
|
|
|
+ <div class="stat-label">{{ stat.title }}</div>
|
|
|
+ <div class="stat-value">{{ stat.value }}</div>
|
|
|
+ <div class="stat-trend" :class="stat.trend > 0 ? 'up' : 'down'">
|
|
|
+ <img :src="stat.trend > 0 ? arrowUpIcon : arrowDownIcon" alt="" class="trend-icon" />
|
|
|
+ {{ stat.changeText }}
|
|
|
</div>
|
|
|
- <div class="p-3 rounded-lg" :class="getStatColorClasses(stat.color, 'bg')">
|
|
|
- <i class="text-xl" :class="['fas', stat.icon, getStatColorClasses(stat.color, 'text')]" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="mt-4">
|
|
|
- <p class="text-sm" :class="stat.trend > 0 ? 'text-green-500' : 'text-red-500'">
|
|
|
- <i class="mr-1" :class="stat.trend > 0 ? 'fas fa-arrow-up' : 'fas fa-arrow-down'" />{{ stat.changeText }}
|
|
|
- </p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 物料分类区域 -->
|
|
|
- <div class="mb-16">
|
|
|
- <h2 class="text-2xl font-bold text-gray-800 mb-6">物料分类</h2>
|
|
|
- <div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
|
|
+ <!-- 操作按钮区域 -->
|
|
|
+ <div class="buttons-section">
|
|
|
+ <template v-if="isOut">
|
|
|
<div
|
|
|
- v-for="category in materialCategories" :key="category.name"
|
|
|
- class="bg-white rounded-lg shadow-sm p-4 text-center cursor-pointer hover:shadow-md transition-shadow"
|
|
|
+ v-for="action in outButtons" :key="action.label" class="action-btn"
|
|
|
+ @click="handleAction(action.action)"
|
|
|
>
|
|
|
- <div class="w-full h-20 overflow-hidden mb-3 rounded-lg">
|
|
|
- <img :src="category.image" :alt="category.name" class="w-full h-full object-cover object-top" />
|
|
|
- </div>
|
|
|
- <p class="font-medium">{{ category.name }}</p>
|
|
|
- <p class="text-gray-500 text-sm">{{ category.count }} 种</p>
|
|
|
+ <img :src="buttonBg" alt="" class="btn-bg" />
|
|
|
+ <span class="btn-text">{{ action.label }}</span>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div
|
|
|
+ v-for="action in inButtons" :key="action.label" class="action-btn"
|
|
|
+ @click="handleAction(action.action)"
|
|
|
+ >
|
|
|
+ <img :src="buttonBg" alt="" class="btn-bg" />
|
|
|
+ <span class="btn-text">{{ action.label }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 最近操作记录 -->
|
|
|
- <div>
|
|
|
- <div class="flex justify-between items-center mb-6">
|
|
|
- <h2 class="text-2xl font-bold text-gray-800">最近操作记录</h2>
|
|
|
- <button class="text-blue-500 hover:text-blue-700 font-medium" @click="viewAllRecords">
|
|
|
- 查看全部 <i class="fas fa-chevron-right ml-1 text-xs" />
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- <div class="bg-white rounded-xl shadow-sm overflow-hidden">
|
|
|
- <div class="simple-table">
|
|
|
- <div class="table-header">
|
|
|
- <div class="table-row">
|
|
|
- <div v-for="col in columns" :key="col.key" class="table-cell">
|
|
|
- {{ col.title }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="table-body">
|
|
|
- <div v-for="(record, index) in recentRecords" :key="index" class="table-row">
|
|
|
- <div class="table-cell">{{ record.time }}</div>
|
|
|
- <div class="table-cell">{{ record.operator }}</div>
|
|
|
- <div class="table-cell">
|
|
|
- <span class="px-3 py-1 rounded-full text-sm" :class="getOperationTypeClass(record.operationType)">
|
|
|
- {{ record.operationType }}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <div class="table-cell">{{ record.material }}</div>
|
|
|
- <div class="table-cell">{{ record.quantity }}</div>
|
|
|
- <div class="table-cell">
|
|
|
- <span class="text-green-500">
|
|
|
- <i class="fas fa-check-circle mr-1" />{{ record.status }}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 表格区域 -->
|
|
|
+ <div class="table-section">
|
|
|
+ <dv-scroll-board :config="config" style="width:1080px;height:780px" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 底部装饰 -->
|
|
|
+ <div class="divider-section">
|
|
|
+ <img :src="bottomImg" alt="" class="divider-img" />
|
|
|
+ </div>
|
|
|
+ <!-- 拣货确认弹窗 - 科技感风格 -->
|
|
|
+ <div v-if="pickingConfirmVisible" class="tech-modal-overlay" @click.self="pickingConfirmVisible = false">
|
|
|
+ <div class="tech-modal">
|
|
|
+ <div class="modal-content-row">
|
|
|
+ <div class="modal-text">
|
|
|
+ <h3>请确认您要进行的操作</h3>
|
|
|
+ <p>您是否已经申请了领料?</p>
|
|
|
+ </div>
|
|
|
+ <div class="modal-icon">
|
|
|
+ <div class="icon-box">
|
|
|
+ <i class="fas fa-clipboard-check" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </main>
|
|
|
-
|
|
|
- <!-- 底部圆形功能按钮 -->
|
|
|
- <footer class="fixed bottom-0 left-0 right-0 bg-white shadow-lg py-6 z-50">
|
|
|
- <div class="container mx-auto px-6">
|
|
|
- <div class="flex justify-center space-x-12">
|
|
|
- <template v-if="isOut">
|
|
|
- <button
|
|
|
- v-for="action in outButtons" :key="action.label" class="circle-button text-white"
|
|
|
- :class="getButtonClass(action.color)" @click="handleAction(action.action)"
|
|
|
- >
|
|
|
- <i :class="`fas ${action.icon}`" />
|
|
|
- <span>{{ action.label }}</span>
|
|
|
- </button>
|
|
|
- </template>
|
|
|
- <template v-if="!isOut">
|
|
|
- <button
|
|
|
- v-for="action in inButtons" :key="action.label" class="circle-button text-white"
|
|
|
- :class="getButtonClass(action.color)" @click="handleAction(action.action)"
|
|
|
- >
|
|
|
- <i :class="`fas ${action.icon}`" />
|
|
|
- <span>{{ action.label }}</span>
|
|
|
- </button>
|
|
|
- </template>
|
|
|
+ <div class="modal-footer">
|
|
|
+ <button class="modal-btn cancel-btn" @click="handlePickingNo">否</button>
|
|
|
+ <button class="modal-btn confirm-btn" @click="handlePickingYes">是</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </footer>
|
|
|
-
|
|
|
- <!-- 拣货确认弹窗 -->
|
|
|
- <van-dialog
|
|
|
- v-model:show="pickingModalVisible" title="请确认您要进行的操作" show-cancel-button class-name="large-dialog"
|
|
|
- confirm-button-text="是" cancel-button-text="否" @confirm="handlePickingConfirm" @cancel="handlePickingCancel"
|
|
|
- >
|
|
|
- <div class="large-dialog-content">
|
|
|
- <p>您是否已经申请了领料?</p>
|
|
|
- </div>
|
|
|
- </van-dialog>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <Loading v-if="loading" />
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, reactive, onMounted } from 'vue';
|
|
|
+import { ref, reactive, onMounted, onUnmounted } from 'vue';
|
|
|
import { useRouter } from 'vue-router';
|
|
|
-import PageHeader from '../common/PageHeader.vue';
|
|
|
-import { cfStockInLeave } from '../api/stockIn.js';
|
|
|
-import { Dialog as VanDialog, showNotify } from 'vant';
|
|
|
|
|
|
-// 路由
|
|
|
+// 图片资源 - 从 assets/images 目录加载
|
|
|
+import cardIcon1 from '../assets/images/card1.png';
|
|
|
+import cardIcon2 from '../assets/images/card2.png';
|
|
|
+import cardIcon3 from '../assets/images/card3.png';
|
|
|
+import airplaneImg from '../assets/images/airplane.png';
|
|
|
+import buttonBg from '../assets/images/buttonBg.png';
|
|
|
+import bgImg from '../assets/images/bj.png';
|
|
|
+import settingsIcon from '../assets/images/setting.png';
|
|
|
+import arrowUpIcon from '../assets/images/up.png';
|
|
|
+import arrowDownIcon from '../assets/images/down.png';
|
|
|
+import headerImg from '../assets/images/header.png';
|
|
|
+import bottomImg from '../assets/images/bottom.png';
|
|
|
+
|
|
|
const router = useRouter();
|
|
|
+const username = ref('admin');
|
|
|
|
|
|
+// 是否为外侧屏幕
|
|
|
+const isOut = ref(true);
|
|
|
|
|
|
-// 加载状态
|
|
|
-const loading = ref(false);
|
|
|
+// 设置下拉菜单状态
|
|
|
+const showSettings = ref(false);
|
|
|
|
|
|
-// 弹窗控制
|
|
|
-const pickingModalVisible = ref(false);
|
|
|
+// 拣货确认弹窗
|
|
|
+const pickingConfirmVisible = ref(false);
|
|
|
+const settingsDropdown = ref(null);
|
|
|
|
|
|
-// 是否为外侧屏幕
|
|
|
-const isOut = ref(false);
|
|
|
+const config = {
|
|
|
+ header: ['名称', '图号', '类型', '操作', '时间', '操作人员'],
|
|
|
+ data: [
|
|
|
+ ['我是一个测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '张三'],
|
|
|
+ ['我是一个测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '服务员'],
|
|
|
+ ['测试名称', '2025001C10', '芯角', '出库', '2025-11-26 11:15', '周世豪'],
|
|
|
+ ['测试名称', '2025001C10', '货物', '入库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '治物', '入库', '2025-11-26 11:15', '陈静雅'],
|
|
|
+ ['测试名称', '2025001C10', '货物', '入库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '芯角', '出库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '货物', '出库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '周世豪'],
|
|
|
+ ['测试名称', '2025001C10', '货物', '出库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ['测试名称', '2025001C10', '芯角', '出库', '2025-11-26 11:15', '周世豪'],
|
|
|
+ ['测试名称', '2025001C10', '货物', '出库', '2025-11-26 11:15', '管理员'],
|
|
|
+ ],
|
|
|
+ index: true,
|
|
|
+ columnWidth: [50, 200, 200, 120, 100, 200, 120],
|
|
|
+ align: ['center', 'center', 'center', 'center', 'center','center','center'],
|
|
|
+ rowNum: 14,
|
|
|
+ headerBGC:'#0c5897',
|
|
|
+ oddRowBGC:'#0c3367',
|
|
|
+ evenRowBGC:'#153d75',
|
|
|
+};
|
|
|
|
|
|
-// 初始化时从localStorage读取isOut值
|
|
|
+// 从 localStorage 获取用户名和isOut状态
|
|
|
onMounted(() => {
|
|
|
+ const storedUser = localStorage.getItem('username');
|
|
|
+ if (storedUser) {
|
|
|
+ username.value = storedUser;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取isOut状态
|
|
|
const storedIsOut = localStorage.getItem('isOut');
|
|
|
if (storedIsOut !== null) {
|
|
|
isOut.value = storedIsOut === 'true';
|
|
|
}
|
|
|
+
|
|
|
+ // 添加点击外部关闭下拉菜单的事件监听
|
|
|
+ document.addEventListener('click', handleClickOutside);
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ // 移除事件监听
|
|
|
+ document.removeEventListener('click', handleClickOutside);
|
|
|
});
|
|
|
|
|
|
// 统计数据
|
|
|
@@ -163,287 +203,119 @@ const statistics = reactive([
|
|
|
{
|
|
|
title: '总库存量',
|
|
|
value: '12,847',
|
|
|
- icon: 'fa-boxes',
|
|
|
- color: 'blue',
|
|
|
+ bg: cardIcon1,
|
|
|
trend: 1,
|
|
|
changeText: '较昨日 +2.3%',
|
|
|
},
|
|
|
{
|
|
|
title: '今日入库',
|
|
|
value: '1,248',
|
|
|
- icon: 'fa-truck-loading',
|
|
|
- color: 'green',
|
|
|
+ bg: cardIcon2,
|
|
|
trend: 1,
|
|
|
changeText: '较昨日 +5.7%',
|
|
|
},
|
|
|
{
|
|
|
title: '今日出库',
|
|
|
value: '36',
|
|
|
- icon: 'fa-tasks',
|
|
|
- color: 'yellow',
|
|
|
+ bg: cardIcon3,
|
|
|
trend: -1,
|
|
|
- changeText: '较昨日 -1.2%',
|
|
|
- },
|
|
|
- {
|
|
|
- title: '库存周转率',
|
|
|
- value: '4.2',
|
|
|
- icon: 'fa-sync-alt',
|
|
|
- color: 'purple',
|
|
|
- trend: 1,
|
|
|
- changeText: '较上月 +0.8%',
|
|
|
+ changeText: '较昨日 +2.3%',
|
|
|
},
|
|
|
]);
|
|
|
|
|
|
-// 物料分类
|
|
|
-const materialCategories = reactive([
|
|
|
- {
|
|
|
- name: '电子元件',
|
|
|
- count: 248,
|
|
|
- image: 'https://ai-public.mastergo.com/ai/img_res/b752a3a8cb35d2b915a23b12981693d8.jpg',
|
|
|
- },
|
|
|
- {
|
|
|
- name: '机械零件',
|
|
|
- count: 186,
|
|
|
- image: 'https://ai-public.mastergo.com/ai/img_res/1d4cf39dc61dadac88754be3bd525e3c.jpg',
|
|
|
- },
|
|
|
- {
|
|
|
- name: '化工原料',
|
|
|
- count: 92,
|
|
|
- image: 'https://ai-public.mastergo.com/ai/img_res/4f12a387c9413be821c1d203bda09622.jpg',
|
|
|
- },
|
|
|
- {
|
|
|
- name: '包装材料',
|
|
|
- count: 64,
|
|
|
- image: 'https://ai-public.mastergo.com/ai/img_res/c2d2f76aebbef43067223fd11e120c49.jpg',
|
|
|
- },
|
|
|
- {
|
|
|
- name: '办公用品',
|
|
|
- count: 127,
|
|
|
- image: 'https://ai-public.mastergo.com/ai/img_res/404ab042346c15d0722e9d2eae6bda99.jpg',
|
|
|
- },
|
|
|
- {
|
|
|
- name: '维修工具',
|
|
|
- count: 89,
|
|
|
- image: 'https://ai-public.mastergo.com/ai/img_res/048d0b638d5cb1f1bd11916983979fed.jpg',
|
|
|
- },
|
|
|
+// 外侧屏幕操作按钮
|
|
|
+const outButtons = reactive([
|
|
|
+ { label: '领料', action: 'materialOut' },
|
|
|
+ { label: '拣货', action: 'materialReturn' },
|
|
|
+ { label: '还料', action: 'materialIn' },
|
|
|
+ { label: 'AGV RFID\n校验', action: 'agvRfidRecognition' },
|
|
|
+ { label: '成品\n入库', action: 'finishedProductIn' },
|
|
|
]);
|
|
|
|
|
|
-// 表格列定义
|
|
|
-const columns = [
|
|
|
- {
|
|
|
- title: '时间',
|
|
|
- dataIndex: 'time',
|
|
|
- key: 'time',
|
|
|
- width: 150,
|
|
|
- },
|
|
|
- {
|
|
|
- title: '操作类型',
|
|
|
- dataIndex: 'operationType',
|
|
|
- key: 'operationType',
|
|
|
- width: 120,
|
|
|
- },
|
|
|
- {
|
|
|
- title: '物料名称',
|
|
|
- dataIndex: 'materialName',
|
|
|
- key: 'materialName',
|
|
|
- width: 200,
|
|
|
- },
|
|
|
- {
|
|
|
- title: '数量',
|
|
|
- dataIndex: 'quantity',
|
|
|
- key: 'quantity',
|
|
|
- width: 100,
|
|
|
- },
|
|
|
- {
|
|
|
- title: '操作员',
|
|
|
- dataIndex: 'operator',
|
|
|
- key: 'operator',
|
|
|
- width: 100,
|
|
|
- },
|
|
|
- {
|
|
|
- title: '状态',
|
|
|
- dataIndex: 'status',
|
|
|
- key: 'status',
|
|
|
- width: 120,
|
|
|
- },
|
|
|
-];
|
|
|
-
|
|
|
-// 最近操作记录
|
|
|
-const recentRecords = reactive([
|
|
|
- {
|
|
|
- key: '1',
|
|
|
- time: '2023-12-15 14:32',
|
|
|
- operationType: '入库',
|
|
|
- materialName: '集成电路芯片 IC-2023',
|
|
|
- quantity: '+500',
|
|
|
- operator: '张伟',
|
|
|
- status: '已完成',
|
|
|
- },
|
|
|
- {
|
|
|
- key: '2',
|
|
|
- time: '2023-12-15 13:45',
|
|
|
- operationType: '领料',
|
|
|
- materialName: '电阻 R-1KΩ 1/4W',
|
|
|
- quantity: '-200',
|
|
|
- operator: '李娜',
|
|
|
- status: '已完成',
|
|
|
- },
|
|
|
- {
|
|
|
- key: '3',
|
|
|
- time: '2023-12-15 11:20',
|
|
|
- operationType: '还料',
|
|
|
- materialName: '电容 C-100μF 50V',
|
|
|
- quantity: '+50',
|
|
|
- operator: '王强',
|
|
|
- status: '已完成',
|
|
|
- },
|
|
|
- {
|
|
|
- key: '4',
|
|
|
- time: '2023-12-15 09:15',
|
|
|
- operationType: '出库',
|
|
|
- materialName: '连接器 CONN-USB-C',
|
|
|
- quantity: '-150',
|
|
|
- operator: '赵敏',
|
|
|
- status: '已完成',
|
|
|
- },
|
|
|
- {
|
|
|
- key: '5',
|
|
|
- time: '2023-12-14 16:40',
|
|
|
- operationType: '入库',
|
|
|
- materialName: '传感器 SHT-30',
|
|
|
- quantity: '+300',
|
|
|
- operator: '孙磊',
|
|
|
- status: '已完成',
|
|
|
- },
|
|
|
+// 内侧屏幕操作按钮
|
|
|
+const inButtons = reactive([
|
|
|
+ { label: '出库\n确认', action: 'materialOutLeave' },
|
|
|
+ { label: '还料\n离开', action: 'materialInLeave' },
|
|
|
+ { label: '成品\n出库', action: 'finishedProductOut' },
|
|
|
+ { label: '料箱\n上架', action: 'feedingArea' },
|
|
|
+ { label: '还料区\n管理', action: 'returnManagement' },
|
|
|
+ // { label: '取料区\n管理', action: 'deliverManagement' },
|
|
|
]);
|
|
|
|
|
|
-// 底部操作按钮
|
|
|
-const outButtons = reactive([
|
|
|
- {
|
|
|
- label: '领料',
|
|
|
- icon: 'fa-hand-holding',
|
|
|
- color: 'blue',
|
|
|
- action: 'materialOut',
|
|
|
- },
|
|
|
- {
|
|
|
- label: '拣货',
|
|
|
- icon: 'fa-undo',
|
|
|
- color: 'green',
|
|
|
- action: 'materialReturn',
|
|
|
- },
|
|
|
- {
|
|
|
- label: '还料',
|
|
|
- icon: 'fa-arrow-up',
|
|
|
- color: 'yellow',
|
|
|
- action: 'materialIn',
|
|
|
- },
|
|
|
- {
|
|
|
- label: 'AGV RFID校验',
|
|
|
- icon: 'fa-wifi',
|
|
|
- color: 'red',
|
|
|
- action: 'agvRfidRecognition',
|
|
|
- },
|
|
|
- {
|
|
|
- label: '成品入库',
|
|
|
- icon: 'fa-boxes',
|
|
|
- color: 'blue',
|
|
|
- action: 'finishedProductIn',
|
|
|
- },
|
|
|
|
|
|
- // 测试待删除
|
|
|
- // {
|
|
|
- // label: '还料区管理',
|
|
|
- // icon: 'fa-undo',
|
|
|
- // color: 'green',
|
|
|
- // action: 'returnManagement',
|
|
|
- // },
|
|
|
- // {
|
|
|
- // label: '取料区管理',
|
|
|
- // icon: 'fa-arrow-down',
|
|
|
- // color: 'red',
|
|
|
- // action: 'deliverManagement',
|
|
|
- // },
|
|
|
-]);
|
|
|
-const inButtons = reactive([
|
|
|
- {
|
|
|
- label: '出库确认',
|
|
|
- icon: 'fa-undo',
|
|
|
- color: 'blue',
|
|
|
- action: 'materialOutLeave',
|
|
|
- },
|
|
|
- {
|
|
|
- label: '还料离开',
|
|
|
- icon: 'fa-arrow-down',
|
|
|
- color: 'green',
|
|
|
- action: 'materialInLeave',
|
|
|
- },
|
|
|
- {
|
|
|
- label: '成品出库',
|
|
|
- icon: 'fa-boxes',
|
|
|
- color: 'red',
|
|
|
- action: 'finishedProductOut',
|
|
|
- },
|
|
|
-]);
|
|
|
+// 切换设置下拉菜单
|
|
|
+const toggleSettings = event => {
|
|
|
+ event.stopPropagation();
|
|
|
+ showSettings.value = !showSettings.value;
|
|
|
+};
|
|
|
|
|
|
-// 查看全部记录逻辑
|
|
|
-const viewAllRecords = () => {
|
|
|
- console.log('查看全部');
|
|
|
+// 点击外部关闭下拉菜单
|
|
|
+const handleClickOutside = event => {
|
|
|
+ if (settingsDropdown.value && !settingsDropdown.value.contains(event.target)) {
|
|
|
+ showSettings.value = false;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-// 拣货确认弹窗处理
|
|
|
-const handlePickingConfirm = () => {
|
|
|
- pickingModalVisible.value = false;
|
|
|
- router.push('/order-picking');
|
|
|
+// 跳转到指纹录入页面
|
|
|
+const goToFingerprintEnroll = () => {
|
|
|
+ showSettings.value = false;
|
|
|
+ router.push('/fingerprint-enroll');
|
|
|
};
|
|
|
|
|
|
-// 去领料
|
|
|
-const handlePickingCancel = () => {
|
|
|
- pickingModalVisible.value = false;
|
|
|
- router.push('/stock-requisition');
|
|
|
+// 切换菜单
|
|
|
+const toggleMenu = () => {
|
|
|
+ isOut.value = !isOut.value;
|
|
|
+ localStorage.setItem('isOut', isOut.value);
|
|
|
+};
|
|
|
+
|
|
|
+// 处理退出
|
|
|
+const handleLogout = () => {
|
|
|
+ localStorage.removeItem('#LoginInfo');
|
|
|
+ localStorage.removeItem('#token');
|
|
|
+ localStorage.removeItem('#accountId');
|
|
|
+
|
|
|
+ // 检查localStorage中的isOut值,如果为true则在登录页面添加isOut参数
|
|
|
+ const isOutValue = localStorage.getItem('isOut') === 'true';
|
|
|
+ if (isOutValue) {
|
|
|
+ router.push({ path: '/fingerprint-login', query: { isOut: 'true' } });
|
|
|
+ } else {
|
|
|
+ router.push('/fingerprint-login');
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-// 根据不同的action执行不同的逻辑
|
|
|
+// 处理按钮操作
|
|
|
const handleAction = action => {
|
|
|
console.log('Action clicked:', action);
|
|
|
switch (action) {
|
|
|
+ // 外侧屏幕操作
|
|
|
case 'materialOut':
|
|
|
- // 领料 - 跳转到领料界面
|
|
|
router.push('/stock-requisition');
|
|
|
break;
|
|
|
case 'materialReturn':
|
|
|
- // 拣货 - 显示确认弹窗
|
|
|
- pickingModalVisible.value = true;
|
|
|
- break;
|
|
|
- case 'materialOutLeave':
|
|
|
- // 领料出库离开
|
|
|
- router.push('/outbound-confirm');
|
|
|
+ pickingConfirmVisible.value = true;
|
|
|
break;
|
|
|
- case 'materialReturnLeave':
|
|
|
- // 还料出库离开
|
|
|
+ case 'materialIn':
|
|
|
+ router.push('/in-confirm');
|
|
|
break;
|
|
|
case 'agvRfidRecognition':
|
|
|
- // RFID识别
|
|
|
router.push('/agv-rfid-recognition');
|
|
|
break;
|
|
|
- case 'materialIn':
|
|
|
- // 还料 - 跳转到还料界面
|
|
|
- router.push('/in-confirm');
|
|
|
+ case 'finishedProductIn':
|
|
|
+ router.push('/finish-product-in');
|
|
|
+ break;
|
|
|
+ // 内侧屏幕操作
|
|
|
+ case 'materialOutLeave':
|
|
|
+ router.push('/outbound-confirm');
|
|
|
break;
|
|
|
case 'materialInLeave':
|
|
|
- // 还料出库离开
|
|
|
- // validateMaterialInLeave();
|
|
|
router.push('/returned-leave');
|
|
|
break;
|
|
|
- case 'finishedProductIn':
|
|
|
- // 成品入库
|
|
|
- router.push('/finish-product-in');
|
|
|
- break;
|
|
|
case 'finishedProductOut':
|
|
|
- // 成品出库
|
|
|
router.push('/finish-product-out');
|
|
|
break;
|
|
|
-
|
|
|
- // 测试待删除
|
|
|
+ case 'feedingArea':
|
|
|
+ router.push('/feeding-area');
|
|
|
+ break;
|
|
|
case 'returnManagement':
|
|
|
router.push('/return-management');
|
|
|
break;
|
|
|
@@ -451,235 +323,933 @@ const handleAction = action => {
|
|
|
router.push('/delivery-management');
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-// 校验还料离开时是否带有工装设备信息
|
|
|
-const validateMaterialInLeave = async () => {
|
|
|
- loading.value = true;
|
|
|
- try {
|
|
|
- const res = await cfStockInLeave();
|
|
|
- if (res.errorCode === 0) {
|
|
|
- if (res.datas && res.datas.length > 0) {
|
|
|
- router.push('/in-confirm?isLeave=true');
|
|
|
- } else {
|
|
|
- showNotify({ type: 'success', message: '您已完成还料操作,请在闸机开门后离开' });
|
|
|
- }
|
|
|
- } else {
|
|
|
- showNotify({ type: 'danger', message: res.errorMessage });
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('校验还料离开时是否带有工装设备信息失败:', error);
|
|
|
- showNotify({ type: 'danger', message: '校验还料离开时是否带有工装设备信息失败' });
|
|
|
- } finally {
|
|
|
- loading.value = false;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 渲染样式
|
|
|
-const getOperationTypeClass = type => {
|
|
|
- const classMap = {
|
|
|
- '入库': 'bg-green-100 text-green-800',
|
|
|
- '领料': 'bg-blue-100 text-blue-800',
|
|
|
- '还料': 'bg-yellow-100 text-yellow-800',
|
|
|
- '出库': 'bg-red-100 text-red-800',
|
|
|
- };
|
|
|
- return classMap[type] || 'bg-gray-100 text-gray-800';
|
|
|
};
|
|
|
|
|
|
-// 按钮样式
|
|
|
-const getButtonClass = color => {
|
|
|
- const colorMap = {
|
|
|
- blue: 'bg-blue-500 hover:bg-blue-600',
|
|
|
- green: 'bg-green-500 hover:bg-green-600',
|
|
|
- yellow: 'bg-yellow-500 hover:bg-yellow-600',
|
|
|
- red: 'bg-red-500 hover:bg-red-600',
|
|
|
- };
|
|
|
- return colorMap[color] || 'bg-gray-500 hover:bg-gray-600';
|
|
|
+// 拣货确认弹窗 - 点击"否"跳转到领料页
|
|
|
+const handlePickingNo = () => {
|
|
|
+ pickingConfirmVisible.value = false;
|
|
|
+ router.push('/stock-requisition');
|
|
|
};
|
|
|
|
|
|
-// 统计样式
|
|
|
-const getStatColorClasses = (color, type) => {
|
|
|
- const colorMap = {
|
|
|
- blue: {
|
|
|
- border: 'border-blue-500',
|
|
|
- bg: 'bg-blue-100',
|
|
|
- text: 'text-blue-500',
|
|
|
- },
|
|
|
- green: {
|
|
|
- border: 'border-green-500',
|
|
|
- bg: 'bg-green-100',
|
|
|
- text: 'text-green-500',
|
|
|
- },
|
|
|
- yellow: {
|
|
|
- border: 'border-yellow-500',
|
|
|
- bg: 'bg-yellow-100',
|
|
|
- text: 'text-yellow-500',
|
|
|
- },
|
|
|
- purple: {
|
|
|
- border: 'border-purple-500',
|
|
|
- bg: 'bg-purple-100',
|
|
|
- text: 'text-purple-500',
|
|
|
- },
|
|
|
- };
|
|
|
- return colorMap[color]?.[type] || '';
|
|
|
+// 拣货确认弹窗 - 点击"是"跳转到拣货页
|
|
|
+const handlePickingYes = () => {
|
|
|
+ pickingConfirmVisible.value = false;
|
|
|
+ router.push('/order-picking');
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-/* 大弹窗样式,适合触摸屏 */
|
|
|
-:deep(.large-dialog) {
|
|
|
- width: 85vw !important;
|
|
|
- max-width: 600px !important;
|
|
|
- border-radius: 16px !important;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.large-dialog .van-dialog__header) {
|
|
|
- padding-top: 2rem !important;
|
|
|
- padding-bottom: 1rem !important;
|
|
|
- padding-left: 1.5rem !important;
|
|
|
- padding-right: 1.5rem !important;
|
|
|
- font-size: 1.5rem !important;
|
|
|
- font-weight: 700 !important;
|
|
|
- color: #111827 !important;
|
|
|
-}
|
|
|
-
|
|
|
-.large-dialog-content {
|
|
|
- padding-top: 1.5rem !important;
|
|
|
- padding-bottom: 2.5rem !important;
|
|
|
- padding-left: 2rem !important;
|
|
|
- padding-right: 2rem !important;
|
|
|
-}
|
|
|
-
|
|
|
-.large-dialog-content p {
|
|
|
- margin-top: 0;
|
|
|
- margin-bottom: 1rem;
|
|
|
- margin-left: 0;
|
|
|
- margin-right: 0;
|
|
|
- font-size: 1.25rem !important;
|
|
|
- line-height: 1.8 !important;
|
|
|
- font-weight: 600;
|
|
|
- color: #111827;
|
|
|
- text-align: center;
|
|
|
+/* 基础样式 - 1080x1920 竖屏优化,支持横屏滚动 */
|
|
|
+.home-page {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 100vh;
|
|
|
+ position: relative;
|
|
|
+ font-family: 'Microsoft YaHei', sans-serif;
|
|
|
+ color: #fff;
|
|
|
+ overflow-x: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+/* 自定义滚动条样式 - WebKit */
|
|
|
+.home-page::-webkit-scrollbar {
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.home-page::-webkit-scrollbar-track {
|
|
|
+ background: rgba(4, 28, 61, 0.9);
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.home-page::-webkit-scrollbar-thumb {
|
|
|
+ background: linear-gradient(180deg, #1e90ff 0%, #00bfff 100%);
|
|
|
+ border-radius: 5px;
|
|
|
+ border: 2px solid rgba(4, 28, 61, 0.9);
|
|
|
+}
|
|
|
+
|
|
|
+.home-page::-webkit-scrollbar-thumb:hover {
|
|
|
+ background: linear-gradient(180deg, #00bfff 0%, #1e90ff 100%);
|
|
|
+}
|
|
|
+
|
|
|
+/* 自定义滚动条样式 - Firefox */
|
|
|
+.home-page {
|
|
|
+ scrollbar-width: thin;
|
|
|
+ scrollbar-color: #1e90ff rgba(4, 28, 61, 0.9);
|
|
|
+}
|
|
|
+
|
|
|
+/* 背景层 */
|
|
|
+.bg-layer {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #041c3d;
|
|
|
+ background-size: cover;
|
|
|
+ background-position: center;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ z-index: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 飞机图片 - 背景层,位于内容下方 */
|
|
|
+.airplane-layer {
|
|
|
+ position: fixed;
|
|
|
+ top: 100px;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 55%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ z-index: 1;
|
|
|
+ pointer-events: none;
|
|
|
+}
|
|
|
+
|
|
|
+.airplane-img {
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 100%;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 顶部标题区域 - 全宽无边距 ========== */
|
|
|
+.header-section {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ flex-shrink: 0;
|
|
|
+ z-index: 10;
|
|
|
}
|
|
|
|
|
|
-.large-dialog-content p:last-child {
|
|
|
- margin-bottom: 0;
|
|
|
+.header-bg {
|
|
|
+ width: 100%;
|
|
|
+ height: 100px;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.title {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ font-size: 32px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #ffffff;
|
|
|
+ letter-spacing: 6px;
|
|
|
+ margin: 0;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.user-badge {
|
|
|
+ position: absolute;
|
|
|
+ top: 62px;
|
|
|
+ left: 22px;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
|
|
|
+ border: 1px solid #2a7fff;
|
|
|
+ border-radius: 20px;
|
|
|
+ padding: 6px 15px;
|
|
|
}
|
|
|
|
|
|
-.large-dialog-content .dialog-subtitle {
|
|
|
- font-size: 1.125rem !important;
|
|
|
- color: #6b7280 !important;
|
|
|
+.user-icon {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #00bfff;
|
|
|
+}
|
|
|
+
|
|
|
+.username {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #fff;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.header-actions {
|
|
|
+ position: absolute;
|
|
|
+ top: 62px;
|
|
|
+ right: 22px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__footer) {
|
|
|
- padding-top: 1rem !important;
|
|
|
- padding-bottom: 1.5rem !important;
|
|
|
- padding-left: 1.5rem !important;
|
|
|
- padding-right: 1.5rem !important;
|
|
|
+.icon-btn {
|
|
|
+ width: 36px;
|
|
|
+ height: 36px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.icon-btn:hover {
|
|
|
+ transform: scale(1.1);
|
|
|
+}
|
|
|
+
|
|
|
+.settings-icon {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ object-fit: contain;
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__footer > *) {
|
|
|
- margin-right: 1rem;
|
|
|
+/* 设置下拉菜单样式 */
|
|
|
+.settings-dropdown {
|
|
|
+ position: relative;
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__footer > *:last-child) {
|
|
|
- margin-right: 0;
|
|
|
+.dropdown-menu {
|
|
|
+ position: absolute;
|
|
|
+ top: calc(100% + 0.5rem);
|
|
|
+ right: 0;
|
|
|
+ background: linear-gradient(135deg, rgba(13, 58, 106, 0.95) 0%, rgba(9, 45, 82, 0.95) 100%);
|
|
|
+ border: 1px solid #2a7fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ min-width: 160px;
|
|
|
+ z-index: 1000000;
|
|
|
+ overflow: hidden;
|
|
|
+ animation: dropdownFadeIn 0.2s ease;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__cancel),
|
|
|
-:deep(.large-dialog .van-dialog__confirm) {
|
|
|
+@keyframes dropdownFadeIn {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-10px);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-item {
|
|
|
+ padding: 12px 16px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-item:hover {
|
|
|
+ background: rgba(30, 144, 255, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-item i {
|
|
|
+ color: #00bfff;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.exit-btn {
|
|
|
+ padding: 6px 18px;
|
|
|
+ border-radius: 20px;
|
|
|
+ background: linear-gradient(90deg, #1e90ff 0%, #00bfff 100%);
|
|
|
+ border: none;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.exit-btn:hover {
|
|
|
+ box-shadow: 0 0 15px rgba(30, 144, 255, 0.6);
|
|
|
+}
|
|
|
+
|
|
|
+/* 页面容器 - 内容区域 */
|
|
|
+.page-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 1080px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 0 20px 0 30px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ position: relative;
|
|
|
+ z-index: 9;
|
|
|
+ margin-top: 66px;
|
|
|
+ gap: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 统计卡片区域 ========== */
|
|
|
+.stats-section {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card {
|
|
|
flex: 1;
|
|
|
- height: 56px !important;
|
|
|
- font-size: 1.125rem !important;
|
|
|
- font-weight: 600 !important;
|
|
|
- border-radius: 8px !important;
|
|
|
- border: none !important;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center;
|
|
|
+ height: 120px;
|
|
|
+ padding: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-info {
|
|
|
+ margin-left: clamp(80px, 15vw, 166px);
|
|
|
+}
|
|
|
+
|
|
|
+.stat-label {
|
|
|
+ font-family: 'Alibaba PuHuiTi 2.0', 'Microsoft YaHei', sans-serif;
|
|
|
+ font-weight: normal;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #FFFFFF;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-value {
|
|
|
+ font-family: Arial, sans-serif;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 28px;
|
|
|
+ color: #FFFFFF;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-trend {
|
|
|
+ font-size: 12px;
|
|
|
+ margin-top: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-label,
|
|
|
+.stat-value,
|
|
|
+.stat-trend {
|
|
|
+ margin-top: 0px;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-trend.up {
|
|
|
+ color: #00ff88;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-trend.down {
|
|
|
+ color: #ff6b6b;
|
|
|
+}
|
|
|
+
|
|
|
+.trend-icon {
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ margin-right: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 操作按钮区域 ========== */
|
|
|
+.buttons-section {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 15px;
|
|
|
+ background: rgba(9, 61, 140, 0.5);
|
|
|
+ border-radius: 12px;
|
|
|
+ border: 1px solid #049FD8;
|
|
|
+ padding: 15px 20px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-top: 516px;
|
|
|
+}
|
|
|
+
|
|
|
+.action-btn {
|
|
|
+ width: clamp(100px, 12vw, 160px);
|
|
|
+ height: clamp(100px, 12vw, 160px);
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s;
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__cancel) {
|
|
|
- background-color: #f3f4f6 !important;
|
|
|
- color: #374151 !important;
|
|
|
+.action-btn:hover {
|
|
|
+ transform: scale(1.05);
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__cancel:active) {
|
|
|
- background-color: #e5e7eb !important;
|
|
|
+.btn-bg {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: contain;
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__confirm) {
|
|
|
- background-color: #10b981 !important;
|
|
|
- color: white !important;
|
|
|
+.btn-text {
|
|
|
+ font-size: clamp(14px, 2vw, 24px);
|
|
|
+ font-weight: bold;
|
|
|
+ color: #ffffff;
|
|
|
+ text-align: center;
|
|
|
+ white-space: pre-line;
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ line-height: 1.3;
|
|
|
}
|
|
|
|
|
|
-:deep(.large-dialog .van-dialog__confirm:active) {
|
|
|
- background-color: #059669 !important;
|
|
|
+/* ========== 分隔装饰 ========== */
|
|
|
+.divider-section {
|
|
|
+ width: 100%;
|
|
|
+ flex-shrink: 0;
|
|
|
+ position: relative;
|
|
|
+ z-index: 10;
|
|
|
+ margin-top: auto;
|
|
|
}
|
|
|
|
|
|
-/* 简单表格样式 */
|
|
|
-.simple-table {
|
|
|
+.divider-img {
|
|
|
width: 100%;
|
|
|
- overflow-x: auto;
|
|
|
+ height: auto;
|
|
|
+ display: block;
|
|
|
+ max-height: 80px;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 表格区域 ========== */
|
|
|
+.table-section {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background: rgba(5, 20, 50, 0.6);
|
|
|
+ border: 1px solid rgba(30, 144, 255, 0.2);
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.table-header {
|
|
|
- background-color: #f9fafb;
|
|
|
- border-bottom: 2px solid #e5e7eb;
|
|
|
+ display: flex;
|
|
|
+ background: rgba(30, 144, 255, 0.15);
|
|
|
+ border-bottom: 1px solid rgba(30, 144, 255, 0.3);
|
|
|
+ padding: 12px 10px;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
-.table-header .table-row {
|
|
|
+.table-header .table-col {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #7ec8ff;
|
|
|
font-weight: 600;
|
|
|
- color: #374151;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.table-body {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.table-body::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.table-body::-webkit-scrollbar-track {
|
|
|
+ background: rgba(30, 144, 255, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.table-body::-webkit-scrollbar-thumb {
|
|
|
+ background: rgba(30, 144, 255, 0.3);
|
|
|
+ border-radius: 3px;
|
|
|
}
|
|
|
|
|
|
.table-row {
|
|
|
display: flex;
|
|
|
- min-width: 800px;
|
|
|
+ padding: 10px;
|
|
|
+ border-bottom: 1px solid rgba(30, 144, 255, 0.1);
|
|
|
+ transition: background 0.2s;
|
|
|
}
|
|
|
|
|
|
-.table-header .table-row {
|
|
|
- padding: 1rem;
|
|
|
+.table-row:nth-child(odd) {
|
|
|
+ background: rgba(0, 44, 81, 0.2);
|
|
|
}
|
|
|
|
|
|
-.table-body .table-row {
|
|
|
- padding: 1rem;
|
|
|
- border-bottom: 1px solid #e5e7eb;
|
|
|
- transition: background-color 0.2s;
|
|
|
+.table-row:hover {
|
|
|
+ background: rgba(30, 144, 255, 0.15);
|
|
|
+}
|
|
|
+
|
|
|
+.table-col {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #a0d2ff;
|
|
|
+ text-align: center;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
-.table-body .table-row:hover {
|
|
|
- background-color: #f9fafb;
|
|
|
+.table-col:nth-child(1) {
|
|
|
+ flex: 0.5;
|
|
|
}
|
|
|
|
|
|
-.table-cell {
|
|
|
+.table-col:nth-child(2) {
|
|
|
+ flex: 1.8;
|
|
|
+}
|
|
|
+
|
|
|
+.cell-out {
|
|
|
+ color: #ff9500 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.cell-in {
|
|
|
+ color: #00ff88 !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 响应式 - 小屏幕手机 ========== */
|
|
|
+@media screen and (max-width: 480px) {
|
|
|
+ .page-container {
|
|
|
+ max-width: 100%;
|
|
|
+ padding: 0 10px 20px;
|
|
|
+ margin-top: 40px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 18px;
|
|
|
+ letter-spacing: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .user-badge {
|
|
|
+ padding: 4px 8px;
|
|
|
+ top: 40px;
|
|
|
+ left: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .username {
|
|
|
+ font-size: 11px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-actions {
|
|
|
+ top: 40px;
|
|
|
+ right: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .exit-btn {
|
|
|
+ padding: 4px 10px;
|
|
|
+ font-size: 11px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stats-section {
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-card {
|
|
|
+ height: 70px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-info {
|
|
|
+ margin-left: 80px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-label {
|
|
|
+ font-size: 11px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .buttons-section {
|
|
|
+ margin-top: 280px;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ width: 56px;
|
|
|
+ height: 56px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-text {
|
|
|
+ font-size: 9px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-col {
|
|
|
+ font-size: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-header .table-col {
|
|
|
+ font-size: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .airplane-layer {
|
|
|
+ height: 35%;
|
|
|
+ top: 120px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 响应式 - 中等屏幕 ========== */
|
|
|
+@media screen and (min-width: 481px) and (max-width: 768px) {
|
|
|
+ .page-container {
|
|
|
+ max-width: 100%;
|
|
|
+ padding: 0 15px 0 20px;
|
|
|
+ margin-top: 50px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-card {
|
|
|
+ height: 90px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-info {
|
|
|
+ margin-left: 100px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 22px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .buttons-section {
|
|
|
+ margin-top: 350px;
|
|
|
+ gap: 12px;
|
|
|
+ padding: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ width: 80px;
|
|
|
+ height: 80px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-text {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .airplane-layer {
|
|
|
+ height: 40%;
|
|
|
+ top: 100px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 响应式 - 横屏模式 (如1920x1080) - 保持与1080x1920竖屏一致的布局 ========== */
|
|
|
+@media screen and (orientation: landscape) {
|
|
|
+ .home-page {
|
|
|
+ min-height: 100vh;
|
|
|
+ height: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-section {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-bg {
|
|
|
+ max-width: 1080px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ left: 50%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .user-badge {
|
|
|
+ left: calc(50% - 540px + 22px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-actions {
|
|
|
+ right: calc(50% - 540px + 22px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-container {
|
|
|
+ max-width: 1080px;
|
|
|
+ padding: 0 15px 0 30px;
|
|
|
+ margin: 0 auto;
|
|
|
+ margin-top: 66px;
|
|
|
+ gap: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .airplane-layer {
|
|
|
+ position: absolute;
|
|
|
+ width: 1080px;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ height: 680px;
|
|
|
+ top: 216px;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stats-section {
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-card {
|
|
|
+ height: 120px;
|
|
|
+ padding: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-info {
|
|
|
+ margin-left: 166px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 28px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-label {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-trend {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .buttons-section {
|
|
|
+ margin-top: 516px;
|
|
|
+ gap: 42px;
|
|
|
+ padding: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ width: 160px;
|
|
|
+ height: 160px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-text {
|
|
|
+ font-size: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-row {
|
|
|
+ padding: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-col {
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-header .table-col {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .divider-section {
|
|
|
+ max-width: 1080px;
|
|
|
+ margin: 20px auto 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 响应式 - 大屏竖屏 (1080x1920) ========== */
|
|
|
+@media screen and (orientation: portrait) and (min-width: 900px) {
|
|
|
+ .page-container {
|
|
|
+ max-width: 1080px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 42px;
|
|
|
+ letter-spacing: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .user-badge {
|
|
|
+ padding: 12px 20px;
|
|
|
+ top: 62px;
|
|
|
+ left: 22px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .username {
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .user-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header-actions {
|
|
|
+ top: 62px;
|
|
|
+ right: 22px;
|
|
|
+ gap: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .exit-btn {
|
|
|
+ padding: 10px 25px;
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .settings-icon {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-card {
|
|
|
+ height: 140px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-info {
|
|
|
+ margin-left: 150px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 36px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-label {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-trend {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .airplane-layer {
|
|
|
+ height: 50%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .buttons-section {
|
|
|
+ gap: 42px;
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ width: 160px;
|
|
|
+ height: 160px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-text {
|
|
|
+ font-size: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-header .table-col {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-col {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-row {
|
|
|
+ padding: 12px 10px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.dv-scroll-board .header) {
|
|
|
+ font-size: 22px !important;
|
|
|
+ color: #52dff5 !important;
|
|
|
+ background: linear-gradient(90deg, rgba(4,253,255,0) 0%, rgba(10,115,241,0.5) 50%, rgba(4,244,246,0) 100%)!important
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.dv-scroll-board .rows .row-item) {
|
|
|
+ font-size: 17px !important;
|
|
|
+ color:#ffffff !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* ========== 科技感弹窗样式 ========== */
|
|
|
+.tech-modal-overlay {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: rgba(4, 28, 61, 0.85);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ z-index: 1000;
|
|
|
+ animation: fadeIn 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes fadeIn {
|
|
|
+ from { opacity: 0; }
|
|
|
+ to { opacity: 1; }
|
|
|
+}
|
|
|
+
|
|
|
+.tech-modal {
|
|
|
+ background: linear-gradient(135deg, rgba(9, 45, 82, 0.98) 0%, rgba(5, 30, 60, 0.98) 100%);
|
|
|
+ border: 1px solid #2a7fff;
|
|
|
+ border-radius: 16px;
|
|
|
+ padding: 30px;
|
|
|
+ min-width: 450px;
|
|
|
+ max-width: 90%;
|
|
|
+ box-shadow: 0 0 40px rgba(30, 144, 255, 0.3), 0 20px 60px rgba(0, 0, 0, 0.5);
|
|
|
+ animation: slideIn 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes slideIn {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-20px);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.modal-content-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 30px;
|
|
|
+ margin-bottom: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-text {
|
|
|
flex: 1;
|
|
|
- padding: 0 0.5rem;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-text h3 {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #fff;
|
|
|
+ margin: 0 0 15px 0;
|
|
|
+ text-shadow: 0 0 10px rgba(0, 191, 255, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.modal-text p {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #7ec8ff;
|
|
|
+ margin: 0;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-icon {
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.icon-box {
|
|
|
+ width: 80px;
|
|
|
+ height: 80px;
|
|
|
+ background: linear-gradient(135deg, #1e90ff 0%, #00bfff 100%);
|
|
|
+ border-radius: 50%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-shadow: 0 0 30px rgba(30, 144, 255, 0.4);
|
|
|
}
|
|
|
|
|
|
-.table-cell:first-child {
|
|
|
- min-width: 150px;
|
|
|
+.icon-box i {
|
|
|
+ font-size: 36px;
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
|
|
|
-.table-cell:nth-child(2) {
|
|
|
- min-width: 100px;
|
|
|
+.modal-footer {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-btn {
|
|
|
+ flex: 1;
|
|
|
+ padding: 16px 0;
|
|
|
+ border-radius: 10px;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s;
|
|
|
+ border: none;
|
|
|
}
|
|
|
|
|
|
-.table-cell:nth-child(3) {
|
|
|
- min-width: 120px;
|
|
|
+.cancel-btn {
|
|
|
+ background: rgba(13, 58, 106, 0.8);
|
|
|
+ border: 1px solid #2a7fff;
|
|
|
+ color: #7ec8ff;
|
|
|
}
|
|
|
|
|
|
-.table-cell:nth-child(4) {
|
|
|
- min-width: 200px;
|
|
|
+.cancel-btn:hover {
|
|
|
+ background: rgba(26, 74, 122, 0.9);
|
|
|
+ box-shadow: 0 0 15px rgba(30, 144, 255, 0.3);
|
|
|
}
|
|
|
|
|
|
-.table-cell:nth-child(5) {
|
|
|
- min-width: 80px;
|
|
|
+.confirm-btn {
|
|
|
+ background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
|
|
|
-.table-cell:last-child {
|
|
|
- min-width: 100px;
|
|
|
+.confirm-btn:hover {
|
|
|
+ box-shadow: 0 0 20px rgba(16, 185, 129, 0.5);
|
|
|
+ transform: translateY(-2px);
|
|
|
}
|
|
|
</style>
|