MRobot/app/code_page/module_interface.py
2026-01-01 22:13:44 +08:00

256 lines
9.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout
from qfluentwidgets import (
BodyLabel, CheckBox, SubtitleLabel, PushButton, FluentIcon,
InfoBar, InfoBarPosition, CardWidget, TitleLabel
)
from PyQt5.QtCore import Qt
from app.tools.code_generator import CodeGenerator
import os
import shutil
import csv
def get_module_page(module_type, subtype, project_path, parent=None):
"""获取模块配置页面"""
return ModulePage(module_type, subtype, project_path, parent)
class ModulePage(QWidget):
"""单个模块配置页面"""
def __init__(self, module_type, subtype, project_path, parent=None):
super().__init__(parent)
self.module_type = module_type
self.subtype = subtype
self.project_path = project_path
# 获取模块路径
module_dir = CodeGenerator.get_assets_dir("User_code/module")
if subtype:
self.module_path = os.path.join(module_dir, module_type, subtype)
self.module_key = module_type # 使用类型名作为目标文件夹
else:
self.module_path = os.path.join(module_dir, module_type)
self.module_key = module_type
# 加载描述
self.descriptions = self._load_descriptions()
self._init_ui()
self._check_generated_status()
def _load_descriptions(self):
"""从 describe.csv 加载模块描述"""
descriptions = {}
describe_path = os.path.join(
CodeGenerator.get_assets_dir("User_code/module"),
"describe.csv"
)
if os.path.exists(describe_path):
try:
with open(describe_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
module_name = row.get('module_name', '').strip()
description = row.get('description', '').strip()
if module_name and description:
descriptions[module_name] = description
except Exception as e:
print(f"读取模块描述失败: {e}")
return descriptions
def _init_ui(self):
"""初始化界面"""
layout = QVBoxLayout(self)
layout.setSpacing(16)
layout.setContentsMargins(48, 48, 48, 48)
# 标题
if self.subtype:
title_text = f"{self.module_type} / {self.subtype}"
else:
title_text = self.module_type
title = TitleLabel(title_text)
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(title)
# 描述
desc_text = self.descriptions.get(self.module_key, "模块功能说明")
desc = BodyLabel(desc_text)
desc.setWordWrap(True)
desc.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(desc)
layout.addSpacing(24)
# 文件列表卡片
files_card = CardWidget()
files_layout = QVBoxLayout(files_card)
files_layout.setContentsMargins(16, 16, 16, 16)
files_title = SubtitleLabel("包含文件")
files_layout.addWidget(files_title)
files = self._get_module_files()
if files:
for file in files:
file_label = BodyLabel(f"{file}")
files_layout.addWidget(file_label)
else:
files_layout.addWidget(BodyLabel("未找到文件"))
layout.addWidget(files_card)
# 状态显示
self.status_label = BodyLabel()
self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(self.status_label)
layout.addSpacing(24)
# 按钮
btn_layout = QHBoxLayout()
btn_layout.addStretch()
self.generate_btn = PushButton(FluentIcon.SAVE, "生成模块代码")
self.generate_btn.clicked.connect(self._generate_code)
btn_layout.addWidget(self.generate_btn)
btn_layout.addStretch()
layout.addLayout(btn_layout)
layout.addStretch()
def _get_module_files(self):
"""获取模块文件列表"""
files = []
try:
if os.path.exists(self.module_path):
for item in os.listdir(self.module_path):
if item.endswith(('.c', '.h')):
files.append(item)
except Exception as e:
print(f"读取模块文件失败: {e}")
return sorted(files)
def _check_generated_status(self):
"""检查模块是否已生成"""
dst_dir = os.path.join(self.project_path, "User/module", self.module_key)
if os.path.exists(dst_dir):
has_code = any(
f.endswith(('.c', '.h'))
for f in os.listdir(dst_dir)
if os.path.isfile(os.path.join(dst_dir, f))
)
if has_code:
self.status_label.setText("✓ 模块已生成")
self.status_label.setStyleSheet("color: green; font-weight: bold;")
self.generate_btn.setEnabled(False)
return
self.status_label.setText("○ 模块未生成")
self.status_label.setStyleSheet("color: orange;")
def _generate_code(self):
"""生成模块代码"""
try:
# 首先生成 config如果不存在
self._generate_config()
# 目标目录:展平到 User/module/{module_key}
dst_dir = os.path.join(self.project_path, "User/module", self.module_key)
# 检查是否已存在
if os.path.exists(dst_dir):
has_code = any(
f.endswith(('.c', '.h'))
for f in os.listdir(dst_dir)
if os.path.isfile(os.path.join(dst_dir, f))
)
if has_code:
InfoBar.warning(
title="已存在",
content="模块代码已存在,不会覆盖",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP,
duration=2000,
parent=self
)
return
# 创建目录
os.makedirs(dst_dir, exist_ok=True)
# 复制所有文件
file_count = 0
for item in os.listdir(self.module_path):
src_file = os.path.join(self.module_path, item)
dst_file = os.path.join(dst_dir, item)
if os.path.isfile(src_file):
if os.path.exists(dst_file):
continue
shutil.copy2(src_file, dst_file)
file_count += 1
print(f"生成文件: {dst_file}")
if file_count > 0:
InfoBar.success(
title="生成成功",
content=f"已生成 {file_count} 个文件",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP,
duration=2000,
parent=self
)
self._check_generated_status()
else:
InfoBar.warning(
title="无需生成",
content="所有文件已存在",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP,
duration=2000,
parent=self
)
except Exception as e:
print(f"生成模块失败: {e}")
InfoBar.error(
title="生成失败",
content=str(e),
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP,
duration=3000,
parent=self
)
def _generate_config(self):
"""生成 config 文件(如果不存在)"""
config_dir = os.path.join(self.project_path, "User/module")
config_c = os.path.join(config_dir, "config.c")
config_h = os.path.join(config_dir, "config.h")
os.makedirs(config_dir, exist_ok=True)
template_dir = CodeGenerator.get_assets_dir("User_code/module")
template_c = os.path.join(template_dir, "config.c")
template_h = os.path.join(template_dir, "config.h")
if not os.path.exists(config_c) and os.path.exists(template_c):
shutil.copy2(template_c, config_c)
print(f"生成 config.c")
if not os.path.exists(config_h) and os.path.exists(template_h):
shutil.copy2(template_h, config_h)
print(f"生成 config.h")