<?php
include 'db/config.php';
$sql = "SELECT *, IFNULL(download_count, 0) as download_count, IFNULL(view_count, 0) as view_count FROM applications ORDER BY created_at DESC";
$result = $conn->query($sql);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>刺狸刺IOSIPA下载站</title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #ff7eb9;
--secondary-color: #7e6bff;
--accent-color: #6bd5ff;
--dark-color: #3a3a5a;
--light-color: #fff9fc;
--success-color: #6bff7e;
--danger-color: #ff6b7e;
--warning-color: #ffd56b;
--card-bg: #ffffff;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background-color: white;
color: var(--dark-color);
line-height: 1.6;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.anime-container {
max-width: 1400px;
width: 100%;
background-color: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
position: relative;
overflow: hidden;
margin: 20px 0;
animation: fadeIn 0.5s ease-out;
}
.anime-container::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 10px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color), var(--accent-color));
border-radius: 20px 20px 0 0;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.anime-title {
font-size: 2.5rem;
margin-bottom: 25px;
text-align: center;
color: var(--dark-color);
position: relative;
display: inline-block;
padding-bottom: 10px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.anime-title::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 4px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
border-radius: 2px;
}
.anime-search-box {
margin-bottom: 30px;
position: relative;
max-width: 600px;
margin: 0 auto 30px;
}
.anime-search-input {
padding: 14px 20px 14px 50px;
border-radius: 50px;
font-size: 1rem;
border: 2px solid #e0e0e0;
outline: none;
width: 100%;
background-color: white;
transition: all 0.3s ease;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
}
.anime-search-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(255, 126, 185, 0.2);
}
.anime-search-icon {
position: absolute;
left: 18px;
top: 50%;
transform: translateY(-50%);
color: var(--primary-color);
font-size: 1.2rem;
}
.anime-category-filter {
margin-bottom: 30px;
text-align: center;
}
.category-buttons {
display: flex;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
}
.category-btn {
padding: 10px 20px;
border-radius: 50px;
font-size: 0.9rem;
border: 2px solid #e0e0e0;
background-color: white;
cursor: pointer;
transition: all 0.3s ease;
font-family: 'Noto Sans SC', sans-serif;
color: var(--dark-color);
}
.category-btn.active {
background: linear-gradient(135deg, var(--primary-color), #ff9ec7);
color: white;
border-color: transparent;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.category-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.anime-app-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 20px;
}
.anime-app-card {
background-color: white;
border-radius: 15px;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
border: 1px solid #f0f0f0;
position: relative;
overflow: hidden;
animation: cardAppear 0.5s ease-out;
cursor: pointer;
}
@keyframes cardAppear {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
.anime-app-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 5px;
height: 100%;
background: linear-gradient(to bottom, var(--primary-color), var(--secondary-color));
}
.anime-app-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.anime-app-icon {
width: 80px;
height: 80px;
margin-bottom: 15px;
background-color: white;
border-radius: 15px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
}
.anime-app-icon img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.anime-app-name {
font-size: 1.1rem;
margin-bottom: 10px;
font-weight: 600;
color: var(--dark-color);
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
padding: 0 10px;
}
.anime-app-desc {
font-size: 0.85rem;
color: #666;
margin-bottom: 15px;
line-height: 1.4;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
padding: 0 10px;
min-height: auto;
}
.anime-download-count {
font-size: 0.8rem;
color: var(--primary-color);
margin-bottom: 15px;
font-weight: 500;
}
.anime-btn {
padding: 10px 20px;
border-radius: 50px;
font-size: 0.9rem;
font-weight: 500;
text-decoration: none;
transition: all 0.3s ease;
cursor: pointer;
border: none;
outline: none;
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
border: 2px solid transparent;
}
.anime-btn i {
margin-right: 8px;
font-size: 1rem;
}
.anime-btn::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
transition: all 0.5s ease;
}
.anime-btn:hover::before {
left: 100%;
}
.anime-btn:hover {
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.anime-btn:active {
transform: translateY(1px);
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-color), #ff9ec7);
color: white;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
z-index: 1000;
justify-content: center;
align-items: center;
animation: fadeIn 0.3s ease-out;
}
.modal-content {
background-color: white;
border-radius: 20px;
max-width: 600px;
width: 90%;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
position: relative;
animation: modalAppear 0.5s ease-out;
}
@keyframes modalAppear {
from { opacity: 0; transform: translateY(-50px); }
to { opacity: 1; transform: translateY(0); }
}
.modal-close {
position: absolute;
top: 15px;
right: 15px;
font-size: 1.5rem;
cursor: pointer;
color: #888;
transition: all 0.3s ease;
}
.modal-close:hover {
color: var(--danger-color);
}
.modal-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.modal-icon {
width: 80px;
height: 80px;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
margin-right: 20px;
}
.modal-icon img {
width: 100%;
height: 100%;
object-fit: contain;
}
.modal-title {
font-size: 1.8rem;
color: var(--dark-color);
margin-bottom: 5px;
word-break: break-word;
}
.modal-download-count {
font-size: 0.9rem;
color: var(--primary-color);
}
.modal-body {
margin-bottom: 20px;
line-height: 1.6;
color: #555;
white-space: pre-wrap;
word-break: break-word;
}
.modal-footer {
text-align: right;
}
.modal-btn {
padding: 10px 25px;
border-radius: 50px;
font-size: 1rem;
font-weight: 500;
background: linear-gradient(135deg, var(--primary-color), #ff9ec7);
color: white;
border: none;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.modal-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
@media (max-width: 1200px) {
.anime-app-grid {
grid-template-columns: repeat(4, 1fr);
}
}
@media (max-width: 992px) {
.anime-app-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 768px) {
.anime-container {
padding: 20px;
}
.anime-title {
font-size: 2rem;
}
.anime-app-grid {
grid-template-columns: repeat(2, 1fr);
}
.anime-app-card {
padding: 15px;
}
.anime-app-icon {
width: 70px;
height: 70px;
}
.anime-app-name {
font-size: 1rem;
}
.anime-app-desc {
font-size: 0.8rem;
min-height: 50px;
}
.anime-btn {
padding: 8px 16px;
font-size: 0.85rem;
}
.category-buttons {
flex-direction: column;
align-items: center;
}
}
@media (max-width: 480px) {
.anime-app-grid {
grid-template-columns: 1fr;
}
.anime-title {
font-size: 1.8rem;
}
}
.anime-empty {
text-align: center;
color: #888;
padding: 30px;
font-size: 1.1rem;
background-color: #f9f9f9;
border-radius: 15px;
border: 1px dashed #e0e0e0;
grid-column: 1 / -1;
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f5f5f5;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: #d0d0d0;
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: #b0b0b0;
}
</style>
</head>
<body>
<div class="anime-container">
<h1 class="anime-title">✨ 刺狸刺IOSIPA下载站<h1>
<div class="anime-category-filter">
<div class="category-buttons">
<button class="category-btn active" data-category="newest">最新上架</button>
<button class="category-btn" data-category="downloads">热门应用</button>
</div>
</div>
<div class="anime-search-box">
<i class="fas fa-search anime-search-icon"></i>
<input type="text" class="anime-search-input" placeholder="搜索应用..." id="search-input">
</div>
<div class="anime-app-grid" id="app-grid">
<?php
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo '
<div class="anime-app-card" data-id="' . $row["id"] . '" data-name="' . $row["name"] . '" data-description="' . $row["description"] . '" data-icon="' . $row["icon_path"] . '" data-download-url="' . $row["download_url"] . '" data-download-count="' . $row["download_count"] . '" data-view-count="' . $row["view_count"] . '" data-created-date="' . $row["created_at"] . '">
<div class="anime-app-icon">
<img src="' . $row["icon_path"] . '" alt="' . $row["name"] . '">
</div>
<h3 class="anime-app-name" title="' . $row["name"] . '">' .
(mb_strlen($row["name"], 'UTF-8') > 8 ?
mb_substr($row["name"], 0, 8, 'UTF-8') . '...' :
$row["name"]) .
'</h3>
<p class="anime-app-desc" title="' . $row["description"] . '">' .
(mb_strlen($row["description"], 'UTF-8') > 12 ?
mb_substr($row["description"], 0, 12, 'UTF-8') . '...' :
$row["description"]) .
'</p>
<p class="anime-download-count"><i class="fas fa-download"></i> ' . $row["download_count"] . '</p>
<a href="' . $row["download_url"] . '" class="anime-btn btn-primary" target="_blank" onclick="event.preventDefault(); handleDownload(this);">
<i class="fas fa-download"></i> 下载/访问
</a>
</div>
';
}
} else {
echo '<div class="anime-empty"><i class="fas fa-box-open" style="font-size: 2rem; margin-bottom: 10px; display: block;"></i>暂无应用可供下载</div>';
}
?>
</div>
</div>
<!-- 模态框 -->
<div class="modal" id="app-modal">
<div class="modal-content">
<div class="modal-header">
<div class="modal-icon">
<img id="modal-icon-img" src="" alt="">
</div>
<div>
<h2 class="modal-title" id="modal-title"></h2>
<p class="modal-download-count" id="modal-download-count"></p>
</div>
</div>
<div class="modal-body" id="modal-body"></div>
<div class="modal-footer">
<a href="" class="modal-btn" id="modal-download-btn" target="_blank" onclick="event.preventDefault(); handleDownload(this);">
<i class="fas fa-download"></i> 下载/访问
</a>
</div>
</div>
</div>
<script>
const searchInput = document.getElementById('search-input');
const appGrid = document.getElementById('app-grid');
const categoryButtons = document.querySelectorAll('.category-btn');
const modal = document.getElementById('app-modal');
const modalTitle = document.getElementById('modal-title');
const modalBody = document.getElementById('modal-body');
const modalIconImg = document.getElementById('modal-icon-img');
const modalDownloadCount = document.getElementById('modal-download-count');
const modalDownloadBtn = document.getElementById('modal-download-btn');
function handleDownload(element) {
const appId = element.getAttribute('data-id');
const downloadUrl = element.getAttribute('href');
fetch(`update_download_count.php?id=${appId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
const card = document.querySelector(`.anime-app-card[data-id="${appId}"]`);
if (card) {
const downloadCountElement = card.querySelector('.anime-download-count');
const currentCount = parseInt(card.dataset.downloadCount) + 1;
card.dataset.downloadCount = currentCount;
downloadCountElement.innerHTML = `<i class="fas fa-download"></i> ${currentCount}`;
}
if (modal.style.display === 'flex') {
modalDownloadCount.innerHTML = `<i class="fas fa-download"></i> ${currentCount} 次下载`;
}
}
})
.catch(error => console.error('Error:', error));
window.open(downloadUrl, '_blank');
}
searchInput.addEventListener('input', function () {
const searchText = this.value.toLowerCase();
const appCards = appGrid.querySelectorAll('.anime-app-card');
appCards.forEach(card => {
const appName = card.querySelector('.anime-app-name').textContent.toLowerCase();
if (appName.includes(searchText)) {
card.style.display = 'flex';
} else {
card.style.display = 'none';
}
});
});
categoryButtons.forEach(button => {
button.addEventListener('click', function () {
categoryButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
const category = this.dataset.category;
const appCards = Array.from(appGrid.querySelectorAll('.anime-app-card'));
appCards.sort((a, b) => {
const aData = a.dataset;
const bData = b.dataset;
if (category === 'newest') {
return new Date(b.dataset.createdDate) - new Date(a.dataset.createdDate);
} else if (category === 'downloads') {
return parseInt(b.dataset.downloadCount) - parseInt(a.dataset.downloadCount);
}
return 0;
});
appCards.forEach(card => {
appGrid.appendChild(card);
});
});
});
appGrid.addEventListener('click', function (e) {
const card = e.target.closest('.anime-app-card');
if (card && !e.target.closest('.anime-btn')) {
const xhr = new XMLHttpRequest();
xhr.open('GET', `update_view_count.php?id=${card.dataset.id}`, true);
xhr.send();
modalTitle.textContent = card.dataset.name;
modalBody.textContent = card.dataset.description;
modalIconImg.src = card.dataset.icon;
modalDownloadCount.innerHTML = `<i class="fas fa-download"></i> ${card.dataset.downloadCount} 次下载`;
modalDownloadBtn.href = card.dataset.downloadUrl;
modalDownloadBtn.setAttribute('data-id', card.dataset.id);
modal.style.display = 'flex';
}
});
modal.addEventListener('click', function (e) {
if (e.target === modal || !e.target.closest('.modal-content')) {
modal.style.display = 'none';
}
});
document.querySelectorAll('.anime-btn.btn-primary').forEach(btn => {
const card = btn.closest('.anime-app-card');
btn.onclick = function(e) {
e.preventDefault();
handleDownload(this);
};
btn.href = card.dataset.downloadUrl;
btn.setAttribute('data-id', card.dataset.id);
});
</script>