修改上传html 加入文件校验
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<title>文件上传</title>
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
@@ -352,30 +353,60 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 状态提示框容器 */
|
||||
.status-messages-container {
|
||||
pointer-events: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 状态提示框 */
|
||||
.status-message {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
transform: translateY(-50%);
|
||||
background: rgb(238, 238, 238);
|
||||
border-radius: 16px;
|
||||
padding: 30px 25px;
|
||||
text-align: center;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1001;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
|
||||
margin: 0 auto 20px;
|
||||
display: none;
|
||||
animation: popUp 0.3s ease;
|
||||
max-width: 85%;
|
||||
pointer-events: auto;
|
||||
position: fixed;
|
||||
top: 45%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1001;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* 点击关闭按钮 */
|
||||
.status-message .close-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.status-message .close-btn:hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@keyframes popUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-40%) scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(-50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,13 +646,8 @@
|
||||
<div class="loading-text" id="loadingText">上传中,请稍候...</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态提示框 -->
|
||||
<div class="status-message" id="statusMessage">
|
||||
<span class="status-icon" id="statusIcon">✅</span>
|
||||
<h3 class="status-title" id="statusTitle">上传成功!</h3>
|
||||
<p class="status-desc" id="statusDesc">文件已成功上传到电脑端</p>
|
||||
<button class="status-btn" id="statusBtn">完成</button>
|
||||
</div>
|
||||
<!-- 状态提示框容器 -->
|
||||
<div class="status-messages-container" id="statusMessagesContainer"></div>
|
||||
|
||||
<!-- 图片预览模态框 -->
|
||||
<div class="image-preview-modal" id="imagePreviewModal">
|
||||
@@ -629,7 +655,11 @@
|
||||
<button class="close-preview" id="closePreview">×</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script type="module">
|
||||
import { FileValidator } from './FileValidator.js'; //文件校验JS
|
||||
// 创建文件校验器实例
|
||||
const fileValidator = new FileValidator();
|
||||
|
||||
// 获取URL中的参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const sessionId = urlParams.get('sessionId');
|
||||
@@ -655,11 +685,7 @@
|
||||
const uploadBtn = document.getElementById('uploadBtn');
|
||||
const loadingOverlay = document.getElementById('loadingOverlay');
|
||||
const loadingText = document.getElementById('loadingText');
|
||||
const statusMessage = document.getElementById('statusMessage');
|
||||
const statusIcon = document.getElementById('statusIcon');
|
||||
const statusTitle = document.getElementById('statusTitle');
|
||||
const statusDesc = document.getElementById('statusDesc');
|
||||
const statusBtn = document.getElementById('statusBtn');
|
||||
const statusMessagesContainer = document.getElementById('statusMessagesContainer');
|
||||
const imagePreviewModal = document.getElementById('imagePreviewModal');
|
||||
const previewImage = document.getElementById('previewImage');
|
||||
const closePreview = document.getElementById('closePreview');
|
||||
@@ -673,6 +699,8 @@
|
||||
let isUploading = false;
|
||||
let uploadedCount = 0; // 已上传的总文件数量
|
||||
|
||||
let statusMessageCount = 0; // 弹窗计数器
|
||||
|
||||
// 初始化
|
||||
function init() {
|
||||
// 更新限制提示文本
|
||||
@@ -688,12 +716,28 @@
|
||||
fileInput.addEventListener('change', handleFileSelect);
|
||||
clearBtn.addEventListener('click', clearAllFiles);
|
||||
uploadBtn.addEventListener('click', startUpload);
|
||||
statusBtn.addEventListener('click', hideStatus);
|
||||
closePreview.addEventListener('click', () => {
|
||||
imagePreviewModal.classList.remove('show');
|
||||
document.body.style.overflow = '';
|
||||
});
|
||||
|
||||
// 添加事件委托来处理状态消息的关闭按钮
|
||||
statusMessagesContainer.addEventListener('click', (e) => {
|
||||
if (e.target.matches('[data-action="close"]')) {
|
||||
const messageId = e.target.dataset.messageId;
|
||||
closeStatusMessage(messageId);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加事件委托来处理删除按钮
|
||||
fileList.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('remove-btn')) {
|
||||
const name = e.target.dataset.name;
|
||||
const size = parseInt(e.target.dataset.size);
|
||||
removeFile(name, size);
|
||||
}
|
||||
});
|
||||
|
||||
// 图片预览模态框点击外部关闭
|
||||
imagePreviewModal.addEventListener('click', (e) => {
|
||||
if (e.target === imagePreviewModal) {
|
||||
@@ -795,7 +839,7 @@
|
||||
}
|
||||
|
||||
// 处理文件
|
||||
function handleFiles(files) {
|
||||
async function handleFiles(files) {
|
||||
// 检查是否已达到总文件数量上限
|
||||
if (MAX_FILE_COUNT > 0 && uploadedCount >= MAX_FILE_COUNT) {
|
||||
showError(`已超过文件上传总数限制(${MAX_FILE_COUNT}个)`);
|
||||
@@ -816,6 +860,7 @@
|
||||
}
|
||||
|
||||
for (let file of files) {
|
||||
console.log(file);
|
||||
// 检查是否已达到本次选择的文件数量上限
|
||||
if (selectedFiles.length >= MAX_FILE_COUNT) {
|
||||
showError(`最多只能选择 ${MAX_FILE_COUNT} 个文件,已忽略多余文件`);
|
||||
@@ -839,12 +884,18 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
// 添加到文件列表
|
||||
selectedFiles.push(file);
|
||||
addFileToList(file);
|
||||
fileValidator
|
||||
.validate(file)
|
||||
.then(() => {
|
||||
console.log(1111);
|
||||
selectedFiles.push(file);
|
||||
addFileToList(file);
|
||||
updateUI();
|
||||
})
|
||||
.catch((err) => {
|
||||
showError(file.name + err);
|
||||
});
|
||||
}
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
// 检查是否为图片文件
|
||||
@@ -888,12 +939,26 @@
|
||||
};
|
||||
return icons[ext] || icons.default;
|
||||
}
|
||||
// 移除文件
|
||||
function removeFile(name, size) {
|
||||
selectedFiles = selectedFiles.filter((f) => !(f.name === name && f.size === size));
|
||||
|
||||
const fileItem = document.querySelector(`.file-item[data-name="${name}"]`);
|
||||
if (fileItem) {
|
||||
fileItem.style.animation = 'slideIn 0.3s ease reverse';
|
||||
setTimeout(() => {
|
||||
fileItem.remove();
|
||||
updateUI();
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加文件到列表
|
||||
function addFileToList(file) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'file-item';
|
||||
li.dataset.name = file.name;
|
||||
li.dataset.size = file.size; // 添加 size 到 dataset
|
||||
|
||||
// 检查是否为图片
|
||||
const isImage = isImageType(file) && isImageFile(file.name);
|
||||
@@ -901,24 +966,24 @@
|
||||
// 获取文件图标
|
||||
const fileIcon = getFileIcon(file.name);
|
||||
|
||||
// 创建HTML
|
||||
// 创建HTML(移除 onclick,改为 data 属性)
|
||||
li.innerHTML = `
|
||||
<div class="file-icon-container" id="icon-${escapeHtml(file.name)}">
|
||||
${
|
||||
isImage
|
||||
? `<img class="thumbnail" src="#" alt="${escapeHtml(file.name)}" />`
|
||||
: `<div class="file-icon">${fileIcon}</div>`
|
||||
}
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<div class="file-name">${escapeHtml(file.name)}</div>
|
||||
<div class="file-size">${formatFileSize(file.size)}</div>
|
||||
<div class="file-progress">
|
||||
<div class="file-progress-bar" id="progress-${escapeHtml(file.name)}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="remove-btn" onclick="removeFile('${escapeHtml(file.name)}', ${file.size})">×</button>
|
||||
`;
|
||||
<div class="file-icon-container" id="icon-${escapeHtml(file.name)}">
|
||||
${
|
||||
isImage
|
||||
? `<img class="thumbnail" src="#" alt="${escapeHtml(file.name)}" />`
|
||||
: `<div class="file-icon">${fileIcon}</div>`
|
||||
}
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<div class="file-name">${escapeHtml(file.name)}</div>
|
||||
<div class="file-size">${formatFileSize(file.size)}</div>
|
||||
<div class="file-progress">
|
||||
<div class="file-progress-bar" id="progress-${escapeHtml(file.name)}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="remove-btn" data-name="${escapeHtml(file.name)}" data-size="${file.size}">×</button>
|
||||
`;
|
||||
|
||||
fileList.appendChild(li);
|
||||
|
||||
@@ -934,7 +999,6 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 生成缩略图
|
||||
function generateThumbnail(file, containerId) {
|
||||
const reader = new FileReader();
|
||||
@@ -977,20 +1041,6 @@
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 移除文件
|
||||
function removeFile(name, size) {
|
||||
selectedFiles = selectedFiles.filter((f) => !(f.name === name && f.size === size));
|
||||
|
||||
const fileItem = document.querySelector(`.file-item[data-name="${name}"]`);
|
||||
if (fileItem) {
|
||||
fileItem.style.animation = 'slideIn 0.3s ease reverse';
|
||||
setTimeout(() => {
|
||||
fileItem.remove();
|
||||
updateUI();
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
// 清空所有文件
|
||||
function clearAllFiles() {
|
||||
selectedFiles = [];
|
||||
@@ -1197,43 +1247,125 @@
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// 显示成功提示
|
||||
function showSuccess(message) {
|
||||
statusMessage.className = 'status-message status-success';
|
||||
statusIcon.textContent = '✅';
|
||||
statusTitle.textContent = '上传成功!';
|
||||
statusDesc.textContent = message;
|
||||
statusMessage.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
// 创建状态提示框
|
||||
function createStatusMessage(type, title, desc, autoClose = false, closeTime = 3000) {
|
||||
// 创建唯一的ID
|
||||
const messageId = 'status-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
||||
|
||||
// 计算当前弹窗的偏移量(每个弹窗下移20px)
|
||||
const offset = statusMessageCount * 40;
|
||||
|
||||
// 创建弹窗HTML,添加自定义的偏移样式
|
||||
const messageHtml = `
|
||||
<div class="status-message status-${type}" id="${messageId}"
|
||||
data-message-id="${messageId}"
|
||||
style="margin-top: ${offset}px;">
|
||||
<button class="close-btn" data-action="close" data-message-id="${messageId}">×</button>
|
||||
<span class="status-icon">${type === 'success' ? '✅' : '❌'}</span>
|
||||
<h3 class="status-title">${escapeHtml(title)}</h3>
|
||||
<p class="status-desc">${escapeHtml(desc)}</p>
|
||||
<button class="status-btn" data-action="close" data-message-id="${messageId}">完成</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 添加到容器
|
||||
statusMessagesContainer.innerHTML += messageHtml;
|
||||
|
||||
// 显示弹窗
|
||||
const messageElement = document.getElementById(messageId);
|
||||
messageElement.style.display = 'block';
|
||||
|
||||
// 增加弹窗计数
|
||||
statusMessageCount++;
|
||||
|
||||
// 自动关闭
|
||||
if (autoClose) {
|
||||
setTimeout(() => {
|
||||
closeStatusMessage(messageId);
|
||||
}, closeTime);
|
||||
}
|
||||
|
||||
// 限制最大显示数量(最多显示5个)
|
||||
const messages = statusMessagesContainer.querySelectorAll('.status-message');
|
||||
if (messages.length > 5) {
|
||||
// 移除最早的消息
|
||||
const oldestMessage = messages[0];
|
||||
closeStatusMessage(oldestMessage.id);
|
||||
}
|
||||
|
||||
return messageId;
|
||||
}
|
||||
|
||||
// 显示错误提示
|
||||
function showError(message) {
|
||||
statusMessage.className = 'status-message status-error';
|
||||
statusIcon.textContent = '❌';
|
||||
statusTitle.textContent = '出错了';
|
||||
statusDesc.textContent = message;
|
||||
statusMessage.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
// 关闭状态提示框
|
||||
function closeStatusMessage(messageId) {
|
||||
const messageElement = document.getElementById(messageId);
|
||||
if (messageElement) {
|
||||
// 添加淡出动画
|
||||
messageElement.style.animation = 'popUp 0.3s ease reverse';
|
||||
messageElement.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
messageElement.remove();
|
||||
|
||||
// 减少弹窗计数
|
||||
statusMessageCount--;
|
||||
|
||||
// 重新计算并更新剩余弹窗的位置
|
||||
updateRemainingStatusMessages();
|
||||
|
||||
// 检查是否还有消息显示
|
||||
const remainingMessages = statusMessagesContainer.querySelectorAll('.status-message');
|
||||
if (remainingMessages.length === 0) {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏状态提示
|
||||
function hideStatus() {
|
||||
statusMessage.style.display = 'none';
|
||||
// 更新剩余弹窗的位置
|
||||
function updateRemainingStatusMessages() {
|
||||
const messages = statusMessagesContainer.querySelectorAll('.status-message');
|
||||
|
||||
messages.forEach((message, index) => {
|
||||
const offset = index * 20; // 每个弹窗下移20px
|
||||
message.style.marginTop = `${offset}px`;
|
||||
});
|
||||
}
|
||||
|
||||
// 隐藏所有状态提示
|
||||
function hideAllStatus() {
|
||||
const messages = statusMessagesContainer.querySelectorAll('.status-message');
|
||||
messages.forEach((message) => {
|
||||
closeStatusMessage(message.id);
|
||||
});
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// 防止页面滚动
|
||||
// 显示成功提示(创建新弹窗)
|
||||
function showSuccess(message, options = {}) {
|
||||
const { autoClose = true, closeTime = 3000 } = options;
|
||||
return createStatusMessage('success', '上传成功!', message, autoClose, closeTime);
|
||||
}
|
||||
|
||||
// 显示错误提示(创建新弹窗)
|
||||
function showError(message, options = {}) {
|
||||
const { autoClose = false, closeTime = 5000 } = options;
|
||||
return createStatusMessage('error', '出错了', message, autoClose, closeTime);
|
||||
}
|
||||
|
||||
// 修改防止页面滚动函数
|
||||
function preventScroll(e) {
|
||||
const messages = statusMessagesContainer.querySelectorAll('.status-message');
|
||||
const hasMessages = messages.length > 0;
|
||||
|
||||
if (
|
||||
loadingOverlay.classList.contains('show') ||
|
||||
statusMessage.style.display === 'block' ||
|
||||
hasMessages ||
|
||||
imagePreviewModal.classList.contains('show')
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// HTML转义
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
|
||||
Reference in New Issue
Block a user