Files
Ai-Single-Page/deepseek/url.php
T

875 lines
27 KiB
PHP

<?php
/**
* 个人导航页面 - 带登录鉴权与链接管理
* 参考 Tiny File Manager 的单文件设计思路
*/
// 配置信息
define('DATA_FILE', 'nav_links.json');
define('USER_FILE', 'users.json');
define('SESSION_TIMEOUT', 3600); // 1小时
// 启动会话
session_start();
// 初始化数据文件
init_data_files();
// 处理登录/登出
handle_authentication();
// 处理链接操作
handle_link_operations();
// 获取链接数据
$links = get_links();
$categories = get_categories($links);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人导航管理系统</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}
body {
background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
min-height: 100vh;
color: #333;
line-height: 1.6;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
header {
background: linear-gradient(135deg, #6a89cc 0%, #4a69bd 100%);
color: white;
padding: 25px 30px;
display: flex;
justify-content: between;
align-items: center;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
h1 {
font-size: 1.8rem;
font-weight: 600;
}
.user-info {
display: flex;
align-items: center;
gap: 15px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 5px;
}
.btn-logout {
background: rgba(255, 255, 255, 0.2);
color: white;
}
.btn-logout:hover {
background: rgba(255, 255, 255, 0.3);
}
.btn-primary {
background: #4a69bd;
color: white;
}
.btn-primary:hover {
background: #3c5aa8;
}
.btn-edit {
background: #2ecc71;
color: white;
padding: 5px 10px;
font-size: 0.8rem;
}
.btn-delete {
background: #e74c3c;
color: white;
padding: 5px 10px;
font-size: 0.8rem;
}
.content {
padding: 30px;
}
.nav-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 25px;
margin-bottom: 40px;
}
.nav-card {
background: #f8f9fa;
border-radius: 12px;
padding: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
border-left: 4px solid #6a89cc;
}
.nav-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #e9ecef;
}
.card-title {
font-size: 1.3rem;
color: #2c3e50;
font-weight: 600;
}
.card-actions {
display: flex;
gap: 5px;
}
.link-list {
list-style: none;
}
.link-item {
margin-bottom: 10px;
padding: 10px;
background: white;
border-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.2s ease;
}
.link-item:hover {
background: #f1f3f5;
}
.link-item a {
text-decoration: none;
color: #5a6c7d;
flex-grow: 1;
display: flex;
align-items: center;
gap: 8px;
}
.link-item a:hover {
color: #3498db;
}
.link-actions {
display: flex;
gap: 5px;
}
.login-container {
max-width: 400px;
margin: 100px auto;
padding: 30px;
background: white;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #2c3e50;
}
.form-group input {
width: 100%;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
}
.form-group input:focus {
border-color: #6a89cc;
box-shadow: 0 0 0 3px rgba(106, 137, 204, 0.1);
outline: none;
}
.btn-login {
width: 100%;
padding: 12px;
background: #6a89cc;
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-login:hover {
background: #5a79bc;
}
.message {
padding: 12px 15px;
margin-bottom: 20px;
border-radius: 8px;
text-align: center;
}
.message.error {
background: #ffeaea;
color: #e74c3c;
border: 1px solid #f5c6cb;
}
.message.success {
background: #e8f6ef;
color: #27ae60;
border: 1px solid #c8e6c9;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: white;
padding: 30px;
border-radius: 12px;
width: 90%;
max-width: 500px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #e9ecef;
}
.modal-title {
font-size: 1.4rem;
color: #2c3e50;
font-weight: 600;
}
.close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: #7f8c8d;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
}
.btn-cancel {
background: #95a5a6;
color: white;
}
.btn-cancel:hover {
background: #7f8c8d;
}
.add-category-btn {
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="container">
<?php if (!is_logged_in()): ?>
<!-- 登录表单 -->
<div class="login-container">
<h1 style="text-align: center; margin-bottom: 30px;">个人导航管理系统</h1>
<?php if (isset($_SESSION['message'])): ?>
<div class="message error"><?php echo $_SESSION['message']; unset($_SESSION['message']); ?></div>
<?php endif; ?>
<form method="POST">
<input type="hidden" name="action" value="login">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="btn-login">登录</button>
</form>
</div>
<?php else: ?>
<!-- 主界面 -->
<header>
<div class="header-content">
<h1>个人导航管理系统</h1>
<div class="user-info">
<span>欢迎,<?php echo htmlspecialchars($_SESSION['username']); ?></span>
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="logout">
<button type="submit" class="btn btn-logout"><i class="fas fa-sign-out-alt"></i> 退出</button>
</form>
</div>
</div>
</header>
<div class="content">
<?php if (isset($_SESSION['message'])): ?>
<div class="message <?php echo $_SESSION['message_type']; ?>"><?php echo $_SESSION['message']; unset($_SESSION['message']); unset($_SESSION['message_type']); ?></div>
<?php endif; ?>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<h2>我的导航链接</h2>
<div>
<button class="btn btn-primary" onclick="openModal('category')"><i class="fas fa-folder-plus"></i> 添加分类</button>
<button class="btn btn-primary" onclick="openModal('link')"><i class="fas fa-plus"></i> 添加链接</button>
</div>
</div>
<div class="nav-grid">
<?php foreach ($categories as $category): ?>
<div class="nav-card">
<div class="card-header">
<h3 class="card-title"><?php echo htmlspecialchars($category); ?></h3>
<div class="card-actions">
<button class="btn btn-edit" onclick="editCategory('<?php echo htmlspecialchars($category); ?>')"><i class="fas fa-edit"></i></button>
<button class="btn btn-delete" onclick="deleteCategory('<?php echo htmlspecialchars($category); ?>')"><i class="fas fa-trash"></i></button>
</div>
</div>
<ul class="link-list">
<?php foreach ($links as $link): ?>
<?php if ($link['category'] === $category): ?>
<li class="link-item">
<a href="<?php echo htmlspecialchars($link['url']); ?>" target="_blank">
<i class="fas fa-link"></i>
<?php echo htmlspecialchars($link['title']); ?>
</a>
<div class="link-actions">
<button class="btn btn-edit" onclick="editLink(<?php echo htmlspecialchars($link['id']); ?>)"><i class="fas fa-edit"></i></button>
<button class="btn btn-delete" onclick="deleteLink(<?php echo htmlspecialchars($link['id']); ?>)"><i class="fas fa-trash"></i></button>
</div>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<!-- 添加/编辑链接模态框 -->
<div id="linkModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title" id="linkModalTitle">添加链接</h3>
<button class="close" onclick="closeModal('linkModal')">&times;</button>
</div>
<form id="linkForm" method="POST">
<input type="hidden" name="action" value="save_link">
<input type="hidden" id="link_id" name="link_id" value="">
<div class="form-group">
<label for="link_title">链接标题</label>
<input type="text" id="link_title" name="title" required>
</div>
<div class="form-group">
<label for="link_url">链接地址</label>
<input type="url" id="link_url" name="url" required>
</div>
<div class="form-group">
<label for="link_category">分类</label>
<input type="text" id="link_category" name="category" list="categories" required>
<datalist id="categories">
<?php foreach ($categories as $category): ?>
<option value="<?php echo htmlspecialchars($category); ?>">
<?php endforeach; ?>
</datalist>
</div>
<div class="form-actions">
<button type="button" class="btn btn-cancel" onclick="closeModal('linkModal')">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
<!-- 添加/编辑分类模态框 -->
<div id="categoryModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title" id="categoryModalTitle">添加分类</h3>
<button class="close" onclick="closeModal('categoryModal')">&times;</button>
</div>
<form id="categoryForm" method="POST">
<input type="hidden" name="action" value="save_category">
<input type="hidden" id="old_category_name" name="old_category_name" value="">
<div class="form-group">
<label for="category_name">分类名称</label>
<input type="text" id="category_name" name="category_name" required>
</div>
<div class="form-actions">
<button type="button" class="btn btn-cancel" onclick="closeModal('categoryModal')">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
<script>
// 模态框控制函数
function openModal(type) {
if (type === 'link') {
document.getElementById('linkModalTitle').textContent = '添加链接';
document.getElementById('linkForm').reset();
document.getElementById('link_id').value = '';
document.getElementById('linkModal').style.display = 'flex';
} else if (type === 'category') {
document.getElementById('categoryModalTitle').textContent = '添加分类';
document.getElementById('categoryForm').reset();
document.getElementById('old_category_name').value = '';
document.getElementById('categoryModal').style.display = 'flex';
}
}
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
function editLink(id) {
// 在实际应用中,这里应该通过AJAX获取链接数据
// 这里简化处理,直接重定向到带参数的URL
window.location.href = '?action=edit_link&id=' + id;
}
function deleteLink(id) {
if (confirm('确定要删除这个链接吗?')) {
window.location.href = '?action=delete_link&id=' + id;
}
}
function editCategory(name) {
document.getElementById('categoryModalTitle').textContent = '编辑分类';
document.getElementById('category_name').value = name;
document.getElementById('old_category_name').value = name;
document.getElementById('categoryModal').style.display = 'flex';
}
function deleteCategory(name) {
if (confirm('确定要删除分类 "' + name + '" 吗?此操作会删除该分类下的所有链接!')) {
window.location.href = '?action=delete_category&name=' + encodeURIComponent(name);
}
}
// 点击模态框外部关闭
window.onclick = function(event) {
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
}
// 编辑链接时的处理
<?php if (isset($_GET['action']) && $_GET['action'] === 'edit_link' && isset($_GET['id'])): ?>
<?php
$edit_id = intval($_GET['id']);
$edit_link = null;
foreach ($links as $link) {
if ($link['id'] === $edit_id) {
$edit_link = $link;
break;
}
}
if ($edit_link): ?>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('linkModalTitle').textContent = '编辑链接';
document.getElementById('link_id').value = '<?php echo $edit_link['id']; ?>';
document.getElementById('link_title').value = '<?php echo htmlspecialchars($edit_link['title']); ?>';
document.getElementById('link_url').value = '<?php echo htmlspecialchars($edit_link['url']); ?>';
document.getElementById('link_category').value = '<?php echo htmlspecialchars($edit_link['category']); ?>';
document.getElementById('linkModal').style.display = 'flex';
});
<?php endif; ?>
<?php endif; ?>
</script>
</body>
</html>
<?php
// 函数定义
/**
* 初始化数据文件
*/
function init_data_files() {
// 初始化用户文件
if (!file_exists(USER_FILE)) {
$users = [
'admin' => password_hash('admin123', PASSWORD_DEFAULT)
];
file_put_contents(USER_FILE, json_encode($users));
}
// 初始化链接数据文件
if (!file_exists(DATA_FILE)) {
$default_links = [
[
'id' => 1,
'title' => 'GitHub',
'url' => 'https://github.com',
'category' => '开发资源'
],
[
'id' => 2,
'title' => 'Stack Overflow',
'url' => 'https://stackoverflow.com',
'category' => '开发资源'
],
[
'id' => 3,
'title' => '腾讯云',
'url' => 'https://cloud.tencent.com',
'category' => '云服务'
]
];
file_put_contents(DATA_FILE, json_encode($default_links));
}
}
/**
* 处理认证逻辑
*/
function handle_authentication() {
// 检查会话是否过期
if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > SESSION_TIMEOUT)) {
session_unset();
session_destroy();
session_start();
}
$_SESSION['last_activity'] = time();
// 处理登录请求 - 只有在明确是登录操作时才处理
if (isset($_POST['action']) && $_POST['action'] === 'login') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (authenticate_user($username, $password)) {
$_SESSION['logged_in'] = true;
$_SESSION['username'] = $username;
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
} else {
$_SESSION['message'] = '用户名或密码错误!';
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
}
// 处理退出请求 - 只有在明确是退出操作时才处理
if (isset($_POST['action']) && $_POST['action'] === 'logout') {
session_unset();
session_destroy();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
}
/**
* 用户认证
*/
function authenticate_user($username, $password) {
if (!file_exists(USER_FILE)) {
return false;
}
$users = json_decode(file_get_contents(USER_FILE), true);
if (isset($users[$username]) && password_verify($password, $users[$username])) {
return true;
}
return false;
}
/**
* 检查是否已登录
*/
function is_logged_in() {
return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
}
/**
* 处理链接操作
*/
function handle_link_operations() {
if (!is_logged_in()) {
return;
}
$action = $_POST['action'] ?? $_GET['action'] ?? '';
switch ($action) {
case 'save_link':
save_link();
break;
case 'delete_link':
delete_link();
break;
case 'save_category':
save_category();
break;
case 'delete_category':
delete_category();
break;
case 'edit_link':
// 只是显示编辑模态框,不需要特殊处理
break;
}
}
/**
* 保存链接
*/
function save_link() {
$links = get_links();
$id = intval($_POST['link_id'] ?? 0);
$title = trim($_POST['title'] ?? '');
$url = trim($_POST['url'] ?? '');
$category = trim($_POST['category'] ?? '');
if (empty($title) || empty($url) || empty($category)) {
$_SESSION['message'] = '请填写所有必填字段!';
$_SESSION['message_type'] = 'error';
return;
}
// 如果是编辑现有链接
if ($id > 0) {
foreach ($links as &$link) {
if ($link['id'] === $id) {
$link['title'] = $title;
$link['url'] = $url;
$link['category'] = $category;
break;
}
}
} else {
// 添加新链接
$new_id = !empty($links) ? max(array_column($links, 'id')) + 1 : 1;
$links[] = [
'id' => $new_id,
'title' => $title,
'url' => $url,
'category' => $category
];
}
if (save_links($links)) {
$_SESSION['message'] = $id > 0 ? '链接更新成功!' : '链接添加成功!';
$_SESSION['message_type'] = 'success';
} else {
$_SESSION['message'] = '操作失败,请重试!';
$_SESSION['message_type'] = 'error';
}
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
/**
* 删除链接
*/
function delete_link() {
$id = intval($_GET['id'] ?? 0);
if ($id <= 0) {
return;
}
$links = get_links();
$new_links = array_filter($links, function($link) use ($id) {
return $link['id'] !== $id;
});
if (save_links(array_values($new_links))) {
$_SESSION['message'] = '链接删除成功!';
$_SESSION['message_type'] = 'success';
} else {
$_SESSION['message'] = '删除失败,请重试!';
$_SESSION['message_type'] = 'error';
}
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
/**
* 保存分类
*/
function save_category() {
$old_name = trim($_POST['old_category_name'] ?? '');
$new_name = trim($_POST['category_name'] ?? '');
if (empty($new_name)) {
$_SESSION['message'] = '分类名称不能为空!';
$_SESSION['message_type'] = 'error';
return;
}
$links = get_links();
$updated = false;
foreach ($links as &$link) {
if ($link['category'] === $old_name) {
$link['category'] = $new_name;
$updated = true;
}
}
if ($updated && save_links($links)) {
$_SESSION['message'] = empty($old_name) ? '分类添加成功!' : '分类更新成功!';
$_SESSION['message_type'] = 'success';
} else {
$_SESSION['message'] = '操作失败,请重试!';
$_SESSION['message_type'] = 'error';
}
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
/**
* 删除分类
*/
function delete_category() {
$category_name = urldecode($_GET['name'] ?? '');
if (empty($category_name)) {
return;
}
$links = get_links();
$new_links = array_filter($links, function($link) use ($category_name) {
return $link['category'] !== $category_name;
});
if (save_links(array_values($new_links))) {
$_SESSION['message'] = '分类删除成功!';
$_SESSION['message_type'] = 'success';
} else {
$_SESSION['message'] = '删除失败,请重试!';
$_SESSION['message_type'] = 'error';
}
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
/**
* 获取链接数据
*/
function get_links() {
if (!file_exists(DATA_FILE)) {
return [];
}
$data = file_get_contents(DATA_FILE);
return json_decode($data, true) ?: [];
}
/**
* 保存链接数据
*/
function save_links($links) {
return file_put_contents(DATA_FILE, json_encode($links, JSON_PRETTY_PRINT)) !== false;
}
/**
* 获取分类列表
*/
function get_categories($links) {
$categories = [];
foreach ($links as $link) {
if (!in_array($link['category'], $categories)) {
$categories[] = $link['category'];
}
}
return $categories;
}
?>