上传文件至 /
This commit is contained in:
400
upload.php
Normal file
400
upload.php
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->query("SELECT * FROM tags ORDER BY name");
|
||||||
|
$allTags = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$allTags = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
$uploadResults = [];
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_FILES['images'])) {
|
||||||
|
$is_public = isset($_POST['is_public']) ? 1 : 0;
|
||||||
|
$uploadedFiles = $_FILES['images'];
|
||||||
|
|
||||||
|
$fileCount = count($uploadedFiles['name']);
|
||||||
|
$successCount = 0;
|
||||||
|
$errorCount = 0;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $fileCount; $i++) {
|
||||||
|
if ($uploadedFiles['error'][$i] === UPLOAD_ERR_NO_FILE) continue;
|
||||||
|
|
||||||
|
$title = trim($_POST['titles'][$i] ?? '');
|
||||||
|
$file_tags = $_POST['tags'][$i] ?? [];
|
||||||
|
$file = [
|
||||||
|
'name' => $uploadedFiles['name'][$i],
|
||||||
|
'type' => $uploadedFiles['type'][$i],
|
||||||
|
'tmp_name' => $uploadedFiles['tmp_name'][$i],
|
||||||
|
'error' => $uploadedFiles['error'][$i],
|
||||||
|
'size' => $uploadedFiles['size'][$i]
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
if (empty($title)) $title = pathinfo($file['name'], PATHINFO_FILENAME);
|
||||||
|
|
||||||
|
if ($file['error'] !== UPLOAD_ERR_OK) {
|
||||||
|
$uploadResults[] = ['success' => false, 'filename' => $file['name'], 'message' => t('upload_failed')];
|
||||||
|
$errorCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($file['size'] > MAX_FILE_SIZE) {
|
||||||
|
$uploadResults[] = ['success' => false, 'filename' => $file['name'], 'message' => t('max_size') . ': 5MB'];
|
||||||
|
$errorCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||||
|
if (!in_array($file_extension, ALLOWED_TYPES)) {
|
||||||
|
$uploadResults[] = ['success' => false, 'filename' => $file['name'], 'message' => t('supported_formats') . ': JPG, PNG, GIF, WebP'];
|
||||||
|
$errorCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$filename = uniqid() . '_' . time() . '.' . $file_extension;
|
||||||
|
$upload_path = 'uploads/' . $filename;
|
||||||
|
|
||||||
|
if (move_uploaded_file($file['tmp_name'], $upload_path)) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO images (user_id, title, filename, is_public, file_size, mime_type) VALUES (?, ?, ?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$_SESSION['user_id'], $title, $filename, $is_public, $file['size'], $file['type']]);
|
||||||
|
|
||||||
|
$image_id = $pdo->lastInsertId();
|
||||||
|
$tagNames = [];
|
||||||
|
|
||||||
|
|
||||||
|
if (!empty($file_tags)) {
|
||||||
|
foreach ($file_tags as $tag_id) {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO image_tags (image_id, tag_id) VALUES (?, ?)");
|
||||||
|
$stmt->execute([$image_id, $tag_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tagIds = implode(',', array_map('intval', $file_tags));
|
||||||
|
$stmt = $pdo->query("SELECT name FROM tags WHERE id IN ($tagIds)");
|
||||||
|
$tagNames = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
}
|
||||||
|
|
||||||
|
$uploadResults[] = [
|
||||||
|
'success' => true,
|
||||||
|
'filename' => $file['name'],
|
||||||
|
'title' => $title,
|
||||||
|
'tags' => $tagNames,
|
||||||
|
'url' => SITE_URL . '/uploads/' . $filename,
|
||||||
|
'view_url' => SITE_URL . '/view-image.php?id=' . $image_id
|
||||||
|
];
|
||||||
|
$successCount++;
|
||||||
|
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
unlink($upload_path);
|
||||||
|
$uploadResults[] = ['success' => false, 'filename' => $file['name'], 'message' => t('error') . ': ' . $e->getMessage()];
|
||||||
|
$errorCount++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$uploadResults[] = ['success' => false, 'filename' => $file['name'], 'message' => t('upload_failed')];
|
||||||
|
$errorCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($successCount > 0) {
|
||||||
|
$success = t('upload_success') . " {$successCount} " . t('images') . ($errorCount > 0 ? ",{$errorCount} " . t('upload_failed') : "");
|
||||||
|
}
|
||||||
|
if ($errorCount > 0 && $successCount === 0) {
|
||||||
|
$error = t('upload_failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<?php echo $lang; ?>" data-theme="<?php echo $currentUserSettings['dark_mode'] ? 'dark' : 'light'; ?>">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?php echo t('upload_title'); ?> - <?php echo SITE_NAME; ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'components/navbar.php'; ?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="upload-container">
|
||||||
|
<div class="upload-card card">
|
||||||
|
<h2><i class="fas fa-cloud-upload-alt"></i> <?php echo t('batch_upload'); ?></h2>
|
||||||
|
|
||||||
|
<?php if($error): ?>
|
||||||
|
<div class="alert alert-error">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i> <?php echo $error; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if($success): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="fas fa-check-circle"></i> <?php echo $success; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form method="POST" action="" enctype="multipart/form-data" id="uploadForm">
|
||||||
|
|
||||||
|
<div class="upload-area" id="uploadArea">
|
||||||
|
<div>
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="fas fa-cloud-upload-alt"></i>
|
||||||
|
</div>
|
||||||
|
<h3><?php echo t('drag_drop'); ?></h3>
|
||||||
|
<p><?php echo t('supported_formats'); ?>: JPG, PNG, GIF, WebP | <?php echo t('max_size'); ?>: 5MB</p>
|
||||||
|
<p class="text-muted"><?php echo t('multiple_files'); ?></p>
|
||||||
|
</div>
|
||||||
|
<input type="file" id="fileInput" name="images[]" multiple accept="image/*" style="display: none;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="batch-actions mt-2" id="batchActions" style="display: none;">
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="setAllTitles()">
|
||||||
|
<i class="fas fa-heading"></i> <?php echo t('set_all_titles'); ?>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="setAllTags()">
|
||||||
|
<i class="fas fa-tags"></i> <?php echo t('set_all_tags'); ?>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-danger" onclick="clearAllFiles()">
|
||||||
|
<i class="fas fa-trash"></i> <?php echo t('clear_all'); ?>
|
||||||
|
</button>
|
||||||
|
<span id="fileCount" class="text-muted">0 <?php echo t('files_selected'); ?></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="file-list" id="fileList"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group mt-2">
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input type="checkbox" name="is_public" checked>
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
<i class="fas fa-globe"></i> <?php echo t('set_public'); ?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary btn-full mt-2" id="uploadButton" style="display: none;">
|
||||||
|
<i class="fas fa-upload"></i> <?php echo t('start_upload'); ?>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if(!empty($uploadResults)): ?>
|
||||||
|
<div class="upload-results mt-3">
|
||||||
|
<h3><i class="fas fa-list"></i> <?php echo t('upload_results'); ?></h3>
|
||||||
|
<?php foreach($uploadResults as $result): ?>
|
||||||
|
<div class="result-item <?php echo $result['success'] ? 'alert alert-success' : 'alert alert-error'; ?>">
|
||||||
|
<?php if($result['success']): ?>
|
||||||
|
<i class="fas fa-check-circle"></i> <strong><?php echo htmlspecialchars($result['filename']); ?></strong> - <?php echo t('upload_success'); ?>
|
||||||
|
<br>
|
||||||
|
<small>
|
||||||
|
<i class="fas fa-heading"></i> <?php echo t('title'); ?>: <?php echo htmlspecialchars($result['title']); ?> |
|
||||||
|
<?php if(!empty($result['tags'])): ?>
|
||||||
|
<i class="fas fa-tags"></i> <?php echo t('tags'); ?>: <?php echo implode(', ', $result['tags']); ?> |
|
||||||
|
<?php endif; ?>
|
||||||
|
<a href="<?php echo $result['view_url']; ?>" target="_blank"><i class="fas fa-eye"></i> <?php echo t('view'); ?></a> |
|
||||||
|
<a href="#" onclick="copyToClipboard('<?php echo $result['url']; ?>'); return false;"><i class="fas fa-copy"></i> <?php echo t('copy'); ?></a>
|
||||||
|
</small>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-times-circle"></i> <strong><?php echo htmlspecialchars($result['filename']); ?></strong> - <?php echo t('upload_failed'); ?>: <?php echo $result['message']; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const allTags = <?php echo json_encode($allTags); ?>;
|
||||||
|
let fileCounter = 0;
|
||||||
|
const fileList = document.getElementById('fileList');
|
||||||
|
const fileInput = document.getElementById('fileInput');
|
||||||
|
const uploadArea = document.getElementById('uploadArea');
|
||||||
|
const batchActions = document.getElementById('batchActions');
|
||||||
|
const uploadButton = document.getElementById('uploadButton');
|
||||||
|
const fileCount = document.getElementById('fileCount');
|
||||||
|
|
||||||
|
|
||||||
|
uploadArea.addEventListener('click', () => fileInput.click());
|
||||||
|
|
||||||
|
uploadArea.addEventListener('dragover', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadArea.classList.add('dragover');
|
||||||
|
});
|
||||||
|
|
||||||
|
uploadArea.addEventListener('dragleave', () => {
|
||||||
|
uploadArea.classList.remove('dragover');
|
||||||
|
});
|
||||||
|
|
||||||
|
uploadArea.addEventListener('drop', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadArea.classList.remove('dragover');
|
||||||
|
handleFiles(e.dataTransfer.files);
|
||||||
|
});
|
||||||
|
|
||||||
|
fileInput.addEventListener('change', (e) => {
|
||||||
|
handleFiles(e.target.files);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function handleFiles(files) {
|
||||||
|
for (let file of files) {
|
||||||
|
if (file.type.startsWith('image/')) {
|
||||||
|
addFileToList(file);
|
||||||
|
} else {
|
||||||
|
alert(`文件 "${file.name}" 不是图片格式,已跳过。`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFileToList(file) {
|
||||||
|
const fileId = 'file_' + fileCounter++;
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = function(e) {
|
||||||
|
const fileItem = document.createElement('div');
|
||||||
|
fileItem.className = 'file-item';
|
||||||
|
fileItem.id = fileId;
|
||||||
|
|
||||||
|
fileItem.innerHTML = `
|
||||||
|
<div class="file-preview">
|
||||||
|
<img src="${e.target.result}" alt="预览">
|
||||||
|
</div>
|
||||||
|
<div class="file-info">
|
||||||
|
<div class="file-name">${file.name}</div>
|
||||||
|
<div class="file-size">${formatFileSize(file.size)}</div>
|
||||||
|
</div>
|
||||||
|
<div class="file-metadata">
|
||||||
|
<input type="text" class="file-title-input" name="titles[]"
|
||||||
|
placeholder="<?php echo t('title'); ?>(<?php echo t('optional'); ?>)"
|
||||||
|
value="${file.name.replace(/\.[^/.]+$/, "")}">
|
||||||
|
<div class="tags-selector">
|
||||||
|
<select name="tags[]" multiple class="tags-select" style="width: 100%; height: 80px; padding: 5px;">
|
||||||
|
<option value=""><?php echo t('select_tags'); ?></option>
|
||||||
|
${allTags.map(tag =>
|
||||||
|
`<option value="${tag.id}">${tag.name}</option>`
|
||||||
|
).join('')}
|
||||||
|
</select>
|
||||||
|
<small><?php echo t('hold_ctrl_multiselect'); ?></small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="remove-file" onclick="removeFile('${fileId}')">
|
||||||
|
<i class="fas fa-times"></i> <?php echo t('delete'); ?>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
fileList.appendChild(fileItem);
|
||||||
|
updateUI();
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFile(fileId) {
|
||||||
|
const fileItem = document.getElementById(fileId);
|
||||||
|
if (fileItem) {
|
||||||
|
fileItem.remove();
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAllFiles() {
|
||||||
|
if (confirm('<?php echo t('confirm_clear_all'); ?>')) {
|
||||||
|
fileList.innerHTML = '';
|
||||||
|
fileInput.value = '';
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAllTitles() {
|
||||||
|
const title = prompt('<?php echo t('enter_title_for_all'); ?>:');
|
||||||
|
if (title !== null) {
|
||||||
|
const inputs = document.querySelectorAll('.file-title-input');
|
||||||
|
inputs.forEach(input => {
|
||||||
|
input.value = title || input.defaultValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAllTags() {
|
||||||
|
const selectedTags = prompt('<?php echo t('enter_tag_ids'); ?>:');
|
||||||
|
if (selectedTags) {
|
||||||
|
const tagInputs = selectedTags.split(',').map(t => t.trim());
|
||||||
|
const selects = document.querySelectorAll('.tags-select');
|
||||||
|
|
||||||
|
selects.forEach(select => {
|
||||||
|
Array.from(select.options).forEach(option => {
|
||||||
|
option.selected = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
tagInputs.forEach(tagInput => {
|
||||||
|
let option = Array.from(select.options).find(opt => opt.value === tagInput);
|
||||||
|
if (!option) {
|
||||||
|
option = Array.from(select.options).find(opt =>
|
||||||
|
opt.text.toLowerCase() === tagInput.toLowerCase()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (option) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUI() {
|
||||||
|
const fileItems = fileList.querySelectorAll('.file-item');
|
||||||
|
const hasFiles = fileItems.length > 0;
|
||||||
|
|
||||||
|
batchActions.style.display = hasFiles ? 'flex' : 'none';
|
||||||
|
uploadButton.style.display = hasFiles ? 'block' : 'none';
|
||||||
|
fileCount.textContent = `${fileItems.length} <?php echo t('files_selected'); ?>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatFileSize(bytes) {
|
||||||
|
if (bytes >= 1073741824) return (bytes / 1073741824).toFixed(2) + ' GB';
|
||||||
|
else if (bytes >= 1048576) return (bytes / 1048576).toFixed(2) + ' MB';
|
||||||
|
else if (bytes >= 1024) return (bytes / 1024).toFixed(2) + ' KB';
|
||||||
|
else return bytes + ' bytes';
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipboard(text) {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
alert('<?php echo t('copied_to_clipboard'); ?>');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = text;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
alert('<?php echo t('copied_to_clipboard'); ?>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('uploadForm').addEventListener('submit', function() {
|
||||||
|
const uploadButton = document.getElementById('uploadButton');
|
||||||
|
uploadButton.disabled = true;
|
||||||
|
uploadButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> <?php echo t('uploading'); ?>...';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
175
verify.php
Normal file
175
verify.php
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
$verification_code = $_GET['code'] ?? '';
|
||||||
|
|
||||||
|
if (empty($verification_code)) {
|
||||||
|
$error = '无效的验证链接';
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT id, username, email FROM users WHERE verification_code = ? AND is_verified = 0");
|
||||||
|
$stmt->execute([$verification_code]);
|
||||||
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$error = '验证链接已过期或无效';
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare("UPDATE users SET is_verified = 1, verification_code = NULL WHERE id = ?");
|
||||||
|
if ($stmt->execute([$user['id']])) {
|
||||||
|
$success = '邮箱验证成功!您现在可以登录了。';
|
||||||
|
|
||||||
|
sendNotification(
|
||||||
|
$user['id'],
|
||||||
|
'announcement',
|
||||||
|
'邮箱验证成功',
|
||||||
|
"恭喜您,{$user['username']}!您的邮箱验证已成功完成。现在您可以享受PicHost的所有功能。",
|
||||||
|
'dashboard.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
sendEmailNotification(
|
||||||
|
$user['id'],
|
||||||
|
'PicHost - 邮箱验证成功',
|
||||||
|
"
|
||||||
|
<h2>邮箱验证成功</h2>
|
||||||
|
<p>亲爱的 {$user['username']},</p>
|
||||||
|
<p>您的PicHost账户邮箱验证已成功完成!</p>
|
||||||
|
<p>现在您可以:</p>
|
||||||
|
<ul>
|
||||||
|
<li>上传和管理图片</li>
|
||||||
|
<li>使用API接口</li>
|
||||||
|
<li>接收重要通知</li>
|
||||||
|
<li>享受完整的功能体验</li>
|
||||||
|
</ul>
|
||||||
|
<p>立即登录开始使用:<a href='" . SITE_URL . "/login.php'>" . SITE_URL . "/login.php</a></p>
|
||||||
|
"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$error = '验证失败,请稍后重试';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$error = '系统错误:' . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<?php echo $lang; ?>" data-theme="<?php echo $currentUserSettings['dark_mode'] ? 'dark' : 'light'; ?>">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>邮箱验证 - <?php echo SITE_NAME; ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'components/navbar.php'; ?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="auth-container">
|
||||||
|
<div class="auth-card card">
|
||||||
|
<h2><i class="fas fa-envelope-circle-check"></i> 邮箱验证</h2>
|
||||||
|
|
||||||
|
<?php if($error): ?>
|
||||||
|
<div class="alert alert-error">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i> <?php echo $error; ?>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-2">
|
||||||
|
<p>遇到问题?</p>
|
||||||
|
<a href="contact.php" class="btn btn-secondary">
|
||||||
|
<i class="fas fa-headset"></i> 联系支持
|
||||||
|
</a>
|
||||||
|
<a href="index.php" class="btn">
|
||||||
|
<i class="fas fa-home"></i> 返回首页
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if($success): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="fas fa-check-circle"></i> <?php echo $success; ?>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-3">
|
||||||
|
<div class="success-animation">
|
||||||
|
<i class="fas fa-check-circle" style="font-size: 4rem; color: var(--success-color);"></i>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2">您的账户现已完全激活</p>
|
||||||
|
<div class="auth-links">
|
||||||
|
<a href="login.php" class="btn btn-primary">
|
||||||
|
<i class="fas fa-sign-in-alt"></i> 立即登录
|
||||||
|
</a>
|
||||||
|
<a href="index.php" class="btn btn-secondary">
|
||||||
|
<i class="fas fa-home"></i> 返回首页
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="features-highlight mt-3">
|
||||||
|
<h4><i class="fas fa-gift"></i> 现在您可以:</h4>
|
||||||
|
<ul style="text-align: left; margin: 15px 0; padding-left: 20px;">
|
||||||
|
<li><i class="fas fa-cloud-upload-alt"></i> 上传和管理图片</li>
|
||||||
|
<li><i class="fas fa-code"></i> 使用API接口</li>
|
||||||
|
<li><i class="fas fa-bell"></i> 接收重要通知</li>
|
||||||
|
<li><i class="fas fa-share-alt"></i> 分享图片链接</li>
|
||||||
|
<li><i class="fas fa-tags"></i> 使用标签分类</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if(empty($error) && empty($success)): ?>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="loading-spinner">
|
||||||
|
<i class="fas fa-spinner fa-spin" style="font-size: 3rem; color: var(--primary-color);"></i>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2">正在验证您的邮箱...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelector('.loading-spinner').innerHTML = '<i class="fas fa-exclamation-triangle" style="font-size: 3rem; color: var(--warning-color);"></i>';
|
||||||
|
document.querySelector('.loading-spinner + p').textContent = '验证时间较长,请耐心等待...';
|
||||||
|
}, 3000);
|
||||||
|
</script>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if(empty($error) && empty($success)): ?>
|
||||||
|
<div class="card mt-2">
|
||||||
|
<h4><i class="fas fa-info-circle"></i> 验证说明</h4>
|
||||||
|
<ul style="text-align: left; margin: 10px 0; padding-left: 20px;">
|
||||||
|
<li>邮箱验证确保您的账户安全</li>
|
||||||
|
<li>验证后可以享受完整功能</li>
|
||||||
|
<li>如果长时间未完成验证,请检查垃圾邮件</li>
|
||||||
|
<li>如需帮助,请联系客服支持</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.success-animation {
|
||||||
|
animation: bounce 0.6s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 20%, 50%, 80%, 100% {transform: translateY(0);}
|
||||||
|
40% {transform: translateY(-10px);}
|
||||||
|
60% {transform: translateY(-5px);}
|
||||||
|
}
|
||||||
|
|
||||||
|
.features-highlight {
|
||||||
|
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border-left: 4px solid var(--success-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .features-highlight {
|
||||||
|
background: linear-gradient(135deg, #2d2d2d, #3d3d3d);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
404
view-image.php
Normal file
404
view-image.php
Normal file
@@ -0,0 +1,404 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
$image_id = $_GET['id'] ?? 0;
|
||||||
|
$feedback_success = '';
|
||||||
|
$feedback_error = '';
|
||||||
|
|
||||||
|
if (!$image_id) {
|
||||||
|
die('图片ID不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT i.*, u.username,
|
||||||
|
GROUP_CONCAT(t.name) as tag_names,
|
||||||
|
GROUP_CONCAT(t.color) as tag_colors,
|
||||||
|
GROUP_CONCAT(t.id) as tag_ids,
|
||||||
|
(SELECT COUNT(*) FROM image_feedbacks WHERE image_id = i.id AND type = 'like') as like_count,
|
||||||
|
(SELECT COUNT(*) FROM image_feedbacks WHERE image_id = i.id AND type = 'report') as report_count,
|
||||||
|
(SELECT COUNT(*) FROM image_feedbacks WHERE image_id = i.id AND user_id = ? AND type = 'like') as user_liked
|
||||||
|
FROM images i
|
||||||
|
LEFT JOIN users u ON i.user_id = u.id
|
||||||
|
LEFT JOIN image_tags it ON i.id = it.image_id
|
||||||
|
LEFT JOIN tags t ON it.tag_id = t.id
|
||||||
|
WHERE i.id = ?
|
||||||
|
GROUP BY i.id
|
||||||
|
");
|
||||||
|
$stmt->execute([$_SESSION['user_id'] ?? 0, $image_id]);
|
||||||
|
$image = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$image) {
|
||||||
|
die('图片不存在或已被删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = [];
|
||||||
|
if ($image['tag_names']) {
|
||||||
|
$tagNames = explode(',', $image['tag_names']);
|
||||||
|
$tagColors = explode(',', $image['tag_colors']);
|
||||||
|
$tagIds = explode(',', $image['tag_ids']);
|
||||||
|
|
||||||
|
for ($i = 0; $i < count($tagNames); $i++) {
|
||||||
|
if (!empty($tagNames[$i])) {
|
||||||
|
$tags[] = [
|
||||||
|
'id' => $tagIds[$i],
|
||||||
|
'name' => $tagNames[$i],
|
||||||
|
'color' => $tagColors[$i]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($_SESSION['viewed_images'])) {
|
||||||
|
$_SESSION['viewed_images'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($image_id, $_SESSION['viewed_images'])) {
|
||||||
|
$pdo->prepare("UPDATE images SET views = views + 1 WHERE id = ?")->execute([$image_id]);
|
||||||
|
$_SESSION['viewed_images'][] = $image_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
die('数据库错误: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SESSION['user_id'])) {
|
||||||
|
$type = $_POST['type'];
|
||||||
|
$comment = trim($_POST['comment'] ?? '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM image_feedbacks WHERE image_id = ? AND user_id = ? AND type = ?");
|
||||||
|
$stmt->execute([$image_id, $_SESSION['user_id'], $type]);
|
||||||
|
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
$feedback_error = '您已经对此图片进行过此操作';
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO image_feedbacks (image_id, user_id, type, comment) VALUES (?, ?, ?, ?)");
|
||||||
|
if ($stmt->execute([$image_id, $_SESSION['user_id'], $type, $comment])) {
|
||||||
|
$feedback_success = $type === 'like' ? '感谢您的喜欢!' : '举报已提交,我们会尽快处理。';
|
||||||
|
|
||||||
|
if ($type === 'like' && $image['user_id'] != $_SESSION['user_id']) {
|
||||||
|
sendNotification(
|
||||||
|
$image['user_id'],
|
||||||
|
'image_feedback',
|
||||||
|
'您的图片被喜欢了!',
|
||||||
|
"用户 {$_SESSION['username']} 喜欢了您的图片「{$image['title']}」",
|
||||||
|
"view-image.php?id={$image_id}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Location: view-image.php?id={$image_id}");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$feedback_error = '操作失败:' . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<?php echo $lang; ?>" data-theme="<?php echo $currentUserSettings['dark_mode'] ? 'dark' : 'light'; ?>">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?php echo htmlspecialchars($image['title'] ?: '图片详情'); ?> - <?php echo SITE_NAME; ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
<style>
|
||||||
|
.image-preview {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
background: var(--card-bg);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.image-preview img {
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 70vh;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
transition: var(--transition);
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
.image-preview img.zoomed {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 90vh;
|
||||||
|
cursor: zoom-out;
|
||||||
|
}
|
||||||
|
.image-info {
|
||||||
|
background: var(--card-bg);
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.info-item {
|
||||||
|
padding: 15px;
|
||||||
|
background: var(--bg-color);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
border-left: 4px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
.info-label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.copy-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.copy-btn {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
.feedback-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.like-btn, .report-btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
transition: var(--transition);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.like-btn {
|
||||||
|
background: #e8f5e9;
|
||||||
|
color: #27ae60;
|
||||||
|
border: 2px solid #27ae60;
|
||||||
|
}
|
||||||
|
.like-btn:hover {
|
||||||
|
background: #27ae60;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.like-btn.liked {
|
||||||
|
background: #27ae60;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.report-btn {
|
||||||
|
background: #ffeaea;
|
||||||
|
color: #e74c3c;
|
||||||
|
border: 2px solid #e74c3c;
|
||||||
|
}
|
||||||
|
.report-btn:hover {
|
||||||
|
background: #e74c3c;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
[data-theme="dark"] .like-btn {
|
||||||
|
background: #1e3a2e;
|
||||||
|
color: #4ade80;
|
||||||
|
border-color: #4ade80;
|
||||||
|
}
|
||||||
|
[data-theme="dark"] .report-btn {
|
||||||
|
background: #3a1e1e;
|
||||||
|
color: #f87171;
|
||||||
|
border-color: #f87171;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'components/navbar.php'; ?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="image-detail">
|
||||||
|
<div class="image-preview">
|
||||||
|
<img src="uploads/<?php echo $image['filename']; ?>"
|
||||||
|
alt="<?php echo htmlspecialchars($image['title']); ?>"
|
||||||
|
id="previewImage">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="image-info">
|
||||||
|
<h1><?php echo htmlspecialchars($image['title'] ?: '未命名图片'); ?></h1>
|
||||||
|
|
||||||
|
<?php if($image['description']): ?>
|
||||||
|
<p class="image-description"><?php echo nl2br(htmlspecialchars($image['description'])); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if(!empty($tags)): ?>
|
||||||
|
<div class="tags-container">
|
||||||
|
<?php foreach($tags as $tag): ?>
|
||||||
|
<span class="tag" style="background: <?php echo $tag['color']; ?>">
|
||||||
|
<i class="fas fa-tag"></i> <?php echo htmlspecialchars($tag['name']); ?>
|
||||||
|
</span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="info-grid">
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label"><i class="fas fa-user"></i> 上传者</div>
|
||||||
|
<div><?php echo htmlspecialchars($image['username']); ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label"><i class="fas fa-calendar"></i> 上传时间</div>
|
||||||
|
<div><?php echo date('Y-m-d H:i', strtotime($image['uploaded_at'])); ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label"><i class="fas fa-eye"></i> 浏览量</div>
|
||||||
|
<div><?php echo $image['views']; ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label"><i class="fas fa-heart"></i> 喜欢数</div>
|
||||||
|
<div><?php echo $image['like_count']; ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label"><i class="fas fa-globe"></i> 状态</div>
|
||||||
|
<div>
|
||||||
|
<span class="status-badge <?php echo $image['is_public'] ? 'status-public' : 'status-private'; ?>">
|
||||||
|
<?php echo $image['is_public'] ? '公开' : '私有'; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if(isset($_SESSION['user_id'])): ?>
|
||||||
|
<div class="image-feedback">
|
||||||
|
<h3><i class="fas fa-comment-dots"></i> 图片反馈</h3>
|
||||||
|
|
||||||
|
<?php if($feedback_success): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="fas fa-check-circle"></i> <?php echo $feedback_success; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if($feedback_error): ?>
|
||||||
|
<div class="alert alert-error">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i> <?php echo $feedback_error; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="feedback-buttons">
|
||||||
|
<form method="POST" style="display: inline;">
|
||||||
|
<input type="hidden" name="type" value="like">
|
||||||
|
<button type="submit" class="like-btn <?php echo $image['user_liked'] ? 'liked' : ''; ?>">
|
||||||
|
<?php if($image['user_liked']): ?>
|
||||||
|
<i class="fas fa-heart"></i> 已喜欢
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="far fa-heart"></i> 喜欢
|
||||||
|
<?php endif; ?>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button type="button" class="report-btn" onclick="showReportForm()">
|
||||||
|
<i class="fas fa-flag"></i> 举报
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="reportForm" style="display: none; margin-top: 15px;">
|
||||||
|
<form method="POST">
|
||||||
|
<input type="hidden" name="type" value="report">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>举报原因(可选)</label>
|
||||||
|
<textarea name="comment" rows="3" placeholder="请描述举报原因..."></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-danger">
|
||||||
|
<i class="fas fa-paper-plane"></i> 提交举报
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="hideReportForm()">
|
||||||
|
<i class="fas fa-times"></i> 取消
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<h3><i class="fas fa-share-alt"></i> 分享链接</h3>
|
||||||
|
<div class="copy-buttons">
|
||||||
|
<?php
|
||||||
|
$image_url = SITE_URL . '/view-image.php?id=' . $image_id;
|
||||||
|
$direct_url = SITE_URL . '/uploads/' . $image['filename'];
|
||||||
|
$bbcode = "[img]{$direct_url}[/img]";
|
||||||
|
$markdown = "![{$image['title']}]({$direct_url})";
|
||||||
|
$html = "<img src=\"{$direct_url}\" alt=\"{$image['title']}\">";
|
||||||
|
?>
|
||||||
|
|
||||||
|
<button class="btn copy-btn" data-text="<?php echo $image_url; ?>">
|
||||||
|
<i class="fas fa-link"></i> 页面链接
|
||||||
|
</button>
|
||||||
|
<button class="btn copy-btn" data-text="<?php echo $direct_url; ?>">
|
||||||
|
<i class="fas fa-image"></i> 图片直链
|
||||||
|
</button>
|
||||||
|
<button class="btn copy-btn" data-text="<?php echo htmlspecialchars($bbcode); ?>">
|
||||||
|
<i class="fas fa-code"></i> BBCode
|
||||||
|
</button>
|
||||||
|
<button class="btn copy-btn" data-text="<?php echo htmlspecialchars($markdown); ?>">
|
||||||
|
<i class="fab fa-markdown"></i> Markdown
|
||||||
|
</button>
|
||||||
|
<button class="btn copy-btn" data-text="<?php echo htmlspecialchars($html); ?>">
|
||||||
|
<i class="fab fa-html5"></i> HTML
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if(isset($_SESSION['user_id']) && $_SESSION['user_id'] == $image['user_id']): ?>
|
||||||
|
<div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--border-color);">
|
||||||
|
<a href="delete-image.php?id=<?php echo $image['id']; ?>"
|
||||||
|
class="btn btn-danger"
|
||||||
|
onclick="return confirm('确定要删除这张图片吗?此操作不可恢复!')">
|
||||||
|
<i class="fas fa-trash"></i> 删除图片
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showReportForm() {
|
||||||
|
document.getElementById('reportForm').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideReportForm() {
|
||||||
|
document.getElementById('reportForm').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('previewImage').addEventListener('click', function() {
|
||||||
|
this.classList.toggle('zoomed');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.copy-btn').forEach(button => {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
const text = this.getAttribute('data-text');
|
||||||
|
copyToClipboard(text);
|
||||||
|
|
||||||
|
const originalText = this.innerHTML;
|
||||||
|
this.innerHTML = '<i class="fas fa-check"></i> 已复制!';
|
||||||
|
this.style.background = 'var(--success-color)';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.innerHTML = originalText;
|
||||||
|
this.style.background = '';
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function copyToClipboard(text) {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = text;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user