prepare('SELECT * FROM categories WHERE key = ? LIMIT 1'); $stCat->execute([$cat]); $catRow = $stCat->fetch(); if (!$catRow) { http_response_code(404); die('分类不存在'); } $saved = isset($_GET['ok']); $errorMsg = ''; // ---------- 保存处理 ---------- if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save') { if (!csrf_verify()) { $errorMsg = '安全校验失败,请刷新页面重试。'; } else { $raw = (string)($_POST['data'] ?? ''); $data = json_decode($raw, true); if (!is_array($data)) { $errorMsg = '提交数据格式错误。'; } else { try { $pdo->beginTransaction(); // 现有块 $st = $pdo->prepare('SELECT id FROM nav_blocks WHERE cat_id = ?'); $st->execute([(int)$catRow['id']]); $oldBlocks = array_map('intval', array_column($st->fetchAll(), 'id')); // 现有链接(按块分组) $oldItemsByBlock = []; foreach ($oldBlocks as $bid) { $st = $pdo->prepare('SELECT id FROM nav_items WHERE block_id = ?'); $st->execute([$bid]); $oldItemsByBlock[$bid] = array_map('intval', array_column($st->fetchAll(), 'id')); } // 本轮保留的块 id $keepBlocks = []; $keepItems = []; foreach ($data as $b) { if (is_array($b) && isset($b['title'])) { $id = (int)($b['id'] ?? 0); if ($id > 0) $keepBlocks[] = $id; foreach (($b['items'] ?? []) as $it) { if (is_array($it) && (int)($it['id'] ?? 0) > 0) { $keepItems[] = (int)$it['id']; } } } } // 删除被移除的块及其链接 $delBlocks = array_values(array_diff($oldBlocks, $keepBlocks)); foreach ($delBlocks as $dbid) { $pdo->prepare('DELETE FROM nav_items WHERE block_id = ?')->execute([$dbid]); $pdo->prepare('DELETE FROM nav_blocks WHERE id = ?')->execute([$dbid]); unset($oldItemsByBlock[$dbid]); } // 删除被移除的链接 foreach ($oldItemsByBlock as $bid => $ids) { $del = array_values(array_diff($ids, $keepItems)); foreach ($del as $did) { $pdo->prepare('DELETE FROM nav_items WHERE id = ?')->execute([$did]); } } // 写回块与链接 $stInsBlock = $pdo->prepare('INSERT INTO nav_blocks (cat_id, title, sort) VALUES (?,?,?)'); $stUpdBlock = $pdo->prepare('UPDATE nav_blocks SET title = ?, sort = ? WHERE id = ?'); $stInsItem = $pdo->prepare('INSERT INTO nav_items (block_id, label, url, note, sort) VALUES (?,?,?,?,?)'); $stUpdItem = $pdo->prepare('UPDATE nav_items SET label = ?, url = ?, note = ?, sort = ? WHERE id = ? AND block_id = ?'); $blockSort = 0; foreach ($data as $b) { if (!is_array($b) || !isset($b['title'])) continue; $title = trim((string)$b['title']); if ($title === '') continue; $bid = (int)($b['id'] ?? 0); $blockBelongs = in_array($bid, $oldBlocks, true); if ($bid > 0 && $blockBelongs) { $stUpdBlock->execute([$title, $blockSort, $bid]); } else { $stInsBlock->execute([(int)$catRow['id'], $title, $blockSort]); $bid = (int)$pdo->lastInsertId(); } $itemSort = 0; foreach (($b['items'] ?? []) as $it) { if (!is_array($it)) continue; $label = trim((string)($it['label'] ?? '')); $url = trim((string)($it['url'] ?? '')); $note = trim((string)($it['note'] ?? '')); if ($label === '' && $url === '') continue; $iid = (int)($it['id'] ?? 0); if ($iid > 0 && in_array($iid, $oldItemsByBlock[$bid] ?? [], true)) { $stUpdItem->execute([$label, $url, $note, $itemSort, $iid, $bid]); } else { $stInsItem->execute([$bid, $label, $url, $note, $itemSort]); } $itemSort++; } $blockSort++; } $pdo->commit(); touch_last_updated(); header('Location: nav.php?c=' . urlencode($cat) . '&ok=1'); exit; } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } $errorMsg = '保存失败:' . $e->getMessage(); } } } } // ---------- 读取现有数据用于展示 ---------- $st = $pdo->prepare('SELECT * FROM nav_blocks WHERE cat_id = ? ORDER BY sort ASC, id ASC'); $st->execute([(int)$catRow['id']]); $blocks = $st->fetchAll(); $itemsMap = []; if ($blocks) { $ids = array_map('intval', array_column($blocks, 'id')); $in = implode(',', array_fill(0, count($ids), '?')); $st = $pdo->prepare("SELECT * FROM nav_items WHERE block_id IN ($in) ORDER BY sort ASC, id ASC"); $st->execute($ids); foreach ($st->fetchAll() as $it) { $itemsMap[(int)$it['block_id']][] = $it; } } $catNames = []; foreach ($catKeys as $ck) { $row = $pdo->query("SELECT key, name FROM categories WHERE key = '" . $ck . "'")->fetch(); $catNames[$ck] = $row['name'] ?? $ck; } $csrfVal = csrf_token(); layout_head('导航内容管理'); admin_topbar('nav'); ?> 导航内容管理 管理 = he($catNames[$cat]) ?> 的导航块与链接;块内最多 15 个链接(3 小列 × 5 行),超出部分请拆分到新块。 = he($catNames[$ck]) ?> 保存成功,前台页面已同步更新。 = he($errorMsg) ?> = csrf_field() ?> ↑ ↓ 删除块 ✕ + 添加链接 + 新建导航块 保存全部修改
管理 = he($catNames[$cat]) ?> 的导航块与链接;块内最多 15 个链接(3 小列 × 5 行),超出部分请拆分到新块。