add-img-store
This commit is contained in:
@@ -122,8 +122,11 @@
|
|||||||
|
|
||||||
<h1 id="title_phase2" class="h3 mb-0 text-gray-800" style="display:inline-block;font-weight:bold;font-size:1.25rem;"></h1>
|
<h1 id="title_phase2" class="h3 mb-0 text-gray-800" style="display:inline-block;font-weight:bold;font-size:1.25rem;"></h1>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<span style="font-size:0.8rem;color:#858796;cursor:pointer" class="lang" key="CONNECTINGSERVER" id="connect_span" onclick="check_link()" hidden><i class="fa fa-spinner fa-spin" style="margin-right:3px"></i></span>
|
<span style="font-size:0.8rem;color:#858796;cursor:pointer" class="lang" key="CONNECTINGSERVER" id="connect_span" onclick="check_link()" hidden><i class="fa fa-spinner fa-spin" style="margin-right:3px"></i></span>
|
||||||
</div>
|
<span style="font-size:0.8rem;color:#36b9cc;cursor:pointer;margin-left:5px" id="storage_space" onclick="open_storage()" hidden><i class="fa fa-database" style="margin-right:3px"></i>存储空间</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a href="//mixly.org" target="_blank" class="d-none d-md-block" style="margin-right:30px;color:gray;font-size:0.7rem;user-select:none">
|
<a href="//mixly.org" target="_blank" class="d-none d-md-block" style="margin-right:30px;color:gray;font-size:0.7rem;user-select:none">
|
||||||
Copyright© Mixly Team @ BNU, CHINA
|
Copyright© Mixly Team @ BNU, CHINA
|
||||||
|
|||||||
1
icons/store.svg
Normal file
1
icons/store.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg t="1749628239598" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4207" width="200" height="200"><path d="M511.875 128.125c-211.875 0-383.75 76.25-383.75 170.625 0 94.375 171.875 170.625 383.75 170.625 211.875 0 383.75-76.25 383.75-170.625C896.25 204.375 724.375 128.125 511.875 128.125M128.125 383.75l0 128.125c0 94.375 171.875 170.625 383.75 170.625 211.875 0 383.75-76.25 383.75-170.625l0-128.125c0 94.375-171.875 170.625-383.75 170.625C300 555 128.125 478.125 128.125 383.75M128.125 597.5l0 128.125c0 94.375 171.875 170.625 383.75 170.625 211.875 0 383.75-76.25 383.75-170.625l0-128.125c0 94.375-171.875 170.625-383.75 170.625C300 768.125 128.125 691.875 128.125 597.5z" p-id="4208" fill="#4e73df"></path></svg>
|
||||||
|
After Width: | Height: | Size: 764 B |
8
img/store/.gitignore
vendored
Normal file
8
img/store/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
*.txt
|
||||||
|
*.png
|
||||||
|
*.bmp
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.gif
|
||||||
|
*.svg
|
||||||
|
*.ico
|
||||||
114
js/projects.js
114
js/projects.js
@@ -809,6 +809,7 @@ function view_project(projectName, projectType) {
|
|||||||
$("#accordionSidebar").remove()
|
$("#accordionSidebar").remove()
|
||||||
$("#sidebarToggleTop").remove()
|
$("#sidebarToggleTop").remove()
|
||||||
$("#connect_span").removeAttr("hidden")
|
$("#connect_span").removeAttr("hidden")
|
||||||
|
$("#storage_space").removeAttr("hidden")
|
||||||
init_layout()
|
init_layout()
|
||||||
$("#projMode").click(function() {
|
$("#projMode").click(function() {
|
||||||
if (globalProjectType != PROJ_MODE) {
|
if (globalProjectType != PROJ_MODE) {
|
||||||
@@ -4203,3 +4204,116 @@ setInterval(function(){
|
|||||||
isChanged = false
|
isChanged = false
|
||||||
}
|
}
|
||||||
}, 30000)
|
}, 30000)
|
||||||
|
|
||||||
|
|
||||||
|
function open_storage(){
|
||||||
|
var editForm = $('<div class="nnt" style="width:80vw;height:80vh;display:flex;flex-direction:column"/>')
|
||||||
|
editForm.append($('<div style="margin-top:-63px;margin-left:calc(40vw - 43px);margin-bottom:15px;box-shadow: 1px 1px 20px #4e73df;background-color:white;width:75px;height:75px;padding:40px;border-radius:80px;border:solid #4e73df 3px;display:flex;align-items:center;justify-content:center"><img src="icons/store.svg" style="width:45px;"></div>'))
|
||||||
|
editForm.append($('<h3 style="text-align:center;margin-bottom:5px">所有发送到<span style="color:#4e73df;font-weight:bold">/storage</span>主题下的消息和图片会被自动保存</h3>'))
|
||||||
|
var messagesContainer = $('<div style="flex:1;overflow-y:auto;padding:20px;display:grid;grid-template-columns:repeat(auto-fill, minmax(200px, 1fr));gap:15px;align-content:flex-start"/>')
|
||||||
|
var sync_stor = function(){
|
||||||
|
messagesContainer.empty()
|
||||||
|
var sampleMessages = [
|
||||||
|
]
|
||||||
|
$.getJSON('getImgStore', {
|
||||||
|
'projectName': globalProjectName
|
||||||
|
}, function(res) {
|
||||||
|
if(res.length==0)
|
||||||
|
{
|
||||||
|
messagesContainer.append($('<div style="background:white;border-radius:8px;padding:15px;box-shadow:0 2px 5px rgba(0,0,0,0.1);height:150px;display:flex;flex-direction:column;align-items:center;justify-content:center">暂无存储</div>'))
|
||||||
|
}
|
||||||
|
for (let ri = 0; ri < res.length; ri++) {
|
||||||
|
{
|
||||||
|
let url = "img/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 = $('<div style="background:white;border-radius:8px;padding:15px;box-shadow:0 2px 5px rgba(0,0,0,0.1);height:150px;display:flex;flex-direction:column"/>')
|
||||||
|
|
||||||
|
if (msg.type === 'text') {
|
||||||
|
$.ajax({
|
||||||
|
url: msg.content,
|
||||||
|
success: function(res) {
|
||||||
|
messageBox.append($('<div style="font-size:14px;word-break:break-all;height:100px"/>').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 = $('<div style="font-size:11px;color:#999;margin-top:10px;text-align:right"></div>')
|
||||||
|
btdiv.append("<span>" + timeString +"</span>")
|
||||||
|
let deletebtn = $('<a class="btn btn-danger btn-sm" style="margin-left:10px"><i class="fa fa-trash"></i></a>')
|
||||||
|
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($('<div style="width:100%;height:100px;text-align:center;overflow:hidden"/><img src="' + msg.content + '" style="max-width:100%;max-height:100px;object-fit:contain;margin:auto"/></div>'))
|
||||||
|
// Add timestamp (sample)
|
||||||
|
let timeStamp = parseInt(msg.content.split("/")[msg.content.split("/").length - 1].split(".")[0])
|
||||||
|
let timeString = new Date(timeStamp).toLocaleString()
|
||||||
|
let btdiv = $('<div style="font-size:11px;color:#999;margin-top:10px;text-align:right"></div>')
|
||||||
|
btdiv.append("<span>" + timeString +"</span>")
|
||||||
|
let viewbtn = $('<a class="btn btn-primary btn-sm" style="margin-left:10px"><i class="fa fa-eye"></i></a>')
|
||||||
|
viewbtn.click(function(){
|
||||||
|
// 全屏显示图片,点击任意退出
|
||||||
|
let fullDialog = dialog({
|
||||||
|
content: $('<div style="width:60vw;height:60vh;display:flex;align-items:center;justify-content:center"><img src="' + msg.content + '" style="max-width:100%;max-height:100%"/></div>')[0],
|
||||||
|
cancel: true,
|
||||||
|
cancelValue: '关闭'
|
||||||
|
})
|
||||||
|
fullDialog.showModal()
|
||||||
|
|
||||||
|
})
|
||||||
|
let deletebtn = $('<a class="btn btn-danger btn-sm" style="margin-left:10px"><i class="fa fa-trash"></i></a>')
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
// Bottom section
|
||||||
|
var bottomDiv = $('<div style="width:100%;margin-top:15px;display:flex;flex-direction:row;align-items:center;justify-content:space-around"/>')
|
||||||
|
var cancelEdit = $('<a class="btn btn-danger btn-circle" style="box-shadow:1px 1px 5px #e74a3b"><i class="fa fa-arrow-left"></i></a>')
|
||||||
|
bottomDiv.append(cancelEdit)
|
||||||
|
editForm.append(bottomDiv)
|
||||||
|
|
||||||
|
var modifyDia = dialog({
|
||||||
|
content: editForm[0],
|
||||||
|
cancel: false
|
||||||
|
})
|
||||||
|
|
||||||
|
cancelEdit.click(function() {
|
||||||
|
modifyDia.close().remove()
|
||||||
|
})
|
||||||
|
|
||||||
|
modifyDia.showModal()
|
||||||
|
}
|
||||||
79
mixio.js
79
mixio.js
@@ -830,6 +830,30 @@ var mixioServer = async function() {
|
|||||||
var topic = packet.topic.split('/')
|
var topic = packet.topic.split('/')
|
||||||
var payload = String(packet.payload)
|
var payload = String(packet.payload)
|
||||||
if (topic.length == 3) {
|
if (topic.length == 3) {
|
||||||
|
if(topic[2] == 'storage') {
|
||||||
|
// 判断是否是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,/;
|
||||||
|
const match = payload.match(base64Reg);
|
||||||
|
if (match && allowFormats.includes(match[1])) {
|
||||||
|
// 是base64
|
||||||
|
const format = match[1];
|
||||||
|
const timeStamp = Date.now();
|
||||||
|
const fileName = `${timeStamp}.${format}`;
|
||||||
|
const filePath = path.join(__dirname, 'img', 'store', topic[0], topic[1], fileName);
|
||||||
|
const base64Data = payload.replace(base64Reg, '');
|
||||||
|
const buffer = Buffer.from(base64Data, 'base64');
|
||||||
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||||
|
fs.writeFileSync(filePath, buffer);
|
||||||
|
} else {
|
||||||
|
// 全部明文存为txt
|
||||||
|
const timeStamp = Date.now();
|
||||||
|
const fileName = `${timeStamp}.txt`;
|
||||||
|
const filePath = path.join(__dirname, 'img', 'store', topic[0], topic[1], fileName);
|
||||||
|
fs.mkdirSync(path.dirname(filePath), { recursive: true});
|
||||||
|
fs.writeFileSync(filePath, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (topic[2] == 'b640a0ce465fa2a4150c36b305c1c11b') {
|
if (topic[2] == 'b640a0ce465fa2a4150c36b305c1c11b') {
|
||||||
if (STORAGE_ENGINE == "sqlite")
|
if (STORAGE_ENGINE == "sqlite")
|
||||||
db.run("insert or ignore into devices (userName, clientid) values (?,?)", [topic[0], payload])
|
db.run("insert or ignore into devices (userName, clientid) values (?,?)", [topic[0], payload])
|
||||||
@@ -1323,6 +1347,61 @@ var mixioServer = async function() {
|
|||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.get('/getImgStore', function(req, res) {
|
||||||
|
if (req.session.userName && req.query.projectName){
|
||||||
|
var projectName = req.query.projectName
|
||||||
|
// img/store/username/projectName
|
||||||
|
var imgStorePath = path.join(__dirname, 'img', 'store', req.session.userName, projectName)
|
||||||
|
// 文件名发送列表
|
||||||
|
fs.readdir(imgStorePath, function(err, files) {
|
||||||
|
res.send(files || [])
|
||||||
|
})
|
||||||
|
} else
|
||||||
|
res.redirect('/')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/clearImgStore', function(req, res) {
|
||||||
|
if (req.session.userName && req.query.projectName){
|
||||||
|
var projectName = req.query.projectName
|
||||||
|
// img/store/username/projectName
|
||||||
|
var imgStorePath = path.join(__dirname, 'img', 'store', req.session.userName, projectName)
|
||||||
|
// 清空文件
|
||||||
|
fs.readdir(imgStorePath, function(err, files) {
|
||||||
|
files.forEach(function(file) {
|
||||||
|
fs.unlink(path.join(imgStorePath, file), function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
res.send({
|
||||||
|
"status": "success"
|
||||||
|
})
|
||||||
|
} else
|
||||||
|
res.redirect('/')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/deleteImgStore', function(req, res) {
|
||||||
|
if (req.session.userName && req.query.projectName && req.query.filename){
|
||||||
|
var projectName = req.query.projectName
|
||||||
|
var filename = req.query.filename
|
||||||
|
// img/store/username/projectName
|
||||||
|
var imgStorePath = path.join(__dirname, 'img', 'store', req.session.userName, projectName)
|
||||||
|
// 删除文件
|
||||||
|
fs.unlink(path.join(imgStorePath, filename), function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
res.send({
|
||||||
|
"status": "success"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else
|
||||||
|
res.redirect('/')
|
||||||
|
})
|
||||||
|
|
||||||
app.get('/projects', function(req, res) {
|
app.get('/projects', function(req, res) {
|
||||||
if (req.session.userName) {
|
if (req.session.userName) {
|
||||||
ejs.renderFile(__dirname + '/ejs/projects.ejs', {
|
ejs.renderFile(__dirname + '/ejs/projects.ejs', {
|
||||||
|
|||||||
Reference in New Issue
Block a user