index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电影列表</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36CFC9',
dark: '#121826',
darker: '#0D1117',
light: '#F5F7FA',
'neutral-100': '#E5E6EB',
'neutral-200': '#C9CDD4',
'neutral-300': '#86909C',
'neutral-400': '#4E5969',
},
fontFamily: {
inter: ['Inter', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.movie-card {
@apply bg-darker rounded-lg overflow-hidden shadow-md transition-all duration-300 hover:shadow-lg hover:-translate-y-1;
}
.btn-primary {
@apply bg-primary text-white px-4 py-2 rounded-md hover:bg-primary/90 transition-colors;
}
.btn-secondary {
@apply bg-secondary text-white px-4 py-2 rounded-md hover:bg-secondary/90 transition-colors;
}
.input-field {
@apply w-full px-4 py-2 rounded-md border border-neutral-400 bg-darker text-white focus:outline-none focus:ring-2 focus:ring-primary;
}
}
</style>
</head>
<body class="bg-dark text-white font-inter min-h-screen flex flex-col">
<!-- 导航栏 -->
<nav class="bg-darker py-4 px-6 shadow-lg sticky top-0 z-10">
<div class="container mx-auto flex justify-between items-center">
<div class="text-xl font-bold text-white flex items-center gap-2">
<i class="fa fa-film text-primary"></i>
<span>电影天堂</span>
</div>
<div class="flex gap-4">
<button id="open-admin" class="btn-primary hidden md:block">
<i class="fa fa-cog mr-1"></i> 管理后台
</button>
<button id="mobile-menu-btn" class="md:hidden text-white text-xl">
<i class="fa fa-bars"></i>
</button>
</div>
</div>
<!-- 移动端菜单 -->
<div id="mobile-menu" class="md:hidden hidden bg-darker mt-2 rounded-lg shadow-lg">
<button id="mobile-open-admin" class="btn-primary w-full my-2">
<i class="fa fa-cog mr-1"></i> 管理后台
</button>
</div>
</nav>
<!-- 主要内容 -->
<main class="flex-grow container mx-auto px-4 py-8">
<!-- 分类标签 -->
<div class="mb-8 overflow-x-auto">
<div class="flex gap-2 py-2 min-w-max">
<button class="category-btn btn-primary" data-category="全部">全部</button>
<button class="category-btn bg-darker hover:bg-neutral-400/30 transition-colors" data-category="动作">动作</button>
<button class="category-btn bg-darker hover:bg-neutral-400/30 transition-colors" data-category="科幻">科幻</button>
<button class="category-btn bg-darker hover:bg-neutral-400/30 transition-colors" data-category="喜剧">喜剧</button>
<button class="category-btn bg-darker hover:bg-neutral-400/30 transition-colors" data-category="爱情">爱情</button>
<button class="category-btn bg-darker hover:bg-neutral-400/30 transition-colors" data-category="恐怖">恐怖</button>
</div>
</div>
<!-- 搜索框 -->
<div class="mb-8">
<div class="relative">
<input type="text" id="search-input" placeholder="搜索电影..." class="input-field pl-10">
<i class="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-neutral-300"></i>
</div>
</div>
<!-- 电影列表 -->
<div id="movies-container" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
<!-- 电影卡片将通过JavaScript动态生成 -->
<div class="col-span-full text-center text-neutral-300 py-12">
<i class="fa fa-film text-4xl mb-4 block"></i>
<p>暂无电影数据</p>
<p class="text-sm mt-2">点击"管理后台"添加电影</p>
</div>
</div>
</main>
<!-- 页脚 -->
<footer class="bg-darker py-6 mt-8">
<div class="container mx-auto text-center text-neutral-300 text-sm">
<p>© 2025 电影天堂 - 版权所有</p>
<p class="mt-2">本网站仅用于演示,非商业用途</p>
</div>
</footer>
<!-- 管理后台模态框 -->
<div id="admin-modal" class="fixed inset-0 bg-black/70 z-50 hidden flex items-center justify-center p-4">
<div class="bg-dark rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div class="p-6 border-b border-neutral-400 flex justify-between items-center">
<h2 class="text-xl font-bold">电影管理后台</h2>
<button id="close-admin-modal" class="text-neutral-300 hover:text-white">
<i class="fa fa-times text-xl"></i>
</button>
</div>
<div class="p-6" id="admin-content">
<!-- 管理后台内容将通过JavaScript加载 -->
</div>
</div>
</div>
<script>
// 初始化电影数据
const initializeMovieData = () => {
if (!localStorage.getItem('moviesData')) {
const defaultMovies = [
{
id: 1,
title: "复仇者联盟4",
poster: "https://picsum.photos/id/237/200/300",
rating: 8.5,
year: 2019,
genre: "动作/科幻",
description: "漫威影业的巅峰之作",
link: "https://example.com/movie/1",
category: "动作"
},
{
id: 2,
title: "流浪地球2",
poster: "https://picsum.photos/id/238/200/300",
rating: 8.2,
year: 2023,
genre: "科幻/冒险",
description: "中国科幻电影的里程碑",
link: "https://example.com/movie/2",
category: "科幻"
}
];
const moviesData = [
{ category: "全部", items: [...defaultMovies] },
{ category: "动作", items: [defaultMovies[0]] },
{ category: "科幻", items: [defaultMovies[1]] },
{ category: "喜剧", items: [] },
{ category: "爱情", items: [] },
{ category: "恐怖", items: [] }
];
localStorage.setItem('moviesData', JSON.stringify(moviesData));
}
};
// 获取电影数据
const getMoviesData = () => {
const data = localStorage.getItem('moviesData');
return data ? JSON.parse(data) : [];
};
// 保存电影数据
const saveMoviesData = (data) => {
localStorage.setItem('moviesData', JSON.stringify(data));
};
// 添加电影到分类
const addMovieToCategory = (categoryName, movie) => {
const moviesData = getMoviesData();
// 添加到"全部"分类
const allCategory = moviesData.find(cat => cat.category === "全部");
if (allCategory) {
allCategory.items.push({...movie});
}
// 添加到指定分类
const targetCategory = moviesData.find(cat => cat.category === categoryName);
if (targetCategory && categoryName !== "全部") {
targetCategory.items.push({...movie});
}
saveMoviesData(moviesData);
return true;
};
// 按分类显示电影
const showMoviesByCategory = (categoryName) => {
const moviesContainer = document.getElementById('movies-container');
const moviesData = getMoviesData();
const targetCategory = moviesData.find(cat => cat.category === categoryName);
if (!targetCategory || targetCategory.items.length === 0) {
moviesContainer.innerHTML = `
<div class="col-span-full text-center text-neutral-300 py-12">
<i class="fa fa-film text-4xl mb-4 block"></i>
<p>暂无${categoryName}类电影</p>
</div>
`;
return;
}
moviesContainer.innerHTML = '';
targetCategory.items.forEach(movie => {
const movieCard = document.createElement('div');
movieCard.className = 'movie-card';
movieCard.innerHTML = `
<div class="relative">
<img src="${movie.poster}" alt="${movie.title}" class="w-full h-64 object-cover">
<div class="absolute top-2 right-2 bg-primary/80 text-white rounded-full px-2 py-1 text-sm font-medium">
${movie.rating}
</div>
</div>
<div class="p-4">
<h3 class="font-bold text-lg mb-2">${movie.title}</h3>
<div class="flex items-center text-sm text-neutral-300 mb-2">
<span>${movie.year}</span>
<span class="mx-2">•</span>
<span>${movie.genre}</span>
</div>
<p class="text-sm text-neutral-200 line-clamp-2 mb-4">${movie.description}</p>
${movie.link ?
`<a href="${movie.link}" target="_blank" class="btn-secondary w-full inline-block text-center">
<i class="fa fa-external-link-alt mr-1"></i> 查看详情
</a>` :
`<button class="btn-secondary w-full inline-block text-center opacity-50 cursor-not-allowed">
<i class="fa fa-external-link-alt mr-1"></i> 暂无详情
</button>`
}
</div>
`;
moviesContainer.appendChild(movieCard);
});
};
// 搜索电影
const searchMovies = (keyword) => {
const moviesContainer = document.getElementById('movies-container');
const moviesData = getMoviesData();
const allMovies = moviesData.find(cat => cat.category === "全部").items;
if (!keyword.trim()) {
showMoviesByCategory('全部');
return;
}
const filteredMovies = allMovies.filter(movie =>
movie.title.toLowerCase().includes(keyword.toLowerCase()) ||
movie.description.toLowerCase().includes(keyword.toLowerCase()) ||
movie.genre.toLowerCase().includes(keyword.toLowerCase())
);
if (filteredMovies.length === 0) {
moviesContainer.innerHTML = `
<div class="col-span-full text-center text-neutral-300 py-12">
<i class="fa fa-search text-4xl mb-4 block"></i>
<p>没有找到与"${keyword}"相关的电影</p>
</div>
`;
return;
}
moviesContainer.innerHTML = '';
filteredMovies.forEach(movie => {
const movieCard = document.createElement('div');
movieCard.className = 'movie-card';
movieCard.innerHTML = `
<div class="relative">
<img src="${movie.poster}" alt="${movie.title}" class="w-full h-64 object-cover">
<div class="absolute top-2 right-2 bg-primary/80 text-white rounded-full px-2 py-1 text-sm font-medium">
${movie.rating}
</div>
</div>
<div class="p-4">
<h3 class="font-bold text-lg mb-2">${movie.title}</h3>
<div class="flex items-center text-sm text-neutral-300 mb-2">
<span>${movie.year}</span>
<span class="mx-2">•</span>
<span>${movie.genre}</span>
</div>
<p class="text-sm text-neutral-200 line-clamp-2 mb-4">${movie.description}</p>
${movie.link ?
`<a href="${movie.link}" target="_blank" class="btn-secondary w-full inline-block text-center">
<i class="fa fa-external-link-alt mr-1"></i> 查看详情
</a>` :
`<button class="btn-secondary w-full inline-block text-center opacity-50 cursor-not-allowed">
<i class="fa fa-external-link-alt mr-1"></i> 暂无详情
</button>`
}
</div>
`;
moviesContainer.appendChild(movieCard);
});
};
// 加载管理后台内容
const loadAdminContent = () => {
fetch('admin.html')
.then(response => response.text())
.then(html => {
document.getElementById('admin-content').innerHTML = html;
// 初始化管理后台的JavaScript
initAdminPage();
})
.catch(error => {
console.error('加载管理后台失败:', error);
document.getElementById('admin-content').innerHTML = `
<div class="text-center text-red-500 py-8">
<i class="fa fa-exclamation-triangle text-4xl mb-4"></i>
<p>加载管理后台失败,请确保admin.html文件存在</p>
<p class="text-sm mt-2">错误信息: ${error.message}</p>
</div>
`;
});
};
// 初始化管理后台页面
const initAdminPage = () => {
// 在这里初始化admin.html中的事件处理程序
// 由于我们是通过fetch加载的HTML,需要确保DOM已经加载完成
// 添加电影表单提交
const movieForm = document.getElementById('movie-form');
if (movieForm) {
movieForm.addEventListener('submit', function(e) {
e.preventDefault();
// 收集表单数据
const formData = {
title: document.getElementById('title').value,
poster: document.getElementById('poster').value,
rating: parseFloat(document.getElementById('rating').value),
year: parseInt(document.getElementById('year').value),
genre: document.getElementById('genre').value,
description: document.getElementById('description').value,
link: document.getElementById('link').value,
category: document.getElementById('category').value
};
try {
// 验证表单数据
if (!validateMovieForm(formData)) {
return;
}
// 创建电影对象
const newMovie = {
id: Date.now(),
...formData
};
// 添加电影到数据存储
if (addMovieToCategory(formData.category, newMovie)) {
// 清空表单
this.reset();
// 更新电影列表显示
showMoviesByCategory('全部');
alert('电影添加成功!');
} else {
alert('添加电影失败,请重试');
}
} catch (error) {
console.error('添加电影失败:', error);
alert('添加电影失败: ' + error.message);
}
});
}
// 显示电影列表
displayMovies();
};
// 验证电影表单数据
const validateMovieForm = (formData) => {
if (!formData.title.trim()) {
alert('请输入电影标题');
return false;
}
if (!formData.poster.trim()) {
alert('请输入海报链接');
return false;
}
// 简单验证URL格式
if (formData.poster.trim() && !formData.poster.startsWith('http')) {
alert('海报链接格式不正确');
return false;
}
if (isNaN(formData.rating) || formData.rating < 0 || formData.rating > 10) {
alert('请输入有效的评分 (0-10)');
return false;
}
if (isNaN(formData.year) || formData.year < 1900 || formData.year > new Date().getFullYear()) {
alert('请输入有效的年份 (1900-' + new Date().getFullYear() + ')');
return false;
}
if (!formData.genre.trim()) {
alert('请输入电影类型');
return false;
}
if (!formData.description.trim()) {
alert('请输入电影描述');
return false;
}
// 验证链接格式(如果有)
if (formData.link.trim() && !formData.link.startsWith('http')) {
alert('详情链接格式不正确');
return false;
}
return true;
};
// 显示电影信息
const displayMovies = () => {
const movieTable = document.getElementById('movie-table');
if (!movieTable) return;
const tbody = movieTable.getElementsByTagName('tbody')[0];
tbody.innerHTML = '';
try {
const moviesData = getMoviesData();
moviesData.forEach(categoryData => {
categoryData.items.forEach(movie => {
const row = tbody.insertRow();
const titleCell = row.insertCell(0);
const posterCell = row.insertCell(1);
const ratingCell = row.insertCell(2);
const yearCell = row.insertCell(3);
const genreCell = row.insertCell(4);
const descriptionCell = row.insertCell(5);
const categoryCell = row.insertCell(6);
const linkCell = row.insertCell(7);
const actionCell = row.insertCell(8);
titleCell.textContent = movie.title;
posterCell.innerHTML = `<img src="${movie.poster}" alt="${movie.title}" width="50">`;
ratingCell.textContent = movie.rating;
yearCell.textContent = movie.year;
genreCell.textContent = movie.genre;
descriptionCell.textContent = movie.description;
categoryCell.textContent = categoryData.category;
// 处理链接单元格
if (movie.link) {
linkCell.className = 'link-cell';
linkCell.innerHTML = `
<button class="link-button">
<i class="fa fa-external-link-alt"></i> 查看详情
</button>
`;
linkCell.querySelector('button').addEventListener('click', () => {
window.open(movie.link, '_blank');
});
} else {
linkCell.textContent = '无链接';
}
const deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.addEventListener('click', () => deleteMovie(categoryData.category, movie.id));
actionCell.appendChild(deleteButton);
});
});
} catch (error) {
console.error('加载电影列表失败:', error);
const row = tbody.insertRow();
const cell = row.insertCell(0);
cell.colSpan = 9;
cell.textContent = '无法加载电影数据: ' + error.message;
cell.style.textAlign = 'center';
cell.style.color = 'red';
}
};
// 删除电影
const deleteMovie = (categoryName, movieId) => {
if (!confirm('确定要删除这部电影吗?')) {
return;
}
try {
const moviesData = getMoviesData();
const targetCategory = moviesData.find(cat => cat.category === categoryName);
if (targetCategory) {
const index = targetCategory.items.findIndex(movie => movie.id === movieId);
if (index > -1) {
const deletedMovie = targetCategory.items.splice(index, 1)[0];
// 如果是从"全部"分类删除,也从对应具体分类删除
if (categoryName === '全部') {
const specificCategory = deletedMovie.genre.split('/')[0];
const specificCategoryData = moviesData.find(cat => cat.category === specificCategory);
if (specificCategoryData) {
const specificIndex = specificCategoryData.items.findIndex(movie => movie.id === movieId);
if (specificIndex > -1) {
specificCategoryData.items.splice(specificIndex, 1);
}
}
}
// 保存更新后的数据
saveMoviesData(moviesData);
// 刷新电影列表
displayMovies();
// 更新当前分类的显示
const activeCategory = document.querySelector('.category-btn.bg-primary').dataset.category;
showMoviesByCategory(activeCategory);
alert('电影删除成功!');
}
}
} catch (error) {
console.error('删除电影失败:', error);
alert('删除电影失败: ' + error.message);
}
};
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
// 初始化电影数据
initializeMovieData();
// 显示默认分类的电影
showMoviesByCategory('全部');
// 分类按钮事件
document.querySelectorAll('.category-btn').forEach(btn => {
btn.addEventListener('click', () => {
// 更新按钮样式
document.querySelectorAll('.category-btn').forEach(b => {
b.classList.remove('btn-primary');
b.classList.add('bg-darker', 'hover:bg-neutral-400/30');
});
btn.classList.add('btn-primary');
btn.classList.remove('bg-darker', 'hover:bg-neutral-400/30');
// 显示对应分类的电影
showMoviesByCategory(btn.dataset.category);
});
});
// 搜索功能
document.getElementById('search-input').addEventListener('input', (e) => {
searchMovies(e.target.value);
});
// 打开管理后台
document.getElementById('open-admin').addEventListener('click', () => {
document.getElementById('admin-modal').classList.remove('hidden');
loadAdminContent();
});
// 移动端打开管理后台
document.getElementById('mobile-open-admin').addEventListener('click', () => {
document.getElementById('admin-modal').classList.remove('hidden');
loadAdminContent();
document.getElementById('mobile-menu').classList.add('hidden');
});
// 关闭管理后台
document.getElementById('close-admin-modal').addEventListener('click', () => {
document.getElementById('admin-modal').classList.add('hidden');
});
// 移动端菜单切换
document.getElementById('mobile-menu-btn').addEventListener('click', () => {
const mobileMenu = document.getElementById('mobile-menu');
mobileMenu.classList.toggle('hidden');
});
});
</script>
</body>
</html>
admin.html
<!-- admin.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电影管理后台</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36CFC9',
dark: '#121826',
darker: '#0D1117',
light: '#F5F7FA',
'neutral-100': '#E5E6EB',
'neutral-200': '#C9CDD4',
'neutral-300': '#86909C',
'neutral-400': '#4E5969',
},
fontFamily: {
inter: ['Inter', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.btn-primary {
@apply bg-primary text-white px-4 py-2 rounded-md hover:bg-primary/90 transition-colors;
}
.btn-secondary {
@apply bg-secondary text-white px-4 py-2 rounded-md hover:bg-secondary/90 transition-colors;
}
.btn-danger {
@apply bg-red-500 text-white px-4 py-2 rounded-md hover:bg-red-600 transition-colors;
}
.input-field {
@apply w-full px-4 py-2 rounded-md border border-neutral-400 bg-darker text-white focus:outline-none focus:ring-2 focus:ring-primary;
}
}
</style>
</head>
<body class="bg-dark text-white font-inter">
<!-- 管理后台内容将被加载到index.html的模态框中 -->
<div class="p-6">
<h2 class="text-xl font-bold mb-6">添加电影</h2>
<form id="movie-form" class="space-y-6">
<div>
<label for="title" class="block text-sm font-medium text-neutral-100 mb-1">电影标题</label>
<input type="text" id="title" class="input-field" required>
</div>
<div>
<label for="poster" class="block text-sm font-medium text-neutral-100 mb-1">海报链接</label>
<input type="text" id="poster" class="input-field" required>
</div>
<div>
<label for="rating" class="block text-sm font-medium text-neutral-100 mb-1">评分</label>
<input type="number" id="rating" step="0.1" min="0" max="10" class="input-field" required>
</div>
<div>
<label for="year" class="block text-sm font-medium text-neutral-100 mb-1">年份</label>
<input type="number" id="year" min="1900" max="2100" class="input-field" required>
</div>
<div>
<label for="genre" class="block text-sm font-medium text-neutral-100 mb-1">类型</label>
<input type="text" id="genre" class="input-field" required placeholder="例如: 动作/科幻">
</div>
<div>
<label for="description" class="block text-sm font-medium text-neutral-100 mb-1">描述</label>
<textarea id="description" rows="3" class="input-field" required></textarea>
</div>
<div>
<label for="link" class="block text-sm font-medium text-neutral-100 mb-1">详情链接</label>
<input type="url" id="link" class="input-field" placeholder="https://example.com/movie/123">
</div>
<div>
<label for="category" class="block text-sm font-medium text-neutral-100 mb-1">分类</label>
<select id="category" class="input-field">
<option value="全部">全部</option>
<option value="动作">动作</option>
<option value="科幻">科幻</option>
<option value="喜剧">喜剧</option>
<option value="爱情">爱情</option>
<option value="恐怖">恐怖</option>
</select>
</div>
<div class="flex justify-end">
<button type="submit" class="btn-primary">
<i class="fa fa-plus mr-1"></i> 添加电影
</button>
</div>
</form>
<h2 class="text-xl font-bold mt-10 mb-6">电影列表</h2>
<div class="overflow-x-auto">
<table id="movie-table" class="min-w-full divide-y divide-neutral-400">
<thead>
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">标题</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">海报</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">评分</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">年份</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">类型</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">描述</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">分类</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">链接</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-200 uppercase tracking-wider">操作</th>
</tr>
</thead>
<tbody class="bg-darker divide-y divide-neutral-400">
<!-- 电影信息将通过JavaScript动态生成 -->
</tbody>
</table>
</div>
</div>
<script>
// 注意:admin.html中的JavaScript将在index.html中初始化
// 请查看index.html中的initAdminPage函数
</script>
</body>
</html>