52 lines
20 KiB
HTML
52 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
<title>柏悦物流 PDA · 仓储作业平台</title>
|
||
<link rel="icon" href="data:,">
|
||
<style>
|
||
:root { --primary:#1769e0; --primary-deep:#123b72; --primary-soft:#eaf2ff; --bg:#f3f6fa; --card:#fff; --text:#172b4d; --text-secondary:#6b788c; --border:#d9e4f2; --danger:#dc2626; --success:#0d9488; --shadow:0 4px 14px rgba(18,59,114,.08); }
|
||
* { box-sizing:border-box; margin:0; padding:0; }
|
||
body { min-height:100vh; max-width:480px; margin:0 auto; overflow-x:hidden; background:var(--bg); color:var(--text); font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Noto Sans SC",sans-serif; }
|
||
button,input { font:inherit; }
|
||
.hidden { display:none !important; }
|
||
.toast { position:fixed; top:70px; left:50%; z-index:400; padding:10px 20px; border-radius:8px; transform:translateX(-50%) translateY(-20px); opacity:0; color:#fff; background:#1f2937; transition:all .3s; pointer-events:none; }
|
||
.toast.show { transform:translateX(-50%) translateY(0); opacity:1; }
|
||
.toast.success { background:var(--success); }
|
||
.login-page { display:flex; flex-direction:column; justify-content:center; min-height:100vh; padding:32px 24px; background:linear-gradient(160deg,#1769e0 0%,#0d47a1 100%); }
|
||
.login-logo { margin:0 -22px; padding:54px 22px 42px; text-align:left; }.login-brand-line { display:flex; align-items:center; gap:14px; }.login-logo-icon { display:flex; align-items:center; justify-content:center; width:62px; height:62px; border-radius:16px; background:rgba(255,255,255,.15); }.login-logo-icon svg { width:31px; height:31px; }.login-logo-title { color:#fff; font-size:21px; font-weight:700; }.login-logo-sub { margin-top:5px; color:rgba(255,255,255,.72); font-size:12px; }.login-status { display:flex; align-items:center; gap:6px; margin-top:25px; color:rgba(255,255,255,.8); font-size:11px; }.login-status::before { width:7px; height:7px; border-radius:50%; background:#48d5bc; box-shadow:0 0 0 4px rgba(72,213,188,.12); content:""; }
|
||
.login-card { padding:22px; border-radius:12px; background:#fff; box-shadow:0 8px 32px rgba(0,0,0,.18); }.login-card-title { color:#172033; font-size:18px; font-weight:750; }.login-card-desc { margin:5px 0 20px; color:#78869a; font-size:12px; }.login-field { margin-bottom:15px; }.login-field-label { margin-bottom:7px; color:#445168; font-size:13px; font-weight:600; }.login-input-wrap { position:relative; }.login-input-icon { position:absolute; top:50%; left:13px; display:flex; color:#8290a4; transform:translateY(-50%); }.login-input-icon svg,.password-toggle svg { width:18px; height:18px; }.login-field-input { width:100%; height:46px; padding:0 42px; border:1px solid #d7e0eb; border-radius:8px; outline:0; color:#243b53; background:#f9fbfd; font-size:14px; }.login-field-input:focus { border-color:var(--primary); background:#fff; box-shadow:0 0 0 3px rgba(23,105,224,.08); }.password-toggle { position:absolute; top:50%; right:10px; display:flex; align-items:center; justify-content:center; width:28px; height:28px; border:0; color:#8290a4; background:transparent; transform:translateY(-50%); cursor:pointer; }.login-error { display:none; margin-bottom:12px; padding:9px 11px; border-radius:7px; color:var(--danger); background:#fff1f1; font-size:13px; }.login-error.show { display:block; }.login-btn { width:100%; height:48px; margin-top:5px; border:0; border-radius:8px; color:#fff; background:#1769e0; box-shadow:0 6px 14px rgba(23,105,224,.2); font-size:16px; font-weight:600; cursor:pointer; }.login-demo-tip { margin-top:13px; padding:10px 12px; border-radius:7px; color:#6b788c; background:#f2f5f9; font-size:11px; text-align:center; }.login-accounts { margin-top:16px; padding-top:14px; border-top:1px solid #e3e8ef; }.login-accounts-title { margin-bottom:9px; color:#78869a; font-size:11px; text-align:left; }.login-quick-btns { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px; }.login-quick-btn { padding:10px; border:1px solid #dbe4ee; border-radius:8px; color:#334e68; background:#fff; text-align:left; cursor:pointer; }.login-quick-btn-name,.login-quick-btn-role { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }.login-quick-btn-name { font-size:13px; font-weight:650; }.login-quick-btn-role { margin-top:3px; color:#78869a; font-size:11px; }
|
||
.workbench-page { --wb-brand:#155eef; --wb-brand-deep:#123b72; --wb-brand-surface:#f4f8ff; --wb-brand-border:#a7c4f4; --wb-surface:#fff; --wb-border:#d9e4f2; --wb-text:#172b4d; --wb-text-secondary:#627388; --wb-danger:#e5484d; }.app-shell { min-height:100vh; padding-bottom:28px; background:var(--bg); }.app-topbar { padding:15px 16px 24px; border-radius:0 0 16px 16px; color:#fff; background:linear-gradient(140deg,var(--wb-brand-deep),var(--wb-brand)); box-shadow:0 8px 20px rgba(18,59,114,.18); }.app-topbar-row,.welcome-card,.section-heading { display:flex; align-items:center; justify-content:space-between; }.app-topbar-row { gap:12px; }.app-brand { display:flex; align-items:center; gap:10px; }.app-brand-mark { display:flex; align-items:center; justify-content:center; width:36px; height:36px; border-radius:9px; background:rgba(255,255,255,.18); font-size:18px; }.app-brand-title { font-size:17px; font-weight:700; }.app-brand-sub { margin-top:2px; font-size:11px; opacity:.72; }.profile-entry { display:flex; align-items:center; justify-content:center; width:40px; height:40px; border:1px solid rgba(255,255,255,.25); border-radius:10px; color:#fff; background:rgba(255,255,255,.16); font-size:17px; font-weight:700; cursor:pointer; }.welcome-card { align-items:flex-end; gap:12px; margin-top:18px; }.welcome-kicker { font-size:12px; opacity:.75; }.welcome-name { margin-top:3px; font-size:21px; font-weight:700; }.welcome-meta { margin-top:5px; font-size:12px; opacity:.82; }.shift-badge { flex:none; padding:7px 10px; border-radius:10px; background:rgba(255,255,255,.15); font-size:11px; }.shift-badge::before { display:inline-block; width:7px; height:7px; margin-right:5px; border-radius:50%; background:#24b886; content:""; }.workbench-content { padding:14px 12px 22px; }.today-panel { display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin-bottom:14px; }.today-stat { padding:12px 8px; border:1px solid var(--wb-border); border-radius:12px; background:var(--wb-surface); box-shadow:var(--shadow); text-align:center; }.today-stat-num { color:var(--wb-brand-deep); font-size:20px; font-weight:750; line-height:1.1; }.today-stat-label { margin-top:5px; color:var(--wb-text-secondary); font-size:11px; }.section-heading { margin:18px 2px 8px; }.section-heading-title { display:flex; align-items:center; gap:8px; color:var(--wb-text); font-size:15px; font-weight:700; }.section-heading-title::before { width:4px; height:16px; border-radius:3px; background:var(--wb-brand); content:""; }.module-card { padding:4px 6px; border:1px solid var(--wb-border); border-radius:10px; background:var(--wb-surface); box-shadow:var(--shadow); }.module-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); }.module-item { position:relative; min-height:78px; margin:3px; padding:7px 3px; border:1px solid var(--wb-brand-border); border-radius:9px; color:#174ea6; background:var(--wb-brand-surface); box-shadow:0 4px 10px rgba(18,59,114,.1); cursor:pointer; }.module-icon { display:flex; align-items:center; justify-content:center; width:40px; height:40px; margin:0 auto 7px; border-radius:10px; color:#fff; background:var(--wb-brand); box-shadow:0 5px 12px rgba(18,59,114,.16); font-size:20px; }.module-name { font-size:12px; line-height:1.3; white-space:nowrap; }.module-badge { position:absolute; top:7px; right:5px; min-width:17px; height:17px; padding:0 4px; border-radius:9px; color:#fff; background:var(--wb-danger); font-size:9px; line-height:17px; }
|
||
.page-back { width:38px; height:38px; border:0; border-radius:11px; color:#fff; background:rgba(255,255,255,.14); font-size:20px; cursor:pointer; }.profile-cover { height:132px; padding:16px; color:#fff; background:linear-gradient(140deg,#123b72,#1769e0); }.profile-card { position:relative; margin:-49px 12px 12px; padding:18px; border-radius:12px; background:#fff; box-shadow:0 10px 28px rgba(20,49,82,.13); text-align:center; }.profile-avatar { display:flex; align-items:center; justify-content:center; width:68px; height:68px; margin:-50px auto 10px; border:4px solid #fff; border-radius:16px; color:#155eef; background:#eaf2ff; font-size:25px; font-weight:800; }.profile-name { color:#172b4d; font-size:19px; font-weight:700; }.profile-role { margin-top:4px; color:#728196; font-size:12px; }.profile-stats { display:grid; grid-template-columns:repeat(3,1fr); margin-top:16px; padding-top:14px; border-top:1px solid #edf1f5; }.profile-stat strong { display:block; color:#163b68; font-size:17px; }.profile-stat span { color:#8a97a8; font-size:10px; }.profile-list { margin:12px; padding:2px 14px; border:1px solid #e3e8ef; border-radius:10px; background:#fff; }.profile-list-item { display:flex; align-items:center; gap:12px; padding:15px 0; border-bottom:1px solid #edf1f5; color:#334e68; font-size:13px; }.profile-list-item:last-child { border-bottom:0; }.profile-list-icon { display:flex; align-items:center; justify-content:center; width:32px; height:32px; border-radius:8px; background:#eef4ff; }.profile-list-value { margin-left:auto; color:#829ab1; font-size:12px; }.profile-logout { width:calc(100% - 24px); margin:4px 12px 24px; padding:13px; border:1px solid #fecaca; border-radius:9px; color:#dc2626; background:#fff; font-size:14px; font-weight:600; cursor:pointer; }
|
||
@media (max-width:360px) { .login-page { padding-right:16px; padding-left:16px; } .login-logo { margin-right:-16px; margin-left:-16px; padding-right:18px; padding-left:18px; } .module-name { font-size:11px; } }
|
||
</style>
|
||
<link rel="stylesheet" href="domestic-overseas-theme.css">
|
||
</head>
|
||
<body>
|
||
<div class="toast" id="toast"></div>
|
||
<div class="login-page" id="loginPage"><div class="login-logo"><div class="login-brand-line"><div class="login-logo-icon"><svg viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 3v18"/></svg></div><div><div class="login-logo-title">柏悦物流 PDA</div><div class="login-logo-sub">仓储移动作业平台</div></div></div><div class="login-status">作业系统运行正常</div></div><div class="login-card"><div class="login-card-title">账号登录</div><div class="login-card-desc">请输入作业人员账号进入工作台</div><div class="login-field"><div class="login-field-label">用户名</div><div class="login-input-wrap"><span class="login-input-icon">♙</span><input class="login-field-input" id="loginUser" placeholder="请输入用户名" autocomplete="username"></div></div><div class="login-field"><div class="login-field-label">密码</div><div class="login-input-wrap"><span class="login-input-icon">▣</span><input class="login-field-input" id="loginPass" type="password" placeholder="请输入密码" autocomplete="current-password"><button class="password-toggle" id="passwordToggle" type="button" onclick="togglePassword()" aria-label="显示密码">◉</button></div></div><div class="login-error" id="loginError">用户名或密码错误</div><button class="login-btn" type="button" onclick="handleLogin()">登录</button><div class="login-demo-tip">演示账号:W001 密码:123456</div><div class="login-accounts"><div class="login-accounts-title">快捷登录</div><div class="login-quick-btns"><button class="login-quick-btn" type="button" onclick="quickLogin('W001','张伟','拣货员')"><span class="login-quick-btn-name">W001 · 张伟</span><span class="login-quick-btn-role">拣货员 · 洛杉矶仓</span></button><button class="login-quick-btn" type="button" onclick="quickLogin('W002','李敏','拣货组长')"><span class="login-quick-btn-name">W002 · 李敏</span><span class="login-quick-btn-role">拣货组长 · 洛杉矶仓</span></button></div></div></div></div>
|
||
<div class="workbench-page hidden" id="workbenchPage"><div class="app-shell"><div class="app-topbar"><div class="app-topbar-row"><div class="app-brand"><div class="app-brand-mark">▦</div><div><div class="app-brand-title">柏悦物流 PDA</div><div class="app-brand-sub">仓储移动作业平台</div></div></div><button class="profile-entry" id="workbenchAvatar" type="button" onclick="openProfile()" aria-label="个人中心">张</button></div><div class="welcome-card"><div><div class="welcome-kicker">欢迎回来</div><div class="welcome-name" id="workbenchUserName">张伟</div><div class="welcome-meta"><span id="workbenchRole">拣货员</span> · <span id="workbenchWarehouse">洛杉矶仓</span></div></div><div class="shift-badge">白班 · 作业中</div></div></div><div class="workbench-content"><div class="today-panel"><div class="today-stat"><div class="today-stat-num">3</div><div class="today-stat-label">待拣集装箱</div></div><div class="today-stat"><div class="today-stat-num">0</div><div class="today-stat-label">今日已完成</div></div><div class="today-stat"><div class="today-stat-num">17</div><div class="today-stat-label">待拣货品</div></div></div><div class="section-heading"><div class="section-heading-title">入库</div></div><div class="module-card"><div class="module-grid"><button class="module-item active-menu" id="receiveEntry" type="button" onclick="navigateToModule('入库/收货登记.html')"><span class="module-badge">3</span><span class="module-icon">📥</span><span class="module-name">收货登记</span></button><button class="module-item active-menu" id="palletEntry" type="button" onclick="navigateToModule('入库/入库打托.html')"><span class="module-badge">2</span><span class="module-icon">🪵</span><span class="module-name">入库打托</span></button></div></div><div class="section-heading"><div class="section-heading-title">出库</div></div><div class="module-card"><div class="module-grid" id="outboundModuleGrid"><button class="module-item active-menu" id="consolidationEntry" type="button" onclick="navigateToModule('出库/合托.html')"><span class="module-badge">1</span><span class="module-icon">🪵</span><span class="module-name">合托</span></button><button class="module-item active-menu" id="pickingEntry" type="button" onclick="navigateToModule('出库/集装箱拣货.html')"><span class="module-badge">3</span><span class="module-icon">📦</span><span class="module-name">集装箱拣货</span></button></div></div></div></div></div>
|
||
<div class="profile-page hidden" id="profilePage"><div class="app-shell"><div class="profile-cover"><button class="page-back" type="button" onclick="backFromProfile()">‹</button></div><div class="profile-card"><div class="profile-avatar" id="profileAvatar">张</div><div class="profile-name" id="profileName">张伟</div><div class="profile-role" id="profileRole">W001 · 拣货员</div><div class="profile-stats"><div class="profile-stat"><strong>28</strong><span>今日完成</span></div><div class="profile-stat"><strong>156</strong><span>本月任务</span></div><div class="profile-stat"><strong>99.2%</strong><span>作业准确率</span></div></div></div><div class="profile-list"><div class="profile-list-item"><span class="profile-list-icon">🏢</span><span>当前仓库</span><span class="profile-list-value" id="profileWarehouse">洛杉矶仓</span></div><div class="profile-list-item"><span class="profile-list-icon">🕘</span><span>当前班次</span><span class="profile-list-value">白班 08:00–17:00</span></div><div class="profile-list-item"><span class="profile-list-icon">🔐</span><span>修改密码</span><span class="profile-list-value">›</span></div><div class="profile-list-item"><span class="profile-list-icon">⚙️</span><span>系统设置</span><span class="profile-list-value">›</span></div><div class="profile-list-item"><span class="profile-list-icon">ℹ️</span><span>版本信息</span><span class="profile-list-value">V1.0.0</span></div></div><button class="profile-logout" type="button" onclick="handleLogout()">退出登录</button></div></div>
|
||
<script>
|
||
const DEMO_ACCOUNTS = { W001:{pass:'123456',name:'张伟',role:'拣货员',warehouse:'洛杉矶仓'}, W002:{pass:'123456',name:'李敏',role:'拣货组长',warehouse:'洛杉矶仓'}, W003:{pass:'123456',name:'王磊',role:'仓管员',warehouse:'新泽西仓'} };
|
||
const USER_STORAGE_KEY = 'pdaCurrentUser'; let currentUser = null; let toastTimer = null;
|
||
function buildUserParams(user) { return new URLSearchParams({ id:user.id, name:user.name, role:user.role, warehouse:user.warehouse }); }
|
||
function persistCurrentUser() { localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(currentUser)); }
|
||
function navigateToModule(relativePath) { persistCurrentUser(); location.href = `${relativePath}?${buildUserParams(currentUser)}`; }
|
||
function togglePassword() { const input = document.getElementById('loginPass'); const showing = input.type === 'text'; input.type = showing ? 'password' : 'text'; document.getElementById('passwordToggle').setAttribute('aria-label', showing ? '显示密码' : '隐藏密码'); }
|
||
function showToast(message,type='') { const toast=document.getElementById('toast'); toast.textContent=message; toast.className=`toast show ${type}`; clearTimeout(toastTimer); toastTimer=setTimeout(()=>{toast.className='toast';},2200); }
|
||
function showLoginError(message) { const error=document.getElementById('loginError'); error.textContent=message; error.classList.add('show'); } function hideLoginError() { document.getElementById('loginError').classList.remove('show'); }
|
||
function updateUserUI() { const initial=currentUser.name.slice(0,1); document.getElementById('workbenchAvatar').textContent=initial; document.getElementById('workbenchUserName').textContent=currentUser.name; document.getElementById('workbenchRole').textContent=currentUser.role; document.getElementById('workbenchWarehouse').textContent=currentUser.warehouse; document.getElementById('profileAvatar').textContent=initial; document.getElementById('profileName').textContent=currentUser.name; document.getElementById('profileRole').textContent=`${currentUser.id} · ${currentUser.role}`; document.getElementById('profileWarehouse').textContent=currentUser.warehouse; }
|
||
function showAppPage(pageId) { ['workbenchPage','profilePage'].forEach(id=>document.getElementById(id).classList.toggle('hidden',id!==pageId)); window.scrollTo(0,0); }
|
||
function enterMainPage(showWelcome=true) { document.getElementById('loginPage').classList.add('hidden'); showAppPage('workbenchPage'); updateUserUI(); hideLoginError(); if(showWelcome) showToast(`${currentUser.name},欢迎登录`,'success'); }
|
||
function handleLogin() { const userId=document.getElementById('loginUser').value.trim(); const password=document.getElementById('loginPass').value; if(!userId) return showLoginError('请输入用户名'); if(!password) return showLoginError('请输入密码'); const account=DEMO_ACCOUNTS[userId]; if(!account||account.pass!==password) return showLoginError('用户名或密码错误'); currentUser={id:userId,name:account.name,role:account.role,warehouse:account.warehouse}; persistCurrentUser(); enterMainPage(); }
|
||
function quickLogin(id,name,role) { currentUser={id,name,role,warehouse:DEMO_ACCOUNTS[id].warehouse}; persistCurrentUser(); enterMainPage(); } function openProfile() { showAppPage('profilePage'); } function backFromProfile() { showAppPage('workbenchPage'); }
|
||
function handleLogout() { currentUser=null; localStorage.removeItem(USER_STORAGE_KEY); document.getElementById('loginPage').classList.remove('hidden'); document.getElementById('workbenchPage').classList.add('hidden'); document.getElementById('profilePage').classList.add('hidden'); document.getElementById('loginUser').value=''; document.getElementById('loginPass').value=''; hideLoginError(); }
|
||
function readUserFromParams(params) { if(!params.get('id')) return null; return Object.fromEntries(['id','name','role','warehouse'].map(key=>[key,params.get(key)||''])); } function readStoredUser() { try { const stored=JSON.parse(localStorage.getItem(USER_STORAGE_KEY)); return stored?.id ? stored : null; } catch { return null; } }
|
||
function restoreWorkbenchSession() { const params=new URLSearchParams(location.search); if(params.get('resume')!=='1') return; currentUser=readUserFromParams(params)||readStoredUser(); if(!currentUser) return; persistCurrentUser(); enterMainPage(false); }
|
||
document.getElementById('loginPass').addEventListener('keydown',event=>{if(event.key==='Enter')handleLogin();}); document.getElementById('loginUser').addEventListener('keydown',event=>{if(event.key==='Enter')document.getElementById('loginPass').focus();}); restoreWorkbenchSession();
|
||
</script>
|
||
</body>
|
||
</html>
|