$r) { if (!is_array($r)) continue; $name = trim((string)($r['name'] ?? '')); $url = trim((string)($r['url'] ?? '')); $icon = trim((string)($r['icon'] ?? '')); $desc = trim((string)($r['description'] ?? '')); $ext = ((string)($r['ext'] ?? '0') === '1') ? 1 : 0; if ($name === '' && $url === '') continue; // 空行忽略 if ($name === '' || $url === '') { $errorMsg = '第 ' . ((int)$i + 1) . ' 行:名称与地址均不能为空。'; break; } if ($ext === 1) { if (!preg_match('#^https?://#i', $url)) { $errorMsg = '第 ' . ((int)$i + 1) . ' 行:外部链接需以 http(s):// 开头。'; break; } } else { if (preg_match('#^https?://#i', $url)) { $errorMsg = '第 ' . ((int)$i + 1) . ' 行:站内页面地址请勿填写完整网址(填如 codec.php),如需外链请选择“外部链接”。'; break; } if (preg_match('/^[a-z][a-z0-9+.-]*:/i', $url) || strpos($url, '//') === 0) { $errorMsg = '第 ' . ((int)$i + 1) . ' 行:站内页面仅支持相对地址(如 codec.php),不允许填写协议或跨协议地址。'; break; } } $clean[] = [ 'id' => (int)($r['id'] ?? 0), 'icon' => ($icon !== '' ? $icon : '🧩'), 'name' => $name, 'description' => $desc, 'url' => $url, 'ext' => $ext, 'enabled' => (((string)($r['enabled'] ?? '1') === '1')) ? 1 : 0, ]; } if ($errorMsg === '') { if (!$clean) { $errorMsg = '功能区至少需要保留一个工具。'; } else { try { $pdo->beginTransaction(); $oldIds = array_map('intval', array_column($pdo->query('SELECT id FROM func_tools')->fetchAll(), 'id')); $keep = []; foreach ($clean as $c) { if ($c['id'] > 0) $keep[] = $c['id']; } $del = array_values(array_diff($oldIds, $keep)); foreach ($del as $did) { $pdo->prepare('DELETE FROM func_tools WHERE id = ?')->execute([$did]); } $stUpd = $pdo->prepare('UPDATE func_tools SET name=?, icon=?, description=?, url=?, is_external=?, enabled=?, sort=? WHERE id=?'); $stIns = $pdo->prepare('INSERT INTO func_tools (name, icon, description, url, is_external, enabled, sort) VALUES (?,?,?,?,?,?,?)'); $sort = 0; foreach ($clean as $c) { $sort++; if ($c['id'] > 0 && in_array($c['id'], $oldIds, true)) { $stUpd->execute([$c['name'], $c['icon'], $c['description'], $c['url'], $c['ext'], $c['enabled'], $sort, $c['id']]); } else { $stIns->execute([$c['name'], $c['icon'], $c['description'], $c['url'], $c['ext'], $c['enabled'], $sort]); } } $pdo->commit(); touch_last_updated(); header('Location: tools.php?ok=1'); exit; } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } $errorMsg = '保存失败:' . $e->getMessage(); } } } } } } // ---------- 展示现有工具 ---------- $tools = $pdo->query('SELECT * FROM func_tools ORDER BY sort ASC, id ASC')->fetchAll(); layout_head('功能区管理'); admin_topbar('tools'); ?>

功能区管理

管理功能区首页展示的工具卡片。站内工具页需先在 func/ 下开发对应页面,再到此处登记入口; 也可登记外部网址作为外链卡片(新窗口打开)。

保存成功,功能区首页已同步更新。
工具数量与展示顺序实时反映到前台功能区首页