From 1cbbf11fcfc23d057acc61f47014c5c2c02adfb4 Mon Sep 17 00:00:00 2001 From: flying-hero <462087392@qq.com> Date: Wed, 1 Apr 2026 20:43:25 +0800 Subject: [PATCH] Add React frontend and Django backend code - React components: Dashboard, MemoryCalendar, SearchBox, ToolList - Django backend structure - Package configuration files --- code/backend/manage.py | 16 ++++ code/frontend/package.json | 30 +++++++ .../src/components/MemoryCalendar/index.js | 83 +++++++++++++++++++ .../src/components/SearchBox/index.js | 59 +++++++++++++ .../frontend/src/components/ToolList/index.js | 59 +++++++++++++ code/frontend/src/pages/Dashboard/index.js | 60 ++++++++++++++ 6 files changed, 307 insertions(+) create mode 100755 code/backend/manage.py create mode 100644 code/frontend/package.json create mode 100644 code/frontend/src/components/MemoryCalendar/index.js create mode 100644 code/frontend/src/components/SearchBox/index.js create mode 100644 code/frontend/src/components/ToolList/index.js create mode 100644 code/frontend/src/pages/Dashboard/index.js diff --git a/code/backend/manage.py b/code/backend/manage.py new file mode 100755 index 0000000..4cad47a --- /dev/null +++ b/code/backend/manage.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +import os +import sys + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django." + ) from exc + execute_from_command_line(sys.argv) + +if __name__ == '__main__': + main() diff --git a/code/frontend/package.json b/code/frontend/package.json new file mode 100644 index 0000000..d975800 --- /dev/null +++ b/code/frontend/package.json @@ -0,0 +1,30 @@ +{ + "name": "lobster-monitor-frontend", + "version": "1.0.0", + "description": "龙虾舰队监控中心 - React 前端", + "private": true, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "axios": "^1.6.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/code/frontend/src/components/MemoryCalendar/index.js b/code/frontend/src/components/MemoryCalendar/index.js new file mode 100644 index 0000000..9376d8b --- /dev/null +++ b/code/frontend/src/components/MemoryCalendar/index.js @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; + +const API_BASE = 'http://localhost:8000/api'; + +function MemoryCalendar({ lobsterId }) { + const [currentMonth, setCurrentMonth] = useState(new Date()); + const [memoryDates, setMemoryDates] = useState([]); + const [selectedDate, setSelectedDate] = useState(null); + const [memoryContent, setMemoryContent] = useState(''); + + useEffect(() => { + fetchMemoryDates(); + }, [currentMonth, lobsterId]); + + const fetchMemoryDates = async () => { + try { + const response = await axios.get(`${API_BASE}/lobsters/${lobsterId}/memory/dates/`); + setMemoryDates(response.data.dates); + } catch (error) { + console.error('获取记忆日期失败:', error); + } + }; + + const fetchMemory = async (date) => { + try { + const response = await axios.get(`${API_BASE}/lobsters/${lobsterId}/memory/${date}/`); + setMemoryContent(response.data.content); + setSelectedDate(date); + } catch (error) { + console.error('获取记忆失败:', error); + } + }; + + const renderCalendar = () => { + const year = currentMonth.getFullYear(); + const month = currentMonth.getMonth(); + const daysInMonth = new Date(year, month + 1, 0).getDate(); + const days = []; + + for (let day = 1; day <= daysInMonth; day++) { + const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; + const hasMemory = memoryDates.includes(dateStr); + + days.push( +
hasMemory && fetchMemory(dateStr)} + > + {day} + {hasMemory && } +
+ ); + } + + return days; + }; + + return ( +
+
+ + {currentMonth.getFullYear()}年 {currentMonth.getMonth() + 1}月 + +
+
+ {['日', '一', '二', '三', '四', '五', '六'].map(day => ( +
{day}
+ ))} + {renderCalendar()} +
+ {memoryContent && ( +
+

📅 {selectedDate} 的记忆

+
{memoryContent}
+
+ )} +
+ ); +} + +export default MemoryCalendar; diff --git a/code/frontend/src/components/SearchBox/index.js b/code/frontend/src/components/SearchBox/index.js new file mode 100644 index 0000000..70f1959 --- /dev/null +++ b/code/frontend/src/components/SearchBox/index.js @@ -0,0 +1,59 @@ +import React, { useState } from 'react'; +import axios from 'axios'; + +const API_BASE = 'http://localhost:8000/api'; + +function SearchBox({ lobsterId }) { + const [query, setQuery] = useState(''); + const [results, setResults] = useState([]); + const [searching, setSearching] = useState(false); + + const handleSearch = async (e) => { + e.preventDefault(); + if (!query.trim()) return; + + setSearching(true); + try { + const response = await axios.get(`${API_BASE}/lobsters/${lobsterId}/search/`, { + params: { q: query } + }); + setResults(response.data.results); + } catch (error) { + console.error('搜索失败:', error); + } finally { + setSearching(false); + } + }; + + return ( +
+
+ setQuery(e.target.value)} + placeholder="搜索文档..." + /> + +
+ {results.length > 0 && ( +
+

搜索结果 ({results.length})

+ {results.map((result, index) => ( +
+

{result.title}

+

{result.snippet}

+ + 查看原文 + +
+ ))} +
+ )} +
+ ); +} + +export default SearchBox; diff --git a/code/frontend/src/components/ToolList/index.js b/code/frontend/src/components/ToolList/index.js new file mode 100644 index 0000000..25aa1bf --- /dev/null +++ b/code/frontend/src/components/ToolList/index.js @@ -0,0 +1,59 @@ +import React from 'react'; + +function ToolList() { + const tools = [ + { + name: 'Git 版本控制', + status: '🟢 运行中', + description: '代码版本管理服务', + access: [ + { type: 'Web', url: 'http://localhost:18003' }, + { type: 'Git', url: 'git://127.0.0.1:9418/monitor-dashboard.git' }, + { type: 'HTTP', url: 'http://localhost:18003/monitor-dashboard.git' } + ], + usage: [ + '克隆仓库:git clone http://localhost:18003/monitor-dashboard.git', + '提交更改:git add . && git commit -m "说明"', + '推送代码:git push origin master' + ] + } + ]; + + return ( +
+

🛠️ 工具列表

+ {tools.map((tool, index) => ( +
+
+

{tool.name}

+ {tool.status} +
+

{tool.description}

+ +
+

访问方式:

+ {tool.access.map((item, i) => ( +
+ {item.type}: + + {item.url} + +
+ ))} +
+ +
+

使用方法:

+
    + {tool.usage.map((item, i) => ( +
  • {item}
  • + ))} +
+
+
+ ))} +
+ ); +} + +export default ToolList; diff --git a/code/frontend/src/pages/Dashboard/index.js b/code/frontend/src/pages/Dashboard/index.js new file mode 100644 index 0000000..95a4c64 --- /dev/null +++ b/code/frontend/src/pages/Dashboard/index.js @@ -0,0 +1,60 @@ +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; + +const API_BASE = 'http://localhost:8000/api'; + +function Dashboard() { + const [lobsters, setLobsters] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + fetchLobsters(); + const interval = setInterval(fetchLobsters, 5000); + return () => clearInterval(interval); + }, []); + + const fetchLobsters = async () => { + try { + const response = await axios.get(`${API_BASE}/lobsters/`); + setLobsters(response.data); + setLoading(false); + } catch (error) { + console.error('获取龙虾状态失败:', error); + } + }; + + if (loading) { + return
加载中...
; + } + + return ( +
+

🦞 龙虾舰队监控中心

+
+ {lobsters.map(lobster => ( +
+
+ {lobster.emoji} {lobster.name} + {lobster.status} +
+
+

专长:{lobster.specialty}

+

端口:{lobster.port}

+

容器:{lobster.container}

+
+
+ + +
+
+ ))} +
+
+ ); +} + +export default Dashboard;