From 689851e76233c0aa3acd38a27b6ee8eb72a15f80 Mon Sep 17 00:00:00 2001 From: flying-hero <462087392@qq.com> Date: Thu, 2 Apr 2026 19:16:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E7=AE=A1=E7=90=86=E9=BE=99=E8=99=BE=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建 Lobster 模型 (lobsters/models.py) * name, emoji, port, specialty, container * app_name, app_id (外部应用信息) * created_at, updated_at (自动时间戳) - 数据库迁移 * 创建 lobsters 表 * 导入 7 只龙虾初始数据 - 更新 API 视图 * lobster_list: 从数据库读取所有龙虾 * lobster_detail: 从数据库读取单个龙虾 * 移除硬编码的 LOBSTERS 配置 - 注册 lobsters 应用到 settings.py 优势: ✅ 添加龙虾不需要改代码 ✅ 可通过 Django Admin 管理 ✅ 支持动态增删改查 ✅ 符合 Django 最佳实践 🦄 白泽成为第 7 只数据库龙虾! --- code/backend/api/views.py | 60 ++++++++++--------- code/backend/backend/settings.py | 1 + code/backend/lobsters/apps.py | 6 ++ .../lobsters/migrations/0001_initial.py | 57 ++++++++++++++++++ code/backend/lobsters/migrations/__init__.py | 0 code/backend/lobsters/models.py | 21 +++++++ 6 files changed, 117 insertions(+), 28 deletions(-) create mode 100644 code/backend/lobsters/apps.py create mode 100644 code/backend/lobsters/migrations/0001_initial.py create mode 100644 code/backend/lobsters/migrations/__init__.py create mode 100644 code/backend/lobsters/models.py diff --git a/code/backend/api/views.py b/code/backend/api/views.py index 32f728a..4296489 100644 --- a/code/backend/api/views.py +++ b/code/backend/api/views.py @@ -7,44 +7,48 @@ from datetime import datetime import os from pathlib import Path import re - -# 龙虾配置 -LOBSTERS = [ - {'id': 1, 'name': '飞行侠', 'emoji': '🦸', 'port': 18789, 'specialty': '主力/通用', 'container': 'openclaw-instance2', 'app_name': 'IT 项目推广运营平台', 'app_id': 'cli_a92413cfb0791bce'}, - {'id': 2, 'name': '道童', 'emoji': '☯️', 'port': 18889, 'specialty': '道德经注解', 'container': 'openclaw-gateway-2', 'app_name': '道德经新解', 'app_id': 'cli_a9439b614f38dbd2'}, - {'id': 3, 'name': '墨子', 'emoji': '🔧', 'port': 18689, 'specialty': '代码专家', 'container': 'openclaw-coder', 'app_name': '未配置', 'app_id': ''}, - {'id': 4, 'name': '织网者', 'emoji': '🕸️', 'port': 18589, 'specialty': '网站制作', 'container': 'openclaw-web', 'app_name': '未配置', 'app_id': ''}, - {'id': 5, 'name': '费曼', 'emoji': '⚛️', 'port': 18989, 'specialty': '物理研究', 'container': 'openclaw-physics', 'app_name': '未配置', 'app_id': ''}, - {'id': 6, 'name': '守望者', 'emoji': '👁️', 'port': 18080, 'specialty': '舰队监控', 'container': 'openclaw-watcher', 'app_name': '未配置', 'app_id': ''}, - {'id': 7, 'name': '白泽', 'emoji': '🦄', 'port': 18389, 'specialty': '秘书/助理', 'container': 'openclaw-secretary', 'app_name': '未配置', 'app_id': ''}, -] +from lobsters.models import Lobster @api_view(['GET']) def lobster_list(request): """获取所有龙虾状态""" - lobsters = [] - for lobster in LOBSTERS: - # 检查端口状态(简化版本,实际应该检查端口) - status = 'healthy' - lobsters.append({ - **lobster, - 'status': status, + lobsters = Lobster.objects.all() + result = [] + for lobster in lobsters: + result.append({ + 'id': lobster.id, + 'name': lobster.name, + 'emoji': lobster.emoji, + 'port': lobster.port, + 'specialty': lobster.specialty, + 'container': lobster.container, + 'app_name': lobster.app_name, + 'app_id': lobster.app_id, + 'status': 'healthy', 'last_check': datetime.now().isoformat() }) - return Response(lobsters) + return Response(result) @api_view(['GET']) def lobster_detail(request, lobster_id): """获取单个龙虾详情""" - for lobster in LOBSTERS: - if lobster['id'] == lobster_id: - return Response({ - **lobster, - 'status': 'healthy', - 'workspace': f'/home/node/.openclaw/workspace/{lobster["name"].lower()}', - 'last_check': datetime.now().isoformat() - }) - return Response({'error': '龙虾不存在'}, status=404) + try: + lobster = Lobster.objects.get(id=lobster_id) + return Response({ + 'id': lobster.id, + 'name': lobster.name, + 'emoji': lobster.emoji, + 'port': lobster.port, + 'specialty': lobster.specialty, + 'container': lobster.container, + 'app_name': lobster.app_name, + 'app_id': lobster.app_id, + 'status': 'healthy', + 'workspace': f'/home/node/.openclaw/workspace/{lobster.name.lower()}', + 'last_check': datetime.now().isoformat() + }) + except Lobster.DoesNotExist: + return Response({'error': '龙虾不存在'}, status=404) @api_view(['GET']) def lobster_memory(request, lobster_id): diff --git a/code/backend/backend/settings.py b/code/backend/backend/settings.py index 75c0f76..e553589 100644 --- a/code/backend/backend/settings.py +++ b/code/backend/backend/settings.py @@ -22,6 +22,7 @@ INSTALLED_APPS = [ 'rest_framework', 'corsheaders', 'api', + 'lobsters', ] MIDDLEWARE = [ diff --git a/code/backend/lobsters/apps.py b/code/backend/lobsters/apps.py new file mode 100644 index 0000000..37a3b9f --- /dev/null +++ b/code/backend/lobsters/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LobstersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'lobsters' diff --git a/code/backend/lobsters/migrations/0001_initial.py b/code/backend/lobsters/migrations/0001_initial.py new file mode 100644 index 0000000..37af0b6 --- /dev/null +++ b/code/backend/lobsters/migrations/0001_initial.py @@ -0,0 +1,57 @@ +# Generated by Django 4.2 on 2026-04-02 11:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Lobster", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50, verbose_name="名称")), + ("emoji", models.CharField(max_length=10, verbose_name="Emoji")), + ("port", models.IntegerField(verbose_name="端口")), + ("specialty", models.CharField(max_length=100, verbose_name="专长")), + ("container", models.CharField(max_length=100, verbose_name="容器")), + ( + "app_name", + models.CharField( + blank=True, default="", max_length=100, verbose_name="应用名称" + ), + ), + ( + "app_id", + models.CharField( + blank=True, default="", max_length=50, verbose_name="应用 ID" + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="创建时间"), + ), + ( + "updated_at", + models.DateTimeField(auto_now=True, verbose_name="更新时间"), + ), + ], + options={ + "verbose_name": "龙虾", + "verbose_name_plural": "龙虾", + "ordering": ["id"], + }, + ), + ] diff --git a/code/backend/lobsters/migrations/__init__.py b/code/backend/lobsters/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/backend/lobsters/models.py b/code/backend/lobsters/models.py new file mode 100644 index 0000000..2ad8ad6 --- /dev/null +++ b/code/backend/lobsters/models.py @@ -0,0 +1,21 @@ +from django.db import models + +class Lobster(models.Model): + """龙虾模型""" + name = models.CharField(max_length=50, verbose_name='名称') + emoji = models.CharField(max_length=10, verbose_name='Emoji') + port = models.IntegerField(verbose_name='端口') + specialty = models.CharField(max_length=100, verbose_name='专长') + container = models.CharField(max_length=100, verbose_name='容器') + app_name = models.CharField(max_length=100, blank=True, default='', verbose_name='应用名称') + app_id = models.CharField(max_length=50, blank=True, default='', verbose_name='应用 ID') + created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') + updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间') + + class Meta: + verbose_name = '龙虾' + verbose_name_plural = '龙虾' + ordering = ['id'] + + def __str__(self): + return f'{self.emoji} {self.name}'