From d6e1c45e8b681f8d5b0a4796a36d4b45fadce646 Mon Sep 17 00:00:00 2001 From: Eason010212 <1371033826@qq.com> Date: Sun, 22 Jun 2025 15:32:36 +0800 Subject: [PATCH] update-file-storage --- js/projects.js | 300 +++++++++++++++++++++++++++++++++---------------- mixio.js | 6 +- 2 files changed, 204 insertions(+), 102 deletions(-) diff --git a/js/projects.js b/js/projects.js index 99e6eed..eed639e 100644 --- a/js/projects.js +++ b/js/projects.js @@ -4205,115 +4205,217 @@ setInterval(function(){ } }, 30000) - +storDia = false function open_storage(){ var editForm = $('
') editForm.append($('
')) - editForm.append($('

所有发送到/storage主题下的消息和图片会被自动保存

')) - var messagesContainer = $('
') - var sync_stor = function(){ - messagesContainer.empty() - var sampleMessages = [ - ] - $.getJSON('getImgStore', { - 'projectName': globalProjectName - }, function(res) { - if(res.length==0) - { - messagesContainer.append($('
暂无存储
')) - } - for (let ri = 0; ri < res.length; ri++) { - { - let url = "store/" + globalUserName + "/" + globalProjectName + "/" + res[ri] - if (url.endsWith('.txt')) { - sampleMessages.push({ type: 'text', content: url }) - } else{ - sampleMessages.push({ type: 'image', content: url }) - } - } - } - for(let ji = 0; ji < sampleMessages.length; ji++) { - let msg = sampleMessages[ji] - let messageBox = $('
') - - if (msg.type === 'text') { - $.ajax({ - url: msg.content, - success: function(res) { - messageBox.append($('
').text(res)) - // Add timestamp (sample) - let timeStamp = parseInt(msg.content.split("/")[msg.content.split("/").length - 1].split(".")[0]) - let timeString = new Date(timeStamp).toLocaleString() - let btdiv = $('
') - btdiv.append("" + timeString +"") - let deletebtn = $('') - deletebtn.click(function(){ - $.getJSON('deleteImgStore', { - 'projectName': globalProjectName, - 'filename': msg.content.split("/")[msg.content.split("/").length - 1] - }, function(){ - sync_stor() - }) - }) - btdiv.append(deletebtn) - messageBox.append(btdiv) - } - }) - } else if (msg.type === 'image') { - messageBox.append($('
')) - // Add timestamp (sample) - let timeStamp = parseInt(msg.content.split("/")[msg.content.split("/").length - 1].split(".")[0]) - let timeString = new Date(timeStamp).toLocaleString() - let btdiv = $('
') - btdiv.append("" + timeString +"") - let viewbtn = $('') - viewbtn.click(function(){ - // 全屏显示图片,点击任意退出 - let fullDialog = dialog({ - content: $('
')[0], - cancel: true, - cancelValue: '关闭' - }) - fullDialog.showModal() - - }) - let deletebtn = $('') - deletebtn.click(function(){ - $.getJSON('deleteImgStore', { - 'projectName': globalProjectName, - 'filename': msg.content.split("/")[msg.content.split("/").length - 1] - }, function(){ - sync_stor() - }) - }) - btdiv.append(viewbtn) - btdiv.append(deletebtn) - messageBox.append(btdiv) - } - messagesContainer.prepend(messageBox) - } - }) - } - editForm.append(messagesContainer) - sync_stor() - client.on('message', function(topic, msg) { - if(topic.split("/")[2] == "storage") - sync_stor() - }) + editForm.append($('

所有前缀为$主题下的消息和图片会被自动保存

')) + + // Create table structure + var tableContainer = $('
') + var fileTable = $('' + + '' + + '' + + '' + + '' + + '' + + '
文件名类型日期大小操作
') + + // Add action buttons + var actionBar = $('
' + + '
' + + '
') + + tableContainer.append(actionBar) + tableContainer.append(fileTable) + editForm.append(tableContainer) + // Bottom section var bottomDiv = $('
') var cancelEdit = $('') bottomDiv.append(cancelEdit) editForm.append(bottomDiv) - var modifyDia = dialog({ - content: editForm[0], - cancel: false - }) + var selectedFiles = []; + + // Function to trigger file download + function downloadFile(filename) { + let url = "store/" + globalUserName + "/" + globalProjectName + "/" + filename; + let a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + } + + var sync_stor = function(){ + $('#fileTableBody').empty() + selectedFiles = []; + $('#deleteSelected').prop('disabled', true); + $('#downloadSelected').prop('disabled', true); + $('#selectAll').prop('checked', false); + + $.getJSON('getImgStore', { + 'projectName': globalProjectName + }, function(res) { + if(res.length == 0) { + $('#fileTableBody').append('暂无存储文件') + return; + } + + for (let ri = 0; ri < res.length; ri++) { + let filename = res[ri]; + let url = "store/" + globalUserName + "/" + globalProjectName + "/" + filename; + let isText = filename.endsWith('.txt'); + let timeStamp; + if(filename.split("_").length>1) { + timeStamp = parseInt(filename.split("_")[1].split('.')[0]) + } else { + timeStamp = parseInt(filename.split('.')[0]); + } + let timeString = new Date(timeStamp).toLocaleString(); + let fileType = isText ? '文本' : '图片'; + + let row = $(''); + + // Checkbox + row.append(''); + + // Filename + row.append('' + filename + ''); + + // Type + row.append('' + fileType + ''); + + // Date + row.append('' + timeString + ''); + + // Size (placeholder - you might need to get actual file size from server) + row.append('--'); + + // Actions + let actionCell = $(''); + + // Download button (added for each file) + let downloadBtn = $(''); + downloadBtn.click(function() { + downloadFile(filename); + }); + actionCell.append(downloadBtn); + + if (isText) { + let viewBtn = $(''); + viewBtn.click(function() { + $.ajax({ + url: url, + success: function(content) { + let textDialog = dialog({ + content: $('
' + content + '
')[0], + cancel: true, + cancelValue: '关闭' + }); + textDialog.showModal(); + } + }); + }); + actionCell.append(viewBtn); + } else { + let viewBtn = $(''); + viewBtn.click(function() { + let fullDialog = dialog({ + content: $('
')[0], + cancel: true, + cancelValue: '关闭' + }); + fullDialog.showModal(); + }); + actionCell.append(viewBtn); + } + + let deleteBtn = $(''); + deleteBtn.click(function() { + if(confirm('确定要删除此文件吗?')) { + $.getJSON('deleteImgStore', { + 'projectName': globalProjectName, + 'filename': filename + }, function() { + sync_stor(); + }); + } + }); + actionCell.append(deleteBtn); + + row.append(actionCell); + $('#fileTableBody').append(row); + } + + // Add checkbox event handlers + $('.fileCheckbox').change(function() { + let filename = $(this).data('filename'); + if($(this).is(':checked')) { + if(!selectedFiles.includes(filename)) { + selectedFiles.push(filename); + } + } else { + selectedFiles = selectedFiles.filter(f => f !== filename); + $('#selectAll').prop('checked', false); + } + $('#deleteSelected').prop('disabled', selectedFiles.length === 0); + $('#downloadSelected').prop('disabled', selectedFiles.length === 0); + }); + }); + } + + sync_stor(); + + client.on('message', function(topic, msg) { + if(topic.split("/")[2][0] == "$") + sync_stor(); + }); + + if(!storDia) + storDia = dialog({ + content: editForm[0], + cancel: false + }); cancelEdit.click(function() { - modifyDia.close().remove() - }) + storDia.close(); + }); - modifyDia.showModal() + storDia.showModal(); + + // Select all checkbox + $('#selectAll').change(function() { + $('.fileCheckbox').prop('checked', $(this).is(':checked')).trigger('change'); + }); + + // Delete selected button + $('#deleteSelected').click(function() { + if(selectedFiles.length === 0) return; + + if(confirm('确定要删除选中的 ' + selectedFiles.length + ' 个文件吗?')) { + let deletePromises = selectedFiles.map(filename => { + return $.getJSON('deleteImgStore', { + 'projectName': globalProjectName, + 'filename': filename + }); + }); + + Promise.all(deletePromises).then(() => { + sync_stor(); + }); + } + }); + + // Download selected button + $('#downloadSelected').click(function() { + if(selectedFiles.length === 0) return; + + // Download each file one by one + selectedFiles.forEach(filename => { + downloadFile(filename); + }); + }); } \ No newline at end of file diff --git a/mixio.js b/mixio.js index e152e48..319cc1f 100644 --- a/mixio.js +++ b/mixio.js @@ -833,7 +833,7 @@ var mixioServer = async function() { var topic = packet.topic.split('/') var payload = String(packet.payload) if (topic.length == 3) { - if(topic[2] == 'storage') { + if(topic[2][0] == '$') { // 判断是否是base64, 开头为data:image/***;base64, ***可以为png,bmp,jpg,jpeg,gif,svg,ico const allowFormats = ['png', 'bmp', 'jpg', 'jpeg', 'gif', 'svg', 'ico']; const base64Reg = /^data:image\/(\w+);base64,/; @@ -842,7 +842,7 @@ var mixioServer = async function() { // 是base64 const format = match[1]; const timeStamp = Date.now(); - const fileName = `${timeStamp}.${format}`; + const fileName = topic[2] + '_' + `${timeStamp}.${format}`; const filePath = path.join('store', topic[0], topic[1], fileName); const base64Data = payload.replace(base64Reg, ''); const buffer = Buffer.from(base64Data, 'base64'); @@ -851,7 +851,7 @@ var mixioServer = async function() { } else { // 全部明文存为txt const timeStamp = Date.now(); - const fileName = `${timeStamp}.txt`; + const fileName = topic[2] + '_' + `${timeStamp}.txt`; const filePath = path.join('store', topic[0], topic[1], fileName); fs.mkdirSync(path.dirname(filePath), { recursive: true}); fs.writeFileSync(filePath, payload);