Spaces:
Running
Running
<html lang="zh-CN"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
<meta name="apple-mobile-web-app-capable" content="yes"> | |
<meta name="apple-mobile-web-app-status-bar-style" content="default"> | |
<title>Notion2API 管理面板</title> | |
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet"> | |
<style> | |
:root { | |
--primary-color: #0066cc; | |
--secondary-color: #6c757d; | |
--success-color: #28a745; | |
--danger-color: #dc3545; | |
--warning-color: #ffc107; | |
--light-bg: #f8f9fa; | |
--border-color: #dee2e6; | |
--mobile-navbar-height: 56px; | |
} | |
body { | |
background-color: var(--light-bg); | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
-webkit-font-smoothing: antialiased; | |
-webkit-tap-highlight-color: transparent; | |
} | |
/* 移动端优化 */ | |
@media (max-width: 768px) { | |
body { | |
padding-bottom: 60px; /* 为底部操作栏留出空间 */ | |
} | |
.container { | |
padding-left: 12px; | |
padding-right: 12px; | |
} | |
/* 移动端导航栏优化 */ | |
.navbar { | |
padding: 0.5rem 0; | |
position: sticky; | |
top: 0; | |
z-index: 1030; | |
} | |
.navbar-brand { | |
font-size: 1.1rem; | |
} | |
.navbar-brand i { | |
display: none; /* 移动端隐藏图标 */ | |
} | |
/* 用户信息优化 */ | |
.user-info { | |
gap: 0.5rem ; | |
} | |
.user-info .avatar { | |
width: 28px ; | |
height: 28px ; | |
font-size: 0.875rem; | |
} | |
.user-info span { | |
font-size: 0.875rem; | |
} | |
/* 统计卡片移动端优化 */ | |
.stats-card { | |
padding: 1rem ; | |
margin-bottom: 0.75rem; | |
} | |
.stats-card h3 { | |
font-size: 1.5rem ; | |
} | |
.stats-card p { | |
font-size: 0.875rem; | |
} | |
/* 表格移动端优化 */ | |
.table-container { | |
overflow-x: auto; | |
-webkit-overflow-scrolling: touch; | |
margin: 0 -12px; | |
padding: 0 12px; | |
} | |
.table { | |
font-size: 0.875rem; | |
white-space: nowrap; | |
} | |
.table td, .table th { | |
padding: 0.5rem; | |
} | |
/* 隐藏次要列 */ | |
.mobile-hide { | |
display: none ; | |
} | |
/* 操作按钮优化 */ | |
.action-buttons { | |
gap: 0.25rem ; | |
} | |
.btn-sm { | |
padding: 0.25rem 0.5rem; | |
font-size: 0.75rem; | |
} | |
/* 卡片移动端优化 */ | |
.card { | |
margin-bottom: 1rem; | |
border-radius: 8px; | |
} | |
.card-header { | |
padding: 0.75rem 1rem; | |
font-size: 0.9rem; | |
} | |
.card-body { | |
padding: 1rem; | |
} | |
/* 模态框移动端优化 */ | |
.modal-dialog { | |
margin: 0.5rem; | |
max-width: calc(100% - 1rem); | |
} | |
.modal-content { | |
border-radius: 12px; | |
} | |
/* 表单移动端优化 */ | |
.form-control, .form-select { | |
font-size: 16px; /* 防止iOS缩放 */ | |
padding: 0.75rem; | |
} | |
/* 底部浮动操作栏 */ | |
.mobile-action-bar { | |
position: fixed; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
background: white; | |
border-top: 1px solid var(--border-color); | |
padding: 0.75rem; | |
display: flex; | |
gap: 0.5rem; | |
z-index: 1020; | |
box-shadow: 0 -2px 10px rgba(0,0,0,0.1); | |
} | |
.mobile-action-bar .btn { | |
flex: 1; | |
font-size: 0.875rem; | |
} | |
/* 空状态优化 */ | |
.empty-state { | |
padding: 2rem 1rem; | |
} | |
.empty-state i { | |
font-size: 2rem; | |
} | |
/* Toast移动端位置 */ | |
.toast-container { | |
top: var(--mobile-navbar-height) ; | |
right: 12px ; | |
} | |
} | |
/* 通用样式 */ | |
.navbar { | |
background-color: white ; | |
box-shadow: 0 2px 4px rgba(0,0,0,.1); | |
} | |
.navbar-brand { | |
font-weight: 600; | |
color: var(--primary-color) ; | |
} | |
.main-container { | |
margin-top: 2rem; | |
} | |
.card { | |
border: none; | |
box-shadow: 0 2px 8px rgba(0,0,0,.08); | |
border-radius: 12px; | |
margin-bottom: 1.5rem; | |
} | |
.card-header { | |
background-color: white; | |
border-bottom: 1px solid var(--border-color); | |
padding: 1.25rem; | |
font-weight: 600; | |
} | |
.table { | |
margin-bottom: 0; | |
} | |
.table th { | |
border-bottom: 2px solid var(--border-color); | |
font-weight: 600; | |
color: var(--secondary-color); | |
text-transform: uppercase; | |
font-size: 0.875rem; | |
letter-spacing: 0.5px; | |
} | |
.badge { | |
padding: 0.375rem 0.75rem; | |
font-weight: 500; | |
} | |
.btn { | |
border-radius: 8px; | |
padding: 0.5rem 1rem; | |
font-weight: 500; | |
transition: all 0.2s; | |
} | |
.btn-primary { | |
background-color: var(--primary-color); | |
border-color: var(--primary-color); | |
} | |
.btn-primary:hover { | |
background-color: #0056b3; | |
border-color: #0056b3; | |
transform: translateY(-1px); | |
box-shadow: 0 4px 8px rgba(0,102,204,.25); | |
} | |
.btn-sm { | |
padding: 0.375rem 0.75rem; | |
font-size: 0.875rem; | |
} | |
.status-indicator { | |
display: inline-block; | |
width: 8px; | |
height: 8px; | |
border-radius: 50%; | |
margin-right: 0.5rem; | |
} | |
.status-active { | |
background-color: var(--success-color); | |
animation: pulse 2s infinite; | |
} | |
.status-inactive { | |
background-color: var(--danger-color); | |
} | |
@keyframes pulse { | |
0% { | |
box-shadow: 0 0 0 0 rgba(40, 167, 69, 0.4); | |
} | |
70% { | |
box-shadow: 0 0 0 10px rgba(40, 167, 69, 0); | |
} | |
100% { | |
box-shadow: 0 0 0 0 rgba(40, 167, 69, 0); | |
} | |
} | |
.modal-header { | |
border-bottom: 1px solid var(--border-color); | |
background-color: var(--light-bg); | |
} | |
.form-label { | |
font-weight: 500; | |
color: var(--secondary-color); | |
margin-bottom: 0.5rem; | |
} | |
.form-control, .form-select { | |
border-radius: 8px; | |
border: 1px solid var(--border-color); | |
padding: 0.625rem 0.875rem; | |
} | |
.form-control:focus, .form-select:focus { | |
border-color: var(--primary-color); | |
box-shadow: 0 0 0 0.2rem rgba(0, 102, 204, 0.25); | |
} | |
.alert { | |
border-radius: 8px; | |
border: none; | |
} | |
.text-muted { | |
color: #8492a6 ; | |
} | |
.empty-state { | |
text-align: center; | |
padding: 3rem; | |
color: var(--secondary-color); | |
} | |
.empty-state i { | |
font-size: 3rem; | |
color: var(--border-color); | |
margin-bottom: 1rem; | |
} | |
.stats-card { | |
background: linear-gradient(135deg, var(--primary-color) 0%, #0056b3 100%); | |
color: white; | |
border: none; | |
border-radius: 12px; | |
padding: 1.5rem; | |
} | |
.stats-card h3 { | |
margin-bottom: 0.5rem; | |
font-size: 2rem; | |
font-weight: 700; | |
} | |
.stats-card p { | |
margin-bottom: 0; | |
opacity: 0.9; | |
} | |
.loading-spinner { | |
display: none; | |
position: fixed; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
z-index: 9999; | |
} | |
.loading-spinner.active { | |
display: block; | |
} | |
.toast-container { | |
position: fixed; | |
top: 20px; | |
right: 20px; | |
z-index: 1050; | |
} | |
.cookie-item { | |
transition: background-color 0.2s; | |
} | |
.cookie-item:hover { | |
background-color: var(--light-bg); | |
} | |
.action-buttons { | |
display: flex; | |
gap: 0.5rem; | |
} | |
.thread-id-input { | |
max-width: 200px; | |
} | |
/* 登录页面样式 */ | |
.login-container { | |
min-height: 100vh; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
padding: 1rem; | |
} | |
.login-card { | |
width: 100%; | |
max-width: 400px; | |
padding: 2rem; | |
background: white; | |
border-radius: 16px; | |
box-shadow: 0 10px 25px rgba(0,0,0,.1); | |
} | |
.login-card .logo { | |
text-align: center; | |
margin-bottom: 2rem; | |
} | |
.login-card .logo i { | |
font-size: 3rem; | |
color: var(--primary-color); | |
} | |
.login-card h2 { | |
text-align: center; | |
margin-bottom: 1.5rem; | |
color: #333; | |
font-weight: 600; | |
} | |
.login-error { | |
display: none; | |
margin-bottom: 1rem; | |
} | |
#mainContent { | |
display: none; | |
} | |
.user-info { | |
display: flex; | |
align-items: center; | |
gap: 1rem; | |
} | |
.user-info .avatar { | |
width: 32px; | |
height: 32px; | |
border-radius: 50%; | |
background: var(--primary-color); | |
color: white; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-weight: 600; | |
} | |
/* 表格响应式滚动 */ | |
.table-responsive { | |
-webkit-overflow-scrolling: touch; | |
} | |
/* 移动端触摸优化 */ | |
@media (hover: none) { | |
.btn:hover { | |
transform: none; | |
box-shadow: none; | |
} | |
.cookie-item:hover { | |
background-color: transparent; | |
} | |
} | |
/* 桌面端隐藏移动操作栏 */ | |
@media (min-width: 769px) { | |
.mobile-action-bar { | |
display: none ; | |
} | |
.mobile-only { | |
display: none ; | |
} | |
} | |
/* 改进的响应式断点 */ | |
@media (min-width: 576px) and (max-width: 768px) { | |
.col-sm-6 { | |
flex: 0 0 50%; | |
max-width: 50%; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<!-- 登录页面 --> | |
<div id="loginContainer" class="login-container"> | |
<div class="login-card"> | |
<div class="logo"> | |
<i class="bi bi-cloud-arrow-up-fill"></i> | |
</div> | |
<h2>Notion2API 管理登录</h2> | |
<div class="alert alert-danger login-error" id="loginError" role="alert"> | |
<i class="bi bi-exclamation-circle me-2"></i> | |
<span id="loginErrorText">用户名或密码错误</span> | |
</div> | |
<form id="loginForm"> | |
<div class="mb-3"> | |
<label for="username" class="form-label">用户名</label> | |
<input type="text" class="form-control" id="username" required | |
placeholder="请输入用户名" autocomplete="username"> | |
</div> | |
<div class="mb-3"> | |
<label for="password" class="form-label">密码</label> | |
<input type="password" class="form-control" id="password" required | |
placeholder="请输入密码" autocomplete="current-password"> | |
</div> | |
<div class="mb-3 form-check"> | |
<input type="checkbox" class="form-check-input" id="remember"> | |
<label class="form-check-label" for="remember"> | |
记住我 | |
</label> | |
</div> | |
<button type="submit" class="btn btn-primary w-100"> | |
<i class="bi bi-box-arrow-in-right me-2"></i> | |
登录 | |
</button> | |
</form> | |
<div class="text-center mt-3 text-muted"> | |
<small>默认用户名: admin</small> | |
</div> | |
</div> | |
</div> | |
<!-- 主内容区域 --> | |
<div id="mainContent"> | |
<!-- 导航栏 --> | |
<nav class="navbar navbar-expand-lg navbar-light"> | |
<div class="container"> | |
<a class="navbar-brand" href="#"> | |
<i class="bi bi-cloud-arrow-up-fill me-2"></i> | |
<span class="d-none d-sm-inline">Notion2API 管理面板</span> | |
<span class="d-inline d-sm-none">Notion2API</span> | |
</a> | |
<div class="ms-auto d-flex align-items-center"> | |
<div class="user-info me-3"> | |
<div class="avatar"> | |
<span id="userAvatar">A</span> | |
</div> | |
<span class="text-muted d-none d-sm-inline" id="currentUser">admin</span> | |
</div> | |
<button class="btn btn-outline-secondary btn-sm" onclick="logout()"> | |
<i class="bi bi-box-arrow-right me-1 d-none d-sm-inline"></i> | |
<span class="d-none d-sm-inline">退出</span> | |
<span class="d-inline d-sm-none">退出</span> | |
</button> | |
</div> | |
</div> | |
</nav> | |
<!-- 主容器 --> | |
<div class="container main-container"> | |
<!-- 统计信息 --> | |
<div class="row mb-4"> | |
<div class="col-12 col-sm-6 col-md-4 mb-3 mb-md-0"> | |
<div class="card stats-card"> | |
<div class="card-body"> | |
<h3 id="totalCookies">0</h3> | |
<p>总Cookie数</p> | |
</div> | |
</div> | |
</div> | |
<div class="col-12 col-sm-6 col-md-4 mb-3 mb-md-0"> | |
<div class="card stats-card"> | |
<div class="card-body"> | |
<h3 id="activeCookies">0</h3> | |
<p>有效Cookie数</p> | |
</div> | |
</div> | |
</div> | |
<div class="col-12 col-sm-6 col-md-4"> | |
<div class="card stats-card"> | |
<div class="card-body"> | |
<h3 id="threadIdCount">0</h3> | |
<p>已配置ThreadID</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Cookie管理 --> | |
<div class="card"> | |
<div class="card-header d-flex justify-content-between align-items-center"> | |
<span> | |
<i class="bi bi-key-fill me-2"></i> | |
Cookie 管理 | |
</span> | |
<div class="d-none d-md-block"> | |
<button class="btn btn-success btn-sm me-2" onclick="refreshCookies()"> | |
<i class="bi bi-arrow-clockwise me-1"></i> | |
<span class="d-none d-sm-inline">刷新状态</span> | |
<span class="d-inline d-sm-none">刷新</span> | |
</button> | |
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addCookieModal"> | |
<i class="bi bi-plus-circle me-1"></i> | |
<span class="d-none d-sm-inline">添加Cookie</span> | |
<span class="d-inline d-sm-none">添加</span> | |
</button> | |
</div> | |
</div> | |
<div class="card-body p-0 p-md-3"> | |
<div class="table-container"> | |
<div class="table-responsive"> | |
<table class="table table-hover mb-0"> | |
<thead> | |
<tr> | |
<th width="40"> | |
<i class="bi bi-toggle-on" title="启用/禁用"></i> | |
</th> | |
<th width="50">#</th> | |
<th>用户ID</th> | |
<th class="mobile-hide">空间ID</th> | |
<th class="mobile-hide">Cookie预览</th> | |
<th width="120">状态</th> | |
<th class="mobile-hide" width="150">最后使用</th> | |
<th class="mobile-hide" width="150">Thread ID</th> | |
<th width="100">操作</th> | |
</tr> | |
</thead> | |
<tbody id="cookieTableBody"> | |
<!-- Cookie列表将通过JavaScript动态加载 --> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
<div id="emptyCookieState" class="empty-state" style="display: none;"> | |
<i class="bi bi-inbox d-block"></i> | |
<p>暂无Cookie数据</p> | |
<button class="btn btn-primary btn-sm mt-2" data-bs-toggle="modal" data-bs-target="#addCookieModal"> | |
添加第一个Cookie | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- 操作日志(桌面端显示) --> | |
<div class="card d-none d-md-block"> | |
<div class="card-header"> | |
<i class="bi bi-journal-text me-2"></i> | |
操作日志 | |
</div> | |
<div class="card-body"> | |
<div id="logContainer" style="max-height: 300px; overflow-y: auto;"> | |
<div class="text-muted text-center py-3">暂无操作日志</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 移动端底部操作栏 --> | |
<div class="mobile-action-bar d-md-none"> | |
<button class="btn btn-success btn-sm" onclick="refreshCookies()"> | |
<i class="bi bi-arrow-clockwise"></i> | |
刷新 | |
</button> | |
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addCookieModal"> | |
<i class="bi bi-plus-circle"></i> | |
添加 | |
</button> | |
</div> | |
<!-- 添加Cookie模态框 --> | |
<div class="modal fade" id="addCookieModal" tabindex="-1"> | |
<div class="modal-dialog modal-lg modal-dialog-centered"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<h5 class="modal-title"> | |
<i class="bi bi-plus-circle me-2"></i> | |
添加新Cookie | |
</h5> | |
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
</div> | |
<div class="modal-body"> | |
<form id="addCookieForm"> | |
<div class="mb-3"> | |
<label class="form-label">Cookie内容</label> | |
<textarea class="form-control" id="cookieContent" rows="4" | |
placeholder="请输入Cookie内容..." required></textarea> | |
<small class="text-muted">支持单个Cookie或使用 | 分隔的多个Cookie</small> | |
</div> | |
<div class="mb-3"> | |
<label class="form-label">Thread ID(可选)</label> | |
<input type="text" class="form-control" id="cookieThreadId" | |
placeholder="如需指定Thread ID,请在此输入"> | |
<small class="text-muted">Thread ID需要手动从Notion获取,系统不会自动创建</small> | |
</div> | |
</form> | |
</div> | |
<div class="modal-footer"> | |
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> | |
<button type="button" class="btn btn-primary" onclick="addCookie()"> | |
<i class="bi bi-check-circle me-1"></i> | |
添加 | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 编辑ThreadID模态框 --> | |
<div class="modal fade" id="editThreadIdModal" tabindex="-1"> | |
<div class="modal-dialog modal-dialog-centered"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<h5 class="modal-title"> | |
<i class="bi bi-pencil-square me-2"></i> | |
编辑Thread ID | |
</h5> | |
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
</div> | |
<div class="modal-body"> | |
<form id="editThreadIdForm"> | |
<input type="hidden" id="editCookieIndex"> | |
<div class="mb-3"> | |
<label class="form-label">用户ID</label> | |
<input type="text" class="form-control" id="editUserId" readonly> | |
</div> | |
<div class="mb-3"> | |
<label class="form-label">Thread ID</label> | |
<input type="text" class="form-control" id="editThreadId" | |
placeholder="输入Thread ID"> | |
<small class="text-muted">留空表示不使用特定的Thread ID</small> | |
</div> | |
</form> | |
</div> | |
<div class="modal-footer"> | |
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> | |
<button type="button" class="btn btn-primary" onclick="saveThreadId()"> | |
<i class="bi bi-check-circle me-1"></i> | |
保存 | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- 加载动画 --> | |
<div class="loading-spinner"> | |
<div class="spinner-border text-primary" role="status"> | |
<span class="visually-hidden">加载中...</span> | |
</div> | |
</div> | |
<!-- Toast容器 --> | |
<div class="toast-container"></div> | |
<!-- Scripts --> | |
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> | |
<script src="/admin.js"></script> | |
</div> | |
</body> | |
</html> | |