仓库初始化

This commit is contained in:
lwt
2026-05-22 00:16:08 +08:00
commit 95c96dce42
118 changed files with 23005 additions and 0 deletions
+298
View File
@@ -0,0 +1,298 @@
# -*- coding: utf-8 -*-
"""Main tab views."""
from util.runtime import *
from util.utils import node_host_only, _server_id_sort_key
from models.config import Config, apply_terminal_launch_config
from controllers.workers import (
CommandRunner,
GroupedNodeStatusCheckWorker,
NodeStatusCheckWorker,
StopServerWorker,
)
from views.common import (
NoWheelComboBox,
NoWheelDateTimeEdit,
NoWheelSpinBox,
ServerIdTableItem,
apply_button_style,
make_line_icon,
set_button_icon,
)
from views.console import OutputConsole
from views.dialogs import (
ClearDatabaseDialog,
KvConfigEditDialog,
RemoteConnectDialog,
ServerSelectDialog,
ViewAccountsDialog,
)
class DefaultKvTab(QWidget):
"""默认配置编辑页面 - 编辑 .server_manager/config/default.kv"""
def __init__(self, config: Config, console: OutputConsole):
super().__init__()
self.config = config
self.console = console
self.default_kv_path = None
self.kv_data = {}
self.init_ui()
self.load_default_kv()
def init_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(10)
# 标题和说明
title = QLabel("默认配置管理 (.server_manager/config/default.kv)")
title.setStyleSheet("font-size: 16px; font-weight: bold; color: #25c889;")
layout.addWidget(title)
desc = QLabel("此文件定义创建服务器时的默认值,支持 ${key} 占位符替换")
desc.setStyleSheet("color: #aab4c3;")
layout.addWidget(desc)
# 分割器
splitter = QSplitter(Qt.Orientation.Horizontal)
# 左侧:配置分类列表
left_widget = QWidget()
left_layout = QVBoxLayout(left_widget)
left_layout.setContentsMargins(0, 0, 0, 0)
left_label = QLabel("配置分类")
left_label.setStyleSheet("font-weight: bold;")
left_layout.addWidget(left_label)
self.category_list = QListWidget()
self.category_list.setMaximumWidth(200)
self.category_list.currentRowChanged.connect(self._on_category_changed)
left_layout.addWidget(self.category_list)
# 新增配置按钮
add_btn = QPushButton("+ 新增配置项")
add_btn.clicked.connect(self._add_config_item)
apply_button_style(add_btn, "outline")
set_button_icon(add_btn, "plus", "#4f8cff", 16)
left_layout.addWidget(add_btn)
splitter.addWidget(left_widget)
# 右侧:配置编辑区
right_widget = QWidget()
right_layout = QVBoxLayout(right_widget)
right_layout.setContentsMargins(0, 0, 0, 0)
right_label = QLabel("配置项")
right_label.setStyleSheet("font-weight: bold;")
right_layout.addWidget(right_label)
# 配置表格
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QFrame.Shape.NoFrame)
self.config_widget = QWidget()
self.config_layout = QFormLayout(self.config_widget)
self.config_layout.setSpacing(10)
scroll.setWidget(self.config_widget)
right_layout.addWidget(scroll)
splitter.addWidget(right_widget)
splitter.setSizes([200, 600])
layout.addWidget(splitter)
# 底部按钮
btn_layout = QHBoxLayout()
reload_btn = QPushButton("重新加载")
reload_btn.clicked.connect(self.load_default_kv)
apply_button_style(reload_btn, "outline")
set_button_icon(reload_btn, "refresh", "#4f8cff", 16)
btn_layout.addWidget(reload_btn)
btn_layout.addStretch()
save_btn = QPushButton("保存配置")
apply_button_style(save_btn, "primary")
set_button_icon(save_btn, "save", "#242932", 16)
save_btn.clicked.connect(self.save_default_kv)
btn_layout.addWidget(save_btn)
layout.addLayout(btn_layout)
def load_default_kv(self):
"""加载 default.kv 配置"""
server_root = self.config.get('workspace', 'server_root', default='')
if not server_root:
self.console.append_output("[警告] 请先配置服务器根目录\n")
return
self.default_kv_path = get_server_manager_config_dir(server_root) / 'default.kv'
if not self.default_kv_path.exists():
self.console.append_output(f"[警告] 默认配置文件不存在: {self.default_kv_path}\n")
return
# 读取配置文件
self.kv_data = {}
self.categories = {}
current_category = "其他"
with open(self.default_kv_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line.startswith('# ===') and line.endswith('==='):
# 分类标题
current_category = line.replace('# ===', '').replace('===', '').strip()
if current_category not in self.categories:
self.categories[current_category] = []
elif '=' in line and not line.startswith('#'):
key, value = line.split('=', 1)
key = key.strip()
value = value.strip()
self.kv_data[key] = value
if current_category not in self.categories:
self.categories[current_category] = []
self.categories[current_category].append(key)
# 更新分类列表
self.category_list.clear()
for cat in self.categories.keys():
self.category_list.addItem(cat)
if self.category_list.count() > 0:
self.category_list.setCurrentRow(0)
self.console.append_output(f"[信息] 已加载默认配置: {self.default_kv_path}\n")
def _on_category_changed(self, row):
"""分类切换时更新配置项"""
if row < 0:
return
category = self.category_list.item(row).text()
keys = self.categories.get(category, [])
# 清空现有配置项
while self.config_layout.count():
item = self.config_layout.takeAt(0)
if item.widget():
item.widget().deleteLater()
# 添加配置项
self.config_inputs = {}
for key in keys:
value = self.kv_data.get(key, '')
input_layout = QHBoxLayout()
input_field = QLineEdit(value)
input_field.setMinimumHeight(28)
input_layout.addWidget(input_field)
# 删除按钮
del_btn = QPushButton("×")
del_btn.setFixedSize(28, 28)
apply_button_style(del_btn, "danger", compact=True)
set_button_icon(del_btn, "trash", "#ff5c6a", 14)
del_btn.clicked.connect(lambda checked, k=key: self._delete_config_item(k))
input_layout.addWidget(del_btn)
input_widget = QWidget()
input_widget.setLayout(input_layout)
self.config_layout.addRow(f"{key}:", input_widget)
self.config_inputs[key] = input_field
def _add_config_item(self):
"""新增配置项"""
from PyQt6.QtWidgets import QInputDialog
key, ok1 = QInputDialog.getText(self, "新增配置项", "配置键名:")
if not ok1 or not key:
return
value, ok2 = QInputDialog.getText(self, "新增配置项", f"{key} 的值:")
if not ok2:
return
# 获取当前分类
current_row = self.category_list.currentRow()
if current_row >= 0:
category = self.category_list.item(current_row).text()
else:
category = "其他"
# 添加到数据
self.kv_data[key] = value
if category not in self.categories:
self.categories[category] = []
if key not in self.categories[category]:
self.categories[category].append(key)
# 刷新显示
self._on_category_changed(current_row)
self.console.append_output(f"[信息] 已添加配置项: {key}={value}\n")
def _delete_config_item(self, key):
"""删除配置项"""
reply = QMessageBox.question(
self, "确认删除",
f"确定要删除配置项 '{key}' 吗?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply != QMessageBox.StandardButton.Yes:
return
# 从数据中删除
if key in self.kv_data:
del self.kv_data[key]
for cat, keys in self.categories.items():
if key in keys:
keys.remove(key)
break
# 刷新显示
current_row = self.category_list.currentRow()
self._on_category_changed(current_row)
self.console.append_output(f"[信息] 已删除配置项: {key}\n")
def save_default_kv(self):
"""保存配置到 default.kv"""
if not self.default_kv_path:
QMessageBox.warning(self, "警告", "请先加载配置文件")
return
# 更新数据
if hasattr(self, 'config_inputs'):
for key, input_field in self.config_inputs.items():
self.kv_data[key] = input_field.text()
# 生成文件内容
lines = [
"# 默认配置文件 (kv.config 的模板)",
"# 此文件定义所有可配置的参数和默认值",
"# 创建服务器时会基于此模板生成差异化配置",
"# 占位符格式: ${key} 对应此文件中的 key=value",
""
]
for category, keys in self.categories.items():
if keys:
lines.append(f"# === {category} ===")
for key in keys:
value = self.kv_data.get(key, '')
lines.append(f"{key}={value}")
lines.append("")
# 写入文件
try:
with open(self.default_kv_path, 'w', encoding='utf-8') as f:
f.write('\n'.join(lines))
self.console.append_output(f"[成功] 配置已保存: {self.default_kv_path}\n")
QMessageBox.information(self, "成功", "默认配置已保存")
except Exception as e:
self.console.append_output(f"[错误] 保存失败: {str(e)}\n")
QMessageBox.critical(self, "错误", f"保存失败: {str(e)}")