Files
file-upload/file-upload.php

444 lines
16 KiB
PHP
Raw Permalink Normal View History

2026-06-05 10:23:33 +08:00
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php
if (isset($post) || isset($page)) {
$cid = isset($post) ? $post->cid : $page->cid;
if ($cid) {
\Widget\Contents\Attachment\Related::alloc(['parentId' => $cid])->to($attachment);
} else {
\Widget\Contents\Attachment\Unattached::alloc()->to($attachment);
}
}
?>
<div id="upload-panel" class="p">
<div class="upload-area" data-url="<?php $security->index('/action/upload'); ?>">
<?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?>
</div>
<ul id="file-list">
<?php while ($attachment->next()): ?>
<li data-cid="<?php $attachment->cid(); ?>" data-url="<?php echo $attachment->attachment->url; ?>" data-image="<?php echo $attachment->attachment->isImage ? 1 : 0; ?>"><input type="hidden" name="attachment[]" value="<?php $attachment->cid(); ?>" />
<a class="insert" title="<?php _e('点击插入文件'); ?>" href="###"><?php $attachment->title(); ?></a>
<div class="info">
<?php echo number_format(ceil($attachment->attachment->size / 1024)); ?> Kb
<a class="file" target="_blank" href="<?php $options->adminUrl('media.php?cid=' . $attachment->cid); ?>" title="<?php _e('编辑'); ?>"><i class="i-edit"></i></a>
<a href="###" class="delete" title="<?php _e('删除'); ?>"><i class="i-delete"></i></a>
</div>
</li>
<?php endwhile; ?>
</ul>
</div>
<style>
#upload-notice {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99999;
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 60px 150px;
border-radius: 4px;
font-size: 16px;
text-align: center;
white-space: nowrap;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
animation: fadeInOut 3s ease-in-out forwards;
pointer-events: none;
}
@keyframes fadeInOut {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; visibility: hidden; }
}
</style>
<script>
(function() {
// 防止重复初始化
if (window._uploadFinalFixed) return;
window._uploadFinalFixed = true;
var uploadUrl = document.querySelector('.upload-area').getAttribute('data-url');
var fileList = document.getElementById('file-list');
var isUploading = false;
var isSelecting = false;
// 显示居中提示
function showNotice(message) {
var oldNotice = document.getElementById('upload-notice');
if (oldNotice) {
oldNotice.remove();
}
var notice = document.createElement('div');
notice.id = 'upload-notice';
notice.textContent = message;
document.body.appendChild(notice);
setTimeout(function() {
var n = document.getElementById('upload-notice');
if (n) n.remove();
}, 3000);
}
// 获取当前文章cid
function getCurrentCid() {
var cidInput = document.querySelector('input[name="cid"]');
return cidInput && cidInput.value ? cidInput.value : '';
}
// 激活附件菜单(切换到附件选项卡)
function activateAttachmentsMenu() {
// 根据实际HTML结构附件选项卡的ID是 tab-files-btn
var attachmentsTab = document.getElementById('tab-files-btn');
if (!attachmentsTab) {
// 备用选择器
attachmentsTab = document.querySelector('a[href="#tab-files"]');
}
if (!attachmentsTab) {
// 再尝试查找包含"附件"文字的选项卡
var allTabs = document.querySelectorAll('.typecho-option-tabs li a');
for (var i = 0; i < allTabs.length; i++) {
var text = allTabs[i].innerText || allTabs[i].textContent;
if (text && text.indexOf('附件') !== -1) {
attachmentsTab = allTabs[i];
break;
}
}
}
if (attachmentsTab) {
// 检查是否已经是激活状态
var parentLi = attachmentsTab.parentNode;
if (parentLi && parentLi.className.indexOf('active') !== -1) {
return; // 已经是激活状态,不需要切换
}
// 模拟点击附件选项卡
if (typeof attachmentsTab.click === 'function') {
attachmentsTab.click();
} else if (typeof jQuery !== 'undefined') {
jQuery(attachmentsTab).trigger('click');
}
// 手动切换选项卡内容
var tabFiles = document.getElementById('tab-files');
var tabAdvance = document.getElementById('tab-advance');
if (tabFiles && tabAdvance) {
tabFiles.classList.remove('hidden');
tabAdvance.classList.add('hidden');
}
// 更新选项卡样式
if (parentLi) {
var allTabsLis = document.querySelectorAll('.typecho-option-tabs li');
for (var i = 0; i < allTabsLis.length; i++) {
allTabsLis[i].classList.remove('active');
}
parentLi.classList.add('active');
}
}
}
// 刷新附件列表(不刷新整个页面)
function refreshAttachmentList() {
var cid = getCurrentCid();
var url = window.location.origin + '/admin/ajax/attachment-list?cid=' + cid;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (xhr.status === 200) {
try {
var data = JSON.parse(xhr.responseText);
if (data && data.html) {
// 保存当前滚动位置
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
// 更新附件列表
fileList.innerHTML = data.html;
// 重新绑定事件
document.querySelectorAll('#file-list li').forEach(bindFileEvents);
// 恢复滚动位置
window.scrollTo(0, scrollTop);
// 更新附件数量显示
updateAttachmentCount();
// 上传成功后激活附件菜单
activateAttachmentsMenu();
} else {
// 降级方案:刷新整个页面
window.location.reload();
}
} catch(e) {
window.location.reload();
}
} else {
window.location.reload();
}
};
xhr.onerror = function() {
window.location.reload();
};
xhr.send();
}
// 更新附件数量显示
function updateAttachmentCount() {
var attachmentCount = fileList.children.length;
var tabBtn = document.getElementById('tab-files-btn');
if (tabBtn) {
var balloon = tabBtn.querySelector('.balloon');
if (!balloon && attachmentCount > 0) {
balloon = document.createElement('span');
balloon.className = 'balloon';
tabBtn.appendChild(balloon);
}
if (balloon) {
balloon.textContent = attachmentCount;
if (attachmentCount === 0) {
balloon.style.display = 'none';
} else {
balloon.style.display = '';
}
}
}
}
// 上传文件
function uploadFiles(files) {
if (!files || files.length === 0 || isUploading) return;
isUploading = true;
var total = files.length;
var completed = 0;
var successCount = 0;
var failCount = 0;
function checkComplete() {
if (completed === total) {
isUploading = false;
if (successCount > 0 || failCount > 0) {
var message = '';
if (successCount > 0 && failCount > 0) {
message = '已成功上传 ' + successCount + ' 个附件,失败 ' + failCount + ' 个附件。';
} else if (successCount > 0) {
message = '已成功上传 ' + successCount + ' 个附件。';
} else if (failCount > 0) {
message = '上传失败 ' + failCount + ' 个附件。';
}
showNotice(message);
}
if (successCount > 0) {
// 上传成功后刷新附件列表(会自动激活附件菜单)
refreshAttachmentList();
}
}
}
for (var i = 0; i < files.length; i++) {
(function(file) {
var formData = new FormData();
formData.append('file', file);
var url = uploadUrl;
var cid = getCurrentCid();
if (cid) {
url = uploadUrl + '?cid=' + cid;
}
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onload = function() {
completed++;
if (xhr.status === 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response && response[1] && response[1].cid) {
successCount++;
} else {
failCount++;
}
} catch(e) {
failCount++;
}
} else {
failCount++;
}
checkComplete();
};
xhr.onerror = function() {
completed++;
failCount++;
checkComplete();
};
xhr.send(formData);
})(files[i]);
}
}
function bindFileEvents(li) {
// 插入按钮
var insertBtn = li.querySelector('.insert');
if (insertBtn) {
insertBtn.onclick = function(e) {
e.preventDefault();
var url = li.getAttribute('data-url');
var isImage = li.getAttribute('data-image') === '1';
var title = insertBtn.innerText;
var textarea = document.querySelector('#text, .wmd-input');
if (textarea) {
var insertText = isImage ? '![](' + url + ')' : '<a href="' + url + '">' + title + '</a>';
insertAtCursor(textarea, insertText);
}
return false;
};
}
// 删除按钮
var deleteBtn = li.querySelector('.delete');
if (deleteBtn) {
deleteBtn.onclick = function(e) {
e.preventDefault();
var cid = li.getAttribute('data-cid');
if (confirm('确定要删除这个附件吗?')) {
var xhr = new XMLHttpRequest();
xhr.open('POST', window.location.origin + '/action/upload?do=delete&cid=' + cid, true);
xhr.onload = function() {
if (xhr.status === 200) {
li.remove();
// 更新附件数量
updateAttachmentCount();
// 删除后如果列表为空,保持在附件菜单
if (fileList.children.length === 0) {
activateAttachmentsMenu();
}
}
};
xhr.send();
}
return false;
};
}
}
function insertAtCursor(textarea, text) {
if (textarea.selectionStart !== undefined) {
var start = textarea.selectionStart;
var end = textarea.selectionEnd;
textarea.value = textarea.value.substring(0, start) + text + textarea.value.substring(end);
textarea.selectionStart = textarea.selectionEnd = start + text.length;
} else if (textarea.createTextRange) {
var range = textarea.createTextRange();
range.collapse(true);
range.pasteHTML(text);
}
textarea.focus();
}
// 绑定现有列表项
document.querySelectorAll('#file-list li').forEach(bindFileEvents);
// 更新初始附件数量
updateAttachmentCount();
// 获取上传链接
var uploadLink = document.querySelector('.upload-file');
if (uploadLink) {
// 移除原有的 onclick 属性
uploadLink.removeAttribute('onclick');
// 解绑 jQuery 事件
if (typeof jQuery !== 'undefined') {
jQuery(uploadLink).off('click');
}
// 添加新的事件监听
uploadLink.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
if (isUploading) {
return false;
}
if (isSelecting) {
return false;
}
isSelecting = true;
var input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.setAttribute('multiple', 'multiple');
input.style.position = 'fixed';
input.style.left = '-9999px';
input.style.top = '-9999px';
input.style.opacity = '0';
document.body.appendChild(input);
var cleanup = function() {
setTimeout(function() {
if (input && input.parentNode) {
input.parentNode.removeChild(input);
}
isSelecting = false;
}, 100);
};
input.onchange = function(e) {
var files = input.files;
cleanup();
if (files && files.length > 0) {
uploadFiles(files);
}
};
input.click();
return false;
}, true);
}
// 拖放上传
var uploadArea = document.querySelector('.upload-area');
if (uploadArea) {
if (typeof jQuery !== 'undefined') {
jQuery(uploadArea).off('drop dragover');
}
uploadArea.ondrop = function(e) {
e.preventDefault();
e.stopPropagation();
if (isUploading) {
return false;
}
var files = e.dataTransfer.files;
if (files && files.length > 0) {
uploadFiles(files);
}
return false;
};
uploadArea.ondragover = function(e) {
e.preventDefault();
e.stopPropagation();
return false;
};
}
// 确保初始时如果 URL 包含 #tab-files激活附件菜单
if (window.location.hash === '#tab-files') {
activateAttachmentsMenu();
}
})();
</script>