This commit is contained in:
2026-03-11 20:41:03 +08:00
commit c5af0cc946
21 changed files with 5831 additions and 0 deletions

417
cf-nav-frontend/admin.html Normal file
View File

@@ -0,0 +1,417 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#10b981">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="萌芽导航管理">
<title>萌芽导航-后台管理</title>
<link rel="manifest" href="/manifest.webmanifest">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/logo.png" type="image/png">
<link rel="apple-touch-icon" href="/logo.png">
<link rel="stylesheet" href="styles.css">
<script src="config.js"></script>
<script src="apply-config.js"></script>
<style>
.login-container {
max-width: 480px;
margin: 80px auto;
padding: 32px;
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
text-align: center;
}
.no-permission h2 {
color: #64748b;
margin-bottom: 12px;
}
.no-permission p {
color: #94a3b8;
font-size: 0.9rem;
}
.admin-container {
display: none;
}
.admin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px 20px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
}
.logout-btn {
background: #dc2626;
color: white;
border: none;
padding: 8px 16px;
border-radius: 50px;
cursor: pointer;
font-weight: 600;
font-size: 0.9rem;
}
.logout-btn:hover {
background: #b91c1c;
}
.exit-btn {
background: #64748b;
color: white;
border: none;
padding: 8px 16px;
border-radius: 50px;
cursor: pointer;
font-weight: 600;
font-size: 0.9rem;
}
.exit-btn:hover {
background: #475569;
}
.sites-table {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #f1f5f9;
}
th {
background: #f8fafc;
font-weight: 600;
color: #1e293b;
}
.action-btns {
display: flex;
gap: 8px;
}
.btn-edit, .btn-delete {
padding: 6px 12px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
font-weight: 500;
}
.btn-edit {
background: #3b82f6;
color: white;
}
.btn-edit:hover {
background: #2563eb;
}
.btn-delete {
background: #ef4444;
color: white;
}
.btn-delete:hover {
background: #dc2626;
}
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 9999;
align-items: center;
justify-content: center;
}
.modal-overlay.active {
display: flex;
}
.error-message {
color: #dc2626;
margin-top: 10px;
font-size: 0.9rem;
}
.success-message {
color: #059669;
margin-top: 10px;
font-size: 0.9rem;
}
.tag-display {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.tag-display .tag {
background: #e0e7ff;
color: #4338ca;
padding: 2px 8px;
border-radius: 10px;
font-size: 0.75rem;
}
.categories-panel {
background: white;
border-radius: 10px;
padding: 16px 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
margin-bottom: 16px;
}
.categories-panel .panel-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 12px;
}
.category-add {
display: flex;
align-items: center;
gap: 8px;
}
.category-add input {
padding: 8px 10px;
border: 1px solid #e2e8f0;
border-radius: 8px;
font-size: 0.9rem;
min-width: 160px;
}
.category-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.category-item {
display: inline-flex;
align-items: center;
gap: 6px;
background: #f8fafc;
border: 1px solid #e2e8f0;
padding: 6px 10px;
border-radius: 20px;
font-size: 0.85rem;
}
.category-item .category-actions button {
border: none;
background: transparent;
color: #475569;
cursor: pointer;
font-size: 0.85rem;
padding: 0 2px;
}
.category-item .category-actions button:hover {
color: #1d4ed8;
}
.sites-table-header {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 15px;
}
.sites-table-header h2 {
margin: 0;
}
.sites-filter {
display: flex;
align-items: center;
gap: 8px;
}
.sites-filter label {
font-size: 0.9rem;
color: #64748b;
}
#site-category-filter {
padding: 6px 12px;
border: 1px solid #e2e8f0;
border-radius: 8px;
font-size: 0.9rem;
min-width: 160px;
background: white;
cursor: pointer;
}
#site-category-filter:focus {
outline: none;
border-color: #3b82f6;
}
</style>
</head>
<body>
<div class="container">
<!-- 无 token 或 token 错误时显示 -->
<div class="login-container" id="no-permission">
<h2>⚠️ 无法进入后台</h2>
<p>请使用带 token 的链接访问,例如:</p>
<p style="margin-top: 8px; word-break: break-all; color: #1e293b; font-size: 0.85rem;"><strong>/admin.html?token=管理员密钥</strong></p>
<p style="margin-top: 16px;">链接中的 token 需为后端 Worker 配置的管理员密钥ADMIN_PASSWORD</p>
</div>
<!-- 管理界面(仅 token 正确时显示) -->
<div class="admin-container" id="admin-container">
<div class="admin-header">
<h1 id="admin-title">萌芽导航-管理后台</h1>
<button class="exit-btn" id="logout-btn">退出</button>
</div>
<div class="categories-panel">
<div class="panel-header">
<h2>📁 分类管理</h2>
<div class="category-add">
<input type="text" id="new-category-name" placeholder="新增分类">
<button class="btn-edit" id="add-category-btn">添加分类</button>
</div>
</div>
<div class="category-list" id="category-list">
<!-- 分类标签 -->
</div>
</div>
<div style="margin-bottom: 20px;">
<button class="add-site-btn" id="add-new-site">✚ 添加新网站</button>
</div>
<div class="sites-table">
<div class="sites-table-header">
<h2>网站列表</h2>
<div class="sites-filter">
<label for="site-category-filter">按分类筛选:</label>
<select id="site-category-filter" title="选择分类可快速筛选网站">
<option value="">全部</option>
</select>
</div>
</div>
<table id="sites-table">
<thead>
<tr>
<th>名称</th>
<th>URL</th>
<th>分类</th>
<th>描述</th>
<th>标签</th>
<th>操作</th>
</tr>
</thead>
<tbody id="sites-tbody">
<!-- 动态加载 -->
</tbody>
</table>
</div>
</div>
<!-- 编辑/添加网站模态框 -->
<div class="modal-overlay" id="edit-modal">
<div class="modal-content">
<div class="modal-header">
<h2 id="modal-title">添加网站</h2>
<button class="close-modal" id="close-edit-modal">&times;</button>
</div>
<div class="modal-body">
<form id="edit-site-form">
<input type="hidden" id="edit-site-id">
<div class="form-group">
<label for="edit-site-name">网站名称 *</label>
<input type="text" id="edit-site-name" required>
</div>
<div class="form-group">
<label for="edit-site-url">网站地址 *</label>
<input type="url" id="edit-site-url" required>
</div>
<div class="form-group">
<label for="edit-site-description">网站描述</label>
<textarea id="edit-site-description"></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label for="edit-site-category">网站分类 *</label>
<select id="edit-site-category" required>
<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 for="edit-site-tags">网站标签</label>
<input type="text" id="edit-site-tags" placeholder="用逗号分隔">
</div>
</div>
<button type="submit" class="submit-btn">保存</button>
</form>
</div>
</div>
</div>
<div class="toast" id="toast">
<span class="toast-icon"></span>
<span class="toast-message">操作成功</span>
</div>
</div>
<script src="admin.js"></script>
<script>
// 注册 Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('✅ Service Worker 注册成功:', registration.scope);
})
.catch(error => {
console.error('❌ Service Worker 注册失败:', error);
});
});
}
</script>
</body>
</html>