File manager - Edit - /home/webapp69.cm.in.th/u69319090014/shop non 014/admin.php
Back
<?php // admin.php - Clothing Store Admin Dashboard (Dark Cyberpunk Theme) session_start(); // Access Control check: restrict to 'admin' role if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') { header("Location: login.php"); exit(); } require_once 'db.php'; // ------------------------------------------ // AJAX Endpoint: Update Stock Level (Direct) // ------------------------------------------ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_stock') { header('Content-Type: application/json'); $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; $stock = isset($_POST['stock']) ? intval($_POST['stock']) : 0; if ($product_id > 0 && $stock >= 0) { try { $stmt = $pdo->prepare("UPDATE products SET stock = :stock WHERE id = :id"); $stmt->execute([':stock' => $stock, ':id' => $product_id]); echo json_encode(['success' => true, 'message' => 'อัปเดตสต็อกเรียบร้อยแล้ว']); } catch (Exception $e) { echo json_encode(['success' => false, 'message' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()]); } } else { echo json_encode(['success' => false, 'message' => 'ข้อมูลสต็อกไม่ถูกต้อง']); } exit(); } // ------------------------------------------ // FETCH DATA FOR DASHBOARD // ------------------------------------------ // 1. Fetch Orders: Prioritize VIP orders (total_price >= 5000) at the top, then sort by id DESC $orders_query = " SELECT * FROM orders ORDER BY (CASE WHEN total_price >= 5000 THEN 1 ELSE 0 END) DESC, id DESC "; $orders_stmt = $pdo->query($orders_query); $orders = $orders_stmt->fetchAll(PDO::FETCH_ASSOC); // 2. Fetch Order Items mapped by order_id $items_query = " SELECT oi.*, p.name as product_name, p.image FROM order_items oi JOIN products p ON oi.product_id = p.id "; $items_stmt = $pdo->query($items_query); $all_items = $items_stmt->fetchAll(PDO::FETCH_ASSOC); $order_items_map = []; foreach ($all_items as $item) { $order_items_map[$item['order_id']][] = $item; } // 3. Fetch Products sorted by id DESC $products_query = "SELECT * FROM products ORDER BY id DESC"; $products_stmt = $pdo->query($products_query); $products = $products_stmt->fetchAll(PDO::FETCH_ASSOC); // 4. Calculate stats $total_revenue = 0; $total_orders_count = count($orders); $low_stock_count = 0; $vip_orders_count = 0; foreach ($orders as $o) { if ($o['status'] === 'Paid' || $o['status'] === 'Shipped') { $total_revenue += $o['total_price']; } if ($o['total_price'] >= 5000) { $vip_orders_count++; } } foreach ($products as $p) { if ($p['stock'] < 5) { $low_stock_count++; } } $tab = isset($_GET['tab']) ? $_GET['tab'] : 'orders'; ?> <!DOCTYPE html> <html lang="th" class="dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NON LUXURY // CONTROLLER SALON</title> <!-- Google Fonts --> <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=Cinzel:wght@400;500;600;700;800;900&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300&family=Sarabun:wght@300;400;500;600;700&family=Montserrat:wght@300;400;500;600;700&display=swap" rel="stylesheet"> <!-- Tailwind CSS CDN --> <script src="https://cdn.tailwindcss.com"></script> <script> tailwind.config = { theme: { extend: { colors: { cyber: { bg: '#0A0A0B', // Matte Deep Black card: '#121215', // Warm charcoal card accent: '#D4AF37', // Elegant Satin Gold accentGlow: '#E5C158',// Brighter Champagne Gold success: '#94A89A', // Premium Muted Sage Green danger: '#A94444', // Luxury Wine Red warning: '#C58F39', // Luxury Amber Gold gold: '#D4AF37', // Satin Gold border: '#22211E' // Subtle gold-tinted grey border } }, fontFamily: { sans: ['Sarabun', 'Montserrat', 'sans-serif'], cyber: ['Cinzel', 'Cormorant Garamond', 'Sarabun', 'serif'] } } } } </script> <style> body { background-color: #0A0A0B; color: #EAE6DF; font-family: 'Sarabun', sans-serif; background-image: radial-gradient(circle at 50% 0%, #171512 0%, #0A0A0B 70%); } .neon-text-purple { text-shadow: 0 0 5px #D4AF37, 0 0 10px rgba(212, 175, 55, 0.3); } .neon-text-success { text-shadow: 0 0 5px #94A89A, 0 0 10px rgba(148, 168, 154, 0.3); } .neon-text-warning { text-shadow: 0 0 5px #C58F39, 0 0 10px rgba(197, 143, 57, 0.3); } .neon-text-gold { text-shadow: 0 0 5px #D4AF37, 0 0 10px rgba(212, 175, 55, 0.4); } .neon-border-gold { border-color: #D4AF37; box-shadow: 0 0 15px rgba(212, 175, 55, 0.2); } .pulse-glow-warning { animation: warning-pulse 1.8s infinite ease-in-out; } @keyframes warning-pulse { 0%, 100% { box-shadow: 0 0 8px rgba(197, 143, 57, 0.2); border-color: #C58F39; } 50% { box-shadow: 0 0 18px rgba(197, 143, 57, 0.5); border-color: #D4AF37; } } .cyber-grid { background-size: 40px 40px; background-image: linear-gradient(to right, rgba(212, 175, 55, 0.01) 1px, transparent 1px), linear-gradient(to bottom, rgba(212, 175, 55, 0.01) 1px, transparent 1px); } .cyber-btn-glow:hover { box-shadow: 0 0 15px rgba(212, 175, 55, 0.3); } .cyber-btn-glow-danger:hover { box-shadow: 0 0 15px rgba(169, 68, 68, 0.3); } </style> </head> <body class="flex flex-col min-h-screen cyber-grid text-stone-200"> <!-- Toast Notifications --> <div id="toast-container" class="fixed bottom-6 right-6 z-50 flex flex-col gap-3"></div> <!-- Header Navigation --> <header class="bg-[#0E0E10]/95 backdrop-blur-md border-b border-cyber-border sticky top-0 z-40"> <div class="w-full px-6 md:px-12 py-4 flex flex-col md:flex-row items-center justify-between gap-4"> <!-- Logo & Brand (Gradient from purple to mint with tracking) --> <div class="flex items-center gap-3"> <div class="w-10 h-10 rounded-full bg-gradient-to-br from-cyber-accent to-cyber-border flex items-center justify-center shadow-lg border border-cyber-accent/40"> <span class="font-cyber font-medium text-lg text-cyber-accent">N</span> </div> <div> <h1 class="font-cyber font-medium text-lg"> <span class="tracking-[0.35em] text-white">NON LUXURY</span> <span class="text-cyber-accent text-xs font-mono font-medium ml-2">// CONCIERGE CONTROL</span> </h1> <p class="text-[9px] text-stone-400 font-sans tracking-widest uppercase">PDO MYSQL SYSTEM // VIP PORTAL: 014</p> </div> </div> <!-- Server & Dev Stats --> <div class="flex items-center gap-6 text-xs font-sans bg-[#121215] px-4 py-2 rounded border border-cyber-border"> <div class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-cyber-success animate-pulse"></span> <span class="text-cyber-success font-semibold tracking-wider text-[10px]">SYSTEM ONLINE</span> </div> <div class="hidden sm:block text-stone-400 border-l border-cyber-border pl-4"> CONCIERGE: <span class="text-white font-bold"><?php echo htmlspecialchars($_SESSION['username']); ?></span> </div> <div class="border-l border-cyber-border pl-4 flex gap-4 font-semibold"> <a href="index.php" class="text-cyber-accent hover:text-white transition flex items-center gap-1"> <span>RETURN TO SALON</span> </a> <span class="text-stone-700">|</span> <a href="logout.php" class="text-cyber-danger hover:text-white transition"> <span>LEAVE SALON ✕</span> </a> </div> </div> </div> </header> <!-- Main Container --> <main class="flex-grow w-full px-6 md:px-12 py-8 space-y-8"> <!-- Status Messages from GET Parameters --> <?php if (isset($_GET['success_msg'])): ?> <div class="bg-[#1E221F] border border-cyber-success text-cyber-success px-4 py-3 rounded text-sm font-semibold flex items-center gap-3"> <span>✓</span> <?php echo htmlspecialchars($_GET['success_msg']); ?> </div> <?php endif; ?> <?php if (isset($_GET['error_msg'])): ?> <div class="bg-[#2D1B1B] border border-cyber-danger text-cyber-danger px-4 py-3 rounded text-sm font-semibold flex items-center gap-3"> <span>✕</span> <?php echo htmlspecialchars($_GET['error_msg']); ?> </div> <?php endif; ?> <!-- STATISTICS MATRIX --> <section class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"> <!-- Revenue --> <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 hover:border-cyber-accent transition duration-300"> <div class="flex justify-between items-start"> <span class="text-[10px] font-bold text-stone-400 uppercase tracking-wider">รายได้รวมสะสม (Total Revenue)</span> <span class="text-cyber-success">⚜️</span> </div> <div class="mt-4"> <span class="font-cyber font-medium text-2xl text-white">฿<?php echo number_format($total_revenue, 2); ?></span> <p class="text-[9px] text-stone-500 mt-1 font-sans">// สรุปเฉพาะยอดชำระและส่งมอบสำเร็จ</p> </div> </div> <!-- Orders Count --> <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 hover:border-cyber-accent transition duration-300"> <div class="flex justify-between items-start"> <span class="text-[10px] font-bold text-stone-400 uppercase tracking-wider">คำขอจองสินค้าทั้งหมด (Acquisitions)</span> <span class="text-cyber-accent">💼</span> </div> <div class="mt-4"> <span class="font-cyber font-medium text-2xl text-white"><?php echo $total_orders_count; ?> รายการ</span> <p class="text-[9px] text-stone-500 mt-1 font-sans">// ยอดความต้องการซื้อในฐานข้อมูล</p> </div> </div> <!-- VIP Orders Count --> <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 hover:border-cyber-gold transition duration-300"> <div class="flex justify-between items-start"> <span class="text-[10px] font-bold text-stone-400 uppercase tracking-wider">รายการสิทธิพิเศษ (Elite Reserve)</span> <span class="text-cyber-gold">⚜️</span> </div> <div class="mt-4"> <span class="font-cyber font-medium text-2xl text-cyber-gold neon-text-gold"><?php echo $vip_orders_count; ?> รายการ</span> <p class="text-[9px] text-stone-500 mt-1 font-sans">// ยอดการทำธุรกรรมตั้งแต่ ฿5,000 ขึ้นไป</p> </div> </div> <!-- Low Stock Items Count --> <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 hover:border-cyber-warning transition duration-300 <?php echo $low_stock_count > 0 ? 'pulse-glow-warning bg-opacity-70' : ''; ?>"> <div class="flex justify-between items-start"> <span class="text-[10px] font-bold text-stone-400 uppercase tracking-wider">สินค้าสต็อกคลังจำกัด (Vault Alert)</span> <span class="text-cyber-warning">⚠️</span> </div> <div class="mt-4"> <span class="font-cyber font-medium text-2xl text-cyber-warning neon-text-warning"><?php echo $low_stock_count; ?> รายการ</span> <p class="text-[9px] text-stone-400 mt-1 font-sans font-semibold">// รายการผลงานชิ้นเอกที่เหลือต่ำกว่า 5 ชิ้น</p> </div> </div> </section> <!-- TAB NAVIGATION --> <div class="flex border-b border-cyber-border mb-6"> <a href="admin.php?tab=orders" class="px-6 py-3 font-cyber text-xs tracking-[0.15em] font-medium border-b-2 transition duration-300 outline-none flex items-center gap-2 <?php echo $tab === 'orders' ? 'border-cyber-accent text-white neon-text-purple' : 'border-transparent text-stone-400 hover:text-white'; ?>"> <span>⚜️</span> CLIENT ACQUISITIONS </a> <a href="admin.php?tab=products" class="px-6 py-3 font-cyber text-xs tracking-[0.15em] font-medium border-b-2 transition duration-300 outline-none flex items-center gap-2 <?php echo $tab === 'products' ? 'border-cyber-accent text-white neon-text-purple' : 'border-transparent text-stone-400 hover:text-white'; ?>"> <span>⚜️</span> VAULT INVENTORY </a> </div> <!-- ========================================================== --> <!-- TAB Content: Orders List --> <!-- ========================================================== --> <?php if ($tab === 'orders'): ?> <div class="bg-cyber-card border border-cyber-border rounded-xl overflow-hidden shadow-2xl"> <div class="p-6 border-b border-cyber-border bg-[#101012] flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"> <div> <h2 class="font-cyber font-medium text-sm text-white tracking-widest flex items-center gap-2"> <span>CLIENT ACQUISITIONS DATABASE</span> <span class="text-[9px] bg-amber-950/40 text-cyber-accent font-sans border border-cyber-accent/40 px-2 py-0.5 rounded">SORT: ELITE FIRST</span> </h2> <p class="text-xs text-stone-400 mt-1 font-sans">// ธุรกรรมการจองสะสมระดับพรีเมียม (>= ฿5,000) จะได้รับสิทธิ์เรียงไว้ด้านบนสุดพร้อมกรอบทองซาตินล้อมรอบ</p> </div> </div> <div class="overflow-x-auto w-full"> <table class="w-full text-left border-collapse font-sans"> <thead> <tr class="bg-[#121215] text-cyber-accent text-[10px] uppercase border-b border-cyber-border tracking-wider"> <th class="p-4">รหัสจองสินค้า</th> <th class="p-4">ลูกค้าผู้รับสิทธิ์</th> <th class="p-4">ที่อยู่นำส่ง</th> <th class="p-4 text-right">ยอดรวมธุรกรรม</th> <th class="p-4 text-center">สถานะ</th> <th class="p-4 text-center">อัปเดตสถานะ</th> <th class="p-4 text-center">รายละเอียด</th> </tr> </thead> <tbody class="divide-y divide-cyber-border/40 text-xs"> <?php if (count($orders) > 0): ?> <?php foreach ($orders as $order): ?> <?php $is_vip = ($order['total_price'] >= 5000); $row_style = $is_vip ? 'neon-border-gold bg-[#2B231D]/20 border-l-2 border-l-cyber-accent' : 'hover:bg-[#1C1814]/30'; ?> <tr class="transition-colors <?php echo $row_style; ?>" id="order-row-<?php echo $order['id']; ?>"> <!-- ID --> <td class="p-4"> <div class="flex items-center gap-1 font-sans"> <span class="text-stone-500">#ORD-</span> <strong class="<?php echo $is_vip ? 'text-cyber-gold neon-text-gold' : 'text-white'; ?> font-medium font-cyber"> <?php echo str_pad($order['id'], 5, '0', STR_PAD_LEFT); ?> </strong> </div> <span class="text-[9px] text-stone-500 block mt-1"><?php echo date('d/m/Y H:i', strtotime($order['created_at'])); ?></span> </td> <!-- Customer --> <td class="p-4"> <div class="flex flex-col"> <div class="flex items-center gap-1.5"> <span class="font-semibold text-white"><?php echo htmlspecialchars($order['customer_name']); ?></span> <?php if ($is_vip): ?> <span class="bg-[#4E3917]/80 text-cyber-gold border border-cyber-gold/50 text-[8px] font-bold px-1.5 py-0.5 rounded">ELITE MEMBER ⭐</span> <?php endif; ?> </div> <span class="text-[10px] text-stone-400 mt-0.5"><?php echo htmlspecialchars($order['phone']); ?></span> </div> </td> <!-- Address --> <td class="p-4 max-w-xs"> <p class="text-[11px] text-stone-300 line-clamp-1" title="<?php echo htmlspecialchars($order['address']); ?>"> <?php echo htmlspecialchars($order['address']); ?> </p> </td> <!-- Total --> <td class="p-4 text-right font-cyber font-medium text-sm tracking-wide whitespace-nowrap"> <span class="<?php echo $is_vip ? 'text-cyber-gold neon-text-gold' : 'text-cyber-accent'; ?>"> ฿<?php echo number_format($order['total_price'], 2); ?> </span> </td> <!-- Status Badge --> <td class="p-4 text-center whitespace-nowrap"> <?php $badge_color = 'bg-[#2D1B1B] text-cyber-danger border-cyber-danger/30'; if ($order['status'] === 'Paid') { $badge_color = 'bg-[#1E221F] text-cyber-success border-cyber-success/30'; } elseif ($order['status'] === 'Shipped') { $badge_color = 'bg-stone-900 text-cyan-200 border-cyan-500/30'; } ?> <span class="px-2.5 py-1 rounded text-[10px] font-semibold border <?php echo $badge_color; ?>"> <?php echo htmlspecialchars($order['status']); ?> </span> </td> <!-- Update Status Dropdown Form (Instant Reload) --> <td class="p-4 text-center"> <form action="update_status.php" method="POST" class="inline-block"> <input type="hidden" name="order_id" value="<?php echo $order['id']; ?>"> <select name="status" onchange="this.form.submit()" class="bg-[#0A0A0B] text-stone-200 border border-cyber-border rounded px-3 py-1.5 text-xs font-semibold focus:outline-none focus:border-cyber-accent cursor-pointer hover:bg-stone-900 transition"> <option value="Pending" <?php echo $order['status'] === 'Pending' ? 'selected' : ''; ?>>Pending</option> <option value="Paid" <?php echo $order['status'] === 'Paid' ? 'selected' : ''; ?>>Paid</option> <option value="Shipped" <?php echo $order['status'] === 'Shipped' ? 'selected' : ''; ?>>Shipped</option> </select> </form> </td> <!-- Action: Expand --> <td class="p-4 text-center"> <button onclick="toggleOrderItems(<?php echo $order['id']; ?>)" class="text-xs text-cyber-accent hover:text-white transition flex items-center justify-center gap-1 mx-auto font-semibold"> <span>Masterpieces</span> <span id="chevron-<?php echo $order['id']; ?>" class="inline-block transition duration-200">▼</span> </button> </td> </tr> <!-- Expandable Order Items Row --> <tr id="items-row-<?php echo $order['id']; ?>" class="hidden bg-black/60 border-l-2 border-cyber-accent transition duration-300"> <td colspan="7" class="p-4"> <div class="space-y-3 pl-8"> <h4 class="text-[10px] font-sans font-semibold text-stone-400">// MASTERPIECES ACQUIRED // รายการผลงานศิลปะสั่งซื้อ:</h4> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <?php if (isset($order_items_map[$order['id']])): ?> <?php foreach ($order_items_map[$order['id']] as $item): ?> <div class="bg-cyber-card border border-cyber-border p-3 rounded flex gap-3 items-center"> <img src="<?php echo htmlspecialchars($item['image']); ?>" class="w-12 h-12 object-cover rounded border border-cyber-border" onerror="this.src='https://images.unsplash.com/photo-1521572267360-ee0c2909d518?w=800&auto=format&fit=crop';"> <div> <p class="font-serif text-white text-xs"><?php echo htmlspecialchars($item['product_name']); ?></p> <p class="text-[9px] text-stone-400 mt-0.5 font-sans"> ขนาด: <strong class="text-white"><?php echo htmlspecialchars($item['size']); ?></strong> | เฉดสี: <strong class="text-white"><?php echo htmlspecialchars($item['color']); ?></strong> | จำนวน: <strong class="text-cyber-accent font-semibold"><?php echo $item['quantity']; ?></strong> ชิ้น </p> </div> </div> <?php endforeach; ?> <?php endif; ?> </div> </div> </td> </tr> <?php endforeach; ?> <?php else: ?> <tr> <td colspan="7" class="p-8 text-center text-stone-500 font-sans">// ไม่พบประวัติธุรกรรมสั่งซื้อในระบบขณะนี้</td> </tr> <?php endif; ?> </tbody> </table> </div> </div> <?php endif; ?> <!-- ========================================================== --> <!-- TAB Content: Products Inventory --> <!-- ========================================================== --> <?php if ($tab === 'products'): ?> <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> <!-- Products Card Grid --> <div class="lg:col-span-2 space-y-4"> <div class="flex justify-between items-center"> <h2 class="font-cyber font-medium text-xs text-white tracking-widest uppercase">// ACTIVE COLLECTIONS // รายการสินค้าทั้งหมด</h2> <span class="text-xs font-sans text-stone-500">จำนวนทั้งหมด: <strong class="text-white"><?php echo count($products); ?></strong> ชิ้น</span> </div> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <?php if (count($products) > 0): ?> <?php foreach ($products as $prod): ?> <?php $is_low_stock = ($prod['stock'] < 5); $card_class = $is_low_stock ? 'pulse-glow-warning bg-opacity-40' : 'bg-cyber-card border-cyber-border hover:border-cyber-accent'; ?> <div class="rounded-xl border p-4 flex flex-col justify-between transition duration-300 relative group <?php echo $card_class; ?>" id="product-card-<?php echo $prod['id']; ?>"> <!-- Stock warning label badge --> <div class="absolute top-2 right-2"> <?php if ($is_low_stock): ?> <span class="bg-amber-950/60 text-cyber-warning border border-cyber-warning/40 text-[8px] font-bold px-2 py-0.5 rounded-full animate-pulse"> ⚠️ VAULT STOCK LOW! </span> <?php else: ?> <span class="bg-stone-900 text-cyber-success border border-cyber-success/30 text-[8px] font-bold px-2 py-0.5 rounded-full"> ปกติ </span> <?php endif; ?> </div> <div> <!-- Product Image --> <div class="w-full h-36 rounded overflow-hidden bg-black border border-cyber-border relative mb-3"> <img src="<?php echo htmlspecialchars($prod['image']); ?>" class="w-full h-full object-cover group-hover:scale-105 transition duration-500" onerror="this.src='https://images.unsplash.com/photo-1521572267360-ee0c2909d518?w=800&auto=format&fit=crop';"> <div class="absolute bottom-2 left-2"> <span class="bg-black/80 backdrop-blur-sm text-cyber-accent border border-cyber-border text-[8px] font-semibold px-2 py-0.5 rounded font-sans"> <?php echo htmlspecialchars($prod['category']); ?> </span> </div> </div> <h3 class="font-serif font-semibold text-sm text-white line-clamp-1"><?php echo htmlspecialchars($prod['name']); ?></h3> <p class="text-xs text-stone-400 mt-1 line-clamp-2"><?php echo htmlspecialchars($prod['description']); ?></p> <div class="mt-2.5 space-y-1 text-[9px] text-stone-400 font-sans"> <div>SIZES: <span class="text-stone-300 font-bold"><?php echo htmlspecialchars($prod['sizes']); ?></span></div> <div>COLORS: <span class="text-stone-300 font-bold"><?php echo htmlspecialchars($prod['colors']); ?></span></div> </div> </div> <!-- Price / Stock / Delete --> <div class="mt-4 pt-3 border-t border-cyber-border/40 flex flex-col gap-3"> <div class="flex justify-between items-center"> <span class="text-xs text-stone-400 font-sans">มูลค่าประเมิน:</span> <strong class="text-sm font-cyber font-medium text-cyber-accent neon-text-purple">฿<?php echo number_format($prod['price'], 2); ?></strong> </div> <!-- Stock Adjustment via AJAX --> <div class="bg-black border border-cyber-border p-2 rounded flex items-center justify-between gap-2"> <span class="text-[9px] font-sans text-stone-400 uppercase">Vault Stock:</span> <div class="flex items-center gap-1"> <button type="button" onclick="adjustStockInput(<?php echo $prod['id']; ?>, -1)" class="w-5 h-5 bg-stone-900 hover:bg-stone-800 text-white rounded font-bold text-xs flex items-center justify-center transition focus:outline-none">-</button> <input type="number" id="stock-input-<?php echo $prod['id']; ?>" value="<?php echo $prod['stock']; ?>" min="0" class="w-10 h-5 bg-black text-white text-center font-cyber font-medium text-xs rounded border border-cyber-border focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"> <button type="button" onclick="adjustStockInput(<?php echo $prod['id']; ?>, 1)" class="w-5 h-5 bg-stone-900 hover:bg-stone-800 text-white rounded font-bold text-xs flex items-center justify-center transition focus:outline-none">+</button> <button type="button" onclick="saveStockDirect(<?php echo $prod['id']; ?>)" class="w-6 h-5 bg-cyber-accent hover:bg-cyber-accentGlow text-black rounded text-[10px] flex items-center justify-center transition focus:outline-none ml-1">💾</button> </div> </div> <!-- Output Label --> <div class="flex justify-between items-center text-[10px] font-sans"> <span id="stock-label-<?php echo $prod['id']; ?>" class="text-stone-400"> คงเหลือในคลัง: <strong class="<?php echo $is_low_stock ? 'text-cyber-warning neon-text-warning' : 'text-cyber-success'; ?>"><?php echo $prod['stock']; ?></strong> ชิ้น </span> <!-- Delete Button targeting delete_product.php --> <a href="delete_product.php?id=<?php echo $prod['id']; ?>" onclick="return confirm('คุณต้องการลบผลงานศิลปะชิ้นนี้ และลบไฟล์รูปภาพถาวรจากระบบใช่หรือไม่?')" class="text-cyber-danger hover:text-white transition font-bold uppercase tracking-wider text-[9px]"> ✕ ลบสินค้า </a> </div> </div> </div> <?php endforeach; ?> <?php else: ?> <p class="text-stone-500 font-sans col-span-2 text-center py-12">// ไม่พบคลังข้อมูลสินค้าในระบบ</p> <?php endif; ?> </div> </div> <!-- Product Creation Form (targets add_product.php) --> <div> <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 shadow-2xl space-y-4 sticky top-24"> <div class="border-b border-cyber-border pb-3"> <h3 class="font-cyber font-medium text-xs text-white tracking-widest uppercase">PUBLISH NEW MASTERPIECE</h3> <p class="text-[10px] text-stone-400 mt-0.5 font-sans">// ลงทะเบียนผลงานชิ้นเอกใหม่สู่ห้องจัดแสดง</p> </div> <form action="add_product.php" method="POST" enctype="multipart/form-data" class="space-y-3.5 text-xs font-sans"> <!-- Name --> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">ชื่อผลงานชิ้นเอก (Masterpiece Name) *</label> <input type="text" name="name" required placeholder="เช่น Audemars Piguet Royal Oak Double Balance" class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent transition"> </div> <!-- Category & Price --> <div class="grid grid-cols-2 gap-3"> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">ประเภทผลงาน (Collection Type) *</label> <select name="category" required class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent cursor-pointer"> <option value="นาฬิกาหรู (Luxury Watch)">นาฬิกาหรู (Luxury Watch)</option> <option value="กระเป๋าแบรนด์เนม (High-End Bag)">กระเป๋าแบรนด์เนม (High-End Bag)</option> <option value="เครื่องแต่งกายหรู (Haute Couture)">เครื่องแต่งกายหรู (Haute Couture)</option> <option value="เครื่องประดับและอัญมณี (Fine Jewelry)">เครื่องประดับและอัญมณี (Fine Jewelry)</option> </select> </div> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">มูลค่าสะสม (บาท) *</label> <input type="number" name="price" step="0.01" min="1" required placeholder="85000" class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent font-sans"> </div> </div> <!-- Sizes & Colors --> <div class="grid grid-cols-2 gap-3"> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">ตัวเลือกขนาด (Sizes) *</label> <input type="text" name="sizes" required value="One Size" placeholder="38mm, 41mm" class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent font-sans"> </div> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">ตัวเลือกเฉดสี (Colors) *</label> <input type="text" name="colors" required value="Gold,Black" placeholder="Rose Gold, Silver" class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent font-sans"> </div> </div> <!-- Stock --> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">จำนวนแรกเข้าในคลังส่วนตัว (Stock)</label> <input type="number" name="stock" min="0" value="5" required class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent font-sans"> </div> <!-- Description --> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">รายละเอียดประวัติผลงาน (Description)</label> <textarea name="description" rows="2" placeholder="ประวัติและรายละเอียดความเอ็กซ์คลูซีฟ..." class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-3 py-2 text-white outline-none focus:border-cyber-accent resize-none"></textarea> </div> <!-- Image File Upload --> <div class="space-y-1"> <label class="text-[9px] font-sans tracking-widest uppercase text-cyber-accent font-semibold block">ภาพถ่ายผลงาน (.jpg, .png) *</label> <input type="file" name="image" accept="image/*" required class="w-full bg-[#0A0A0B] border border-cyber-border rounded px-2.5 py-1.5 text-white outline-none focus:border-cyber-accent file:mr-3 file:py-1 file:px-2 file:rounded file:border-0 file:text-[9px] file:font-semibold file:bg-cyber-accent file:text-black hover:file:bg-cyber-accentGlow cursor-pointer"> </div> <button type="submit" class="w-full bg-cyber-accent hover:bg-cyber-accentGlow text-black font-cyber font-semibold tracking-widest py-3 rounded transition uppercase mt-2"> PUBLISH MASTERPIECE </button> </form> </div> </div> </div> <?php endif; ?> </main> <!-- Footer --> <footer class="bg-[#050506] border-t border-cyber-border text-stone-500 py-8 mt-12 text-xs"> <div class="w-full px-6 md:px-12 flex flex-col md:flex-row items-center justify-between gap-4"> <div> <p>⚜️ <span class="font-cyber tracking-[0.25em] text-white">NON LUXURY</span> // CONCIERGE CONTROL SERVICES</p> <p class="text-[9px] text-stone-600 mt-1">DB Connection via PDO MySQL // System Port: 014</p> </div> <div class="text-right"> <p>VIP CLIENT SERVICES: <span class="text-white font-bold">Nontawat 014</span></p> </div> </div> </footer> <!-- Scripts --> <script> // Toggle Expandable Order Items row display function toggleOrderItems(orderId) { const itemsRow = document.getElementById(`items-row-${orderId}`); const chevron = document.getElementById(`chevron-${orderId}`); if (itemsRow.classList.contains('hidden')) { itemsRow.classList.remove('hidden'); chevron.classList.add('rotate-180'); } else { itemsRow.classList.add('hidden'); chevron.classList.remove('rotate-180'); } } // Adjust Stock Level Input in UI (+ / - buttons) function adjustStockInput(prodId, amount) { const input = document.getElementById(`stock-input-${prodId}`); let val = parseInt(input.value) || 0; val += amount; if (val < 0) val = 0; input.value = val; } // AJAX Stock Update function saveStockDirect(productId) { const input = document.getElementById(`stock-input-${productId}`); const stockVal = parseInt(input.value); if (isNaN(stockVal) || stockVal < 0) { showCyberToast("กรุณาระบุจำนวนสต็อกที่ถูกต้อง (ตัวเลข >= 0)", "error"); return; } const formData = new FormData(); formData.append('action', 'update_stock'); formData.append('product_id', productId); formData.append('stock', stockVal); fetch('admin.php', { method: 'POST', body: formData }) .then(res => { if (!res.ok) throw new Error("HTTP error " + res.status); return res.json(); }) .then(data => { if (data.success) { showCyberToast(data.message, 'success'); const card = document.getElementById(`product-card-${productId}`); const labelContainer = document.getElementById(`stock-label-${productId}`); if (stockVal < 5) { labelContainer.innerHTML = `คงเหลือในคลัง: <strong class="text-cyber-warning neon-text-warning">${stockVal}</strong> ชิ้น`; card.className = "rounded-xl border p-4 flex flex-col justify-between transition duration-300 relative group pulse-glow-warning bg-opacity-40"; let badgeContainer = card.querySelector('.absolute.top-2.right-2'); if (badgeContainer) { badgeContainer.innerHTML = ` <span class="bg-amber-950/60 text-cyber-warning border border-cyber-warning/40 text-[8px] font-bold px-2 py-0.5 rounded-full animate-pulse"> ⚠️ VAULT STOCK LOW! </span> `; } } else { labelContainer.innerHTML = `คงเหลือในคลัง: <strong class="text-cyber-success">${stockVal}</strong> ชิ้น`; card.className = "rounded-xl border p-4 flex flex-col justify-between transition duration-300 relative group bg-cyber-card border-cyber-border hover:border-cyber-accent"; let badgeContainer = card.querySelector('.absolute.top-2.right-2'); if (badgeContainer) { badgeContainer.innerHTML = ` <span class="bg-stone-900 text-cyber-success border border-cyber-success/30 text-[8px] font-bold px-2 py-0.5 rounded-full"> ปกติ </span> `; } } recalculateStats(); } else { showCyberToast(data.message, 'error'); } }) .catch(err => { console.error(err); showCyberToast("เกิดข้อผิดพลาดในการบันทึกข้อมูลสินค้า", "error"); }); } // Recalculate low stock metrics card function recalculateStats() { let lowStockCount = 0; const inputs = document.querySelectorAll('[id^="stock-input-"]'); inputs.forEach(inp => { const val = parseInt(inp.value) || 0; if (val < 5) { lowStockCount++; } }); const lowStockNumberEl = document.querySelector('.text-cyber-warning.neon-text-warning'); if (lowStockNumberEl) { lowStockNumberEl.innerText = `${lowStockCount} รายการ`; } const targetStatsCard = document.querySelectorAll('section > div')[3]; // Low Stock Card if (targetStatsCard) { if (lowStockCount > 0) { targetStatsCard.classList.add('pulse-glow-warning', 'bg-opacity-70'); } else { targetStatsCard.classList.remove('pulse-glow-warning', 'bg-opacity-70'); } } } // Toast Helper function showCyberToast(message, type = 'success') { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); let bgClass = 'bg-[#1E221F] text-cyber-success border-[#94A89A]/30'; let icon = '✓'; if (type === 'error') { bgClass = 'bg-[#2D1B1B] text-cyber-danger border-cyber-danger/30'; icon = '❌'; } toast.className = `px-4 py-3 rounded shadow-2xl text-xs border font-sans font-semibold flex items-center gap-3 transform translate-y-4 opacity-0 transition-all duration-300 ${bgClass}`; toast.innerHTML = ` <span class="flex-shrink-0">${icon}</span> <div class="flex-grow">${message}</div> `; container.appendChild(toast); setTimeout(() => { toast.classList.remove('translate-y-4', 'opacity-0'); }, 10); setTimeout(() => { toast.classList.add('translate-y-[-10px]', 'opacity-0'); setTimeout(() => toast.remove(), 300); }, 3000); } </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.24 |
proxy
|
phpinfo
|
Settings