From 130b2ad5f773b0e4a22bb5f2303a198483436b9e Mon Sep 17 00:00:00 2001 From: zhang1106 <849185023@qq.com> Date: Sat, 20 Dec 2025 17:43:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=83=8C=E6=99=AF=E8=AE=BE=E7=BD=AE):=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=83=8C=E6=99=AF=E5=9B=BE=E7=89=87=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=8F=8A=E8=AE=BE=E7=BD=AE=E5=8A=9F=E8=83=BD-=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=83=8C=E6=99=AF=E8=AE=BE=E7=BD=AE=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=92=8C=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD-=20=E6=B7=BB=E5=8A=A0=E9=9D=99=E6=80=81=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9C=8D=E5=8A=A1=E6=94=AF=E6=8C=81-=20=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E5=AE=9E=E7=8E=B0=E8=83=8C=E6=99=AF=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=92=8C=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91?= =?UTF-8?q?-=20=E9=85=8D=E7=BD=AEvite=E4=BB=A3=E7=90=86=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=AE=BF=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/backgroundSettings.json | 5 + backend/fileIndex.json | 1 + backend/routes/background.js | 73 +++++++++++++++ backend/server.js | 5 + frontend/src/pages/RackVisualization.jsx | 112 ++++++++++++++++++----- frontend/vite.config.js | 4 + 6 files changed, 175 insertions(+), 25 deletions(-) create mode 100644 backend/backgroundSettings.json create mode 100644 backend/fileIndex.json create mode 100644 backend/routes/background.js diff --git a/backend/backgroundSettings.json b/backend/backgroundSettings.json new file mode 100644 index 0000000..ffa3dda --- /dev/null +++ b/backend/backgroundSettings.json @@ -0,0 +1,5 @@ +{ + "type": "image", + "image": "/uploads/1766210792626_生成情侣图片.png", + "size": "cover" +} \ No newline at end of file diff --git a/backend/fileIndex.json b/backend/fileIndex.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/backend/fileIndex.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/backend/routes/background.js b/backend/routes/background.js new file mode 100644 index 0000000..1ec3e40 --- /dev/null +++ b/backend/routes/background.js @@ -0,0 +1,73 @@ +const express = require('express'); +const path = require('path'); +const fs = require('fs'); +const router = express.Router(); + +// 确保上传目录存在 +const UPLOAD_DIR = path.join(__dirname, '../uploads'); +if (!fs.existsSync(UPLOAD_DIR)) { + fs.mkdirSync(UPLOAD_DIR, { recursive: true }); +} + +// 确保背景设置文件存在 +const SETTINGS_FILE = path.join(__dirname, '../backgroundSettings.json'); +if (!fs.existsSync(SETTINGS_FILE)) { + fs.writeFileSync(SETTINGS_FILE, JSON.stringify({ + type: 'gradient', + image: '', + size: 'contain' + }, null, 2)); +} + +// 上传图片接口 +router.post('/upload', (req, res) => { + try { + if (!req.files || !req.files.file) { + return res.status(400).json({ error: '没有上传文件' }); + } + + const file = req.files.file; + const fileName = `${Date.now()}_${file.name}`; + const filePath = path.join(UPLOAD_DIR, fileName); + + // 保存文件到服务器 + file.mv(filePath, (err) => { + if (err) { + console.error('文件保存失败:', err); + return res.status(500).json({ error: '文件保存失败' }); + } + + // 返回文件路径 + const fileUrl = `/uploads/${fileName}`; + res.json({ path: fileUrl }); + }); + } catch (error) { + console.error('上传错误:', error); + res.status(500).json({ error: '上传失败' }); + } +}); + +// 获取背景设置 +router.get('/settings', (req, res) => { + try { + const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8')); + res.json(settings); + } catch (error) { + console.error('读取背景设置失败:', error); + res.status(500).json({ error: '读取背景设置失败' }); + } +}); + +// 保存背景设置 +router.post('/settings', (req, res) => { + try { + const settings = req.body; + fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2)); + res.json({ success: true }); + } catch (error) { + console.error('保存背景设置失败:', error); + res.status(500).json({ error: '保存背景设置失败' }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/backend/server.js b/backend/server.js index 139fe01..c1498f8 100644 --- a/backend/server.js +++ b/backend/server.js @@ -38,12 +38,17 @@ const deviceRoutes = require('./routes/devices'); const rackRoutes = require('./routes/racks'); const roomRoutes = require('./routes/rooms'); const deviceFieldRoutes = require('./routes/deviceFields'); +const backgroundRoutes = require('./routes/background'); // 使用路由 app.use('/api/devices', deviceRoutes); app.use('/api/racks', rackRoutes); app.use('/api/rooms', roomRoutes); app.use('/api/deviceFields', deviceFieldRoutes); +app.use('/api/background', backgroundRoutes); + +// 静态文件服务 +app.use('/uploads', express.static('uploads')); // 健康检查 app.get('/health', (req, res) => { diff --git a/frontend/src/pages/RackVisualization.jsx b/frontend/src/pages/RackVisualization.jsx index 369d77b..3eef36f 100644 --- a/frontend/src/pages/RackVisualization.jsx +++ b/frontend/src/pages/RackVisualization.jsx @@ -145,6 +145,7 @@ function RackVisualization() { const [backgroundImage, setBackgroundImage] = useState(null); const [backgroundType, setBackgroundType] = useState('gradient'); // gradient or image const [backgroundSize, setBackgroundSize] = useState('contain'); // cover, contain, auto + const [uploading, setUploading] = useState(false); // 上传状态 // 获取所有机柜 const fetchRacks = async () => { @@ -333,6 +334,7 @@ function RackVisualization() { useEffect(() => { fetchRacks(); + loadBackgroundSettings(); }, []); // 根据设备类型获取图标 @@ -617,6 +619,33 @@ function RackVisualization() { message.success('数据已刷新'); }); }; + + // 保存背景设置到服务器 + const saveBackgroundSettings = async (type, image, size) => { + try { + await axios.post('/api/background/settings', { + type, + image, + size + }); + } catch (error) { + console.error('保存背景设置失败:', error); + } + }; + + // 从服务器加载背景设置 + const loadBackgroundSettings = async () => { + try { + const response = await axios.get('/api/background/settings'); + if (response.data) { + setBackgroundType(response.data.type || 'gradient'); + setBackgroundImage(response.data.image || null); + setBackgroundSize(response.data.size || 'contain'); + } + } catch (error) { + console.error('加载背景设置失败:', error); + } + }; // 重置视角 const handleResetView = () => { @@ -689,45 +718,78 @@ function RackVisualization() { - {backgroundType === 'image' && ( - - setBackgroundImage(e.target.value)} - value={backgroundImage || ''} - /> + placeholder="选择背景类型" + style={{ width: 150 }} + value={backgroundType} + onChange={async (type) => { + setBackgroundType(type); + await saveBackgroundSettings(type, backgroundImage, backgroundSize); + }} + > + + + + {backgroundType === 'image' && ( + + { + const image = e.target.value; + setBackgroundImage(image); + await saveBackgroundSettings(backgroundType, image, backgroundSize); + }} + value={backgroundImage || ''} + /> { + onChange={async (e) => { const file = e.target.files[0]; if (file) { - const reader = new FileReader(); - reader.onload = (event) => { - setBackgroundImage(event.target.result); - }; - reader.readAsDataURL(file); + try { + setUploading(true); + const formData = new FormData(); + formData.append('file', file); + formData.append('type', 'background'); + + // 发送图片到服务器 + const response = await axios.post('/api/background/upload', formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }); + + // 保存服务器返回的图片路径 + if (response.data && response.data.path) { + setBackgroundImage(response.data.path); + message.success('背景图片上传成功'); + // 保存背景设置到服务器 + await saveBackgroundSettings('image', response.data.path, backgroundSize); + } else { + message.error('上传失败:服务器返回格式不正确'); + } + } catch (error) { + console.error('上传失败:', error); + message.error('背景图片上传失败,请重试'); + } finally { + setUploading(false); + } } }} style={{ display: 'none' }} id="backgroundFileInput" /> - +