| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>电商库存管理系统 - 首页</title>
- <script src="https://cdn.tailwindcss.com"></script>
- <style>
- @media (max-width: 640px) {
- .stat-grid { grid-template-columns: repeat(2, 1fr) !important; }
- }
- </style>
- </head>
- <body class="bg-gray-50 min-h-screen">
- <!-- 顶部导航 -->
- <nav class="bg-blue-600 text-white shadow-lg">
- <div class="container mx-auto px-4 py-4">
- <div class="flex justify-between items-center">
- <div class="flex items-center space-x-3">
- <span class="text-2xl">📦</span>
- <h1 class="text-xl font-bold">电商库存管理系统</h1>
- </div>
- <div class="flex space-x-4">
- <a href="/" class="bg-blue-500 px-3 py-2 rounded">首页</a>
- <a href="/shops" class="hover:bg-blue-500 px-3 py-2 rounded">店铺</a>
- <a href="/products" class="hover:bg-blue-500 px-3 py-2 rounded">商品</a>
- <a href="/inventory" class="hover:bg-blue-500 px-3 py-2 rounded">库存</a>
- <a href="/orders" class="hover:bg-blue-500 px-3 py-2 rounded">订单</a>
- </div>
- </div>
- </div>
- </nav>
-
- <!-- 主内容区 -->
- <main class="container mx-auto px-4 py-8">
- <!-- 页面标题 -->
- <div class="mb-8">
- <h2 class="text-3xl font-bold text-gray-800">📊 数据看板</h2>
- <p class="text-gray-600 mt-2">实时掌握库存和销售动态</p>
- </div>
-
- <!-- 统计卡片 -->
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mb-8 stat-grid">
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex items-center justify-between">
- <div>
- <p class="text-gray-500 text-sm">商品总数</p>
- <p id="totalProducts" class="text-3xl font-bold text-blue-600">-</p>
- </div>
- <div class="text-4xl">📦</div>
- </div>
- </div>
-
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex items-center justify-between">
- <div>
- <p class="text-gray-500 text-sm">店铺数量</p>
- <p id="totalShops" class="text-3xl font-bold text-green-600">-</p>
- </div>
- <div class="text-4xl">🏪</div>
- </div>
- </div>
-
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex items-center justify-between">
- <div>
- <p class="text-gray-500 text-sm">库存预警</p>
- <p id="lowStockCount" class="text-3xl font-bold text-red-600">-</p>
- </div>
- <div class="text-4xl">⚠️</div>
- </div>
- </div>
-
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex items-center justify-between">
- <div>
- <p class="text-gray-500 text-sm">今日订单</p>
- <p id="todayOrders" class="text-3xl font-bold text-purple-600">-</p>
- </div>
- <div class="text-4xl">📋</div>
- </div>
- </div>
-
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex items-center justify-between">
- <div>
- <p class="text-gray-500 text-sm">总库存</p>
- <p id="totalInventory" class="text-3xl font-bold text-orange-600">-</p>
- </div>
- <div class="text-4xl">📈</div>
- </div>
- </div>
- </div>
-
- <!-- 快捷操作和预警 -->
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
- <!-- 快捷操作 -->
- <div class="bg-white rounded-lg shadow p-6">
- <h3 class="text-lg font-semibold mb-4">🚀 快捷操作</h3>
- <div class="grid grid-cols-2 gap-3">
- <button onclick="location.href='/shops'" class="bg-green-600 text-white px-4 py-3 rounded-lg hover:bg-green-700 transition">
- ➕ 添加店铺
- </button>
- <button onclick="location.href='/products'" class="bg-blue-600 text-white px-4 py-3 rounded-lg hover:bg-blue-700 transition">
- 📦 添加商品
- </button>
- <button onclick="syncInventory()" class="bg-purple-600 text-white px-4 py-3 rounded-lg hover:bg-purple-700 transition">
- 🔄 同步库存
- </button>
- <button onclick="location.href='/inventory'" class="bg-orange-600 text-white px-4 py-3 rounded-lg hover:bg-orange-700 transition">
- 📊 查看库存
- </button>
- </div>
- </div>
-
- <!-- 库存预警 -->
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex justify-between items-center mb-4">
- <h3 class="text-lg font-semibold">⚠️ 库存预警</h3>
- <span id="alertCount" class="bg-red-500 text-white text-xs px-2 py-1 rounded-full">0</span>
- </div>
- <div id="alertList" class="space-y-3">
- <p class="text-gray-500 text-center py-8">加载中...</p>
- </div>
- </div>
- </div>
-
- <!-- 最近订单 -->
- <div class="bg-white rounded-lg shadow p-6">
- <div class="flex justify-between items-center mb-4">
- <h3 class="text-lg font-semibold">📋 最近订单</h3>
- <a href="/orders" class="text-blue-600 hover:underline">查看全部 →</a>
- </div>
- <div id="recentOrders" class="space-y-3">
- <p class="text-gray-500 text-center py-8">加载中...</p>
- </div>
- </div>
- </main>
-
- <script>
- const API_BASE = '';
-
- // 加载统计数据
- async function loadStats() {
- try {
- const res = await fetch(`${API_BASE}/api/stats/overview`);
- const data = await res.json();
- if (data.success) {
- document.getElementById('totalProducts').textContent = data.data.totalProducts;
- document.getElementById('totalShops').textContent = data.data.totalShops;
- document.getElementById('lowStockCount').textContent = data.data.lowStockCount;
- document.getElementById('todayOrders').textContent = data.data.todayOrders;
- document.getElementById('totalInventory').textContent = data.data.totalInventory;
- }
- } catch (error) {
- console.error('加载统计失败:', error);
- }
- }
-
- // 加载预警
- async function loadAlerts() {
- try {
- const res = await fetch(`${API_BASE}/api/alerts?unread=true`);
- const data = await res.json();
- const container = document.getElementById('alertList');
- const countEl = document.getElementById('alertCount');
-
- if (data.success && data.data.length > 0) {
- countEl.textContent = data.data.length;
- container.innerHTML = data.data.slice(0, 5).map(a => `
- <div class="flex items-center justify-between p-3 bg-red-50 border border-red-200 rounded-lg">
- <div class="flex-1">
- <p class="text-sm text-red-800">${a.message}</p>
- <p class="text-xs text-red-600 mt-1">${new Date(a.created_at).toLocaleString('zh-CN')}</p>
- </div>
- <button onclick="markAlertRead(${a.id})" class="text-red-600 hover:underline text-sm ml-3">标记已读</button>
- </div>
- `).join('');
- } else {
- countEl.textContent = '0';
- container.innerHTML = '<p class="text-gray-500 text-center py-8">暂无预警信息 ✅</p>';
- }
- } catch (error) {
- console.error('加载预警失败:', error);
- }
- }
-
- // 加载最近订单
- async function loadRecentOrders() {
- try {
- const res = await fetch(`${API_BASE}/api/orders?limit=5`);
- const data = await res.json();
- const container = document.getElementById('recentOrders');
-
- if (data.success && data.data.length > 0) {
- container.innerHTML = data.data.map(o => `
- <div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg hover:bg-gray-100">
- <div>
- <p class="font-medium">${o.product_name}</p>
- <p class="text-sm text-gray-500">${o.shop_name} · ${o.order_no}</p>
- </div>
- <div class="text-right">
- <p class="font-medium">¥${o.price}</p>
- <p class="text-xs ${getStatusColor(o.status)}">${getStatusText(o.status)}</p>
- </div>
- </div>
- `).join('');
- } else {
- container.innerHTML = '<p class="text-gray-500 text-center py-8">暂无订单数据</p>';
- }
- } catch (error) {
- console.error('加载订单失败:', error);
- }
- }
-
- // 同步库存
- async function syncInventory() {
- if (!confirm('确定要手动同步所有店铺库存吗?')) return;
-
- try {
- const res = await fetch(`${API_BASE}/api/inventory/sync`, { method: 'POST' });
- const result = await res.json();
- if (result.success) {
- alert('✅ ' + result.message);
- loadStats();
- loadAlerts();
- } else {
- alert('❌ ' + (result.error || '同步失败'));
- }
- } catch (error) {
- alert('❌ 同步失败:' + error.message);
- }
- }
-
- // 标记预警已读
- async function markAlertRead(id) {
- try {
- await fetch(`${API_BASE}/api/alerts/${id}/read`, { method: 'PUT' });
- loadAlerts();
- } catch (error) {
- console.error('标记失败:', error);
- }
- }
-
- // 状态文本
- function getStatusText(status) {
- const map = { pending: '待付款', paid: '已付款', shipped: '已发货', completed: '已完成' };
- return map[status] || status;
- }
-
- // 状态颜色
- function getStatusColor(status) {
- const map = { pending: 'text-yellow-600', paid: 'text-blue-600', shipped: 'text-purple-600', completed: 'text-green-600' };
- return map[status] || 'text-gray-600';
- }
-
- // 页面加载
- document.addEventListener('DOMContentLoaded', () => {
- loadStats();
- loadAlerts();
- loadRecentOrders();
- });
- </script>
- </body>
- </html>
|