docs: initialize documentation repository

This commit is contained in:
2026-07-31 10:43:58 +08:00
commit 1ec28f7cfc
72 changed files with 48272 additions and 0 deletions
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 881 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>%s</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700;900&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { theme: { extend: { colors: { brand: { green:'#4CAF50', greenDark:'#2E7D32', blue:'#1565C0', blueDark:'#0D47A1', teal:'#00838F', light:'#F0F7FF', dark:'#0A1628' } }, fontFamily: { sans:['Inter','Noto Sans SC','system-ui','sans-serif'] } } } };
</script>
<style>
:root { --primary:#1565C0; --primary-dark:#0D47A1; --accent:#4CAF50; --accent-dark:#2E7D32; }
* { scroll-behavior:smooth; }
body { font-family:'Inter','Noto Sans SC',system-ui,sans-serif; overflow-x:hidden; }
.gradient-text { background:linear-gradient(135deg,#1565C0 0%,#4CAF50 100%); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
.gradient-bg { background:linear-gradient(135deg,#0A1628 0%,#1565C0 50%,#00838F 100%); }
.btn-primary { background:linear-gradient(135deg,#1565C0 0%,#0D47A1 100%); transition:all .3s ease; }
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(21,101,192,.35); }
.btn-accent { background:linear-gradient(135deg,#4CAF50 0%,#2E7D32 100%); transition:all .3s ease; }
.btn-accent:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(76,175,80,.35); }
.input-field { transition:all .3s ease; }
.input-field:focus { border-color:#1565C0; box-shadow:0 0 0 4px rgba(21,101,192,.1); }
.auth-logo { display:block; filter:brightness(0) saturate(100%) invert(20%) sepia(84%) saturate(1926%) hue-rotate(202deg) brightness(94%) contrast(93%); }
.lang-switcher { display:flex; align-items:center; background:rgba(21,101,192,.08); border-radius:9999px; padding:3px; border:1px solid rgba(21,101,192,.15); }
.lang-switcher button { font-size:12px; font-weight:600; padding:4px 9px; border-radius:9999px; color:#0A1628; transition:all .25s ease; white-space:nowrap; }
.lang-switcher button:hover { color:#1565C0; }
.lang-switcher button.active { background:#1565C0; color:#fff; }
</style>
</head>
<body class="text-gray-800 antialiased bg-gray-50">
<!-- 顶部栏 -->
<header class="fixed top-0 inset-x-0 z-50 bg-white/95 backdrop-blur border-b border-gray-100">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<a href="index.html" class="flex items-center" aria-label="返回官网">
<img src="assets/logo.png" alt="柏悦物流" class="auth-logo" style="width:161px;height:60px;object-fit:contain;">
</a>
<div class="lang-switcher" id="langSwitcher">
<button data-lang="zh" class="active" title="中文">中</button>
<button data-lang="en" title="English">EN</button>
<button data-lang="es" title="Español (México)">🇲🇽</button>
</div>
</div>
</header>
<section id="loginSection" class="min-h-screen pt-24 pb-12 bg-gray-50 flex items-center">
<div class="w-full max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-3xl shadow-2xl overflow-hidden">
<div class="grid lg:grid-cols-2">
<!-- 左侧视觉 -->
<div class="hidden lg:block relative">
<img src="https://images.unsplash.com/photo-1494412574643-ff11b0a5c1c3?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80" alt="物流" class="absolute inset-0 w-full h-full object-cover">
<div class="absolute inset-0 gradient-bg opacity-90"></div>
<div class="relative z-10 p-12 h-full flex flex-col justify-between text-white">
<div>
<img src="assets/logo.png" alt="虫虫出海" style="width:161px;height:60px;object-fit:contain;">
<h2 class="text-3xl font-bold mb-4" data-i18n="login_welcome">欢迎回来</h2>
<p class="text-white/80" data-i18n="login_desc">登录虫虫出海平台,实时追踪货物轨迹,管理订单与库存。</p>
</div>
<div class="space-y-4">
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="login_feat1">全程可视化追踪</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="login_feat2">智能订单管理</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="login_feat3">在线询价下单</span>
</div>
</div>
</div>
</div>
<!-- 右侧表单 -->
<div class="p-8 sm:p-12 lg:p-16">
<div class="max-w-md mx-auto">
<h2 class="text-3xl font-bold text-gray-900 mb-2" data-i18n="login_title">账号登录</h2>
<p class="text-gray-600 mb-8"><span data-i18n="login_no_account">还没有账号?</span><button onclick="window.location.href='register.html'" class="text-brand-blue font-semibold hover:underline" data-i18n="login_register_link">立即注册</button></p>
<form id="loginForm" class="space-y-5">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="login_account_label">邮箱 / 手机号</label>
<div class="relative">
<i class="fas fa-user absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="text" name="account" required placeholder="请输入邮箱或手机号" data-i18n-ph="login_account_ph" class="input-field w-full pl-11 pr-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="login_password_label">密码</label>
<div class="relative">
<i class="fas fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="password" name="password" required placeholder="请输入密码" data-i18n-ph="login_password_ph" class="input-field w-full pl-11 pr-12 py-3.5 border border-gray-200 rounded-xl outline-none">
<button type="button" class="toggle-password absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600">
<i class="fas fa-eye"></i>
</button>
</div>
</div>
<div class="flex items-center justify-between text-sm">
<label class="flex items-center text-gray-600 cursor-pointer">
<input type="checkbox" class="w-4 h-4 text-brand-blue rounded border-gray-300 mr-2">
<span data-i18n="login_remember">记住我</span>
</label>
<button type="button" onclick="showToast(t('toast_resetpw'))" class="text-brand-blue hover:underline" data-i18n="login_forgot">忘记密码?</button>
</div>
<button type="submit" class="btn-primary w-full text-white font-bold py-4 rounded-xl text-lg" data-i18n="login_submit">
登 录
</button>
</form>
<div class="mt-8">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-200"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white text-gray-500" data-i18n="login_other">其他方式登录</span>
</div>
</div>
<div class="flex justify-center space-x-4 mt-6">
<button onclick="showToast('微信登录即将上线')" class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-green-600 hover:bg-green-50 transition-colors">
<i class="fab fa-weixin text-xl"></i>
</button>
<button onclick="showToast('企业微信登录即将上线')" class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-blue-600 hover:bg-blue-50 transition-colors">
<i class="fas fa-briefcase text-xl"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section> <!-- Toast 提示 -->
<div id="toast" class="fixed top-24 left-1/2 -translate-x-1/2 z-[60] opacity-0 pointer-events-none transition-all duration-300 transform -translate-y-4">
<div class="bg-gray-900 text-white px-6 py-3 rounded-full shadow-2xl flex items-center space-x-2">
<i class="fas fa-info-circle text-brand-green"></i>
<span id="toastMessage">提示信息</span>
</div>
</div>
<script>
let currentLang = localStorage.getItem('cc_lang') || 'zh';
function t(key) {
return (i18n[currentLang] && i18n[currentLang][key] !== undefined) ? i18n[currentLang][key] : key;
}
const i18n = {
zh: {
login_welcome: "欢迎回来",
login_desc: "登录虫虫出海平台,实时追踪货物轨迹,管理订单与库存。",
login_feat1: "全程可视化追踪",
login_feat2: "智能订单管理",
login_feat3: "在线询价下单",
login_title: "账号登录",
login_no_account: "还没有账号?",
login_register_link: "立即注册",
login_account_label: "邮箱 / 手机号",
login_account_ph: "请输入邮箱或手机号",
login_password_label: "密码",
login_password_ph: "请输入密码",
login_remember: "记住我",
login_forgot: "忘记密码?",
login_submit: "登 录",
login_other: "其他方式登录",
toast_resetpw: "请联系客服重置密码",
toast_login_ok: "登录成功!欢迎回来"
},
en: {
login_welcome: "Welcome Back",
login_desc: "Log in to track shipments in real time and manage orders and inventory.",
login_feat1: "Full Visual Tracking",
login_feat2: "Smart Order Management",
login_feat3: "Online Quoting & Ordering",
login_title: "Account Login",
login_no_account: "No account yet?",
login_register_link: "Sign Up Now",
login_account_label: "Email / Phone",
login_account_ph: "Enter email or phone",
login_password_label: "Password",
login_password_ph: "Enter password",
login_remember: "Remember Me",
login_forgot: "Forgot Password?",
login_submit: "Log In",
login_other: "Other Sign-In Methods",
toast_resetpw: "Please contact support to reset your password",
toast_login_ok: "Login successful! Welcome back"
},
es: {
login_welcome: "Bienvenido de nuevo",
login_desc: "Inicia sesión para rastrear envíos en tiempo real y gestionar pedidos e inventario.",
login_feat1: "Seguimiento visual completo",
login_feat2: "Gestión inteligente de pedidos",
login_feat3: "Cotización y pedidos en línea",
login_title: "Inicio de sesión",
login_no_account: "¿Aún no tienes cuenta?",
login_register_link: "Regístrate ahora",
login_account_label: "Correo / Teléfono",
login_account_ph: "Ingresa correo o teléfono",
login_password_label: "Contraseña",
login_password_ph: "Ingresa tu contraseña",
login_remember: "Recuérdame",
login_forgot: "¿Olvidó su contraseña?",
login_submit: "Iniciar sesión",
login_other: "Otros métodos de acceso",
toast_resetpw: "Contacta a soporte para restablecer tu contraseña",
toast_login_ok: "¡Inicio de sesión exitoso! Bienvenido"
}
};
function applyLanguage(lang) {
if (!i18n[lang]) lang = 'zh';
currentLang = lang;
const langAttr = lang === 'zh' ? 'zh-CN' : (lang === 'es' ? 'es-MX' : 'en');
document.documentElement.setAttribute('lang', langAttr);
document.querySelectorAll('[data-i18n]').forEach(el => {
const k = el.getAttribute('data-i18n');
const v = i18n[lang][k];
if (v !== undefined) { if (v.indexOf('<br>') !== -1) el.innerHTML = v; else el.textContent = v; }
});
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
const k = el.getAttribute('data-i18n-ph');
if (i18n[lang][k] !== undefined) el.setAttribute('placeholder', i18n[lang][k]);
});
document.querySelectorAll('[data-lang]').forEach(b => {
b.classList.toggle('active', b.getAttribute('data-lang') === lang);
});
try { localStorage.setItem('cc_lang', lang); } catch (e) {}
}
document.querySelectorAll('#langSwitcher [data-lang]').forEach(b => {
b.addEventListener('click', () => applyLanguage(b.getAttribute('data-lang')));
});
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
toastMessage.textContent = message;
toast.classList.remove('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.add('opacity-100', 'translate-y-0');
setTimeout(() => {
toast.classList.add('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.remove('opacity-100', 'translate-y-0');
}, 3000);
}
function updateAuthUI() {}
document.querySelectorAll('.toggle-password').forEach(button => {
button.addEventListener('click', function() {
const input = this.previousElementSibling;
const icon = this.querySelector('i');
if (input.type === 'password') { input.type = 'text'; icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); }
else { input.type = 'password'; icon.classList.remove('fa-eye-slash'); icon.classList.add('fa-eye'); }
});
});
document.getElementById('loginForm').addEventListener('submit', function(e) {
e.preventDefault();
showToast(t('toast_login_ok'));
setTimeout(() => window.location.href = 'workbench.html', 900);
});
applyLanguage(currentLang);
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

+286
View File
@@ -0,0 +1,286 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>%s</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700;900&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { theme: { extend: { colors: { brand: { green:'#4CAF50', greenDark:'#2E7D32', blue:'#1565C0', blueDark:'#0D47A1', teal:'#00838F', light:'#F0F7FF', dark:'#0A1628' } }, fontFamily: { sans:['Inter','Noto Sans SC','system-ui','sans-serif'] } } } };
</script>
<style>
:root { --primary:#1565C0; --primary-dark:#0D47A1; --accent:#4CAF50; --accent-dark:#2E7D32; }
* { scroll-behavior:smooth; }
body { font-family:'Inter','Noto Sans SC',system-ui,sans-serif; overflow-x:hidden; }
.gradient-text { background:linear-gradient(135deg,#1565C0 0%,#4CAF50 100%); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
.gradient-bg { background:linear-gradient(135deg,#0A1628 0%,#1565C0 50%,#00838F 100%); }
.btn-primary { background:linear-gradient(135deg,#1565C0 0%,#0D47A1 100%); transition:all .3s ease; }
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(21,101,192,.35); }
.btn-accent { background:linear-gradient(135deg,#4CAF50 0%,#2E7D32 100%); transition:all .3s ease; }
.btn-accent:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(76,175,80,.35); }
.input-field { transition:all .3s ease; }
.input-field:focus { border-color:#1565C0; box-shadow:0 0 0 4px rgba(21,101,192,.1); }
.auth-logo { display:block; filter:brightness(0) saturate(100%) invert(20%) sepia(84%) saturate(1926%) hue-rotate(202deg) brightness(94%) contrast(93%); }
.lang-switcher { display:flex; align-items:center; background:rgba(21,101,192,.08); border-radius:9999px; padding:3px; border:1px solid rgba(21,101,192,.15); }
.lang-switcher button { font-size:12px; font-weight:600; padding:4px 9px; border-radius:9999px; color:#0A1628; transition:all .25s ease; white-space:nowrap; }
.lang-switcher button:hover { color:#1565C0; }
.lang-switcher button.active { background:#1565C0; color:#fff; }
</style>
</head>
<body class="text-gray-800 antialiased bg-gray-50">
<!-- 顶部栏 -->
<header class="fixed top-0 inset-x-0 z-50 bg-white/95 backdrop-blur border-b border-gray-100">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<a href="index.html" class="flex items-center" aria-label="返回官网">
<img src="assets/logo.png" alt="柏悦物流" class="auth-logo" style="width:161px;height:60px;object-fit:contain;">
</a>
<div class="lang-switcher" id="langSwitcher">
<button data-lang="zh" class="active" title="中文">中</button>
<button data-lang="en" title="English">EN</button>
<button data-lang="es" title="Español (México)">🇲🇽</button>
</div>
</div>
</header>
<section id="registerSection" class="min-h-screen pt-24 pb-12 bg-gray-50 flex items-center">
<div class="w-full max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-3xl shadow-2xl overflow-hidden">
<div class="grid lg:grid-cols-2">
<!-- 左侧视觉 -->
<div class="hidden lg:block relative">
<img src="https://images.unsplash.com/photo-1566576912321-d58ddd7a6088?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80" alt="物流仓储" class="absolute inset-0 w-full h-full object-cover">
<div class="absolute inset-0 gradient-bg opacity-90"></div>
<div class="relative z-10 p-12 h-full flex flex-col justify-between text-white">
<div>
<img src="assets/logo.png" alt="虫虫出海" style="width:161px;height:60px;object-fit:contain;">
<h2 class="text-3xl font-bold mb-4" data-i18n="reg_welcome">加入我们</h2>
<p class="text-white/80" data-i18n="reg_welcome_desc">注册虫虫出海企业账号,开启高效跨境物流体验。</p>
</div>
<div class="space-y-4">
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="reg_feat1">新用户专属优惠</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="reg_feat2">免费获取物流方案</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="reg_feat3">专属客户经理对接</span>
</div>
</div>
</div>
</div>
<!-- 右侧表单 -->
<div class="p-8 sm:p-12 lg:p-16">
<div class="max-w-md mx-auto">
<h2 class="text-3xl font-bold text-gray-900 mb-2" data-i18n="reg_title">企业注册</h2>
<p class="text-gray-600 mb-8"><span data-i18n="reg_have_account">已有账号?</span><button onclick="window.location.href='login.html'" class="text-brand-blue font-semibold hover:underline" data-i18n="reg_login_link">立即登录</button></p>
<form id="registerForm" class="space-y-5">
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_company_label">企业名称</label>
<input type="text" name="company" required placeholder="请输入企业名称" data-i18n-ph="reg_company_ph" class="input-field w-full px-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_contact_label">联系人</label>
<input type="text" name="contact" required placeholder="请输入联系人姓名" data-i18n-ph="reg_contact_ph" class="input-field w-full px-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_email_label">邮箱</label>
<div class="relative">
<i class="fas fa-envelope absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="email" name="email" required placeholder="请输入企业邮箱" data-i18n-ph="reg_email_ph" class="input-field w-full pl-11 pr-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_phone_label">手机号</label>
<div class="relative">
<i class="fas fa-phone absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="tel" name="phone" required placeholder="请输入手机号" data-i18n-ph="reg_phone_ph" class="input-field w-full pl-11 pr-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_password_label">密码</label>
<div class="relative">
<i class="fas fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="password" name="password" required placeholder="请设置8-20位密码" data-i18n-ph="reg_password_ph" class="input-field w-full pl-11 pr-12 py-3.5 border border-gray-200 rounded-xl outline-none">
<button type="button" class="toggle-password absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600">
<i class="fas fa-eye"></i>
</button>
</div>
</div>
<div class="flex items-start">
<input type="checkbox" id="agree" required class="w-4 h-4 text-brand-blue rounded border-gray-300 mt-1 mr-2">
<label for="agree" class="text-sm text-gray-600">
<span data-i18n="reg_agree">我已阅读并同意</span> <button type="button" onclick="showToast(t('toast_tos'))" class="text-brand-blue hover:underline" data-i18n="reg_agree_tos">《用户服务协议》</button> 和 <button type="button" onclick="showToast(t('toast_pp'))" class="text-brand-blue hover:underline" data-i18n="reg_agree_pp">《隐私政策》</button>
</label>
</div>
<button type="submit" class="btn-accent w-full text-white font-bold py-4 rounded-xl text-lg" data-i18n="reg_submit">
立即注册
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</section> <!-- Toast 提示 -->
<div id="toast" class="fixed top-24 left-1/2 -translate-x-1/2 z-[60] opacity-0 pointer-events-none transition-all duration-300 transform -translate-y-4">
<div class="bg-gray-900 text-white px-6 py-3 rounded-full shadow-2xl flex items-center space-x-2">
<i class="fas fa-info-circle text-brand-green"></i>
<span id="toastMessage">提示信息</span>
</div>
</div>
<script>
let currentLang = localStorage.getItem('cc_lang') || 'zh';
function t(key) {
return (i18n[currentLang] && i18n[currentLang][key] !== undefined) ? i18n[currentLang][key] : key;
}
const i18n = {
zh: {
reg_welcome: "加入我们",
reg_welcome_desc: "注册虫虫出海企业账号,开启高效跨境物流体验。",
reg_feat1: "新用户专属优惠",
reg_feat2: "免费获取物流方案",
reg_feat3: "专属客户经理对接",
reg_title: "企业注册",
reg_have_account: "已有账号?",
reg_login_link: "立即登录",
reg_company_label: "企业名称",
reg_company_ph: "请输入企业名称",
reg_contact_label: "联系人",
reg_contact_ph: "请输入联系人姓名",
reg_email_label: "邮箱",
reg_email_ph: "请输入企业邮箱",
reg_phone_label: "手机号",
reg_phone_ph: "请输入手机号",
reg_password_label: "密码",
reg_password_ph: "请设置8-20位密码",
reg_agree: "我已阅读并同意",
reg_agree_tos: "《用户服务协议》",
reg_agree_pp: "《隐私政策》",
reg_submit: "立即注册",
toast_tos: "服务协议即将上线",
toast_pp: "隐私政策即将上线",
toast_register_ok: "注册成功!欢迎加入虫虫出海"
},
en: {
reg_welcome: "Join Us",
reg_welcome_desc: "Register a Chongchong Global business account and start efficient cross-border logistics.",
reg_feat1: "Exclusive New-User Offers",
reg_feat2: "Free Logistics Plan",
reg_feat3: "Dedicated Account Manager",
reg_title: "Business Registration",
reg_have_account: "Already have an account?",
reg_login_link: "Log In Now",
reg_company_label: "Company Name",
reg_company_ph: "Enter company name",
reg_contact_label: "Contact Person",
reg_contact_ph: "Enter contact name",
reg_email_label: "Email",
reg_email_ph: "Enter company email",
reg_phone_label: "Phone Number",
reg_phone_ph: "Enter phone number",
reg_password_label: "Password",
reg_password_ph: "Set an 8-20 char password",
reg_agree: "I have read and agree to the",
reg_agree_tos: "User Agreement",
reg_agree_pp: "Privacy Policy",
reg_submit: "Sign Up Now",
toast_tos: "Terms of Service coming soon",
toast_pp: "Privacy Policy coming soon",
toast_register_ok: "Registration successful! Welcome to Chongchong Global"
},
es: {
reg_welcome: "Únete a nosotros",
reg_welcome_desc: "Regístrate en la cuenta empresarial de Chongchong Global y comienza una logística eficiente.",
reg_feat1: "Ofertas exclusivas para nuevos usuarios",
reg_feat2: "Plan logístico gratuito",
reg_feat3: "Gerente de cuenta dedicado",
reg_title: "Registro empresarial",
reg_have_account: "¿Ya tienes una cuenta?",
reg_login_link: "Inicia sesión ahora",
reg_company_label: "Nombre de empresa",
reg_company_ph: "Ingresa el nombre de empresa",
reg_contact_label: "Persona de contacto",
reg_contact_ph: "Ingresa el nombre de contacto",
reg_email_label: "Correo electrónico",
reg_email_ph: "Ingresa el correo empresarial",
reg_phone_label: "Número de teléfono",
reg_phone_ph: "Ingresa tu número de teléfono",
reg_password_label: "Contraseña",
reg_password_ph: "Define una contraseña de 8-20 caracteres",
reg_agree: "He leído y acepto los",
reg_agree_tos: "Términos de servicio",
reg_agree_pp: "Política de privacidad",
reg_submit: "Regístrate ahora",
toast_tos: "Términos de servicio próximamente",
toast_pp: "Política de privacidad próximamente",
toast_register_ok: "¡Registro exitoso! Bienvenido a Chongchong Global"
}
};
function applyLanguage(lang) {
if (!i18n[lang]) lang = 'zh';
currentLang = lang;
const langAttr = lang === 'zh' ? 'zh-CN' : (lang === 'es' ? 'es-MX' : 'en');
document.documentElement.setAttribute('lang', langAttr);
document.querySelectorAll('[data-i18n]').forEach(el => {
const k = el.getAttribute('data-i18n');
const v = i18n[lang][k];
if (v !== undefined) { if (v.indexOf('<br>') !== -1) el.innerHTML = v; else el.textContent = v; }
});
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
const k = el.getAttribute('data-i18n-ph');
if (i18n[lang][k] !== undefined) el.setAttribute('placeholder', i18n[lang][k]);
});
document.querySelectorAll('[data-lang]').forEach(b => {
b.classList.toggle('active', b.getAttribute('data-lang') === lang);
});
try { localStorage.setItem('cc_lang', lang); } catch (e) {}
}
document.querySelectorAll('#langSwitcher [data-lang]').forEach(b => {
b.addEventListener('click', () => applyLanguage(b.getAttribute('data-lang')));
});
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
toastMessage.textContent = message;
toast.classList.remove('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.add('opacity-100', 'translate-y-0');
setTimeout(() => {
toast.classList.add('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.remove('opacity-100', 'translate-y-0');
}, 3000);
}
function updateAuthUI() {}
document.querySelectorAll('.toggle-password').forEach(button => {
button.addEventListener('click', function() {
const input = this.previousElementSibling;
const icon = this.querySelector('i');
if (input.type === 'password') { input.type = 'text'; icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); }
else { input.type = 'password'; icon.classList.remove('fa-eye-slash'); icon.classList.add('fa-eye'); }
});
});
document.getElementById('registerForm').addEventListener('submit', function(e) {
e.preventDefault();
showToast(t('toast_register_ok'));
setTimeout(() => window.location.href = 'workbench.html', 900);
});
applyLanguage(currentLang);
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

File diff suppressed because it is too large Load Diff
+210
View File
@@ -0,0 +1,210 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 680 1170" width="100%" role="img" font-family="'PingFang SC','Microsoft YaHei','Hiragino Sans GB',sans-serif">
<title>头程与尾程物流流程图</title>
<desc>头程三大节点(下单、到仓、出仓)经装船发运进入尾程五大节点(到港前、到港、到仓、出仓、签收)的完整流程,左右两栏结构</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</marker>
</defs>
<line x1="340" y1="12" x2="340" y2="1160" stroke="#5F5E5A" stroke-width="1" stroke-dasharray="4 4" opacity="0.5"/>
<rect x="20" y="20" width="310" height="40" rx="8" fill="#185FA5"/>
<text x="175" y="40" text-anchor="middle" dominant-baseline="central" font-size="14" font-weight="500" fill="#FFFFFF">头程物流</text>
<rect x="350" y="20" width="320" height="40" rx="8" fill="#444441"/>
<text x="510" y="40" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#F1EFE8">尾程物流(装船发运后)</text>
<line x1="332" y1="40" x2="347" y2="40" stroke="#7b8190" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="20" y="72" width="310" height="30" rx="6" fill="#185FA5"/>
<text x="175" y="87" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#E6F1FB">一、下单</text>
<g stroke="#85B7EB" stroke-width="1">
<line x1="175" y1="150" x2="175" y2="158"/>
<line x1="175" y1="198" x2="175" y2="206"/>
<line x1="175" y1="246" x2="175" y2="254"/>
</g>
<g>
<rect x="30" y="110" width="290" height="40" rx="8" fill="#042C53" stroke="#85B7EB" stroke-width="0.5"/>
<circle cx="52" cy="130" r="13" fill="#185FA5"/><text x="52" y="130" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E6F1FB">1</text>
<text x="74" y="130" dominant-baseline="central" font-size="12" fill="#B5D4F4">客户下单</text>
<rect x="30" y="158" width="290" height="40" rx="8" fill="#042C53" stroke="#85B7EB" stroke-width="0.5"/>
<circle cx="52" cy="178" r="13" fill="#185FA5"/><text x="52" y="178" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E6F1FB">2</text>
<text x="74" y="178" dominant-baseline="central" font-size="12" fill="#B5D4F4">委托我们下单</text>
<rect x="30" y="206" width="290" height="40" rx="8" fill="#042C53" stroke="#85B7EB" stroke-width="0.5"/>
<circle cx="52" cy="226" r="13" fill="#185FA5"/><text x="52" y="226" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E6F1FB">3</text>
<text x="74" y="226" dominant-baseline="central" font-size="12" fill="#B5D4F4">快速下单(只有唛头)</text>
<rect x="30" y="254" width="290" height="40" rx="8" fill="#042C53" stroke="#85B7EB" stroke-width="0.5"/>
<circle cx="52" cy="274" r="13" fill="#185FA5"/><text x="52" y="274" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E6F1FB">4</text>
<text x="74" y="274" dominant-baseline="central" font-size="12" fill="#B5D4F4">换标下单(中转、退货)</text>
</g>
<rect x="20" y="314" width="310" height="30" rx="6" fill="#3B6D11"/>
<text x="175" y="329" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#EAF3DE">二、到仓</text>
<g stroke="#97C459" stroke-width="1">
<line x1="175" y1="392" x2="175" y2="400"/>
<line x1="175" y1="440" x2="175" y2="448"/>
<line x1="175" y1="488" x2="175" y2="496"/>
<line x1="175" y1="536" x2="175" y2="544"/>
</g>
<g>
<rect x="30" y="352" width="290" height="40" rx="8" fill="#173404" stroke="#97C459" stroke-width="0.5"/>
<circle cx="52" cy="372" r="13" fill="#3B6D11"/><text x="52" y="372" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EAF3DE">1</text>
<text x="74" y="372" dominant-baseline="central" font-size="12" fill="#C0DD97">预约取货</text>
<rect x="30" y="400" width="290" height="40" rx="8" fill="#173404" stroke="#97C459" stroke-width="0.5"/>
<circle cx="52" cy="420" r="13" fill="#3B6D11"/><text x="52" y="420" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EAF3DE">2</text>
<text x="74" y="420" dominant-baseline="central" font-size="12" fill="#C0DD97">送货上门</text>
<rect x="30" y="448" width="290" height="40" rx="8" fill="#173404" stroke="#97C459" stroke-width="0.5"/>
<circle cx="52" cy="468" r="13" fill="#3B6D11"/><text x="52" y="468" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EAF3DE">3</text>
<text x="74" y="468" dominant-baseline="central" font-size="12" fill="#C0DD97">入库测量(称重计费)</text>
<rect x="30" y="496" width="290" height="40" rx="8" fill="#173404" stroke="#97C459" stroke-width="0.5"/>
<circle cx="52" cy="516" r="13" fill="#3B6D11"/><text x="52" y="516" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EAF3DE">4</text>
<text x="74" y="516" dominant-baseline="central" font-size="12" fill="#C0DD97">调整差异核对</text>
<rect x="30" y="544" width="290" height="40" rx="8" fill="#173404" stroke="#97C459" stroke-width="0.5"/>
<circle cx="52" cy="564" r="13" fill="#3B6D11"/><text x="52" y="564" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EAF3DE">5</text>
<text x="74" y="564" dominant-baseline="central" font-size="12" fill="#C0DD97">仓库作业(指定库位)</text>
</g>
<rect x="20" y="604" width="310" height="30" rx="6" fill="#BA7517"/>
<text x="175" y="619" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#FAEEDA">三、出仓</text>
<g stroke="#EF9F27" stroke-width="1">
<line x1="175" y1="682" x2="175" y2="690"/>
<line x1="175" y1="730" x2="175" y2="738"/>
<line x1="175" y1="778" x2="175" y2="786"/>
<line x1="175" y1="826" x2="175" y2="834"/>
<line x1="175" y1="874" x2="175" y2="882"/>
<line x1="175" y1="922" x2="175" y2="930"/>
<line x1="175" y1="970" x2="175" y2="978"/>
<line x1="175" y1="1018" x2="175" y2="1026"/>
<line x1="175" y1="1066" x2="175" y2="1074"/>
</g>
<g>
<rect x="30" y="642" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="662" r="13" fill="#BA7517"/><text x="52" y="662" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">1</text>
<text x="74" y="662" dominant-baseline="central" font-size="12" fill="#FAC775">智能排柜</text>
<rect x="30" y="690" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="710" r="13" fill="#BA7517"/><text x="52" y="710" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">2</text>
<text x="74" y="710" dominant-baseline="central" font-size="12" fill="#FAC775">订舱</text>
<rect x="30" y="738" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="758" r="13" fill="#BA7517"/><text x="52" y="758" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">3</text>
<text x="74" y="758" dominant-baseline="central" font-size="12" fill="#FAC775">预约托车</text>
<rect x="30" y="786" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="806" r="13" fill="#BA7517"/><text x="52" y="806" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">4</text>
<text x="74" y="806" dominant-baseline="central" font-size="12" fill="#FAC775">PDA拣货</text>
<rect x="30" y="834" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="854" r="13" fill="#BA7517"/><text x="52" y="854" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">5</text>
<text x="74" y="854" dominant-baseline="central" font-size="12" fill="#FAC775">拍货柜及铅封照上传</text>
<rect x="30" y="882" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="902" r="13" fill="#BA7517"/><text x="52" y="902" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">6</text>
<text x="74" y="902" dominant-baseline="central" font-size="12" fill="#FAC775">客户上传报关资料</text>
<rect x="30" y="930" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="950" r="13" fill="#BA7517"/><text x="52" y="950" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">7</text>
<text x="74" y="950" dominant-baseline="central" font-size="12" fill="#FAC775">整理给到报关代理报关</text>
<rect x="30" y="978" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="998" r="13" fill="#BA7517"/><text x="52" y="998" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">8</text>
<text x="74" y="998" dominant-baseline="central" font-size="12" fill="#FAC775">回执上传到系统供客户下载</text>
<rect x="30" y="1026" width="290" height="40" rx="8" fill="#412402" stroke="#EF9F27" stroke-width="0.5"/>
<circle cx="52" cy="1046" r="13" fill="#BA7517"/><text x="52" y="1046" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FAEEDA">9</text>
<text x="74" y="1046" dominant-baseline="central" font-size="12" fill="#FAC775">查港务信息(预计开船、到港等)</text>
</g>
<rect x="60" y="1074" width="230" height="28" rx="14" fill="none" stroke="#EF9F27" stroke-width="1"/>
<text x="175" y="1088" text-anchor="middle" dominant-baseline="central" font-size="13" fill="#EF9F27">出仓完成 · 装船发运</text>
<rect x="350" y="72" width="320" height="30" rx="6" fill="#0F6E56"/>
<text x="510" y="87" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#E1F5EE">一、到港前(船在海上)</text>
<g stroke="#5DCAA5" stroke-width="1">
<line x1="510" y1="150" x2="510" y2="158"/>
<line x1="510" y1="198" x2="510" y2="206"/>
<line x1="510" y1="246" x2="510" y2="254"/>
</g>
<g>
<rect x="360" y="110" width="300" height="40" rx="8" fill="#04342C" stroke="#5DCAA5" stroke-width="0.5"/>
<circle cx="382" cy="130" r="13" fill="#0F6E56"/><text x="382" y="130" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E1F5EE">1</text>
<text x="404" y="130" dominant-baseline="central" font-size="12" fill="#E1F5EE">FBA 仓预约</text>
<rect x="360" y="158" width="300" height="40" rx="8" fill="#04342C" stroke="#5DCAA5" stroke-width="0.5"/>
<circle cx="382" cy="178" r="13" fill="#0F6E56"/><text x="382" y="178" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E1F5EE">2</text>
<text x="404" y="178" dominant-baseline="central" font-size="12" fill="#E1F5EE">BOL 预清货(时间、费用、目的仓)</text>
<rect x="360" y="206" width="300" height="40" rx="8" fill="#04342C" stroke="#5DCAA5" stroke-width="0.5"/>
<circle cx="382" cy="226" r="13" fill="#0F6E56"/><text x="382" y="226" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E1F5EE">3</text>
<text x="404" y="226" dominant-baseline="central" font-size="12" fill="#E1F5EE">清关资料上传到对应的货柜</text>
<rect x="360" y="254" width="300" height="40" rx="8" fill="#04342C" stroke="#5DCAA5" stroke-width="0.5"/>
<circle cx="382" cy="274" r="13" fill="#0F6E56"/><text x="382" y="274" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#E1F5EE">4</text>
<text x="404" y="274" dominant-baseline="central" font-size="12" fill="#E1F5EE">明细备注货物中转等</text>
</g>
<rect x="350" y="314" width="320" height="30" rx="6" fill="#A32D2D"/>
<text x="510" y="329" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#FCEBEB">二、到港</text>
<g stroke="#F09595" stroke-width="1">
<line x1="510" y1="392" x2="510" y2="400"/>
</g>
<g>
<rect x="360" y="352" width="300" height="40" rx="8" fill="#501313" stroke="#F09595" stroke-width="0.5"/>
<circle cx="382" cy="372" r="13" fill="#A32D2D"/><text x="382" y="372" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FCEBEB">1</text>
<text x="404" y="372" dominant-baseline="central" font-size="12" fill="#FCEBEB">清关放行</text>
<rect x="360" y="400" width="300" height="40" rx="8" fill="#501313" stroke="#F09595" stroke-width="0.5"/>
<circle cx="382" cy="420" r="13" fill="#A32D2D"/><text x="382" y="420" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FCEBEB">2</text>
<text x="404" y="420" dominant-baseline="central" font-size="12" fill="#FCEBEB">DO或PU邮发并通知码头车队提柜</text>
</g>
<rect x="350" y="460" width="320" height="30" rx="6" fill="#534AB7"/>
<text x="510" y="475" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#EEEDFE">三、到仓</text>
<g stroke="#AFA9EC" stroke-width="1">
<line x1="510" y1="538" x2="510" y2="546"/>
<line x1="510" y1="586" x2="510" y2="594"/>
</g>
<g>
<rect x="360" y="498" width="300" height="40" rx="8" fill="#26215C" stroke="#AFA9EC" stroke-width="0.5"/>
<circle cx="382" cy="518" r="13" fill="#534AB7"/><text x="382" y="518" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EEEDFE">1</text>
<text x="404" y="518" dominant-baseline="central" font-size="12" fill="#EEEDFE">开柜拍照比对</text>
<rect x="360" y="546" width="300" height="40" rx="8" fill="#26215C" stroke="#AFA9EC" stroke-width="0.5"/>
<circle cx="382" cy="566" r="13" fill="#534AB7"/><text x="382" y="566" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EEEDFE">2</text>
<text x="404" y="566" dominant-baseline="central" font-size="12" fill="#EEEDFE">根据 PDA 需求打托作业</text>
<rect x="360" y="594" width="300" height="40" rx="8" fill="#26215C" stroke="#AFA9EC" stroke-width="0.5"/>
<circle cx="382" cy="614" r="13" fill="#534AB7"/><text x="382" y="614" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#EEEDFE">3</text>
<text x="404" y="614" dominant-baseline="central" font-size="12" fill="#EEEDFE">派送车队筛选预约</text>
</g>
<rect x="350" y="654" width="320" height="30" rx="6" fill="#993556"/>
<text x="510" y="669" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#FBEAF0">四、出仓</text>
<g stroke="#ED93B1" stroke-width="1">
<line x1="510" y1="730" x2="510" y2="738"/>
<line x1="510" y1="778" x2="510" y2="786"/>
<line x1="510" y1="826" x2="510" y2="834"/>
<line x1="510" y1="874" x2="510" y2="882"/>
</g>
<g>
<rect x="360" y="692" width="300" height="40" rx="8" fill="#4B1528" stroke="#ED93B1" stroke-width="0.5"/>
<circle cx="382" cy="712" r="13" fill="#993556"/><text x="382" y="712" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FBEAF0">1</text>
<text x="404" y="712" dominant-baseline="central" font-size="12" fill="#FBEAF0">预排车转 BOL 送货</text>
<rect x="360" y="740" width="300" height="40" rx="8" fill="#4B1528" stroke="#ED93B1" stroke-width="0.5"/>
<circle cx="382" cy="760" r="13" fill="#993556"/><text x="382" y="760" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FBEAF0">2</text>
<text x="404" y="760" dominant-baseline="central" font-size="12" fill="#FBEAF0">PDA拣货装车</text>
<rect x="360" y="788" width="300" height="40" rx="8" fill="#4B1528" stroke="#ED93B1" stroke-width="0.5"/>
<circle cx="382" cy="808" r="13" fill="#993556"/><text x="382" y="808" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FBEAF0">3</text>
<text x="404" y="808" dominant-baseline="central" font-size="12" fill="#FBEAF0">派送车队到仓装车</text>
<rect x="360" y="836" width="300" height="40" rx="8" fill="#4B1528" stroke="#ED93B1" stroke-width="0.5"/>
<circle cx="382" cy="856" r="13" fill="#993556"/><text x="382" y="856" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FBEAF0">4</text>
<text x="404" y="856" dominant-baseline="central" font-size="12" fill="#FBEAF0">整柜派送</text>
<rect x="360" y="884" width="300" height="40" rx="8" fill="#4B1528" stroke="#ED93B1" stroke-width="0.5"/>
<circle cx="382" cy="904" r="13" fill="#993556"/><text x="382" y="904" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#FBEAF0">5</text>
<text x="404" y="904" dominant-baseline="central" font-size="12" fill="#FBEAF0">自提出仓(一件代发)</text>
</g>
<rect x="350" y="944" width="320" height="30" rx="6" fill="#B58900"/>
<text x="510" y="959" text-anchor="middle" dominant-baseline="central" font-size="13" font-weight="500" fill="#F5E6B8">五、签收</text>
<g stroke="#D9B94A" stroke-width="1">
<line x1="510" y1="1020" x2="510" y2="1028"/>
<line x1="510" y1="1068" x2="510" y2="1076"/>
</g>
<g>
<rect x="360" y="982" width="300" height="40" rx="8" fill="#3A2E00" stroke="#D9B94A" stroke-width="0.5"/>
<circle cx="382" cy="1002" r="13" fill="#B58900"/><text x="382" y="1002" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#F5E6B8">1</text>
<text x="404" y="1002" dominant-baseline="central" font-size="12" fill="#F5E6B8">私人仓签收回执上传</text>
<rect x="360" y="1030" width="300" height="40" rx="8" fill="#3A2E00" stroke="#D9B94A" stroke-width="0.5"/>
<circle cx="382" cy="1050" r="13" fill="#B58900"/><text x="382" y="1050" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#F5E6B8">2</text>
<text x="404" y="1050" dominant-baseline="central" font-size="12" fill="#F5E6B8">FBA仓签收回执上传</text>
<rect x="360" y="1078" width="300" height="40" rx="8" fill="#3A2E00" stroke="#D9B94A" stroke-width="0.5"/>
<circle cx="382" cy="1098" r="13" fill="#B58900"/><text x="382" y="1098" text-anchor="middle" dominant-baseline="central" font-size="11" font-weight="500" fill="#F5E6B8">3</text>
<text x="404" y="1098" dominant-baseline="central" font-size="12" fill="#F5E6B8">送仓异常</text>
</g>
<rect x="390" y="1126" width="240" height="28" rx="14" fill="none" stroke="#D9B94A" stroke-width="1"/>
<text x="510" y="1140" text-anchor="middle" dominant-baseline="central" font-size="13" fill="#D9B94A">签收完成</text>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>%s</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700;900&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { theme: { extend: { colors: { brand: { green:'#4CAF50', greenDark:'#2E7D32', blue:'#1565C0', blueDark:'#0D47A1', teal:'#00838F', light:'#F0F7FF', dark:'#0A1628' } }, fontFamily: { sans:['Inter','Noto Sans SC','system-ui','sans-serif'] } } } };
</script>
<style>
:root { --primary:#1565C0; --primary-dark:#0D47A1; --accent:#4CAF50; --accent-dark:#2E7D32; }
* { scroll-behavior:smooth; }
body { font-family:'Inter','Noto Sans SC',system-ui,sans-serif; overflow-x:hidden; }
.gradient-text { background:linear-gradient(135deg,#1565C0 0%,#4CAF50 100%); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
.gradient-bg { background:linear-gradient(135deg,#0A1628 0%,#1565C0 50%,#00838F 100%); }
.btn-primary { background:linear-gradient(135deg,#1565C0 0%,#0D47A1 100%); transition:all .3s ease; }
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(21,101,192,.35); }
.btn-accent { background:linear-gradient(135deg,#4CAF50 0%,#2E7D32 100%); transition:all .3s ease; }
.btn-accent:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(76,175,80,.35); }
.input-field { transition:all .3s ease; }
.input-field:focus { border-color:#1565C0; box-shadow:0 0 0 4px rgba(21,101,192,.1); }
.auth-logo { display:block; filter:brightness(0) saturate(100%) invert(20%) sepia(84%) saturate(1926%) hue-rotate(202deg) brightness(94%) contrast(93%); }
.lang-switcher { display:flex; align-items:center; background:rgba(21,101,192,.08); border-radius:9999px; padding:3px; border:1px solid rgba(21,101,192,.15); }
.lang-switcher button { font-size:12px; font-weight:600; padding:4px 9px; border-radius:9999px; color:#0A1628; transition:all .25s ease; white-space:nowrap; }
.lang-switcher button:hover { color:#1565C0; }
.lang-switcher button.active { background:#1565C0; color:#fff; }
</style>
</head>
<body class="text-gray-800 antialiased bg-gray-50">
<!-- 顶部栏 -->
<header class="fixed top-0 inset-x-0 z-50 bg-white/95 backdrop-blur border-b border-gray-100">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<a href="index.html" class="flex items-center" aria-label="返回官网">
<img src="assets/logo.png" alt="柏悦物流" class="auth-logo" style="width:161px;height:60px;object-fit:contain;">
</a>
<div class="lang-switcher" id="langSwitcher">
<button data-lang="zh" class="active" title="中文">中</button>
<button data-lang="en" title="English">EN</button>
<button data-lang="es" title="Español (México)">🇲🇽</button>
</div>
</div>
</header>
<section id="loginSection" class="min-h-screen pt-24 pb-12 bg-gray-50 flex items-center">
<div class="w-full max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-3xl shadow-2xl overflow-hidden">
<div class="grid lg:grid-cols-2">
<!-- 左侧视觉 -->
<div class="hidden lg:block relative">
<img src="https://images.unsplash.com/photo-1494412574643-ff11b0a5c1c3?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80" alt="物流" class="absolute inset-0 w-full h-full object-cover">
<div class="absolute inset-0 gradient-bg opacity-90"></div>
<div class="relative z-10 p-12 h-full flex flex-col justify-between text-white">
<div>
<img src="assets/logo.png" alt="虫虫出海" style="width:161px;height:60px;object-fit:contain;">
<h2 class="text-3xl font-bold mb-4" data-i18n="login_welcome">欢迎回来</h2>
<p class="text-white/80" data-i18n="login_desc">登录虫虫出海平台,实时追踪货物轨迹,管理订单与库存。</p>
</div>
<div class="space-y-4">
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="login_feat1">全程可视化追踪</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="login_feat2">智能订单管理</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="login_feat3">在线询价下单</span>
</div>
</div>
</div>
</div>
<!-- 右侧表单 -->
<div class="p-8 sm:p-12 lg:p-16">
<div class="max-w-md mx-auto">
<h2 class="text-3xl font-bold text-gray-900 mb-2" data-i18n="login_title">账号登录</h2>
<p class="text-gray-600 mb-8"><span data-i18n="login_no_account">还没有账号?</span><button onclick="window.location.href='register.html'" class="text-brand-blue font-semibold hover:underline" data-i18n="login_register_link">立即注册</button></p>
<form id="loginForm" class="space-y-5">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="login_account_label">邮箱 / 手机号</label>
<div class="relative">
<i class="fas fa-user absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="text" name="account" required placeholder="请输入邮箱或手机号" data-i18n-ph="login_account_ph" class="input-field w-full pl-11 pr-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="login_password_label">密码</label>
<div class="relative">
<i class="fas fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="password" name="password" required placeholder="请输入密码" data-i18n-ph="login_password_ph" class="input-field w-full pl-11 pr-12 py-3.5 border border-gray-200 rounded-xl outline-none">
<button type="button" class="toggle-password absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600">
<i class="fas fa-eye"></i>
</button>
</div>
</div>
<div class="flex items-center justify-between text-sm">
<label class="flex items-center text-gray-600 cursor-pointer">
<input type="checkbox" class="w-4 h-4 text-brand-blue rounded border-gray-300 mr-2">
<span data-i18n="login_remember">记住我</span>
</label>
<button type="button" onclick="showToast(t('toast_resetpw'))" class="text-brand-blue hover:underline" data-i18n="login_forgot">忘记密码?</button>
</div>
<button type="submit" class="btn-primary w-full text-white font-bold py-4 rounded-xl text-lg" data-i18n="login_submit">
登 录
</button>
</form>
<div class="mt-8">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-200"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white text-gray-500" data-i18n="login_other">其他方式登录</span>
</div>
</div>
<div class="flex justify-center space-x-4 mt-6">
<button onclick="showToast('微信登录即将上线')" class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-green-600 hover:bg-green-50 transition-colors">
<i class="fab fa-weixin text-xl"></i>
</button>
<button onclick="showToast('企业微信登录即将上线')" class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-blue-600 hover:bg-blue-50 transition-colors">
<i class="fas fa-briefcase text-xl"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section> <!-- Toast 提示 -->
<div id="toast" class="fixed top-24 left-1/2 -translate-x-1/2 z-[60] opacity-0 pointer-events-none transition-all duration-300 transform -translate-y-4">
<div class="bg-gray-900 text-white px-6 py-3 rounded-full shadow-2xl flex items-center space-x-2">
<i class="fas fa-info-circle text-brand-green"></i>
<span id="toastMessage">提示信息</span>
</div>
</div>
<script>
let currentLang = localStorage.getItem('cc_lang') || 'zh';
function t(key) {
return (i18n[currentLang] && i18n[currentLang][key] !== undefined) ? i18n[currentLang][key] : key;
}
const i18n = {
zh: {
login_welcome: "欢迎回来",
login_desc: "登录虫虫出海平台,实时追踪货物轨迹,管理订单与库存。",
login_feat1: "全程可视化追踪",
login_feat2: "智能订单管理",
login_feat3: "在线询价下单",
login_title: "账号登录",
login_no_account: "还没有账号?",
login_register_link: "立即注册",
login_account_label: "邮箱 / 手机号",
login_account_ph: "请输入邮箱或手机号",
login_password_label: "密码",
login_password_ph: "请输入密码",
login_remember: "记住我",
login_forgot: "忘记密码?",
login_submit: "登 录",
login_other: "其他方式登录",
toast_resetpw: "请联系客服重置密码",
toast_login_ok: "登录成功!欢迎回来"
},
en: {
login_welcome: "Welcome Back",
login_desc: "Log in to track shipments in real time and manage orders and inventory.",
login_feat1: "Full Visual Tracking",
login_feat2: "Smart Order Management",
login_feat3: "Online Quoting & Ordering",
login_title: "Account Login",
login_no_account: "No account yet?",
login_register_link: "Sign Up Now",
login_account_label: "Email / Phone",
login_account_ph: "Enter email or phone",
login_password_label: "Password",
login_password_ph: "Enter password",
login_remember: "Remember Me",
login_forgot: "Forgot Password?",
login_submit: "Log In",
login_other: "Other Sign-In Methods",
toast_resetpw: "Please contact support to reset your password",
toast_login_ok: "Login successful! Welcome back"
},
es: {
login_welcome: "Bienvenido de nuevo",
login_desc: "Inicia sesión para rastrear envíos en tiempo real y gestionar pedidos e inventario.",
login_feat1: "Seguimiento visual completo",
login_feat2: "Gestión inteligente de pedidos",
login_feat3: "Cotización y pedidos en línea",
login_title: "Inicio de sesión",
login_no_account: "¿Aún no tienes cuenta?",
login_register_link: "Regístrate ahora",
login_account_label: "Correo / Teléfono",
login_account_ph: "Ingresa correo o teléfono",
login_password_label: "Contraseña",
login_password_ph: "Ingresa tu contraseña",
login_remember: "Recuérdame",
login_forgot: "¿Olvidó su contraseña?",
login_submit: "Iniciar sesión",
login_other: "Otros métodos de acceso",
toast_resetpw: "Contacta a soporte para restablecer tu contraseña",
toast_login_ok: "¡Inicio de sesión exitoso! Bienvenido"
}
};
function applyLanguage(lang) {
if (!i18n[lang]) lang = 'zh';
currentLang = lang;
const langAttr = lang === 'zh' ? 'zh-CN' : (lang === 'es' ? 'es-MX' : 'en');
document.documentElement.setAttribute('lang', langAttr);
document.querySelectorAll('[data-i18n]').forEach(el => {
const k = el.getAttribute('data-i18n');
const v = i18n[lang][k];
if (v !== undefined) { if (v.indexOf('<br>') !== -1) el.innerHTML = v; else el.textContent = v; }
});
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
const k = el.getAttribute('data-i18n-ph');
if (i18n[lang][k] !== undefined) el.setAttribute('placeholder', i18n[lang][k]);
});
document.querySelectorAll('[data-lang]').forEach(b => {
b.classList.toggle('active', b.getAttribute('data-lang') === lang);
});
try { localStorage.setItem('cc_lang', lang); } catch (e) {}
}
document.querySelectorAll('#langSwitcher [data-lang]').forEach(b => {
b.addEventListener('click', () => applyLanguage(b.getAttribute('data-lang')));
});
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
toastMessage.textContent = message;
toast.classList.remove('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.add('opacity-100', 'translate-y-0');
setTimeout(() => {
toast.classList.add('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.remove('opacity-100', 'translate-y-0');
}, 3000);
}
function updateAuthUI() {}
document.querySelectorAll('.toggle-password').forEach(button => {
button.addEventListener('click', function() {
const input = this.previousElementSibling;
const icon = this.querySelector('i');
if (input.type === 'password') { input.type = 'text'; icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); }
else { input.type = 'password'; icon.classList.remove('fa-eye-slash'); icon.classList.add('fa-eye'); }
});
});
document.getElementById('loginForm').addEventListener('submit', function(e) {
e.preventDefault();
showToast(t('toast_login_ok'));
setTimeout(() => window.location.href = 'workbench.html', 900);
});
applyLanguage(currentLang);
</script>
</body>
</html>
+286
View File
@@ -0,0 +1,286 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>%s</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700;900&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { theme: { extend: { colors: { brand: { green:'#4CAF50', greenDark:'#2E7D32', blue:'#1565C0', blueDark:'#0D47A1', teal:'#00838F', light:'#F0F7FF', dark:'#0A1628' } }, fontFamily: { sans:['Inter','Noto Sans SC','system-ui','sans-serif'] } } } };
</script>
<style>
:root { --primary:#1565C0; --primary-dark:#0D47A1; --accent:#4CAF50; --accent-dark:#2E7D32; }
* { scroll-behavior:smooth; }
body { font-family:'Inter','Noto Sans SC',system-ui,sans-serif; overflow-x:hidden; }
.gradient-text { background:linear-gradient(135deg,#1565C0 0%,#4CAF50 100%); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
.gradient-bg { background:linear-gradient(135deg,#0A1628 0%,#1565C0 50%,#00838F 100%); }
.btn-primary { background:linear-gradient(135deg,#1565C0 0%,#0D47A1 100%); transition:all .3s ease; }
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(21,101,192,.35); }
.btn-accent { background:linear-gradient(135deg,#4CAF50 0%,#2E7D32 100%); transition:all .3s ease; }
.btn-accent:hover { transform:translateY(-2px); box-shadow:0 10px 30px rgba(76,175,80,.35); }
.input-field { transition:all .3s ease; }
.input-field:focus { border-color:#1565C0; box-shadow:0 0 0 4px rgba(21,101,192,.1); }
.auth-logo { display:block; filter:brightness(0) saturate(100%) invert(20%) sepia(84%) saturate(1926%) hue-rotate(202deg) brightness(94%) contrast(93%); }
.lang-switcher { display:flex; align-items:center; background:rgba(21,101,192,.08); border-radius:9999px; padding:3px; border:1px solid rgba(21,101,192,.15); }
.lang-switcher button { font-size:12px; font-weight:600; padding:4px 9px; border-radius:9999px; color:#0A1628; transition:all .25s ease; white-space:nowrap; }
.lang-switcher button:hover { color:#1565C0; }
.lang-switcher button.active { background:#1565C0; color:#fff; }
</style>
</head>
<body class="text-gray-800 antialiased bg-gray-50">
<!-- 顶部栏 -->
<header class="fixed top-0 inset-x-0 z-50 bg-white/95 backdrop-blur border-b border-gray-100">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<a href="index.html" class="flex items-center" aria-label="返回官网">
<img src="assets/logo.png" alt="柏悦物流" class="auth-logo" style="width:161px;height:60px;object-fit:contain;">
</a>
<div class="lang-switcher" id="langSwitcher">
<button data-lang="zh" class="active" title="中文">中</button>
<button data-lang="en" title="English">EN</button>
<button data-lang="es" title="Español (México)">🇲🇽</button>
</div>
</div>
</header>
<section id="registerSection" class="min-h-screen pt-24 pb-12 bg-gray-50 flex items-center">
<div class="w-full max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-3xl shadow-2xl overflow-hidden">
<div class="grid lg:grid-cols-2">
<!-- 左侧视觉 -->
<div class="hidden lg:block relative">
<img src="https://images.unsplash.com/photo-1566576912321-d58ddd7a6088?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80" alt="物流仓储" class="absolute inset-0 w-full h-full object-cover">
<div class="absolute inset-0 gradient-bg opacity-90"></div>
<div class="relative z-10 p-12 h-full flex flex-col justify-between text-white">
<div>
<img src="assets/logo.png" alt="虫虫出海" style="width:161px;height:60px;object-fit:contain;">
<h2 class="text-3xl font-bold mb-4" data-i18n="reg_welcome">加入我们</h2>
<p class="text-white/80" data-i18n="reg_welcome_desc">注册虫虫出海企业账号,开启高效跨境物流体验。</p>
</div>
<div class="space-y-4">
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="reg_feat1">新用户专属优惠</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="reg_feat2">免费获取物流方案</span>
</div>
<div class="flex items-center space-x-3">
<i class="fas fa-check-circle text-brand-green"></i>
<span data-i18n="reg_feat3">专属客户经理对接</span>
</div>
</div>
</div>
</div>
<!-- 右侧表单 -->
<div class="p-8 sm:p-12 lg:p-16">
<div class="max-w-md mx-auto">
<h2 class="text-3xl font-bold text-gray-900 mb-2" data-i18n="reg_title">企业注册</h2>
<p class="text-gray-600 mb-8"><span data-i18n="reg_have_account">已有账号?</span><button onclick="window.location.href='login.html'" class="text-brand-blue font-semibold hover:underline" data-i18n="reg_login_link">立即登录</button></p>
<form id="registerForm" class="space-y-5">
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_company_label">企业名称</label>
<input type="text" name="company" required placeholder="请输入企业名称" data-i18n-ph="reg_company_ph" class="input-field w-full px-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_contact_label">联系人</label>
<input type="text" name="contact" required placeholder="请输入联系人姓名" data-i18n-ph="reg_contact_ph" class="input-field w-full px-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_email_label">邮箱</label>
<div class="relative">
<i class="fas fa-envelope absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="email" name="email" required placeholder="请输入企业邮箱" data-i18n-ph="reg_email_ph" class="input-field w-full pl-11 pr-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_phone_label">手机号</label>
<div class="relative">
<i class="fas fa-phone absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="tel" name="phone" required placeholder="请输入手机号" data-i18n-ph="reg_phone_ph" class="input-field w-full pl-11 pr-4 py-3.5 border border-gray-200 rounded-xl outline-none">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2" data-i18n="reg_password_label">密码</label>
<div class="relative">
<i class="fas fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="password" name="password" required placeholder="请设置8-20位密码" data-i18n-ph="reg_password_ph" class="input-field w-full pl-11 pr-12 py-3.5 border border-gray-200 rounded-xl outline-none">
<button type="button" class="toggle-password absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600">
<i class="fas fa-eye"></i>
</button>
</div>
</div>
<div class="flex items-start">
<input type="checkbox" id="agree" required class="w-4 h-4 text-brand-blue rounded border-gray-300 mt-1 mr-2">
<label for="agree" class="text-sm text-gray-600">
<span data-i18n="reg_agree">我已阅读并同意</span> <button type="button" onclick="showToast(t('toast_tos'))" class="text-brand-blue hover:underline" data-i18n="reg_agree_tos">《用户服务协议》</button> 和 <button type="button" onclick="showToast(t('toast_pp'))" class="text-brand-blue hover:underline" data-i18n="reg_agree_pp">《隐私政策》</button>
</label>
</div>
<button type="submit" class="btn-accent w-full text-white font-bold py-4 rounded-xl text-lg" data-i18n="reg_submit">
立即注册
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</section> <!-- Toast 提示 -->
<div id="toast" class="fixed top-24 left-1/2 -translate-x-1/2 z-[60] opacity-0 pointer-events-none transition-all duration-300 transform -translate-y-4">
<div class="bg-gray-900 text-white px-6 py-3 rounded-full shadow-2xl flex items-center space-x-2">
<i class="fas fa-info-circle text-brand-green"></i>
<span id="toastMessage">提示信息</span>
</div>
</div>
<script>
let currentLang = localStorage.getItem('cc_lang') || 'zh';
function t(key) {
return (i18n[currentLang] && i18n[currentLang][key] !== undefined) ? i18n[currentLang][key] : key;
}
const i18n = {
zh: {
reg_welcome: "加入我们",
reg_welcome_desc: "注册虫虫出海企业账号,开启高效跨境物流体验。",
reg_feat1: "新用户专属优惠",
reg_feat2: "免费获取物流方案",
reg_feat3: "专属客户经理对接",
reg_title: "企业注册",
reg_have_account: "已有账号?",
reg_login_link: "立即登录",
reg_company_label: "企业名称",
reg_company_ph: "请输入企业名称",
reg_contact_label: "联系人",
reg_contact_ph: "请输入联系人姓名",
reg_email_label: "邮箱",
reg_email_ph: "请输入企业邮箱",
reg_phone_label: "手机号",
reg_phone_ph: "请输入手机号",
reg_password_label: "密码",
reg_password_ph: "请设置8-20位密码",
reg_agree: "我已阅读并同意",
reg_agree_tos: "《用户服务协议》",
reg_agree_pp: "《隐私政策》",
reg_submit: "立即注册",
toast_tos: "服务协议即将上线",
toast_pp: "隐私政策即将上线",
toast_register_ok: "注册成功!欢迎加入虫虫出海"
},
en: {
reg_welcome: "Join Us",
reg_welcome_desc: "Register a Chongchong Global business account and start efficient cross-border logistics.",
reg_feat1: "Exclusive New-User Offers",
reg_feat2: "Free Logistics Plan",
reg_feat3: "Dedicated Account Manager",
reg_title: "Business Registration",
reg_have_account: "Already have an account?",
reg_login_link: "Log In Now",
reg_company_label: "Company Name",
reg_company_ph: "Enter company name",
reg_contact_label: "Contact Person",
reg_contact_ph: "Enter contact name",
reg_email_label: "Email",
reg_email_ph: "Enter company email",
reg_phone_label: "Phone Number",
reg_phone_ph: "Enter phone number",
reg_password_label: "Password",
reg_password_ph: "Set an 8-20 char password",
reg_agree: "I have read and agree to the",
reg_agree_tos: "User Agreement",
reg_agree_pp: "Privacy Policy",
reg_submit: "Sign Up Now",
toast_tos: "Terms of Service coming soon",
toast_pp: "Privacy Policy coming soon",
toast_register_ok: "Registration successful! Welcome to Chongchong Global"
},
es: {
reg_welcome: "Únete a nosotros",
reg_welcome_desc: "Regístrate en la cuenta empresarial de Chongchong Global y comienza una logística eficiente.",
reg_feat1: "Ofertas exclusivas para nuevos usuarios",
reg_feat2: "Plan logístico gratuito",
reg_feat3: "Gerente de cuenta dedicado",
reg_title: "Registro empresarial",
reg_have_account: "¿Ya tienes una cuenta?",
reg_login_link: "Inicia sesión ahora",
reg_company_label: "Nombre de empresa",
reg_company_ph: "Ingresa el nombre de empresa",
reg_contact_label: "Persona de contacto",
reg_contact_ph: "Ingresa el nombre de contacto",
reg_email_label: "Correo electrónico",
reg_email_ph: "Ingresa el correo empresarial",
reg_phone_label: "Número de teléfono",
reg_phone_ph: "Ingresa tu número de teléfono",
reg_password_label: "Contraseña",
reg_password_ph: "Define una contraseña de 8-20 caracteres",
reg_agree: "He leído y acepto los",
reg_agree_tos: "Términos de servicio",
reg_agree_pp: "Política de privacidad",
reg_submit: "Regístrate ahora",
toast_tos: "Términos de servicio próximamente",
toast_pp: "Política de privacidad próximamente",
toast_register_ok: "¡Registro exitoso! Bienvenido a Chongchong Global"
}
};
function applyLanguage(lang) {
if (!i18n[lang]) lang = 'zh';
currentLang = lang;
const langAttr = lang === 'zh' ? 'zh-CN' : (lang === 'es' ? 'es-MX' : 'en');
document.documentElement.setAttribute('lang', langAttr);
document.querySelectorAll('[data-i18n]').forEach(el => {
const k = el.getAttribute('data-i18n');
const v = i18n[lang][k];
if (v !== undefined) { if (v.indexOf('<br>') !== -1) el.innerHTML = v; else el.textContent = v; }
});
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
const k = el.getAttribute('data-i18n-ph');
if (i18n[lang][k] !== undefined) el.setAttribute('placeholder', i18n[lang][k]);
});
document.querySelectorAll('[data-lang]').forEach(b => {
b.classList.toggle('active', b.getAttribute('data-lang') === lang);
});
try { localStorage.setItem('cc_lang', lang); } catch (e) {}
}
document.querySelectorAll('#langSwitcher [data-lang]').forEach(b => {
b.addEventListener('click', () => applyLanguage(b.getAttribute('data-lang')));
});
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
toastMessage.textContent = message;
toast.classList.remove('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.add('opacity-100', 'translate-y-0');
setTimeout(() => {
toast.classList.add('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.remove('opacity-100', 'translate-y-0');
}, 3000);
}
function updateAuthUI() {}
document.querySelectorAll('.toggle-password').forEach(button => {
button.addEventListener('click', function() {
const input = this.previousElementSibling;
const icon = this.querySelector('i');
if (input.type === 'password') { input.type = 'text'; icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); }
else { input.type = 'password'; icon.classList.remove('fa-eye-slash'); icon.classList.add('fa-eye'); }
});
});
document.getElementById('registerForm').addEventListener('submit', function(e) {
e.preventDefault();
showToast(t('toast_register_ok'));
setTimeout(() => window.location.href = 'workbench.html', 900);
});
applyLanguage(currentLang);
</script>
</body>
</html>
+880
View File
@@ -0,0 +1,880 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虫虫出海 CHONGCHONG GLOBAL | 工作台</title>
<meta name="description" content="虫虫出海工作台 - 海外采购、美国本土卡车、美本土散板一键下单。">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
brand: {
green: '#4CAF50',
greenDark: '#2E7D32',
blue: '#1565C0',
blueDark: '#0D47A1',
teal: '#00838F',
light: '#F0F7FF',
dark: '#0A1628'
}
},
fontFamily: {
sans: ['Inter', 'Noto Sans SC', 'system-ui', 'sans-serif'],
},
boxShadow: {
'card': '0 10px 40px rgba(10, 22, 40, 0.08)',
'card-hover': '0 20px 60px rgba(10, 22, 40, 0.15)',
}
}
}
}
</script>
<style>
* { scroll-behavior: smooth; }
body { font-family: 'Inter', 'Noto Sans SC', system-ui, sans-serif; overflow-x: hidden; }
.btn-primary {
background: linear-gradient(135deg, #1565C0 0%, #0D47A1 100%);
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(21, 101, 192, 0.35);
}
.btn-accent {
background: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%);
transition: all 0.3s ease;
}
.btn-accent:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(76, 175, 80, 0.35);
}
/* 语言切换器 */
.lang-switcher {
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.15);
border-radius: 9999px;
padding: 3px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.lang-switcher button {
font-size: 12px;
font-weight: 600;
padding: 4px 9px;
border-radius: 9999px;
color: rgba(255, 255, 255, 0.9);
transition: all 0.25s ease;
white-space: nowrap;
}
.lang-switcher button:hover { color: #fff; }
.lang-switcher button.active { background: #fff; color: #0D47A1; }
/* ===== 下单工作台 Dashboard ===== */
.dash-view { animation: fadeIn 0.4s ease; }
.dash-card {
background: #fff;
border: 1px solid #eef2f7;
border-radius: 1.25rem;
box-shadow: 0 10px 40px rgba(10, 22, 40, 0.06);
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
}
.dash-card:hover {
transform: translateY(-8px);
box-shadow: 0 24px 60px rgba(10, 22, 40, 0.14);
border-color: rgba(21, 101, 192, 0.35);
}
.dash-form-input {
width: 100%;
padding: 0.75rem 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
outline: none;
font-size: 0.95rem;
color: #1f2937;
background: #fff;
transition: all 0.2s ease;
}
.dash-form-input:focus {
border-color: #1565C0;
box-shadow: 0 0 0 3px rgba(21, 101, 192, 0.12);
}
.dash-form-input::placeholder { color: #9ca3af; }
.dash-label {
display: block;
font-size: 0.875rem;
font-weight: 600;
color: #374151;
margin-bottom: 0.5rem;
}
.dash-label .req { color: #ef4444; margin-left: 2px; }
.seg-input { position: absolute; opacity: 0; width: 0; height: 0; }
.seg-pill {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 0.65rem 1.1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
cursor: pointer;
font-size: 0.9rem;
color: #475569;
background: #fff;
transition: all 0.2s ease;
user-select: none;
}
.seg-pill:hover { border-color: #cbd5e1; }
.seg-input:checked + .seg-pill {
border-color: #1565C0;
background: #EAF2FD;
color: #0D47A1;
font-weight: 600;
box-shadow: 0 0 0 1px #1565C0 inset;
}
.dash-topbar {
background: rgba(255, 255, 255, 0.92);
backdrop-filter: blur(12px);
border-bottom: 1px solid #eef2f7;
}
.dash-sidebar {
width: 250px;
flex-shrink: 0;
background: linear-gradient(180deg, #0B1F3A 0%, #0C2A52 100%);
color: #fff;
display: flex;
flex-direction: column;
position: sticky;
top: 0;
height: 100vh;
padding: 1.25rem 0.875rem;
}
.dash-sidebar-brand {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.4rem 0.55rem 1.1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
margin-bottom: 0.6rem;
}
.dash-sidebar-brand .brand-name { font-weight: 700; font-size: 1rem; line-height: 1.15; }
.dash-sidebar-brand .brand-sub { font-size: 0.62rem; letter-spacing: 0.12em; color: rgba(255, 255, 255, 0.45); }
.dash-nav { flex: 1; display: flex; flex-direction: column; gap: 0.25rem; overflow-y: auto; }
.dash-nav-group {
font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.1em;
color: rgba(255, 255, 255, 0.4); padding: 0.85rem 0.75rem 0.35rem;
}
.dash-nav-link {
display: flex; align-items: center; gap: 0.75rem;
padding: 0.72rem 0.85rem; border-radius: 0.75rem;
color: rgba(255, 255, 255, 0.72); font-size: 0.92rem; font-weight: 500;
cursor: pointer; transition: all 0.2s ease; white-space: nowrap;
}
.dash-nav-link i { width: 1.2rem; text-align: center; font-size: 0.95rem; }
.dash-nav-link:hover { background: rgba(255, 255, 255, 0.07); color: #fff; }
.dash-nav-link.active {
background: linear-gradient(90deg, #1565C0, #1E88E5); color: #fff;
box-shadow: 0 6px 18px rgba(21, 101, 192, 0.4);
}
.dash-sidebar-bottom {
border-top: 1px solid rgba(255, 255, 255, 0.08); padding-top: 0.9rem;
display: flex; flex-direction: column; gap: 0.7rem; align-items: stretch;
}
.dash-sidebar-bottom #langSwitcherDash { align-self: center; }
.dash-logout-btn {
display: flex; align-items: center; justify-content: center; gap: 0.5rem;
padding: 0.6rem; border-radius: 0.7rem; font-size: 0.88rem; font-weight: 600;
background: rgba(239, 68, 68, 0.12); color: #fca5a5; cursor: pointer;
transition: all 0.2s ease;
}
.dash-logout-btn:hover { background: rgba(239, 68, 68, 0.22); color: #fff; }
.dash-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.dash-menu-btn {
display: none; width: 2.25rem; height: 2.25rem; border-radius: 0.6rem;
align-items: center; justify-content: center; color: #374151;
background: #f1f5f9; cursor: pointer;
}
.dash-overlay { display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 45; }
.dash-overlay.show { display: block; }
.dash-right {
width: 320px; flex-shrink: 0;
background: #fff; border-left: 1px solid #eef2f7;
padding: 1.5rem 1.25rem;
position: sticky; top: 4rem; align-self: flex-start;
max-height: calc(100vh - 4rem); overflow-y: auto;
}
.dash-right-card {
background: #f8fafc; border: 1px solid #eef2f7;
border-radius: 1rem; padding: 1.25rem; margin-bottom: 1rem;
}
.dash-right-card h4 {
font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em;
text-transform: uppercase; color: #94a3b8; margin-bottom: 0.9rem;
}
.dash-account { display: flex; align-items: center; gap: 0.75rem; }
.dash-account-avatar {
width: 2.75rem; height: 2.75rem; border-radius: 0.8rem;
background: linear-gradient(135deg, #1565C0, #00BFA5); color: #fff;
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 1.1rem; flex-shrink: 0;
}
.dash-account-name { font-weight: 700; color: #0f172a; font-size: 0.95rem; line-height: 1.2; }
.dash-account-type { font-size: 0.75rem; color: #64748b; margin-top: 0.15rem; }
.dash-stat-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px dashed #e2e8f0; }
.dash-stat-row:last-child { border-bottom: none; }
.dash-stat-label { font-size: 0.85rem; color: #475569; }
.dash-stat-value { font-weight: 700; color: #0f172a; font-size: 0.95rem; }
.dash-help-item {
display: flex; align-items: center; gap: 0.6rem;
padding: 0.6rem 0.55rem; border-radius: 0.6rem; cursor: pointer;
color: #334155; font-size: 0.9rem; transition: background 0.2s, color 0.2s;
}
.dash-help-item:hover { background: #eef2f7; color: #1565C0; }
.dash-help-item i { color: #00BFA5; width: 1.15rem; text-align: center; }
.dash-tip {
background: linear-gradient(135deg, rgba(0,191,165,0.08), rgba(21,101,192,0.08));
border: 1px solid rgba(0,191,165,0.22); border-radius: 1rem;
padding: 1.1rem; font-size: 0.82rem; color: #475569; line-height: 1.65;
}
.dash-tip i { color: #00BFA5; margin-right: 0.4rem; }
.dash-empty { padding: 1rem; color: #94a3b8; }
.dash-empty i { font-size: 3rem; color: #cbd5e1; margin-bottom: 1rem; display: block; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 768px) {
.dash-sidebar {
position: fixed; left: 0; top: 0; z-index: 50;
transform: translateX(-100%); transition: transform 0.3s ease;
}
.dash-sidebar.open { transform: translateX(0); }
.dash-menu-btn { display: inline-flex; }
}
</style>
</head>
<body class="text-gray-800 antialiased bg-gray-50">
<!-- Toast 提示 -->
<div id="toast" class="fixed top-24 left-1/2 -translate-x-1/2 z-[60] opacity-0 pointer-events-none transition-all duration-300 transform -translate-y-4">
<div class="bg-gray-900 text-white px-6 py-3 rounded-full shadow-2xl flex items-center space-x-2">
<i class="fas fa-info-circle text-brand-green"></i>
<span id="toastMessage">提示信息</span>
</div>
</div>
<!-- 工作台 -->
<section id="workbench" class="min-h-screen flex">
<aside id="dashSidebar" class="dash-sidebar">
<div class="dash-sidebar-brand">
<img src="assets/logo.png" alt="虫虫出海" style="width:161px;height:60px;object-fit:contain;">
</div>
<nav class="dash-nav">
<div class="dash-nav-group" data-i18n="dash_menu_main">主导航</div>
<a class="dash-nav-link active" data-view="Home" onclick="goDash('Home')"><i class="fas fa-th-large"></i><span data-i18n="dash_menu_overview">业务总览</span></a>
<a class="dash-nav-link" data-view="Procurement" onclick="goDash('Procurement')"><i class="fas fa-shopping-cart"></i><span data-i18n="dash_menu_proc">海外采购</span></a>
<a class="dash-nav-link" data-view="Truck" onclick="goDash('Truck')"><i class="fas fa-truck-moving"></i><span data-i18n="dash_menu_truck">美国本土卡</span></a>
<a class="dash-nav-link" data-view="Pallet" onclick="goDash('Pallet')"><i class="fas fa-pallet"></i><span data-i18n="dash_menu_pallet">美本土散板</span></a>
<a class="dash-nav-link" data-view="Orders" onclick="goDash('Orders')"><i class="fas fa-clipboard-list"></i><span data-i18n="dash_menu_orders">我的订单</span></a>
</nav>
<div class="dash-sidebar-bottom">
<div id="langSwitcherDash" class="lang-switcher flex">
<button data-lang="zh">中</button>
<button data-lang="en">EN</button>
<button data-lang="es">🇲🇽</button>
</div>
<button class="dash-logout-btn" onclick="doLogout()"><i class="fas fa-sign-out-alt"></i><span data-i18n="dash_logout">退出登录</span></button>
</div>
</aside>
<!-- 移动端遮罩 -->
<div id="dashOverlay" class="dash-overlay" onclick="toggleDashSidebar()"></div>
<!-- 主内容区 -->
<div class="dash-main">
<header class="dash-topbar sticky top-0 z-30">
<div class="px-4 sm:px-6 lg:px-10 h-16 flex items-center justify-between">
<div class="flex items-center space-x-3">
<button class="dash-menu-btn" onclick="toggleDashSidebar()"><i class="fas fa-bars"></i></button>
<span class="text-sm text-gray-500" id="dashUserName">Hi, 客户</span>
</div>
<a href="index.html" class="text-sm text-gray-600 hover:text-brand-blue font-medium px-3 py-2 transition-colors" data-i18n="dash_home_link">返回官网</a>
</div>
</header>
<div class="flex flex-1 min-h-0">
<main class="flex-1 px-4 sm:px-6 lg:px-10 py-8 min-w-0">
<!-- 视图1:选择业务 -->
<div id="dashViewHome" class="dash-view">
<div class="mb-10">
<h1 class="text-3xl lg:text-4xl font-bold text-gray-900 mb-3" data-i18n="dash_welcome_title">选择业务,快速下单</h1>
<p class="text-gray-500" data-i18n="dash_welcome_sub">请选择您需要的业务类型,填写信息后提交订单,我们将尽快为您安排。</p>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div class="dash-card p-8" onclick="openOrder('Procurement')">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-brand-blue to-brand-blueDark flex items-center justify-center text-white text-2xl mb-6">
<i class="fas fa-shopping-cart"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-2" data-i18n="dash_biz1_title">海外采购</h3>
<p class="text-sm text-gray-500 mb-6" data-i18n="dash_biz1_desc">采购代购 · 验货质检 · 集中发货</p>
<span class="inline-flex items-center text-brand-blue font-semibold text-sm">
<span data-i18n="dash_start">开始下单</span><i class="fas fa-arrow-right ml-2"></i>
</span>
</div>
<div class="dash-card p-8" onclick="openOrder('Truck')">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-brand-green to-brand-greenDark flex items-center justify-center text-white text-2xl mb-6">
<i class="fas fa-truck-moving"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-2" data-i18n="dash_biz2_title">美国本土卡</h3>
<p class="text-sm text-gray-500 mb-6" data-i18n="dash_biz2_desc">港口提柜 · 仓到仓 · 仓到门</p>
<span class="inline-flex items-center text-brand-green font-semibold text-sm">
<span data-i18n="dash_start">开始下单</span><i class="fas fa-arrow-right ml-2"></i>
</span>
</div>
<div class="dash-card p-8" onclick="openOrder('Pallet')">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-brand-teal to-cyan-700 flex items-center justify-center text-white text-2xl mb-6">
<i class="fas fa-pallet"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-2" data-i18n="dash_biz3_title">美本土散板</h3>
<p class="text-sm text-gray-500 mb-6" data-i18n="dash_biz3_desc">拼车拼载 · 打盘服务 · 灵活派送</p>
<span class="inline-flex items-center text-brand-teal font-semibold text-sm">
<span data-i18n="dash_start">开始下单</span><i class="fas fa-arrow-right ml-2"></i>
</span>
</div>
</div>
</div>
<!-- 视图2:海外采购下单 -->
<div id="dashViewProcurement" class="dash-view hidden">
<button onclick="showDashView('Home')" class="inline-flex items-center text-gray-500 hover:text-brand-blue mb-6 text-sm font-medium">
<i class="fas fa-arrow-left mr-2"></i><span data-i18n="dash_back">返回业务选择</span>
</button>
<div class="bg-white rounded-2xl shadow-card border border-gray-100 p-8 lg:p-10 max-w-3xl">
<div class="flex items-center space-x-3 mb-8">
<div class="w-11 h-11 rounded-xl bg-gradient-to-br from-brand-blue to-brand-blueDark flex items-center justify-center text-white text-lg"><i class="fas fa-shopping-cart"></i></div>
<h2 class="text-2xl font-bold text-gray-900" data-i18n="po_title">海外采购下单</h2>
</div>
<form class="order-form space-y-5" data-order="海外采购 Overseas Sourcing">
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="po_category">采购品类</span><span class="req">*</span></label>
<input type="text" name="采购品类" required class="dash-form-input" placeholder="如:家居用品 / 3C 配件" data-i18n-ph="po_category_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="po_spec">商品规格</span></label>
<input type="text" name="商品规格" class="dash-form-input" placeholder="如:尺寸 / 颜色 / 材质" data-i18n-ph="po_spec_ph">
</div>
</div>
<div>
<label class="dash-label"><span data-i18n="po_link">商品链接</span></label>
<input type="url" name="商品链接" class="dash-form-input" placeholder="https://" data-i18n-ph="po_link_ph">
</div>
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="po_qty">采购数量</span><span class="req">*</span></label>
<input type="number" min="1" name="采购数量" required class="dash-form-input" placeholder="0" data-i18n-ph="po_qty_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="po_price">预算单价</span></label>
<div class="relative">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 font-medium">$</span>
<input type="number" min="0" step="0.01" name="预算单价($)" class="dash-form-input pl-8" placeholder="0.00" data-i18n-ph="po_price_ph">
</div>
</div>
</div>
<div>
<label class="dash-label"><span data-i18n="po_address">收货地址</span></label>
<input type="text" name="收货地址" class="dash-form-input" placeholder="请输入收货地址" data-i18n-ph="po_address_ph">
</div>
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="po_contact">联系人</span><span class="req">*</span></label>
<input type="text" name="联系人" required class="dash-form-input" placeholder="请输入联系人姓名" data-i18n-ph="po_contact_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="po_phone">联系电话</span><span class="req">*</span></label>
<input type="tel" name="联系电话" required class="dash-form-input" placeholder="请输入联系电话" data-i18n-ph="po_phone_ph">
</div>
</div>
<div>
<label class="dash-label"><span data-i18n="po_note">订单备注</span></label>
<textarea name="订单备注" rows="3" class="dash-form-input" placeholder="其他需求说明(选填)" data-i18n-ph="po_note_ph"></textarea>
</div>
<div class="flex gap-3 pt-2">
<button type="submit" class="btn-primary text-white font-bold px-8 py-3.5 rounded-xl" data-i18n="dash_submit">提交订单</button>
<button type="button" onclick="showDashView('Home')" class="px-8 py-3.5 rounded-xl border border-gray-200 text-gray-600 font-medium hover:bg-gray-50" data-i18n="dash_cancel">取消</button>
</div>
</form>
</div>
</div>
<!-- 视图3:美国本土卡下单 -->
<div id="dashViewTruck" class="dash-view hidden">
<button onclick="showDashView('Home')" class="inline-flex items-center text-gray-500 hover:text-brand-blue mb-6 text-sm font-medium">
<i class="fas fa-arrow-left mr-2"></i><span data-i18n="dash_back">返回业务选择</span>
</button>
<div class="bg-white rounded-2xl shadow-card border border-gray-100 p-8 lg:p-10 max-w-3xl">
<div class="flex items-center space-x-3 mb-8">
<div class="w-11 h-11 rounded-xl bg-gradient-to-br from-brand-green to-brand-greenDark flex items-center justify-center text-white text-lg"><i class="fas fa-truck-moving"></i></div>
<h2 class="text-2xl font-bold text-gray-900" data-i18n="tk_title">美国本土卡下单</h2>
</div>
<form class="order-form space-y-6" data-order="美国本土卡 US Trucking">
<div>
<label class="dash-label"><span data-i18n="ts_type">运输类型</span><span class="req">*</span></label>
<div class="flex flex-wrap gap-3">
<label><input type="radio" name="运输类型" value="港口提柜" class="seg-input" checked><span class="seg-pill"><i class="fas fa-anchor text-xs"></i><span data-i18n="ts_type_port">港口提柜</span></span></label>
<label><input type="radio" name="运输类型" value="仓到仓" class="seg-input"><span class="seg-pill"><i class="fas fa-warehouse text-xs"></i><span data-i18n="ts_type_w2w">仓到仓</span></span></label>
<label><input type="radio" name="运输类型" value="仓到门" class="seg-input"><span class="seg-pill"><i class="fas fa-door-open text-xs"></i><span data-i18n="ts_type_w2d">仓到门</span></span></label>
</div>
</div>
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="ts_origin">起运地</span><span class="req">*</span></label>
<input type="text" name="起运地" required class="dash-form-input" placeholder="城市 / 港口 / 州" data-i18n-ph="ts_origin_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="ts_dest">目的地</span><span class="req">*</span></label>
<input type="text" name="目的地" required class="dash-form-input" placeholder="城市 / 州" data-i18n-ph="ts_dest_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="ts_origin_addr">详细地址</span></label>
<input type="text" name="起运详细地址" class="dash-form-input" placeholder="街道 / 门牌" data-i18n-ph="ts_origin_addr_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="ts_dest_addr">详细地址 / 码头 / 仓号</span></label>
<input type="text" name="目的详细地址/码头/仓号" class="dash-form-input" placeholder="地址 / 码头 / 仓号" data-i18n-ph="ts_dest_addr_ph">
</div>
</div>
<div>
<label class="dash-label mb-3"><i class="fas fa-box mr-1 text-gray-400"></i><span data-i18n="cargo_title">货物信息</span></label>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_container">柜型</label>
<select name="柜型" class="dash-form-input">
<option value="20GP">20GP</option>
<option value="40GP">40GP</option>
<option value="40HQ">40HQ</option>
<option value="45HQ">45HQ</option>
<option value="LTL" data-i18n="cargo_container_ltl">散货/托盘</option>
</select>
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_pieces">件数</label>
<input type="number" min="0" name="件数" class="dash-form-input" placeholder="0">
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_weight">总重量 (kg)</label>
<input type="number" min="0" step="0.01" name="总重量(kg)" class="dash-form-input" placeholder="0">
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_volume">总体积 (m³)</label>
<input type="number" min="0" step="0.01" name="总体积(m³)" class="dash-form-input" placeholder="0">
</div>
</div>
</div>
<div>
<label class="dash-label mb-3"><i class="fas fa-user mr-1 text-gray-400"></i><span data-i18n="contact_title">联系人信息</span></label>
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="contact_name">联系人</span><span class="req">*</span></label>
<input type="text" name="联系人" required class="dash-form-input" placeholder="请输入联系人姓名" data-i18n-ph="contact_name_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="contact_phone">联系方式</span><span class="req">*</span></label>
<input type="text" name="联系方式" required class="dash-form-input" placeholder="电话 / 微信 / 邮箱" data-i18n-ph="contact_phone_ph">
</div>
</div>
</div>
<div class="max-w-xs">
<label class="dash-label"><span data-i18n="req_time">要求时间</span></label>
<input type="date" name="要求时间" class="dash-form-input">
</div>
<div class="flex gap-3 pt-2">
<button type="submit" class="btn-primary text-white font-bold px-8 py-3.5 rounded-xl" data-i18n="dash_submit">提交订单</button>
<button type="button" onclick="showDashView('Home')" class="px-8 py-3.5 rounded-xl border border-gray-200 text-gray-600 font-medium hover:bg-gray-50" data-i18n="dash_cancel">取消</button>
</div>
</form>
</div>
</div>
<!-- 视图4:美本土散板下单 -->
<div id="dashViewPallet" class="dash-view hidden">
<button onclick="showDashView('Home')" class="inline-flex items-center text-gray-500 hover:text-brand-blue mb-6 text-sm font-medium">
<i class="fas fa-arrow-left mr-2"></i><span data-i18n="dash_back">返回业务选择</span>
</button>
<div class="bg-white rounded-2xl shadow-card border border-gray-100 p-8 lg:p-10 max-w-3xl">
<div class="flex items-center space-x-3 mb-8">
<div class="w-11 h-11 rounded-xl bg-gradient-to-br from-brand-teal to-cyan-700 flex items-center justify-center text-white text-lg"><i class="fas fa-pallet"></i></div>
<h2 class="text-2xl font-bold text-gray-900" data-i18n="pl_title">美本土散板下单</h2>
</div>
<form class="order-form space-y-6" data-order="美本土散板 US Pallet">
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="pl_method">运输方式</span><span class="req">*</span></label>
<div class="flex flex-wrap gap-3">
<label><input type="radio" name="运输方式" value="拼车" class="seg-input" checked><span class="seg-pill"><span data-i18n="pl_method_pool">拼车</span></span></label>
<label><input type="radio" name="运输方式" value="优先拼载" class="seg-input"><span class="seg-pill"><span data-i18n="pl_method_priority">优先拼载</span></span></label>
</div>
</div>
<div>
<label class="dash-label"><span data-i18n="pl_palletize">是否打盘</span><span class="req">*</span></label>
<div class="flex flex-wrap gap-3">
<label><input type="radio" name="是否打盘" value="是" class="seg-input" checked><span class="seg-pill"><span data-i18n="pl_yes">是</span></span></label>
<label><input type="radio" name="是否打盘" value="否" class="seg-input"><span class="seg-pill"><span data-i18n="pl_no">否</span></span></label>
</div>
</div>
</div>
<div>
<label class="dash-label"><span data-i18n="ts_type">运输类型</span><span class="req">*</span></label>
<div class="flex flex-wrap gap-3">
<label><input type="radio" name="运输类型" value="港口提柜" class="seg-input" checked><span class="seg-pill"><i class="fas fa-anchor text-xs"></i><span data-i18n="ts_type_port">港口提柜</span></span></label>
<label><input type="radio" name="运输类型" value="仓到仓" class="seg-input"><span class="seg-pill"><i class="fas fa-warehouse text-xs"></i><span data-i18n="ts_type_w2w">仓到仓</span></span></label>
<label><input type="radio" name="运输类型" value="仓到门" class="seg-input"><span class="seg-pill"><i class="fas fa-door-open text-xs"></i><span data-i18n="ts_type_w2d">仓到门</span></span></label>
</div>
</div>
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="ts_origin">起运地</span><span class="req">*</span></label>
<input type="text" name="起运地" required class="dash-form-input" placeholder="城市 / 港口 / 州" data-i18n-ph="ts_origin_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="ts_dest">目的地</span><span class="req">*</span></label>
<input type="text" name="目的地" required class="dash-form-input" placeholder="城市 / 州" data-i18n-ph="ts_dest_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="ts_origin_addr">详细地址</span></label>
<input type="text" name="起运详细地址" class="dash-form-input" placeholder="街道 / 门牌" data-i18n-ph="ts_origin_addr_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="ts_dest_addr">详细地址 / 码头 / 仓号</span></label>
<input type="text" name="目的详细地址/码头/仓号" class="dash-form-input" placeholder="地址 / 码头 / 仓号" data-i18n-ph="ts_dest_addr_ph">
</div>
</div>
<div>
<label class="dash-label mb-3"><i class="fas fa-box mr-1 text-gray-400"></i><span data-i18n="cargo_title">货物信息</span></label>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_container">柜型</label>
<select name="柜型" class="dash-form-input">
<option value="20GP">20GP</option>
<option value="40GP">40GP</option>
<option value="40HQ">40HQ</option>
<option value="45HQ">45HQ</option>
<option value="LTL" data-i18n="cargo_container_ltl">散货/托盘</option>
</select>
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_pieces">件数</label>
<input type="number" min="0" name="件数" class="dash-form-input" placeholder="0">
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_weight">总重量 (kg)</label>
<input type="number" min="0" step="0.01" name="总重量(kg)" class="dash-form-input" placeholder="0">
</div>
<div>
<label class="text-xs text-gray-500 mb-1 block" data-i18n="cargo_volume">总体积 (m³)</label>
<input type="number" min="0" step="0.01" name="总体积(m³)" class="dash-form-input" placeholder="0">
</div>
</div>
</div>
<div>
<label class="dash-label mb-3"><i class="fas fa-user mr-1 text-gray-400"></i><span data-i18n="contact_title">联系人信息</span></label>
<div class="grid sm:grid-cols-2 gap-5">
<div>
<label class="dash-label"><span data-i18n="contact_name">联系人</span><span class="req">*</span></label>
<input type="text" name="联系人" required class="dash-form-input" placeholder="请输入联系人姓名" data-i18n-ph="contact_name_ph">
</div>
<div>
<label class="dash-label"><span data-i18n="contact_phone">联系方式</span><span class="req">*</span></label>
<input type="text" name="联系方式" required class="dash-form-input" placeholder="电话 / 微信 / 邮箱" data-i18n-ph="contact_phone_ph">
</div>
</div>
</div>
<div class="max-w-xs">
<label class="dash-label"><span data-i18n="req_time">要求时间</span></label>
<input type="date" name="要求时间" class="dash-form-input">
</div>
<div class="flex gap-3 pt-2">
<button type="submit" class="btn-primary text-white font-bold px-8 py-3.5 rounded-xl" data-i18n="dash_submit">提交订单</button>
<button type="button" onclick="showDashView('Home')" class="px-8 py-3.5 rounded-xl border border-gray-200 text-gray-600 font-medium hover:bg-gray-50" data-i18n="dash_cancel">取消</button>
</div>
</form>
</div>
</div>
<!-- 视图5:我的订单 -->
<div id="dashViewOrders" class="dash-view hidden">
<div class="bg-white rounded-2xl shadow-card border border-gray-100 p-10 lg:p-14 max-w-3xl mx-auto text-center">
<div class="dash-empty">
<i class="fas fa-clipboard-list"></i>
<h3 class="text-xl font-bold text-gray-700 mb-2" data-i18n="dash_orders_empty">暂无订单</h3>
<p class="text-gray-500" data-i18n="dash_orders_hint">您还没有提交任何订单,前往「业务总览」选择服务开始下单吧。</p>
</div>
</div>
</div>
</main>
<!-- 右侧信息栏 -->
<aside id="dashRight" class="dash-right hidden lg:flex flex-col">
<div class="dash-right-card">
<h4 data-i18n="right_account_title">账户信息</h4>
<div class="dash-account">
<div class="dash-account-avatar" id="dashAvatar">C</div>
<div>
<div class="dash-account-name" id="dashAccountName">虫虫出海客户</div>
<div class="dash-account-type" data-i18n="right_account_type">企业客户</div>
</div>
</div>
</div>
<div class="dash-right-card">
<h4 data-i18n="right_stat_title">数据概览</h4>
<div class="dash-stat-row">
<span class="dash-stat-label" data-i18n="right_stat_progress">进行中订单</span>
<span class="dash-stat-value" id="statProgress">0</span>
</div>
<div class="dash-stat-row">
<span class="dash-stat-label" data-i18n="right_stat_done">已完成订单</span>
<span class="dash-stat-value" id="statDone">0</span>
</div>
<div class="dash-stat-row">
<span class="dash-stat-label" data-i18n="right_stat_month">本月下单</span>
<span class="dash-stat-value" id="statMonth">0</span>
</div>
</div>
<div class="dash-right-card">
<h4 data-i18n="right_help_title">帮助与支持</h4>
<div class="dash-help-item" onclick="showToast(t('right_help_cs_toast'))">
<i class="fas fa-headset"></i><span data-i18n="right_help_cs">联系客服</span>
</div>
<div class="dash-help-item" onclick="showToast(t('right_help_faq_toast'))">
<i class="fas fa-question-circle"></i><span data-i18n="right_help_faq">常见问题</span>
</div>
<div class="dash-help-item" onclick="showToast(t('right_help_quote_toast'))">
<i class="fas fa-tag"></i><span data-i18n="right_help_quote">获取报价</span>
</div>
</div>
<div class="dash-tip">
<i class="fas fa-lightbulb"></i>
<span data-i18n="right_tip_text">提交订单后,专属客户经理将在 24 小时内与您联系,确认运输方案与报价。</span>
</div>
</aside>
</div>
</div>
</section>
<script>
// 工作台交互
function setDashUser(name) {
const display = name ? name : '虫虫出海客户';
const topEl = document.getElementById('dashUserName');
if (topEl) topEl.textContent = 'Hi, ' + display;
const accEl = document.getElementById('dashAccountName');
if (accEl) accEl.textContent = display;
const avEl = document.getElementById('dashAvatar');
if (avEl) avEl.textContent = display.charAt(0).toUpperCase();
}
function showDashView(name) {
document.querySelectorAll('#workbench .dash-view').forEach(v => v.classList.add('hidden'));
const view = document.getElementById('dashView' + name);
if (view) view.classList.remove('hidden');
document.querySelectorAll('.dash-nav-link').forEach(l => l.classList.toggle('active', l.getAttribute('data-view') === name));
window.scrollTo(0, 0);
}
function goDash(name) {
showDashView(name);
closeDashSidebar();
}
function toggleDashSidebar() {
const sb = document.getElementById('dashSidebar');
const ov = document.getElementById('dashOverlay');
if (!sb) return;
const open = sb.classList.toggle('open');
if (ov) ov.classList.toggle('show', open);
document.body.style.overflow = open ? 'hidden' : '';
}
function closeDashSidebar() {
const sb = document.getElementById('dashSidebar');
const ov = document.getElementById('dashOverlay');
if (sb) sb.classList.remove('open');
if (ov) ov.classList.remove('show');
document.body.style.overflow = '';
}
function openOrder(type) {
showDashView(type);
}
function doLogout() {
showToast(t('toast_logout'));
setTimeout(() => { window.location.href = 'index.html'; }, 700);
}
// 订单表单提交
document.querySelectorAll('.order-form').forEach(form => {
form.addEventListener('submit', function(e) {
e.preventDefault();
showToast(t('toast_order_ok'));
this.reset();
setTimeout(() => showDashView('Home'), 1200);
});
});
// ====== 多语言 i18n ======
const i18n = {
zh: {
dash_home_link: "返回官网", dash_logout: "退出登录",
dash_welcome_title: "选择业务,快速下单", dash_welcome_sub: "请选择您需要的业务类型,填写信息后提交订单,我们将尽快为您安排。",
dash_biz1_title: "海外采购", dash_biz1_desc: "采购代购 · 验货质检 · 集中发货",
dash_biz2_title: "美国本土卡", dash_biz2_desc: "港口提柜 · 仓到仓 · 仓到门",
dash_biz3_title: "美本土散板", dash_biz3_desc: "拼车拼载 · 打盘服务 · 灵活派送",
dash_start: "开始下单", dash_back: "返回业务选择", dash_submit: "提交订单", dash_cancel: "取消",
po_title: "海外采购下单", po_category: "采购品类", po_category_ph: "如:家居用品 / 3C 配件",
po_spec: "商品规格", po_spec_ph: "如:尺寸 / 颜色 / 材质", po_link: "商品链接", po_link_ph: "https://",
po_qty: "采购数量", po_qty_ph: "0", po_price: "预算单价", po_price_ph: "0.00",
po_address: "收货地址", po_address_ph: "请输入收货地址", po_contact: "联系人", po_contact_ph: "请输入联系人姓名",
po_phone: "联系电话", po_phone_ph: "请输入联系电话", po_note: "订单备注", po_note_ph: "其他需求说明(选填)",
tk_title: "美国本土卡下单",
pl_title: "美本土散板下单", pl_method: "运输方式", pl_method_pool: "拼车", pl_method_priority: "优先拼载",
pl_palletize: "是否打盘", pl_yes: "是", pl_no: "否",
ts_type: "运输类型", ts_type_port: "港口提柜", ts_type_w2w: "仓到仓", ts_type_w2d: "仓到门",
ts_origin: "起运地", ts_origin_ph: "城市 / 港口 / 州", ts_dest: "目的地", ts_dest_ph: "城市 / 州",
ts_origin_addr: "详细地址", ts_origin_addr_ph: "街道 / 门牌",
ts_dest_addr: "详细地址 / 码头 / 仓号", ts_dest_addr_ph: "地址 / 码头 / 仓号",
cargo_title: "货物信息", cargo_container: "柜型", cargo_container_ltl: "散货/托盘",
cargo_pieces: "件数", cargo_weight: "总重量 (kg)", cargo_volume: "总体积 (m³)",
req_time: "要求时间", contact_title: "联系人信息", contact_name: "联系人", contact_name_ph: "请输入联系人姓名", contact_phone: "联系方式", contact_phone_ph: "电话 / 微信 / 邮箱",
toast_logout: "已退出登录", toast_order_ok: "订单提交成功,我们将尽快为您安排!",
dash_menu_main: "主导航", dash_menu_overview: "业务总览", dash_menu_proc: "海外采购",
dash_menu_truck: "美国本土卡", dash_menu_pallet: "美本土散板", dash_menu_orders: "我的订单",
dash_orders_empty: "暂无订单", dash_orders_hint: "您还没有提交任何订单,前往「业务总览」选择服务开始下单吧。",
right_account_title: "账户信息", right_account_type: "企业客户",
right_stat_title: "数据概览", right_stat_progress: "进行中订单", right_stat_done: "已完成订单", right_stat_month: "本月下单",
right_help_title: "帮助与支持", right_help_cs: "联系客服", right_help_faq: "常见问题", right_help_quote: "获取报价",
right_help_cs_toast: "客服热线:400-XXX-XXXX(工作日 9:00-18:00)", right_help_faq_toast: "常见问题页面即将上线", right_help_quote_toast: "报价顾问将尽快与您联系",
right_tip_text: "提交订单后,专属客户经理将在 24 小时内与您联系,确认运输方案与报价。"
},
en: {
dash_home_link: "Back to Site", dash_logout: "Log Out",
dash_welcome_title: "Choose a Service to Order", dash_welcome_sub: "Select the service you need, fill in the details, and submit your order — we will arrange it for you shortly.",
dash_biz1_title: "Overseas Sourcing", dash_biz1_desc: "Sourcing · Inspection · Consolidation",
dash_biz2_title: "US Domestic Trucking", dash_biz2_desc: "Port Pickup · Warehouse-to-Warehouse · Door-to-Door",
dash_biz3_title: "US Pallet Break", dash_biz3_desc: "Pooled Freight · Palletizing · Flexible Delivery",
dash_start: "Start Order", dash_back: "Back to Services", dash_submit: "Submit Order", dash_cancel: "Cancel",
po_title: "Overseas Sourcing Order", po_category: "Product Category", po_category_ph: "e.g. Home goods / 3C accessories",
po_spec: "Specs", po_spec_ph: "e.g. Size / Color / Material", po_link: "Product Link", po_link_ph: "https://",
po_qty: "Quantity", po_qty_ph: "0", po_price: "Budget Unit Price", po_price_ph: "0.00",
po_address: "Shipping Address", po_address_ph: "Enter shipping address", po_contact: "Contact Name", po_contact_ph: "Enter contact name",
po_phone: "Contact Phone", po_phone_ph: "Enter phone number", po_note: "Order Notes", po_note_ph: "Other requirements (optional)",
tk_title: "US Domestic Trucking Order",
pl_title: "US Pallet Break Order", pl_method: "Transport Mode", pl_method_pool: "Pooled", pl_method_priority: "Priority Load",
pl_palletize: "Palletize?", pl_yes: "Yes", pl_no: "No",
ts_type: "Transport Type", ts_type_port: "Port Pickup", ts_type_w2w: "Warehouse to Warehouse", ts_type_w2d: "Warehouse to Door",
ts_origin: "Origin", ts_origin_ph: "City / Port / State", ts_dest: "Destination", ts_dest_ph: "City / State",
ts_origin_addr: "Detailed Address", ts_origin_addr_ph: "Street / Number",
ts_dest_addr: "Detailed Address / Pier / WH No.", ts_dest_addr_ph: "Address / Pier / WH No.",
cargo_title: "Cargo Info", cargo_container: "Container Type", cargo_container_ltl: "Loose / Pallet",
cargo_pieces: "Pieces", cargo_weight: "Total Weight (kg)", cargo_volume: "Total Volume (m³)",
req_time: "Required By", contact_title: "Contact Info", contact_name: "Contact Person", contact_name_ph: "Enter contact name", contact_phone: "Contact Number", contact_phone_ph: "Phone / WeChat / Email",
toast_logout: "Logged out", toast_order_ok: "Order submitted! We will arrange it for you shortly.",
dash_menu_main: "Main Menu", dash_menu_overview: "Overview", dash_menu_proc: "Overseas Sourcing",
dash_menu_truck: "US Trucking", dash_menu_pallet: "US Pallet Break", dash_menu_orders: "My Orders",
dash_orders_empty: "No Orders Yet", dash_orders_hint: "You haven't placed any orders yet. Go to Overview to start a new order.",
right_account_title: "Account", right_account_type: "Enterprise Client",
right_stat_title: "Overview", right_stat_progress: "In Progress", right_stat_done: "Completed", right_stat_month: "This Month",
right_help_title: "Help & Support", right_help_cs: "Contact Support", right_help_faq: "FAQ", right_help_quote: "Get a Quote",
right_help_cs_toast: "Support Hotline: 400-XXX-XXXX (Mon-Fri 9:00-18:00)", right_help_faq_toast: "FAQ page coming soon", right_help_quote_toast: "A quoting specialist will contact you shortly",
right_tip_text: "After you submit an order, your dedicated account manager will contact you within 24 hours to confirm the shipping plan and quote."
},
es: {
dash_home_link: "Volver al sitio", dash_logout: "Cerrar sesión",
dash_welcome_title: "Elige un servicio para pedir", dash_welcome_sub: "Selecciona el servicio que necesitas, completa los datos y envía tu pedido; lo gestionaremos lo antes posible.",
dash_biz1_title: "Abastecimiento en el extranjero", dash_biz1_desc: "Compras · Inspección · Consolidación",
dash_biz2_title: "Transporte por camión en EE.UU.", dash_biz2_desc: "Recogida en puerto · Almacén a almacén · Puerta a puerta",
dash_biz3_title: "Despaletizado en EE.UU.", dash_biz3_desc: "Carga compartida · Paletizado · Entrega flexible",
dash_start: "Iniciar pedido", dash_back: "Volver a servicios", dash_submit: "Enviar pedido", dash_cancel: "Cancelar",
po_title: "Pedido de abastecimiento", po_category: "Categoría del producto", po_category_ph: "ej. Artículos para el hogar / Accesorios 3C",
po_spec: "Especificaciones", po_spec_ph: "ej. Tamaño / Color / Material", po_link: "Enlace del producto", po_link_ph: "https://",
po_qty: "Cantidad", po_qty_ph: "0", po_price: "Precio unitario estimado", po_price_ph: "0.00",
po_address: "Dirección de envío", po_address_ph: "Ingresa la dirección de envío", po_contact: "Persona de contacto", po_contact_ph: "Ingresa el nombre de contacto",
po_phone: "Teléfono de contacto", po_phone_ph: "Ingresa el teléfono", po_note: "Notas del pedido", po_note_ph: "Otros requisitos (opcional)",
tk_title: "Pedido de camión en EE.UU.",
pl_title: "Pedido de despaletizado en EE.UU.", pl_method: "Modo de transporte", pl_method_pool: "Carga compartida", pl_method_priority: "Carga prioritaria",
pl_palletize: "¿Paletizar?", pl_yes: "Sí", pl_no: "No",
ts_type: "Tipo de transporte", ts_type_port: "Recogida en puerto", ts_type_w2w: "Almacén a almacén", ts_type_w2d: "Almacén a puerta",
ts_origin: "Origen", ts_origin_ph: "Ciudad / Puerto / Estado", ts_dest: "Destino", ts_dest_ph: "Ciudad / Estado",
ts_origin_addr: "Dirección detallada", ts_origin_addr_ph: "Calle / Número",
ts_dest_addr: "Dirección / Muelle / N.º almacén", ts_dest_addr_ph: "Dirección / Muelle / N.º almacén",
cargo_title: "Información de carga", cargo_container: "Tipo de contenedor", cargo_container_ltl: "Carga suelta / Paleta",
cargo_pieces: "Piezas", cargo_weight: "Peso total (kg)", cargo_volume: "Volumen total (m³)",
req_time: "Fecha requerida", contact_title: "Información de contacto", contact_name: "Persona de contacto", contact_name_ph: "Ingrese el nombre de contacto", contact_phone: "Número de contacto", contact_phone_ph: "Teléfono / WeChat / Email",
toast_logout: "Sesión cerrada", toast_order_ok: "¡Pedido enviado! Lo gestionaremos lo antes posible.",
dash_menu_main: "Menú principal", dash_menu_overview: "Resumen", dash_menu_proc: "Abastecimiento",
dash_menu_truck: "Camión en EE.UU.", dash_menu_pallet: "Despaletizado", dash_menu_orders: "Mis pedidos",
dash_orders_empty: "Sin pedidos", dash_orders_hint: "Aún no has enviado pedidos. Ve a Resumen para empezar uno nuevo.",
right_account_title: "Cuenta", right_account_type: "Cliente Empresarial",
right_stat_title: "Resumen", right_stat_progress: "En Progreso", right_stat_done: "Completados", right_stat_month: "Este Mes",
right_help_title: "Ayuda y Soporte", right_help_cs: "Contactar Soporte", right_help_faq: "Preguntas Frecuentes", right_help_quote: "Obtener Cotización",
right_help_cs_toast: "Línea de soporte: 400-XXX-XXXX (Lun-Vie 9:00-18:00)", right_help_faq_toast: "Página de preguntas próximamente", right_help_quote_toast: "Un especialista en cotización te contactará pronto",
right_tip_text: "Después de enviar el pedido, tu ejecutivo de cuenta te contactará en 24 horas para confirmar el plan de envío y la cotización."
}
};
let currentLang = localStorage.getItem('cc_lang') || 'zh';
function t(key) {
return (i18n[currentLang] && i18n[currentLang][key] !== undefined) ? i18n[currentLang][key] : key;
}
function applyLanguage(lang) {
if (!i18n[lang]) lang = 'zh';
currentLang = lang;
const langAttr = lang === 'zh' ? 'zh-CN' : (lang === 'es' ? 'es-MX' : 'en');
document.documentElement.setAttribute('lang', langAttr);
document.querySelectorAll('[data-i18n]').forEach(el => {
const k = el.getAttribute('data-i18n');
if (i18n[lang][k] !== undefined) el.textContent = i18n[lang][k];
});
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
const k = el.getAttribute('data-i18n-ph');
if (i18n[lang][k] !== undefined) el.setAttribute('placeholder', i18n[lang][k]);
});
document.querySelectorAll('#langSwitcherDash [data-lang]').forEach(b => {
b.classList.toggle('active', b.getAttribute('data-lang') === lang);
});
try { localStorage.setItem('cc_lang', lang); } catch (e) {}
}
document.querySelectorAll('#langSwitcherDash [data-lang]').forEach(b => {
b.addEventListener('click', () => applyLanguage(b.getAttribute('data-lang')));
});
// Toast 提示
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
toastMessage.textContent = message;
toast.classList.remove('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.add('opacity-100', 'translate-y-0');
setTimeout(() => {
toast.classList.add('opacity-0', 'pointer-events-none', '-translate-y-4');
toast.classList.remove('opacity-100', 'translate-y-0');
}, 3000);
}
// 初始化
document.addEventListener('DOMContentLoaded', function() {
applyLanguage(currentLang);
// 尝试从官网登录带入用户名(URL ?user=xxx)
const params = new URLSearchParams(window.location.search);
const userParam = params.get('user');
if (userParam) {
setDashUser(decodeURIComponent(userParam));
}
});
applyLanguage(currentLang);
</script>
</body>
</html>
+455
View File
@@ -0,0 +1,455 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虫虫出海 - 用户登录</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', sans-serif;
display: flex;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* ===== 左侧品牌区 ===== */
.brand-side {
width: 50%;
min-width: 420px;
position: relative;
background: linear-gradient(155deg, rgba(30,64,175,0.85) 0%, rgba(37,99,235,0.75) 40%, rgba(59,130,246,0.65) 100%);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* 浮动装饰圆圈 */
.brand-side::before {
content: '';
position: absolute;
top: -20%; right: -20%;
width: 80%; height: 80%;
background: radial-gradient(ellipse, rgba(255,255,255,.2) 0%, transparent 70%);
animation: float1 8s ease-in-out infinite;
pointer-events: none;
}
.brand-side::after {
content: '';
position: absolute;
bottom: -15%; left: -15%;
width: 70%; height: 70%;
background: radial-gradient(ellipse, rgba(147,197,253,.3) 0%, transparent 65%);
animation: float2 10s ease-in-out infinite;
pointer-events: none;
}
@keyframes float1 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(-30px, 30px) scale(1.05); }
}
@keyframes float2 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(20px, -20px) scale(1.1); }
}
.brand-content {
position: relative;
z-index: 1;
text-align: center;
padding: 40px;
animation: fadeInUp 0.8s ease-out;
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
.logo-wrap {
width: 100px; height: 100px;
margin: 0 auto 24px;
border-radius: 26px;
overflow: hidden;
background: rgba(255,255,255,.95);
padding: 12px;
box-shadow: 0 12px 40px rgba(0,0,0,.15), 0 0 0 1px rgba(255,255,255,.5) inset;
animation: logoFloat 3s ease-in-out infinite;
}
@keyframes logoFloat {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
.logo-wrap img { width: 100%; height: 100%; object-fit: contain; }
.brand-title { font-size: 36px; font-weight: 800; color: #fff; letter-spacing: 4px; text-shadow: 0 4px 20px rgba(0,0,0,.15); }
.brand-subtitle { font-size: 15px; color: rgba(255,255,255,.88); margin-top: 12px; letter-spacing: 2px; }
.feature-list { margin-top: 56px; text-align: left; display: inline-block; }
.feature-item {
color: rgba(255,255,255,.9);
font-size: 15px;
line-height: 2.6;
padding-left: 24px;
position: relative;
opacity: 0;
animation: fadeInLeft 0.6s ease-out forwards;
}
.feature-item:nth-child(1) { animation-delay: 0.2s; }
.feature-item:nth-child(2) { animation-delay: 0.4s; }
.feature-item:nth-child(3) { animation-delay: 0.6s; }
@keyframes fadeInLeft {
from { opacity: 0; transform: translateX(-20px); }
to { opacity: 1; transform: translateX(0); }
}
.feature-item::before {
content: '✓';
position: absolute;
left: 0; top: 2px;
width: 18px; height: 18px;
border-radius: 50%;
background: rgba(255,255,255,.25);
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
}
/* ===== 右侧登录区 ===== */
.login-side {
flex: 1;
min-width: 400px;
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
}
.login-card {
width: 100%;
max-width: 420px;
padding: 52px 44px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 25px 80px rgba(0,0,0,.15), 0 0 0 1px rgba(255,255,255,.5) inset;
animation: cardFloat 0.8s ease-out;
}
@keyframes cardFloat {
from { opacity: 0; transform: translateY(40px) scale(0.95); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* 标题区 */
.card-header { margin-bottom: 36px; }
.card-title {
font-size: 30px;
font-weight: 800;
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 1px;
}
.card-desc {
font-size: 15px;
color: #64748b;
margin-top: 10px;
}
/* 表单 */
.form-group { margin-bottom: 22px; }
.form-input {
width: 100%;
height: 52px;
border: 2px solid #e2e8f0;
border-radius: 14px;
padding: 0 18px;
font-size: 15px;
color: #1e293b;
outline: none;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
background: #f8fafc;
}
.form-input:focus {
border-color: #667eea;
background: #fff;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
transform: translateY(-2px);
}
.form-input::placeholder { color: #94a3b8; }
/* 密码框 */
.password-wrap { position: relative; }
.password-toggle {
position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
border: none; background: none; cursor: pointer;
padding: 6px; color: #64748b; font-size: 18px; line-height: 1;
transition: all .2s;
}
.password-toggle:hover { color: #667eea; transform: translateY(-50%) scale(1.1); }
/* 验证码 */
.captcha-row {
display: flex;
gap: 14px;
align-items: center;
}
.captcha-row .form-input { flex: 1; }
.captcha-img {
width: 120px; height: 52px;
border: 2px solid #e2e8f0;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
font-size: 22px;
font-weight: 700;
letter-spacing: 6px;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
flex-shrink: 0;
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
}
.captcha-img:hover {
border-color: #667eea;
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
}
/* 按钮 */
.submit-btn {
width: 100%;
height: 54px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 200% 200%;
color: #fff;
border: none;
border-radius: 14px;
font-size: 16px;
font-weight: 700;
cursor: pointer;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
letter-spacing: 4px;
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4);
}
.submit-btn:hover {
background-position: 100% 0;
transform: translateY(-3px);
box-shadow: 0 12px 32px rgba(102, 126, 234, 0.5);
}
.submit-btn:active { transform: translateY(-1px); }
/* 底部辅助行 */
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 28px;
}
.remember-me {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: #64748b;
cursor: pointer;
user-select: none;
transition: color .2s;
}
.remember-me:hover { color: #475569; }
.remember-me input { accent-color: #667eea; width: 18px; height: 18px; cursor: pointer; }
.forgot-link {
font-size: 14px;
color: #667eea;
text-decoration: none;
font-weight: 500;
transition: all .2s;
}
.forgot-link:hover { color: #764ba2; text-decoration: underline; }
/* 底部注册链接 */
.register-tip {
text-align: center;
margin-top: 28px;
font-size: 14px;
color: #94a3b8;
}
.register-tip a {
color: #667eea;
text-decoration: none;
font-weight: 600;
transition: all .2s;
}
.register-tip a:hover { color: #764ba2; text-decoration: underline; }
/* 错误提示 */
.error-msg {
font-size: 13px;
color: #ef4444;
margin-top: 6px;
display: none;
padding-left: 4px;
animation: shake 0.3s ease-out;
}
.error-msg.show { display: block; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-4px); }
75% { transform: translateX(4px); }
}
/* 响应式 */
@media (max-width: 900px) {
body { flex-direction: column; }
.brand-side { min-width: auto; min-height: 240px; width: 100%; }
.brand-content { padding: 32px; }
.feature-list { display: none; }
.login-side { min-width: auto; padding: 24px 16px; }
.login-card { max-width: 420px; padding: 40px 28px; }
}
</style>
</head>
<body>
<!-- 左侧品牌 -->
<div class="brand-side">
<div class="brand-content">
<div class="logo-wrap">
<img src="logo.png" alt="Logo">
</div>
<h1 class="brand-title">虫虫出海</h1>
<p class="brand-subtitle">一站式跨境物流服务平台</p>
<div class="feature-list">
<div class="feature-item">安全可靠 · 全程可追踪</div>
<div class="feature-item">专业团队 · 快速响应</div>
<div class="feature-item">透明报价 · 无隐藏费用</div>
</div>
</div>
</div>
<!-- 右侧登录 -->
<div class="login-side">
<div class="login-card">
<div class="card-header">
<h2 class="card-title">欢迎回来</h2>
<p class="card-desc">请登录您的账户以继续</p>
</div>
<form id="loginForm" autocomplete="off">
<div class="form-group">
<input type="text" class="form-input" id="loginUsername" placeholder="用户名">
<div class="error-msg" id="loginUserError">请输入用户名</div>
</div>
<div class="form-group">
<div class="password-wrap">
<input type="password" class="form-input" id="loginPassword" placeholder="密码">
<button type="button" class="password-toggle" onclick="togglePassword()">👁</button>
</div>
<div class="error-msg" id="loginPassError">请输入密码</div>
</div>
<div class="form-group">
<div class="captcha-row">
<input type="text" class="form-input" id="loginCaptcha" placeholder="验证码" maxlength="4">
<div class="captcha-img" id="loginCaptchaImg" onclick="refreshCaptcha('login')"></div>
</div>
<div class="error-msg" id="loginCaptchaError">验证码错误</div>
</div>
<div class="form-options">
<label class="remember-me">
<input type="checkbox"> 记住我
</label>
<a href="javascript:void(0)" class="forgot-link">忘记密码?</a>
</div>
<button type="submit" class="submit-btn">登 录</button>
</form>
<div class="register-tip">没有账号?<a href="register.html">立即注册</a></div>
</div>
</div>
<script>
// 验证码
let currentCaptcha = {};
function generateCaptcha() {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789';
let c = '';
for (let i = 0; i < 4; i++) c += chars.charAt(Math.floor(Math.random() * chars.length));
return c;
}
function refreshCaptcha(type) {
const c = generateCaptcha();
currentCaptcha[type] = c;
const el = document.getElementById(type + 'CaptchaImg');
if (!el) return;
el.textContent = c;
el.style.transform = 'rotate(' + (Math.random() * 8 - 4) + 'deg)';
el.style.color = ['#2563eb','#3b82f6','#1d4ed8','#1e40af'][Math.floor(Math.random()*4)];
}
refreshCaptcha('login');
// 密码显隐
function togglePassword() {
const pw = document.getElementById('loginPassword');
pw.type = pw.type === 'password' ? 'text' : 'password';
}
// 表单提交
document.getElementById('loginForm').addEventListener('submit', function(e) {
e.preventDefault();
var username = document.getElementById('loginUsername').value.trim();
var password = document.getElementById('loginPassword').value;
var captcha = document.getElementById('loginCaptcha').value.trim();
document.querySelectorAll('#loginForm .error-msg').forEach(function(el) { el.classList.remove('show'); });
var hasError = false;
if (!username) { document.getElementById('loginUserError').classList.add('show'); hasError = true; }
if (!password) { document.getElementById('loginPassError').classList.add('show'); hasError = true; }
if (captcha.toUpperCase() !== currentCaptcha['login'].toUpperCase()) {
document.getElementById('loginCaptchaError').classList.add('show');
refreshCaptcha('login');
hasError = true;
}
if (hasError) return;
alert('登录成功!欢迎回来,' + username + '!');
});
// 实时清除错误
document.querySelectorAll('.form-input').forEach(function(input) {
input.addEventListener('input', function() {
var group = this.closest('.form-group');
if (!group) return;
var err = group.querySelector('.error-msg');
if (err) err.classList.remove('show');
});
});
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

+511
View File
@@ -0,0 +1,511 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虫虫出海 - 企业注册</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
position: relative;
overflow-x: hidden;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* 装饰性浮动元素 */
body::before {
content: '';
position: fixed;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 60%);
animation: rotate 30s linear infinite;
pointer-events: none;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* ====== 主容器:居中卡片式 ====== */
.container {
width: 100%;
max-width: 580px;
position: relative;
z-index: 1;
animation: fadeInUp 0.8s ease-out;
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(40px); }
to { opacity: 1; transform: translateY(0); }
}
/* 顶部品牌条 */
.top-bar {
text-align: center;
margin-bottom: 32px;
}
.logo-wrap {
width: 120px; height: 120px;
margin: 0 auto 18px;
border-radius: 32px;
background: rgba(255,255,255,0.95);
padding: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,.2), 0 0 0 1px rgba(255,255,255,.5) inset;
overflow: hidden;
animation: logoFloat 3s ease-in-out infinite;
}
@keyframes logoFloat {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.logo-wrap img { width: 100%; height: 100%; object-fit: contain; filter: none; }
.logo-wrap img.no-filter { filter: none; }
.brand-name {
font-size: 30px;
font-weight: 800;
color: #fff;
letter-spacing: 3px;
margin-bottom: 6px;
text-shadow: 0 4px 20px rgba(0,0,0,.2);
}
.brand-sub { font-size: 14px; color: rgba(255,255,255,0.85); letter-spacing: 1.5px; }
/* 卡片 */
.form-card {
background: rgba(255,255,255,0.96);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 28px;
padding: 44px 40px;
box-shadow: 0 25px 80px rgba(0,0,0,.15), 0 0 0 1px rgba(255,255,255,.5) inset;
border: none;
}
/* 标题行 */
.card-header {
display: flex; align-items: center; justify-content: space-between;
margin-bottom: 30px;
}
.card-title {
font-size: 24px; font-weight: 800;
background: linear-gradient(135deg, #1e293b 0%, #475569 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
position: relative;
padding-left: 16px;
}
.card-title::before {
content: '';
position: absolute; left: 0; top: 2px; bottom: 2px;
width: 4px; border-radius: 3px;
background: linear-gradient(180deg, #667eea, #764ba2);
}
.back-link {
font-size: 14px; color: #64748b; text-decoration: none;
transition: all .2s;
font-weight: 500;
padding: 6px 12px;
border-radius: 8px;
}
.back-link:hover { color: #667eea; background: rgba(102,126,234,0.08); }
.back-link::before { content: '← '; font-size: 14px; }
/* 分组标题 */
.section-label {
font-size: 12px; font-weight: 700; color: #94a3b8;
text-transform: uppercase; letter-spacing: 2.5px;
margin-bottom: 16px; margin-top: 24px;
}
.section-label:first-of-type { margin-top: 0; }
/* 表单项 - 单列 */
.form-group { margin-bottom: 20px; position: relative; }
.form-label {
display: block; font-size: 14px; font-weight: 600;
color: #475569; margin-bottom: 8px;
}
.form-label .required { color: #ef4444; margin-right: 3px; font-size: 15px; }
.form-input, .form-select {
width: 100%; padding: 14px 18px; font-size: 15px;
border: 2px solid #e2e8f0; border-radius: 14px; outline: none;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
background: #f8fafc; color: #1e293b;
appearance: none;
height: 54px;
}
.form-input:hover, .form-select:hover {
border-color: #cbd5e1;
background: #fff;
}
.form-input:focus, .form-select:focus {
border-color: #667eea;
background: #fff;
box-shadow: 0 0 0 5px rgba(102,126,234,.12);
transform: translateY(-2px);
}
.form-input::placeholder { color: #94a3b8; }
.form-select {
cursor: pointer;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
background-repeat: no-repeat; background-position: right 18px center; padding-right: 42px;
}
/* 营业执照上传区 */
.license-upload-area {
border: 2px dashed #cbd5e1;
border-radius: 16px; padding: 28px;
text-align: center; cursor: pointer;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
background: linear-gradient(135deg, #fafbfc 0%, #f8fafc 100%);
position: relative;
overflow: hidden;
}
.license-upload-area:hover {
border-color: #667eea;
background: linear-gradient(135deg, #eff6ff 0%, #f0f9ff 100%);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(102,126,234,0.15);
}
.license-upload-area.has-image {
border-style: solid; border-color: #a78bfa; padding: 6px; background: #fff;
}
.license-upload-area.has-image .upload-placeholder { display: none; }
.upload-placeholder .upload-icon-big {
font-size: 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
margin-bottom: 8px;
}
.upload-placeholder .upload-hint {
font-size: 14px; color: #64748b; font-weight: 600;
}
.upload-placeholder .upload-desc {
font-size: 12px; color: #94a3b8; margin-top: 6px;
}
.license-preview-img {
width: 100%; max-height: 180px; object-fit: cover;
border-radius: 12px; display: none;
}
.has-image .license-preview-img { display: block; }
.license-upload-area input[type="file"] { display: none; }
/* 验证码 */
.captcha-group { display: flex; gap: 14px; align-items: stretch; }
.captcha-group .form-input { flex: 1; }
.captcha-img {
flex-shrink: 0; width: 130px;
height: auto; min-height: 54px;
border-radius: 14px; cursor: pointer;
border: 2px solid #e2e8f0;
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
display: flex; align-items: center; justify-content: center;
padding: 0 16px; font-size: 22px; font-weight: 800;
letter-spacing: 6px; color: #667eea; user-select: none;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
}
.captcha-img:hover {
border-color: #667eea;
background: linear-gradient(135deg, #dbeafe 0%, #cffafe 100%);
transform: scale(1.05);
box-shadow: 0 6px 20px rgba(102,126,234,0.2);
}
/* 错误提示 */
.error-msg {
color: #ef4444;
font-size: 13px;
margin-top: 6px;
display: none;
padding-left: 4px;
animation: shake 0.3s ease-out;
}
.error-msg.show { display: block; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-4px); }
75% { transform: translateX(4px); }
}
/* 提交按钮 */
.submit-btn {
width: 100%; padding: 16px; font-size: 16px; font-weight: 700;
color: white;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 200% 200%;
border: none; border-radius: 14px;
cursor: pointer;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 10px 30px rgba(102,126,234,.4);
letter-spacing: 1.5px;
margin-top: 10px;
}
.submit-btn:hover {
background-position: 100% 0;
transform: translateY(-3px);
box-shadow: 0 16px 40px rgba(102,126,234,.5);
}
.submit-btn:active { transform: translateY(-1px); }
/* 底部链接 */
.form-footer { text-align: center; margin-top: 22px; font-size: 14px; color: #64748b; }
.form-footer a {
color: #667eea;
text-decoration: none;
font-weight: 700;
transition: all .2s;
}
.form-footer a:hover { color: #764ba2; text-decoration: underline; }
/* 分割线装饰 */
.divider {
height: 1px;
background: linear-gradient(90deg, transparent, #e2e8f0, #cbd5e1, #e2e8f0, transparent);
margin: 26px 0;
}
@keyframes cardShake {
0%,100%{transform:translateX(0)} 25%{transform:translateX(-8px)} 75%{transform:translateX(8px)}
}
.shake { animation: cardShake .45s; }
/* 响应式 */
@media (max-width: 580px) {
body { padding: 24px 16px; }
.form-card { padding: 32px 26px; border-radius: 22px; }
.brand-name { font-size: 26px; }
.logo-wrap { width: 100px; height: 100px; border-radius: 26px; padding: 16px; }
.captcha-group { flex-direction: column; }
.captcha-img { width: 100%; min-height: 52px; }
}
</style>
</head>
<body>
<div class="container">
<!-- 品牌头部 -->
<div class="top-bar">
<div class="logo-wrap">
<img src="logo.png" alt="虫虫出海" class="no-filter">
</div>
<h1 class="brand-name">虫虫出海</h1>
<p class="brand-sub">一站式跨境物流服务平台</p>
</div>
<!-- 注册表单 -->
<div class="form-card">
<div class="card-header">
<h2 class="card-title">企业注册</h2>
<a href="login-register.html" class="back-link">返回登录</a>
</div>
<form id="registerForm">
<!-- 基本信息 -->
<div class="section-label">基本信息</div>
<div class="form-group">
<label class="form-label"><span class="required">*</span>公司名称</label>
<input type="text" class="form-input" id="regCompany" placeholder="请输入完整公司名称" required autocomplete="organization">
<div class="error-msg" id="regCompanyError">请输入公司名称</div>
</div>
<div class="form-group">
<label class="form-label"><span class="required">*</span>法人姓名</label>
<input type="text" class="form-input" id="regLegalPerson" placeholder="法人代表姓名" required>
<div class="error-msg" id="regLegalPersonError">请输入法人姓名</div>
</div>
<div class="form-group">
<label class="form-label"><span class="required">*</span>法人电话</label>
<input type="tel" class="form-input" id="regLegalPhone" placeholder="用于业务联系的手机号码" required>
<div class="error-msg" id="regLegalPhoneError">请输入法人电话</div>
</div>
<div class="divider"></div>
<!-- 证件信息 -->
<div class="section-label">证件信息</div>
<div class="form-group">
<label class="form-label"><span class="required">*</span>营业执照 / 证件照</label>
<div class="license-upload-area" id="licenseUploadArea" onclick="document.getElementById('regLicenseFile').click()">
<div class="upload-placeholder">
<div class="upload-icon-big">📄</div>
<div class="upload-hint">点击上传证件图片</div>
<div class="upload-desc">支持 JPG、PNG 格式,不超过 5MB</div>
</div>
<img class="license-preview-img" id="licensePreview" alt="">
<input type="file" id="regLicenseFile" accept="image/*" onchange="handleLicenseUpload(this)">
</div>
<div class="error-msg" id="regLicenseError">请上传营业执照或相关证件</div>
</div>
<div class="form-group">
<label class="form-label">法人身份证号</label>
<input type="text" class="form-input" id="regIdCard" placeholder="18位身份证号">
</div>
<div class="divider"></div>
<!-- 地址与发票 -->
<div class="section-label">地址与发票</div>
<div class="form-group">
<label class="form-label">国家/地区</label>
<select class="form-select" id="regCountry">
<option value="中国">中国</option>
<option value="中国香港">中国香港</option>
<option value="中国台湾">中国台湾</option>
<option value="中国澳门">中国澳门</option>
<option value="美国">美国</option>
<option value="英国">英国</option>
<option value="德国">德国</option>
<option value="法国">法国</option>
<option value="日本">日本</option>
<option value="韩国">韩国</option>
<option value="澳大利亚">澳大利亚</option>
<option value="加拿大">加拿大</option>
<option value="其他">其他</option>
</select>
</div>
<div class="form-group">
<label class="form-label">详细地址</label>
<input type="text" class="form-input" id="regAddress" placeholder="公司注册地址或经营地址">
</div>
<div class="form-group">
<label class="form-label">发票抬头</label>
<input type="text" class="form-input" id="regInvoiceTitle" placeholder="用于开具发票的名称(选填)">
</div>
<div class="divider"></div>
<!-- 验证码 -->
<div class="form-group">
<label class="form-label"><span class="required">*</span>验证码</label>
<div class="captcha-group">
<input type="text" class="form-input" id="regCaptcha" placeholder="输入下方验证码" required maxlength="4">
<div class="captcha-img" id="regCaptchaImg" onclick="refreshCaptcha()" title="点击刷新验证码"></div>
</div>
<div class="error-msg" id="regCaptchaError">验证码错误,请重新输入</div>
</div>
<button type="submit" class="submit-btn">提交注册申请</button>
<div class="form-footer">
已有账号?<a href="login-register.html">立即登录 →</a>
</div>
</form>
</div>
</div>
<script>
let currentCaptcha = '';
let licenseUploaded = false;
function generateCaptcha() {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789';
let c = '';
for (let i = 0; i < 4; i++) c += chars.charAt(Math.floor(Math.random() * chars.length));
return c;
}
function refreshCaptcha() {
currentCaptcha = generateCaptcha();
const img = document.getElementById('regCaptchaImg');
img.textContent = currentCaptcha;
img.style.transform = 'rotate(' + (Math.random() * 8 - 4) + 'deg)';
img.style.color = ['#667eea','#764ba2','#818cf8','#a78bfa'][Math.floor(Math.random()*4)];
}
refreshCaptcha();
// 营业执照上传
function handleLicenseUpload(input) {
var file = input.files[0];
if (!file) return;
if (file.size > 5*1024*1024) { alert('图片大小不能超过 5MB'); input.value=''; return; }
var reader = new FileReader();
reader.onload = function(e) {
var preview = document.getElementById('licensePreview');
preview.src = e.target.result;
var area = document.getElementById('licenseUploadArea');
area.classList.add('has-image');
licenseUploaded = true;
document.getElementById('regLicenseError').classList.remove('show');
};
reader.readAsDataURL(file);
}
// 表单提交
document.getElementById('registerForm').addEventListener('submit', function(e) {
e.preventDefault();
var company = document.getElementById('regCompany').value.trim();
var legalPerson = document.getElementById('regLegalPerson').value.trim();
var legalPhone = document.getElementById('regLegalPhone').value.trim();
var captcha = document.getElementById('regCaptcha').value.trim();
document.querySelectorAll('.error-msg').forEach(function(el){ el.classList.remove('show'); });
var hasError = false;
if (!company) { document.getElementById('regCompanyError').classList.add('show'); hasError=true; }
if (!legalPerson) { document.getElementById('regLegalPersonError').classList.add('show'); hasError=true; }
if (!legalPhone) { document.getElementById('regLegalPhoneError').classList.add('show'); hasError=true; }
if (!licenseUploaded) { document.getElementById('regLicenseError').classList.add('show'); hasError=true; }
if (captcha.toUpperCase() !== currentCaptcha.toUpperCase()) {
document.getElementById('regCaptchaError').classList.add('show');
refreshCaptcha(); hasError=true;
}
if (hasError) {
this.querySelector('.submit-btn').classList.add('shake');
setTimeout(() => this.querySelector('.submit-btn').classList.remove('shake'), 450);
return;
}
alert('注册申请已提交!\n\n公司名称:' + company +
'\n\n我们将尽快审核您的资料。');
window.location.href = 'login-register.html';
});
// 实时清除错误
document.querySelectorAll('.form-input,.form-select').forEach(function(input){
input.addEventListener('input', function(){
var group = this.closest('.form-group');
if (group) { var err = group.querySelector('.error-msg'); if (err) err.classList.remove('show'); }
});
});
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

+49
View File
@@ -0,0 +1,49 @@
const http = require('http');
const fs = require('fs');
const path = require('path');
const PORT = 8081;
const mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon'
};
const server = http.createServer((req, res) => {
console.log(`${req.method} ${req.url}`);
let filePath = '.' + req.url;
if (filePath === './') {
filePath = './index.html';
}
const extname = String(path.extname(filePath)).toLowerCase();
const contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, (error, content) => {
if (error) {
if (error.code === 'ENOENT') {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 Not Found</h1>', 'utf-8');
} else {
res.writeHead(500);
res.end('Server Error: ' + error.code, 'utf-8');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
});
server.listen(PORT, () => {
console.log(`[TraePreviewUrl]: http://localhost:${PORT}`);
console.log(`Server running at http://localhost:${PORT}/`);
});
@@ -0,0 +1,290 @@
#!/usr/bin/env python3
"""
柏悦WMS - 分阶段脚本
Phase 1: 登录并保存cookies (需要可见浏览器+手动验证码)
Phase 2: 加载cookies, headless模式抓取所有页面
用法:
python3 scrape_wms_final.py login # 阶段1: 登录保存cookie
python3 scrape_wms_final.py scrape # 阶段2: 用cookie抓取
"""
import asyncio, json, sys, os, time
from playwright.async_api import async_playwright
BASE = "http://39.101.149.173"
API_BASE = "https://adtest.bylogistic.cn"
USERNAME = "admin"
PASSWORD = "ndui#Emdfj23123"
COOKIE_FILE = "/tmp/wms_cookies.json"
OUTPUT_DIR = os.path.expanduser("~/Documents/柏悦")
os.makedirs(OUTPUT_DIR, exist_ok=True)
async def phase_login():
"""打开浏览器让用户登录,然后保存cookies"""
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False, args=["--start-maximized"])
context = await browser.new_context(viewport={"width": 1440, "height": 900})
page = await context.new_page()
print("=== 打开登录页 ===")
await page.goto(f"{BASE}/user/login?redirect=%2Fwms%2FByInstoreList", timeout=30000)
await page.wait_for_timeout(2000)
# 自动填充
inputs_text = page.locator("input[type='text']")
input_pwd = page.locator("input[type='password']")
await inputs_text.nth(0).fill(USERNAME)
await input_pwd.fill(PASSWORD)
print("✅ 账号密码已填写")
print("👉 请在浏览器中输入验证码并点击'确定'")
print("⏳ 等待登录成功...")
try:
await page.wait_for_function(
"() => !window.location.pathname.includes('login')",
timeout=300000 # 等5分钟
)
print(f"✅ 登录成功! URL: {page.url}")
except Exception as e:
print(f"❌ 等待超时: {e}")
try:
await browser.close()
except:
pass
return False
# 立即保存cookies(不等页面加载完)
try:
await page.wait_for_timeout(3000)
except:
pass
try:
cookies = await context.cookies()
with open(COOKIE_FILE, "w") as f:
json.dump(cookies, f, indent=2)
print(f"✅ Cookies已保存到 {COOKIE_FILE} ({len(cookies)} 个)")
except Exception as ce:
print(f"⚠️ Cookie保存出错: {ce}")
# 截图当前页
try:
await page.screenshot(path="/tmp/wms_logged_in.png", full_page=True)
print("📸 当前页面截图: /tmp/wms_logged_in.png")
except Exception as se:
print(f"⚠️ 截图出错: {se}")
# 保持浏览器打开
print("\n浏览器将保持10秒后关闭...")
try:
await asyncio.sleep(10)
except:
pass
try:
await browser.close()
except:
pass
return True
async def phase_scrape():
"""加载cookies并headless抓取所有页面"""
# 读取cookies
if not os.path.exists(COOKIE_FILE):
print(f"❌ Cookie文件不存在: {COOKIE_FILE}")
print("请先运行: python3 scrape_wms_final.py login")
return
with open(COOKIE_FILE) as f:
saved_cookies = json.load(f)
print(f"🍪 加载了 {len(saved_cookies)} 个cookies")
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
context = await browser.new_context(viewport={"width": 1440, "height": 900})
await context.add_cookies(saved_cookies)
page = await context.new_page()
# 监听API
all_apis = []
page.on("response", lambda r: all_apis.append({
"url": r.url, "status": r.status, "method": r.request.method
}))
# 先访问入库单列表(默认首页)
print("\n=== 访问系统首页 ===")
await page.goto(f"{BASE}/wms/ByInstoreList", timeout=20000)
await page.wait_for_timeout(4000)
if "login" in page.url.lower():
print("❌ Cookies已失效,请重新运行 login 命令")
await browser.close()
return
print(f"✅ 已进入系统: {page.url}")
# ===== 抓取菜单结构 =====
print("\n=== 抓取菜单结构 ===")
menu_structure = {}
# 一级菜单
top_menus = page.locator(".ant-menu-submenu-title")
top_count = await top_menus.count()
for i in range(top_count):
try:
name = (await top_menus.nth(i).inner_text()).strip().split("\n")[0].strip()
if not name or len(name) > 20:
continue
# 展开菜单
await top_menus.nth(i).click()
await page.wait_for_timeout(600)
# 获取子菜单
sub_items = page.locator(".ant-menu-submenu-open .ant-menu-item")
subs = []
for j in range(await sub_items.count()):
try:
sn = (await sub_items.nth(j).inner_text()).strip().split("\n")[0]
if sn and len(sn) < 30:
subs.append(sn)
except:
pass
menu_structure[name] = subs
print(f" 📂 {name}: {subs}")
# 收起
await top_menus.nth(i).click()
await page.wait_for_timeout(300)
except Exception as e:
pass
# 所有要访问的页面路径
pages_to_visit = [
("首页", "/wms/Dashboard"),
("入库单列表", "/wms/ByInstoreList"),
("入库单测量", "/wms/ByInstoreList4Measured"),
("测量数据审核", "/wms/ByInstoreList4MeasuredAudit"),
("接收审核", "/wms/ByInstoreList4ReceiveAudit"),
("客户管理", "/wms/ByCustomerList"),
("出库单列表", "/wms/ByOutstoreList"),
("派送单列表", "/wms/ByDispatchList"),
("货柜管理", "/wms/ByContainerList"),
("库存管理", "/wms/ByInventoryList"),
("财务结算", "/wms/ByFinanceList"),
("托盘管理", "/wms/ByTrayList"),
("BOL管理", "/wms/ByBolList"),
("用户管理", "/system/UserList"),
("角色管理", "/system/RoleList"),
("菜单管理", "/system/MenuList"),
("字典管理", "/system/DictList"),
("参数配置", "/system/ConfigList"),
]
# ===== 逐页抓取 =====
print(f"\n=== 逐页抓取 (共{len(pages_to_visit)}页) ===\n")
pages_data = {}
for idx, (name, path) in enumerate(pages_to_visit, 1):
try:
url = BASE + path
print(f"[{idx}/{len(pages_to_visit)}] {name} -> {path}", end=" ... ")
await page.goto(url, timeout=15000)
await page.wait_for_timeout(2500)
if "login" in page.url.lower():
print("❌ 会话过期!")
break
entry = {
"title": await page.title(),
"url": page.url,
}
# 表格列头
headers = []
ths = page.locator(".ant-table-thead th, thead th, [class*='table'] th")
for i in range(min(await ths.count(), 25)):
h = (await ths.nth(i).inner_text()).strip()
if h and h not in headers:
headers.append(h)
# 搜索条件字段
fields = []
labels = page.locator(".ant-form-item-label label, .query-group label, label[for]")
for i in range(min(await labels.count(), 20)):
t = (await labels.nth(i).inner_text()).strip()
if t and t not in fields and len(t) < 30:
fields.append(t)
# 操作按钮
buttons = []
btns = page.locator(".ant-btn:not(.ant-pagination-item):not(.ant-pagination-options-quick-jumper):not([class*='link'])")
for i in range(min(await btns.count(), 15)):
b = (await btns.nth(i).inner_text()).strip()
if b and b not in buttons and len(b) < 20 and b not in ["刷 新","关 闭"]:
buttons.append(b)
# 统计卡片数字
stat_vals = []
stats = page.locator("[class*='statistic'] [class*='value'], [class*='number-card'] [class*='value']")
for i in range(min(await stats.count(), 10)):
s = (await stats.nth(i).inner_text()).strip()
if s:
stat_vals.append(s)
entry["table_headers"] = headers
entry["search_fields"] = fields
entry["buttons"] = buttons
entry["statistics"] = stat_vals
pages_data[name] = entry
print(f"✅ 表头:{len(headers)} 字段:{len(fields)} 按钮:{len(buttons)}")
# 截图每个页面
safe_name = name.replace("/", "_").replace("\\", "_")
await page.screenshot(path=f"/tmp/wms_page_{safe_name}.png")
except Exception as e:
print(f"❌ {e}")
pages_data[name] = {"error": str(e)}
# 保存完整数据
full_data = {
"system_name": "柏悦物流管理系统 (Baiyue WMS)",
"base_url": BASE,
"api_base": API_BASE,
"scrape_time": time.strftime("%Y-%m-%d %H:%M:%S"),
"menu_structure": menu_structure,
"pages": pages_data,
"api_calls": all_apis[-50:], # 最后50个API调用
}
output_file = os.path.join(OUTPUT_DIR, "wms_system_data.json")
with open(output_file, "w", encoding="utf-8") as f:
json.dump(full_data, f, indent=2, ensure_ascii=False)
print(f"\n{'='*60}")
print(f"✅ 全部完成!")
print(f" - 菜单: {len(menu_structure)} 个一级模块")
print(f" - 页面: {len(pages_data)} 个页面")
print(f" - 输出: {output_file}")
print(f"{'='*60}")
await browser.close()
if __name__ == "__main__":
cmd = sys.argv[1] if len(sys.argv) > 1 else "login"
if cmd == "login":
asyncio.run(phase_login())
elif cmd == "scrape":
asyncio.run(phase_scrape())
else:
print(f"Usage: python3 {sys.argv[0]} [login|scrape]")
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
"""
从可见浏览器中提取token,然后用API方式抓取所有数据
"""
import asyncio, json, os, time
from playwright.async_api import async_playwright
BASE = "http://39.101.149.173"
USERNAME = "admin"
PASSWORD = "ndui#Emdfj23123"
TOKEN_FILE = "/tmp/wms_token.json"
OUTPUT_DIR = os.path.expanduser("~/Documents/柏悦")
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False, args=["--start-maximized"])
context = await browser.new_context(viewport={"width": 1440, "height": 900})
page = await context.new_page()
print("=== 打开登录页 ===")
await page.goto(f"{BASE}/user/login?redirect=%2Fwms%2FByInstoreList", timeout=30000)
await page.wait_for_timeout(2000)
# 填充
inputs = page.locator("input[type='text']")
pwd = page.locator("input[type='password']")
await inputs.nth(0).fill(USERNAME)
await pwd.fill(PASSWORD)
print("👉 请在浏览器中输入验证码并点击确定...")
try:
await page.wait_for_function(
"() => !window.location.pathname.includes('login')",
timeout=300000
)
print("✅ 登录成功!")
except:
print("❌ 超时")
await browser.close()
return
await page.wait_for_timeout(3000)
# ========== 抓取完整菜单结构 ==========
print("\n=== 抓取菜单 ===")
menu_structure = {}
page_list = [] # [(display_name, url_path)]
top_menus = page.locator(".ant-menu-submenu-title")
for i in range(await top_menus.count()):
try:
name = (await top_menus.nth(i).inner_text()).strip().split("\n")[0].strip()
if not name or len(name) > 20:
continue
await top_menus.nth(i).click()
await page.wait_for_timeout(500)
subs = []
sub_items = page.locator(".ant-menu-submenu-open .ant-menu-item")
for j in range(await sub_items.count()):
sn = (await sub_items.nth(j).inner_text()).strip().split("\n")[0]
if sn and len(sn) < 30:
subs.append(sn)
menu_structure[name] = subs
print(f" {name}: {subs}")
await top_menus.nth(i).click()
await page.wait_for_timeout(300)
except:
pass
# ========== 逐页截图抓取 ==========
print(f"\n=== 逐页抓取 ===")
# 构建所有要访问的页面
all_pages = [("首页", "/wms/Dashboard")]
for menu_name, subs in menu_structure.items():
for sub in subs:
# 推断URL路径
path_map = {
"入库单列表": "/wms/ByInstoreList",
"入库单测量": "/wms/ByInstoreList4Measured",
"测量数据审核": "/wms/ByInstoreList4MeasuredAudit",
"接收审核": "/wms/ByInstoreList4ReceiveAudit",
"客户管理": "/wms/ByCustomerList",
"出库单列表": "/wms/ByOutstoreList",
"派送单列表": "/wms/ByDispatchList",
"BOL管理": "/wms/ByBolList",
"货柜管理": "/wms/ByContainerList",
"库存管理": "/wms/ByInventoryList",
"财务结算": "/wms/ByFinanceList",
"托盘管理": "/wms/ByTrayList",
"用户管理": "/system/UserList",
"角色管理": "/system/RoleList",
"菜单管理": "/system/MenuList",
"字典管理": "/system/DictList",
"参数配置": "/system/ConfigList",
"通用配置": "/system/ConfigList",
"报表设计": "/wms/Dashboard", # 待确认
"消息中心": "/wms/Dashboard",
"常见案例": "/wms/Dashboard",
"在线开发": "/wms/Dashboard",
"系统监控": "/wms/Dashboard",
"统计报表": "/wms/Dashboard",
}
path = path_map.get(sub, "")
if path:
all_pages.append((f"{menu_name} > {sub}", path))
# 去重
seen = set()
unique_pages = []
for name, path in all_pages:
if path not in seen:
seen.add(path)
unique_pages.append((name, path))
pages_data = {}
success_count = 0
for idx, (name, path) in enumerate(unique_pages, 1):
try:
url = BASE + path
print(f"[{idx}/{len(unique_pages)}] {name}", end=" ... ")
await page.goto(url, timeout=15000)
await page.wait_for_timeout(2500)
if "login" in page.url.lower():
print("会话过期!")
break
# 抓表格列头
headers = []
th_selectors = [".ant-table-thead th", "thead th", "table th"]
for ths in th_selectors:
els = page.locator(ths)
for i in range(min(await els.count(), 30)):
try:
h = (await els.nth(i).inner_text()).strip()
if h and h not in headers:
headers.append(h)
except:
pass
# 搜索字段
fields = []
labels = page.locator("label, .ant-form-item-label")
for i in range(min(await labels.count(), 25)):
try:
t = (await labels.nth(i).inner_text()).strip()
if t and t not in fields and len(t) < 30:
fields.append(t)
except:
pass
# 操作按钮
buttons = []
btns = page.locator("button:not([class*='pagination']):not([class*='quick-jumper'])")
for i in range(min(await btns.count(), 20)):
try:
b = (await btns.nth(i).inner_text()).strip()
if b and b not in buttons and len(b) < 25:
buttons.append(b)
except:
pass
pages_data[name] = {
"url": url,
"title": await page.title(),
"table_headers": headers,
"search_fields": fields,
"buttons": buttons,
}
print(f"✅ headers:{len(headers)} fields:{len(fields)} btns:{len(buttons)}")
success_count += 1
except Exception as e:
print(f"❌ {str(e)[:80]}")
pages_data[name] = {"error": str(e)[:200]}
# 保存数据
output = {
"system_name": "柏悦物流管理系统 (Baiyue WMS)",
"scrape_time": time.strftime("%Y-%m-%d %H:%M:%S"),
"menu_structure": menu_structure,
"pages": pages_data,
"pages_count": success_count,
}
out_path = os.path.join(OUTPUT_DIR, "wms_full_data.json")
with open(out_path, "w", encoding="utf-8") as f:
json.dump(output, f, indent=2, ensure_ascii=False)
print(f"\n✅ 完成! {success_count}/{len(unique_pages)} 页面成功抓取")
print(f"输出: {out_path}")
print("\n浏览器10秒后关闭...")
await asyncio.sleep(10)
await browser.close()
asyncio.run(main())
@@ -0,0 +1,322 @@
{
"system_name": "柏悦物流管理系统 (Baiyue WMS)",
"scrape_time": "2026-06-01 12:06:00",
"menu_structure": {
"客户管理": [
"客户公司管理",
"用户资料",
"海外仓阶梯费用",
"客户账户流水"
],
"入库": [
"入库单列表",
"入库单测量",
"测量数据审核",
"接收审核"
],
"出库": [
"派送单列表",
"BOL",
"自提单"
],
"货柜管理": [
"货柜列表",
"装柜清单"
],
"库存": [
"海外仓库存查询",
"理货管理",
"报损单"
],
"财务结算": [
"客户应收应付",
"客户对账单",
"结算单位应付",
"结算单位对账单",
"洛杉矶仓储成本"
],
"托盘管理": [
"托盘列表",
"生成托盘"
],
"通用": [
"产品信息",
"费用项目",
"FBA编码地址",
"托盘管理",
"库位/货架管理",
"订单流转路径",
"快递公司",
"往来单位"
],
"常见案例": [
"自定义组件",
"对象存储"
],
"在线开发": [
"Online表单开发"
],
"报表设计": [
"积木报表设计",
"生产销售监控",
"智慧物流监控"
],
"消息中心": [
"模板管理",
"消息管理",
"我的消息"
],
"系统管理": [
"用户管理",
"角色管理",
"菜单管理",
"租户管理",
"部门管理",
"我的部门",
"职务管理",
"通讯录",
"数据字典",
"分类字典",
"系统通告",
"菜单管理2"
],
"系统监控": [
"在线用户",
"路由网关",
"定时任务",
"日志管理",
"数据日志",
"SQL监控",
"在线文档"
]
},
"pages": {
"首页": {
"url": "http://39.101.149.173/wms/Dashboard",
"title": "柏悦物流管理系统",
"table_headers": [],
"search_fields": [],
"buttons": [
"返回首页"
]
},
"入库 > 入库单列表": {
"url": "http://39.101.149.173/wms/ByInstoreList",
"title": "入库单列表 · 柏悦物流管理系统",
"table_headers": [
"仓库",
"交货仓",
"配载状态",
"是否扣货",
"扣货理由",
"集装箱号",
"柜号",
"公司",
"业务类型",
"提货方式",
"提货时间",
"提货联系人电话",
"提货地址",
"提货邮编",
"提货联系人邮箱",
"渠道",
"买单/退税",
"是否整柜",
"商检验",
"开船时间",
"到港时间",
"总箱数",
"总毛重(T.K.GW)"
],
"search_fields": [
"定位仓库",
"交货仓",
"入仓码",
"订单状态",
"费用审核状态"
],
"buttons": [
"查询",
"重置",
"国内仓下单",
"海外分仓下单",
"整托下单",
"高级查询",
"导出报表",
"导出入库清单总表",
"导出唛头",
"导出FBA流转单ZIP",
"下载"
]
},
"入库 > 入库单测量": {
"url": "http://39.101.149.173/wms/ByInstoreList4Measured",
"title": "入库单测量 · 柏悦物流管理系统",
"table_headers": [
"入仓码",
"仓库",
"订单状态",
"配载状态",
"测量数据审核状态",
"唛头文件",
"是否扣货",
"扣货理由",
"公司",
"业务类型",
"渠道",
"买单/退税",
"是否整柜",
"商检验",
"总箱数",
"总毛重(T.K.GW)",
"总体积(m³)",
"总材积重",
"总净重(T.K.NW)",
"目的仓类型",
"目的仓",
"货件编号",
"测量完成时间",
"操作"
],
"search_fields": [
"仓库",
"入仓码",
"公司",
"FBA货件编号"
],
"buttons": [
"查询",
"重置",
"下载"
]
},
"入库 > 测量数据审核": {
"url": "http://39.101.149.173/wms/ByInstoreList4MeasuredAudit",
"title": "测量数据审核 · 柏悦物流管理系统",
"table_headers": [
"入仓码",
"仓库",
"订单状态",
"配载状态",
"测量数据审核状态",
"唛头文件",
"是否扣货",
"扣货理由",
"公司",
"业务类型",
"渠道",
"买单/退税",
"是否整柜",
"商检验",
"总箱数",
"总毛重(T.K.GW)",
"总体积(m³)",
"总材积重",
"总净重(T.K.NW)",
"目的仓类型",
"目的仓",
"货件编号",
"测量完成时间",
"操作"
],
"search_fields": [
"仓库",
"入仓码",
"公司",
"FBA货件编号"
],
"buttons": [
"查询",
"重置",
"下载"
]
},
"入库 > 接收审核": {
"url": "http://39.101.149.173/wms/ByInstoreList4ReceiveAudit",
"title": "接收审核 · 柏悦物流管理系统",
"table_headers": [
"入仓码",
"仓库",
"订单状态",
"配载状态",
"测量数据审核状态",
"唛头文件",
"是否扣货",
"扣货理由",
"公司",
"业务类型",
"渠道",
"买单/退税",
"是否整柜",
"商检验",
"总箱数",
"总毛重(T.K.GW)",
"总体积(m³)",
"总材积重",
"总净重(T.K.NW)",
"目的仓类型",
"目的仓",
"货件编号",
"测量完成时间",
"操作"
],
"search_fields": [
"仓库",
"入仓码",
"公司",
"FBA货件编号"
],
"buttons": [
"查询",
"重置",
"下载"
]
},
"出库 > 派送单列表": {
"url": "http://39.101.149.173/wms/ByDispatchList",
"title": "柏悦物流管理系统",
"table_headers": [],
"search_fields": [],
"buttons": [
"返回首页"
]
},
"通用 > 托盘管理": {
"url": "http://39.101.149.173/wms/ByTrayList",
"title": "柏悦物流管理系统",
"table_headers": [],
"search_fields": [],
"buttons": [
"返回首页"
]
},
"系统管理 > 用户管理": {
"url": "http://39.101.149.173/system/UserList",
"title": "柏悦物流管理系统",
"table_headers": [],
"search_fields": [],
"buttons": [
"返回首页"
]
},
"系统管理 > 角色管理": {
"url": "http://39.101.149.173/system/RoleList",
"title": "柏悦物流管理系统",
"table_headers": [],
"search_fields": [],
"buttons": [
"返回首页"
]
},
"系统管理 > 菜单管理": {
"url": "http://39.101.149.173/system/MenuList",
"title": "柏悦物流管理系统",
"table_headers": [],
"search_fields": [],
"buttons": [
"返回首页"
]
}
},
"pages_count": 10
}
@@ -0,0 +1,393 @@
{
"menu_items": [
{
"text": "首页",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "入库单列表",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "入库单测量",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "测量数据审核",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "接收审核",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "刷 新",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "关闭左侧",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "关闭右侧",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "关闭其它",
"selector": ".ant-menu-item",
"href": ""
},
{
"text": "客户管理",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "入库",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "出库",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "货柜管理",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "库存",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "财务结算",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "托盘管理",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "通用",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "常见案例",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "在线开发",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "报表设计",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "消息中心",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "系统管理",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "系统监控",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "统计报表",
"selector": ".ant-menu-submenu-title",
"href": ""
},
{
"text": "入库 入库单列表 入库单测量 测量数据审核 接收审核",
"selector": "li[role='menuitem']",
"href": ""
},
{
"text": "定位仓库 请选择仓库",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "定位仓库",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "请选择仓库",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "交货仓 请选择交货仓",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "交货仓",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "请选择交货仓",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "入仓码",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "订单状态 请选择订单状态",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "订单状态",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "请选择订单状态",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "费用审核状态 请选择费用审核状态",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "费用审核状态",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "请选择费用审核状态",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "1",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "2",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "3",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "4",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "5",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "•••",
"selector": "[class*='menu'] [class*='item']",
"href": ""
},
{
"text": "36",
"selector": "[class*='menu'] [class*='item']",
"href": ""
}
],
"all_links": [
"/system/ConfigList",
"/system/DictList",
"/system/MenuList",
"/system/RoleList",
"/system/UserList",
"/wms/ByBolList",
"/wms/ByContainerList",
"/wms/ByCustomerList",
"/wms/ByDispatchList",
"/wms/ByFinanceList",
"/wms/ByInstoreList",
"/wms/ByInstoreList4Measured",
"/wms/ByInstoreList4MeasuredAudit",
"/wms/ByInstoreList4ReceiveAudit",
"/wms/ByInventoryList",
"/wms/ByOutstoreList",
"/wms/ByTrayList",
"/wms/Dashboard",
"/wms/home",
"/wms/index"
],
"api_calls": [
{
"url": "http://39.101.149.173/user/login?redirect=%2Fwms%2FByInstoreList",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285671792?_t=1780285671",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285691766?_t=1780285691",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285694400?_t=1780285694",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/login",
"status": 200,
"method": "POST"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285703728?_t=1780285703",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/login",
"status": 200,
"method": "POST"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285711155?_t=1780285711",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/login",
"status": 200,
"method": "POST"
},
{
"url": "http://39.101.149.173/user/login?redirect=%2Fwms%2FByInstoreList",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285725968?_t=1780285725",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/randomImage/1780285750913?_t=1780285750",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/login",
"status": 200,
"method": "POST"
},
{
"url": "https://adtest.bylogistic.cn/sys/permission/getUserPermissionByToken?_t=1780285758",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_company,company_name,id",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_order_status,name,value,value%20not%20in%20(1001%5E%5E1002)",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_customer,realname,id",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_store,store_name,store_no",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_order_status,name,value",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_store,store_name,store_no,parent_store_id!=''",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_order_path,path_name,id",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/dict/getDictItems/by_fba,fba_no,fba_no",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/annountCement/listByUser?_t=1780285758",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/permission/getUserPermissionByToken?_t=1780285762",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/loginfo?_t=1780285763",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/visitInfo?_t=1780285763",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/annountCement/listByUser?_t=1780285763",
"status": 200,
"method": "GET"
},
{
"url": "https://adtest.bylogistic.cn/sys/permission/getUserPermissionByToken?_t=1780285764",
"status": 200,
"method": "GET"
}
]
}
@@ -0,0 +1,67 @@
{
"/system/ConfigList": {
"title": "柏悦物流管理系统",
"url": "http://39.101.149.173/dashboard/analysis",
"headers": [],
"buttons": [],
"form_fields": [],
"content_preview": "欢迎进入 柏悦物流管理系统\n欢迎您,管理员 退出登录\n首页\nCopyright 2022 BaiYue Logisitcs"
},
"/system/DictList": {
"error": "Page.wait_for_timeout: Target page, context or browser has been closed"
},
"/system/MenuList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/system/RoleList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/system/UserList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByBolList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByContainerList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByCustomerList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByDispatchList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByFinanceList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByInstoreList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByInstoreList4Measured": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByInstoreList4MeasuredAudit": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByInstoreList4ReceiveAudit": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByInventoryList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByOutstoreList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/ByTrayList": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/Dashboard": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/home": {
"error": "Page.goto: Target page, context or browser has been closed"
},
"/wms/index": {
"error": "Page.goto: Target page, context or browser has been closed"
}
}
@@ -0,0 +1,510 @@
# 柏悦物流管理系统(Baiyue WMS)系统文档
> **版本**: 基于测试系统 2026-06-01 抓取分析
> **访问地址**: http://39.101.149.173
> **后端API**: https://adtest.bylogistic.cn
> **技术栈**: Ant Design Vue + Spring Boot + MySQL + Redis
> **测试账号**: admin / ndui#Emdfj23123
---
## 目录
1. [系统概述](#1-系统概述)
2. [技术架构](#2-技术架构)
3. [首页仪表盘](#3-首页仪表盘)
4. [客户管理模块](#4-客户管理模块)
5. [入库管理模块](#5-入库管理模块)
6. [出库管理模块](#6-出库管理模块)
7. [货柜管理模块](#7-货柜管理模块)
8. [库存管理模块](#8-库存管理模块)
9. [财务结算模块](#9-财务结算模块)
10. [托盘管理模块](#10-托盘管理模块)
11. [通用配置模块](#11-通用配置模块)
12. [常见案例模块](#12-常见案例模块)
13. [在线开发模块](#13-在线开发模块)
14. [报表设计模块](#14-报表设计模块)
15. [消息中心模块](#15-消息中心模块)
16. [系统管理模块](#16-系统管理模块)
17. [系统监控模块](#17-系统监控模块)
18. [API接口清单](#18-api接口清单)
---
## 1. 系统概述
柏悦物流管理系统(Baiyue WMS)是一套面向跨境物流仓储行业的综合管理系统,覆盖从**客户管理 → 入库 → 出库 → 货柜管理 → 库存 → 托盘 → 财务结算**的全链路业务流程。
### 1.1 核心业务流程
```
客户下单 → 入库单 → 入库测量 → 测量审核 → 接收审核 → 库存管理
↓
出库单 → BOL/派送 → 托盘管理 → 货柜管理 → 财务结算
```
### 1.2 系统模块总览
| 序号 | 模块 | 子页面数 | 说明 |
|------|------|----------|------|
| 1 | 首页 | 1 | 数据看板/仪表盘 |
| 2 | 客户管理 | 4 | 客户公司、用户、阶梯费用、流水 |
| 3 | 入库 | 4 | 入库单、测量、审核、接收 |
| 4 | 出库 | 3 | 派送单、BOL、自提单 |
| 5 | 货柜管理 | 2 | 货柜列表、装柜清单 |
| 6 | 库存 | 3 | 海外仓库存查询、理货、报损 |
| 7 | 财务结算 | 5 | 应收应付、对账单、仓储成本 |
| 8 | 托盘管理 | 2 | 托盘列表、生成托盘 |
| 9 | 通用 | 8 | 产品、费用、FBA地址、库位等 |
| 10 | 常见案例 | 2 | 自定义组件、对象存储 |
| 11 | 在线开发 | 1 | Online表单开发 |
| 12 | 报表设计 | 3 | 积木报表、生产监控、物流监控 |
| 13 | 消息中心 | 3 | 模板、消息管理、我的消息 |
| 14 | 系统管理 | 12 | 用户、角色、菜单、租户等 |
| 15 | 系统监控 | 7 | 在线用户、日志、定时任务等 |
| 16 | 统计报表 | - | 报表设计入口 |
---
## 2. 技术架构
### 2.1 前端技术
- **框架**: Vue.js(SPA 单页应用)
- **UI 组件库**: Ant Design Vue
- **路由**: Vue Router(Hash 模式)
- **状态管理**: Vuex
- **图表**: 集成数据可视化组件
### 2.2 后端技术
- **框架**: Spring Boot(推测,基于 Spring 生态)
- **数据库**: MySQL
- **缓存**: Redis
- **认证**: Token-based(JWT)
- **API 风格**: RESTful
### 2.3 认证流程
```
用户登录 → POST /sys/login → 返回 Token
后续请求 → Header: Authorization: Bearer {token}
权限验证 → GET /sys/permission/getUserPermissionByToken
```
---
## 3. 首页仪表盘
- **URL**: `/wms/Dashboard`
- **页面标题**: 柏悦物流管理系统
首页提供系统总览数据看板,展示关键业务指标(订单数、库存状态、财务概况等)。
---
## 4. 客户管理模块
### 4.1 客户公司管理
管理客户公司的基本信息,包括公司名称、联系方式、合作状态等。
### 4.2 用户资料
管理客户下的用户账号资料,包括登录账号、角色权限等。
### 4.3 海外仓阶梯费用
配置客户在海外仓的阶梯式费用规则,按不同量级设置不同单价。
### 4.4 客户账户流水
查看客户账户的资金流水明细,包括充值、消费、退款等记录。
---
## 5. 入库管理模块
入库是系统的核心业务流程模块,包含四个阶段:入库单创建 → 测量 → 测量审核 → 接收审核。
### 5.1 入库单列表
- **URL**: `/wms/ByInstoreList`
- **页面标题**: 入库单列表 · 柏悦物流管理系统
#### 搜索条件
| 字段 | 说明 |
|------|------|
| 定位仓库 | 筛选指定仓库的入库单 |
| 交货仓 | 筛选指定交货仓的入库单 |
| 入仓码 | 按入仓码精确查询 |
| 订单状态 | 按订单状态筛选(如:待处理、处理中、已完成) |
| 费用审核状态 | 按费用审核状态筛选 |
#### 表格列头(23列)
| 列名 | 说明 |
|------|------|
| 仓库 | 入库目标仓库 |
| 交货仓 | 货物来源交货仓 |
| 配载状态 | 货物配载状态 |
| 是否扣货 | 是否被扣货标记 |
| 扣货理由 | 扣货原因说明 |
| 集装箱号 | 集装箱编号 |
| 柜号 | 货柜编号 |
| 公司 | 客户公司名称 |
| 业务类型 | 业务分类 |
| 提货方式 | 提货方式(自提/送货等) |
| 提货时间 | 预约提货时间 |
| 提货联系人电话 | 提货联系人电话 |
| 提货地址 | 提货地址详情 |
| 提货邮编 | 提货地邮编 |
| 提货联系人邮箱 | 提货联系人邮箱 |
| 渠道 | 业务渠道来源 |
| 买单/退税 | 贸易方式(买单/退税) |
| 是否整柜 | 整柜/拼柜标记 |
| 商检验 | 商检检验标记 |
| 开船时间 | 预计开船时间 |
| 到港时间 | 预计到港时间 |
| 总箱数 | 货物总箱数 |
| 总毛重(T.K.GW) | 总毛重(吨/公斤) |
#### 操作按钮
| 按钮 | 功能 |
|------|------|
| 查询 | 根据搜索条件查询数据 |
| 重置 | 清空搜索条件 |
| 国内仓下单 | 创建国内仓入库单 |
| 海外分仓下单 | 创建海外分仓入库单 |
| 整托下单 | 以整托方式创建入库单 |
| 高级查询 | 打开高级筛选面板 |
| 导出报表 | 导出当前查询结果为Excel |
| 导出入库清单总表 | 导出完整的入库清单 |
| 导出唛头 | 导出唛头标签文件 |
| 导出FBA流转单ZIP | 导出FBA流转单压缩包 |
| 下载 | 下载选中记录的相关文件 |
### 5.2 入库单测量
- **URL**: `/wms/ByInstoreList4Measured`
- **页面标题**: 入库单测量 · 柏悦物流管理系统
对入库货物进行实际测量,记录测量数据。
#### 搜索条件
| 字段 | 说明 |
|------|------|
| 仓库 | 筛选仓库 |
| 入仓码 | 按入仓码查询 |
| 公司 | 按客户公司筛选 |
| FBA货件编号 | 按FBA货件编号查询 |
#### 表格列头(24列)
| 列名 | 说明 |
|------|------|
| 入仓码 | 入仓编码 |
| 仓库 | 目标仓库 |
| 订单状态 | 订单处理状态 |
| 配载状态 | 配载情况 |
| 测量数据审核状态 | 测量审核进度 |
| 唛头文件 | 唛头标签文件 |
| 是否扣货 | 扣货标记 |
| 扣货理由 | 扣货原因 |
| 公司 | 客户公司 |
| 业务类型 | 业务分类 |
| 渠道 | 业务渠道 |
| 买单/退税 | 贸易方式 |
| 是否整柜 | 整柜/拼柜 |
| 商检验 | 商检状态 |
| 总箱数 | 货物总箱数 |
| 总毛重(T.K.GW) | 总毛重 |
| 总体积(m³) | 货物总体积 |
| 总材积重 | 材积重量 |
| 总净重(T.K.NW) | 总净重 |
| 目的仓类型 | 目的仓库类型 |
| 目的仓 | 目的仓库 |
| 货件编号 | 货件编号 |
| 测量完成时间 | 测量完成时间 |
| 操作 | 操作按钮列 |
#### 操作按钮
| 按钮 | 功能 |
|------|------|
| 查询 | 根据条件查询 |
| 重置 | 清空条件 |
| 下载 | 下载数据 |
### 5.3 测量数据审核
- **URL**: `/wms/ByInstoreList4MeasuredAudit`
- **页面标题**: 测量数据审核 · 柏悦物流管理系统
对测量数据进行审核确认。表头和搜索条件与入库单测量一致。
### 5.4 接收审核
- **URL**: `/wms/ByInstoreList4ReceiveAudit`
- **页面标题**: 接收审核 · 柏悦物流管理系统
最终接收审核环节,确认货物入库完成。表头和搜索条件与入库单测量一致。
---
## 6. 出库管理模块
### 6.1 派送单列表
- **URL**: `/wms/ByDispatchList`
管理出库派送订单,包括派送地址、物流方式、派送状态等。
### 6.2 BOL(提单管理)
- **URL**: `/wms/ByBolList`
管理 Bill of Lading(提单),是国际物流中的重要单证。包括提单号、船名航次、发货人、收货人等。
### 6.3 自提单
管理客户自提订单,记录自提预约、提货人信息等。
---
## 7. 货柜管理模块
### 7.1 货柜列表
- **URL**: `/wms/ByContainerList`
管理所有货柜信息,包括柜号、类型、尺寸、状态、当前位置等。
### 7.2 装柜清单
记录每个货柜的装柜明细,展示柜内货物列表和装载方案。
---
## 8. 库存管理模块
### 8.1 海外仓库存查询
- **URL**: `/wms/ByInventoryList`
查询海外仓当前库存情况,支持按仓库、产品、SKU等维度查询。
### 8.2 理货管理
对库存货物进行盘点、整理、移位等操作。
### 8.3 报损单
管理货物损耗/损坏的报损申请和审批流程。
---
## 9. 财务结算模块
### 9.1 客户应收应付
- **URL**: `/wms/ByFinanceList`
管理每个客户的应收账款和应付账款明细。
### 9.2 客户对账单
生成和查看客户对账单,用于与客户进行账务核对。
### 9.3 结算单位应付
按结算单位(如承运商、仓库方)管理应付账款。
### 9.4 结算单位对账单
生成结算单位的对账单。
### 9.5 洛杉矶仓储成本
专门针对洛杉矶仓库的仓储成本核算和分析。
---
## 10. 托盘管理模块
### 10.1 托盘列表
- **URL**: `/wms/ByTrayList`
管理所有托盘信息,包括托盘编号、规格、状态、关联货物等。
### 10.2 生成托盘
根据入库货物自动/手动生成托盘,分配货物到托盘。
---
## 11. 通用配置模块
系统基础数据和配置管理。
| 子模块 | 说明 |
|--------|------|
| 产品信息 | 管理产品/货品基础信息(名称、规格、HS编码等) |
| 费用项目 | 定义各类费用项目(仓储费、操作费、运输费等) |
| FBA编码地址 | 管理Amazon FBA仓库编码和地址信息 |
| 托盘管理 | 托盘基础配置 |
| 库位/货架管理 | 仓库库位和货架的编号和配置 |
| 订单流转路径 | 定义订单在不同节点之间的流转规则 |
| 快递公司 | 合作的快递/物流公司信息 |
| 往来单位 | 管理供应商、承运商等往来单位信息 |
---
## 12. 常见案例模块
### 12.1 自定义组件
展示系统自定义组件的使用示例和开发指南。
### 12.2 对象存储
文件/对象存储功能的配置和使用说明。
---
## 13. 在线开发模块
### 13.1 Online表单开发
低代码表单开发工具,允许管理员在线设计和配置业务表单,无需编写代码。
---
## 14. 报表设计模块
### 14.1 积木报表设计
可视化报表设计器,支持拖拽式设计各类业务报表。
### 14.2 生产销售监控
展示生产和销售的监控数据看板。
### 14.3 智慧物流监控
物流全链路监控大屏,展示实时物流数据。
---
## 15. 消息中心模块
### 15.1 模板管理
管理系统通知的消息模板,支持短信、邮件、站内信等类型。
### 15.2 消息管理
查看和管理所有已发送的系统消息。
### 15.3 我的消息
当前登录用户收到的个人消息列表。
---
## 16. 系统管理模块
系统后台管理功能。
| 子模块 | 说明 |
|--------|------|
| 用户管理 | 管理系统用户账号(创建、编辑、禁用、重置密码) |
| 角色管理 | 定义角色并分配权限 |
| 菜单管理 | 配置系统导航菜单结构 |
| 租户管理 | 多租户隔离管理(适用于SaaS模式) |
| 部门管理 | 组织架构部门管理 |
| 我的部门 | 当前用户所属部门信息 |
| 职务管理 | 定义系统内职务 |
| 通讯录 | 系统用户通讯录 |
| 数据字典 | 系统枚举值和字典数据维护 |
| 分类字典 | 分类树形字典维护 |
| 系统通告 | 发布系统级公告通知 |
| 菜单管理2 | 菜单管理的增强版/备用入口 |
---
## 17. 系统监控模块
系统运行状态监控和运维管理。
| 子模块 | 说明 |
|--------|------|
| 在线用户 | 查看当前在线用户列表,支持强制下线 |
| 路由网关 | 查看系统路由配置和网关状态 |
| 定时任务 | 管理系统的定时任务(Cron Job) |
| 日志管理 | 查看系统操作日志 |
| 数据日志 | 数据变更日志记录 |
| SQL监控 | SQL执行监控(基于Druid连接池) |
| 在线文档 | 系统API文档(Swagger/Knife4j) |
---
## 18. API接口清单
系统后端API部署在 `https://adtest.bylogistic.cn`,以下为已发现的API端点:
### 认证相关
| 接口 | 方法 | 说明 |
|------|------|------|
| `/sys/login` | POST | 用户登录 |
| `/sys/randomImage/{timestamp}` | GET | 获取验证码图片 |
| `/sys/permission/getUserPermissionByToken` | GET | 获取用户权限 |
### 数据字典
| 接口 | 方法 | 说明 |
|------|------|------|
| `/sys/dict/getDictItems/by_company` | GET | 获取公司字典 |
| `/sys/dict/getDictItems/by_order_status` | GET | 获取订单状态字典 |
| `/sys/dict/getDictItems/by_customer` | GET | 获取客户字典 |
| `/sys/dict/getDictItems/by_store` | GET | 获取仓库字典 |
| `/sys/dict/getDictItems/by_order_path` | GET | 获取订单路径字典 |
| `/sys/dict/getDictItems/by_fba` | GET | 获取FBA编码字典 |
### 系统功能
| 接口 | 方法 | 说明 |
|------|------|------|
| `/sys/annountCement/listByUser` | GET | 获取用户公告列表 |
| `/sys/loginfo` | GET | 系统日志信息 |
| `/sys/visitInfo` | GET | 访问统计信息 |
---
## 附录:SKU明细区域列头
在入库单详情页面,SKU明细表格包含以下列:
| 列名 | 说明 |
|------|------|
| 操作 | 编辑/删除操作 |
| # | 序号 |
| 报关HS_CODE | 报关用HS海关编码 |
| 货品图片 | 货品图片预览 |
| 仓/储/微(快递)码/纱 | 仓储编码/微信码/快递码 |
| 中品名 | 中文品名 |
| 英品名 | 英文品名 |
| 清关HS_CODE | 清关用HS海关编码 |
| 箱规长(cm) | 外箱长度 |
| 箱规宽(cm) | 外箱宽度 |
---
> **文档生成时间**: 2026-06-01
> **数据来源**: 测试系统 http://39.101.149.173 实际登录抓取
> **说明**: 部分页面因SPA路由限制未能获取完整表头信息,已根据菜单结构推断标注。如需补充具体页面详情,请登录系统确认后更新。
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff