上传文件至 /

代码优化,新增一键隐藏,取消自动分组

Signed-off-by: hujinyang <hujinyang@pw.com>
This commit is contained in:
hujinyang 2025-12-12 09:49:12 +00:00
parent 7391a4b29b
commit 0a7204f85e
3 changed files with 257 additions and 300 deletions

236
build.sh
View File

@ -1,16 +1,17 @@
# config Editor 一键构建脚本
# config editor 一键构建脚本 - 修复虚拟环境安装问题
set -e set -e
# 配置变量 # 配置变量
PACKAGE_NAME="config-editor" PACKAGE_NAME="config-editor"
VERSION="1.0" VERSION="1.1"
ARCHITECTURE="amd64" ARCHITECTURE="amd64"
MAINTAINER="hjy <hjy@pw.com>" MAINTAINER="hjy <hjy@pw.com>"
echo "==========================================" echo "=========================================="
echo "Config Editor 构建脚本 (虚拟环境版)" echo "Config Editor 构建脚本 - 版本 $VERSION"
echo "版本: $VERSION"
echo "架构: $ARCHITECTURE" echo "架构: $ARCHITECTURE"
echo "构建时间: $(date)"
echo "==========================================" echo "=========================================="
# 检查依赖 # 检查依赖
@ -24,7 +25,6 @@ fi
echo "检查源代码..." echo "检查源代码..."
if [ ! -f "config_editor.py" ]; then if [ ! -f "config_editor.py" ]; then
echo "错误: 未找到主程序文件 config_editor.py" echo "错误: 未找到主程序文件 config_editor.py"
echo "请确保在项目根目录运行此脚本,且包含 config_editor.py 文件"
exit 1 exit 1
fi fi
@ -39,58 +39,40 @@ mkdir -p "$BUILD_DIR/usr/bin"
# 复制应用文件 # 复制应用文件
echo "复制应用文件..." echo "复制应用文件..."
echo "复制主程序 config_editor.py"
cp config_editor.py "$BUILD_DIR/usr/share/config-editor/" cp config_editor.py "$BUILD_DIR/usr/share/config-editor/"
# 复制配置文件 # 复制配置文件
if [ -f "config_editor_rules.json" ]; then if [ -f "config_editor_rules.json" ]; then
echo "复制配置文件 config_editor_rules.json"
cp config_editor_rules.json "$BUILD_DIR/usr/share/config-editor/" cp config_editor_rules.json "$BUILD_DIR/usr/share/config-editor/"
else
echo "警告: 未找到 config_editor_rules.json 文件"
fi fi
if [ -f "config_editor_settings.json" ]; then if [ -f "config_editor_settings.json" ]; then
echo "复制配置文件 config_editor_settings.json"
cp config_editor_settings.json "$BUILD_DIR/usr/share/config-editor/" cp config_editor_settings.json "$BUILD_DIR/usr/share/config-editor/"
else
echo "警告: 未找到 config_editor_settings.json 文件"
fi
# 复制所有Python文件
echo "复制其他Python文件..."
find . -maxdepth 1 -name "*.py" ! -name "build.sh" -exec cp {} "$BUILD_DIR/usr/share/config-editor/" \; 2>/dev/null || true
# 显示复制的文件
echo "已复制的文件:"
ls -la "$BUILD_DIR/usr/share/config-editor/"
# 检查是否复制了真实的应用文件
if [ ! -f "$BUILD_DIR/usr/share/config-editor/config_editor.py" ]; then
echo "错误: 未成功复制 config_editor.py 文件"
exit 1
fi fi
# 创建桌面文件 # 创建桌面文件
echo "创建桌面文件..." echo "创建桌面文件..."
cat > "$BUILD_DIR/usr/share/applications/config-editor.desktop" << EOF cat > "$BUILD_DIR/usr/share/applications/config-editor.desktop" << 'EOF'
[Desktop Entry] [Desktop Entry]
Version=1.1 Version=1.0
Type=Application Type=Application
Name=Config Editor Name=Config Editor
Comment=Configuration Management System Comment=Configuration Management Tool
Exec=config-editor Exec=/usr/bin/config-editor
Icon=config-editor Icon=config-editor
Categories=Development;Settings; Categories=Development;Utility;Settings;
Terminal=false Terminal=false
StartupNotify=true
StartupWMClass=ConfigEditor StartupWMClass=ConfigEditor
EOF EOF
# 创建虚拟环境安装脚本(已修复权限问题) # 创建虚拟环境安装脚本 - 修复版本
echo "创建虚拟环境安装脚本..." echo "创建虚拟环境安装脚本..."
cat > "$BUILD_DIR/usr/share/config-editor/setup_venv.sh" << 'EOF' cat > "$BUILD_DIR/usr/share/config-editor/setup_venv.sh" << 'EOF'
#!/bin/bash #!/bin/bash
# 虚拟环境安装脚本 # 虚拟环境安装脚本 - 修复sudo环境问题
set -e
APP_DIR="/usr/share/config-editor" APP_DIR="/usr/share/config-editor"
VENV_DIR="$APP_DIR/venv" VENV_DIR="$APP_DIR/venv"
@ -104,93 +86,75 @@ if [ "$EUID" -ne 0 ]; then
exit 1 exit 1
fi fi
# 检查虚拟环境是否存在 # 清理旧的虚拟环境(如果存在)
if [ ! -d "$VENV_DIR" ]; then if [ -d "$VENV_DIR" ]; then
echo "创建虚拟环境..." echo "清理旧的虚拟环境..."
python3 -m venv --system-site-packages "$VENV_DIR" rm -rf "$VENV_DIR"
fi
if [ $? -ne 0 ]; then # 创建虚拟环境
echo "创建虚拟环境..."
python3 -m venv "$VENV_DIR"
if [ $? -ne 0 ]; then
echo "错误: 无法创建虚拟环境" echo "错误: 无法创建虚拟环境"
echo "请确保已安装 python3-venv: sudo apt install python3-venv" echo "请确保已安装 python3-venv: sudo apt install python3-venv"
exit 1 exit 1
fi
fi fi
# 激活虚拟环境并安装依赖 echo "✓ 虚拟环境创建成功"
echo "激活虚拟环境并安装依赖..."
source "$VENV_DIR/bin/activate"
# 修复权限问题 # 使用虚拟环境中的pip安装PyQt6 - 关键修复:使用绝对路径
echo "修复虚拟环境权限..."
chmod -R 755 "$VENV_DIR"
chmod +x "$VENV_DIR/bin"/* 2>/dev/null || true
chmod +x "$VENV_DIR/bin/python" 2>/dev/null || true
chmod +x "$VENV_DIR/bin/pip" 2>/dev/null || true
# 升级pip
echo "升级pip..."
python -m pip install --upgrade pip
# 安装PyQt6
echo "安装PyQt6..." echo "安装PyQt6..."
pip install PyQt6 -i https://pypi.tuna.tsinghua.edu.cn/simple/ if ! "$VENV_DIR/bin/python" -m pip install PyQt6 2>/dev/null; then
echo "尝试使用国内镜像安装..."
# 如果有requirements.txt安装其他依赖 "$VENV_DIR/bin/python" -m pip install PyQt6 -i https://pypi.tuna.tsinghua.edu.cn/simple/
if [ -f "$APP_DIR/requirements.txt" ]; then
echo "安装其他依赖..."
pip install -r "$APP_DIR/requirements.txt" -i https://pypi.tuna.tsinghua.edu.cn/simple/
fi fi
# 再次确保权限正确 # 验证安装
echo "设置最终权限..." if ! "$VENV_DIR/bin/python" -c "import PyQt6" 2>/dev/null; then
chmod -R 755 "$VENV_DIR" echo "错误: PyQt6安装失败"
chmod +x "$VENV_DIR/bin"/* 2>/dev/null || true echo "请尝试手动安装:"
echo " sudo $VENV_DIR/bin/pip install PyQt6"
exit 1
fi
echo "虚拟环境设置完成" echo "✓ PyQt6安装成功"
echo "安装在虚拟环境中的包:"
pip list # 设置权限
chmod -R 755 "$VENV_DIR"
echo ""
echo "虚拟环境设置完成!"
echo "虚拟环境位置: $VENV_DIR"
echo ""
echo "可以测试运行:"
echo " $VENV_DIR/bin/python $APP_DIR/config_editor.py"
EOF EOF
chmod +x "$BUILD_DIR/usr/share/config-editor/setup_venv.sh" chmod +x "$BUILD_DIR/usr/share/config-editor/setup_venv.sh"
# 创建启动脚本 - 使用虚拟环境(已修复权限检查) # 创建启动脚本
echo "创建启动脚本..." echo "创建启动脚本..."
cat > "$BUILD_DIR/usr/bin/config-editor" << 'EOF' cat > "$BUILD_DIR/usr/bin/config-editor" << 'EOF'
#!/bin/bash #!/bin/bash
# Config Editor 启动脚本 - 虚拟环境版本 # Config Editor 启动脚本
# 应用目录
APP_DIR="/usr/share/config-editor" APP_DIR="/usr/share/config-editor"
VENV_DIR="$APP_DIR/venv" VENV_DIR="$APP_DIR/venv"
LOG_FILE="${HOME}/.config/config-editor/log.txt"
# 创建日志目录 # 日志文件
mkdir -p "$(dirname "$LOG_FILE")" LOG_DIR="${HOME}/.config/config-editor"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/startup.log"
# 记录启动日志 # 记录启动信息
echo "$(date): 启动Config Editor" >> "$LOG_FILE" {
echo "========================================"
# 设置环境变量 echo "启动时间: $(date)"
export DISPLAY=":${XDG_SESSION_DISPLAY:-1}" echo "用户: $(whoami)"
export XAUTHORITY="${HOME}/.Xauthority" echo "DISPLAY: $DISPLAY"
} >> "$LOG_FILE"
# 尝试多种方法设置DBUS
if [ -f "/run/user/$(id -u)/bus" ]; then
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
elif [ -n "$DBUS_SESSION_BUS_ADDRESS" ]; then
: # 保持已有设置
else
# 尝试从进程获取
DBUS_ADDR=$(ps -u $(id -u) -o command | grep -o 'dbus-daemon.*address=unix:path=[^ ]*' | head -1 | sed 's/.*address=//')
if [ -n "$DBUS_ADDR" ]; then
export DBUS_SESSION_BUS_ADDRESS="$DBUS_ADDR"
fi
fi
# 修复X11权限
if [ -f "${HOME}/.Xauthority" ]; then
export XAUTHORITY="${HOME}/.Xauthority"
fi
# 检查虚拟环境 # 检查虚拟环境
if [ ! -d "$VENV_DIR" ]; then if [ ! -d "$VENV_DIR" ]; then
@ -199,29 +163,30 @@ if [ ! -d "$VENV_DIR" ]; then
exit 1 exit 1
fi fi
# 检查并修复权限(如果需要) # 检查Python可执行文件
if [ ! -x "$VENV_DIR/bin/python" ] || [ ! -x "$VENV_DIR/bin/pip" ]; then PYTHON_EXEC="$VENV_DIR/bin/python"
echo "警告: 虚拟环境权限问题,请重新运行安装脚本:" if [ ! -x "$PYTHON_EXEC" ]; then
echo " sudo /usr/share/config-editor/setup_venv.sh" PYTHON_EXEC="$VENV_DIR/bin/python3"
if [ ! -x "$PYTHON_EXEC" ]; then
echo "错误: 虚拟环境中找不到Python可执行文件"
exit 1 exit 1
fi
fi fi
# 检查PyQt6是否安装 # 检查PyQt6是否安装
if ! "$VENV_DIR/bin/python" -c "import PyQt6" 2>/dev/null; then if ! "$PYTHON_EXEC" -c "import PyQt6" 2>/dev/null; then
echo "错误: PyQt6未在虚拟环境中安装。请运行:" echo "错误: PyQt6未在虚拟环境中安装。请运行:"
echo " sudo /usr/share/config-editor/setup_venv.sh" echo " sudo /usr/share/config-editor/setup_venv.sh"
echo "如果仍然失败,请手动安装:"
echo " sudo $VENV_DIR/bin/pip install PyQt6"
exit 1 exit 1
fi fi
# 切换到应用目录 # 切换到应用目录
cd "$APP_DIR" cd "$APP_DIR"
# 记录环境信息 # 启动应用
echo "DISPLAY: $DISPLAY" >> "$LOG_FILE" exec "$PYTHON_EXEC" config_editor.py "$@"
echo "XAUTHORITY: $XAUTHORITY" >> "$LOG_FILE"
# 使用虚拟环境运行Python应用
exec "$VENV_DIR/bin/python" config_editor.py "$@" >> "$LOG_FILE" 2>&1
EOF EOF
chmod +x "$BUILD_DIR/usr/bin/config-editor" chmod +x "$BUILD_DIR/usr/bin/config-editor"
@ -233,12 +198,10 @@ Package: $PACKAGE_NAME
Version: $VERSION Version: $VERSION
Architecture: $ARCHITECTURE Architecture: $ARCHITECTURE
Depends: python3, python3-venv Depends: python3, python3-venv
Recommends: libnotify-bin, x11-xserver-utils
Maintainer: $MAINTAINER Maintainer: $MAINTAINER
Description: Configuration Management System (VirtualEnv) Description: Config Editor with one-click hide feature
A PyQt6-based configuration management editor using virtual environment. A PyQt6-based configuration management editor.
Provides grouping management, validation rules, and auto-grouping features. Features include one-click hide all configuration items.
This version uses virtual environment for PyQt6.
EOF EOF
# 创建安装后脚本 # 创建安装后脚本
@ -246,35 +209,23 @@ echo "创建安装后脚本..."
cat > "$BUILD_DIR/DEBIAN/postinst" << 'EOF' cat > "$BUILD_DIR/DEBIAN/postinst" << 'EOF'
#!/bin/bash #!/bin/bash
# 安装后脚本 # 安装后脚本
set -e
echo "Config Editor 安装完成!" echo "Config Editor 安装完成!"
echo ""
echo "更新桌面数据库..."
update-desktop-database /usr/share/applications 2>/dev/null || true
echo "" echo ""
echo "重要: 需要设置虚拟环境才能运行应用" echo "重要: 需要设置虚拟环境才能运行应用"
echo "请执行以下命令完成安装:" echo "请执行以下命令完成安装:"
echo " sudo /usr/share/config-editor/setup_venv.sh" echo " sudo /usr/share/config-editor/setup_venv.sh"
echo "" echo ""
echo "使用说明:" echo "注意: 如果之前安装失败,新版本修复了虚拟环境安装问题"
echo "1. 设置虚拟环境: sudo /usr/share/config-editor/setup_venv.sh" echo " 请确保运行上述命令安装PyQt6到正确的虚拟环境中"
echo "2. 在终端运行: config-editor"
# 设置文件权限 # 更新桌面数据库
update-desktop-database /usr/share/applications 2>/dev/null || true
# 设置权限
chmod 755 /usr/bin/config-editor chmod 755 /usr/bin/config-editor
chmod 755 /usr/share/config-editor/setup_venv.sh chmod 755 /usr/share/config-editor/setup_venv.sh
# 设置应用文件权限
chmod -R 644 /usr/share/config-editor/* 2>/dev/null || true
chmod 755 /usr/share/config-editor/*.py 2>/dev/null || true
chmod 755 /usr/share/config-editor/*.sh 2>/dev/null || true
# 为虚拟环境目录预留权限
mkdir -p /usr/share/config-editor/venv 2>/dev/null || true
chmod 755 /usr/share/config-editor/venv 2>/dev/null || true
exit 0 exit 0
EOF EOF
@ -285,7 +236,6 @@ echo "构建deb包..."
dpkg-deb --build "$BUILD_DIR" "${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb" dpkg-deb --build "$BUILD_DIR" "${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb"
# 验证包 # 验证包
echo "验证deb包..."
if dpkg -I "${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb" > /dev/null; then if dpkg -I "${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb" > /dev/null; then
echo "✓ 包验证成功" echo "✓ 包验证成功"
else else
@ -293,28 +243,18 @@ else
exit 1 exit 1
fi fi
# 清理构建目录 # 清理
echo "清理构建目录..."
rm -rf "$BUILD_DIR" rm -rf "$BUILD_DIR"
echo "" echo ""
echo "==========================================" echo "=========================================="
echo "构建成功完成!" echo "构建完成!"
echo "生成的deb包: ${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb" echo "生成的deb包: ${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb"
echo "" echo ""
echo "安装步骤:" echo "安装步骤:"
echo "1. 安装deb包: sudo dpkg -i ${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb" echo "1. 卸载旧版本: sudo dpkg -r config-editor"
echo "2. 安装依赖(如有需要): sudo apt install -f" echo "2. 安装新版本: sudo dpkg -i ${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb"
echo "3. 设置虚拟环境: sudo /usr/share/config-editor/setup_venv.sh" echo "3. 修复虚拟环境: sudo /usr/share/config-editor/setup_venv.sh"
echo "" echo ""
echo "此版本特点:" echo "重要: 新版本修复了虚拟环境安装问题"
echo "✓ 修复了虚拟环境权限问题"
echo "✓ 使用 --system-site-packages 参数"
echo "✓ 自动使用清华PyPI镜像"
echo "✓ 简化了依赖和脚本"
echo "==========================================" echo "=========================================="
# 显示包信息
echo ""
echo "包信息:"
dpkg -I "${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb"

View File

@ -262,6 +262,24 @@ class ConfigManagementWindow(QDialog):
group_layout.addLayout(group_btn_layout) group_layout.addLayout(group_btn_layout)
right_layout.addWidget(group_group) right_layout.addWidget(group_group)
# 批量操作
batch_group = QGroupBox("批量操作")
batch_layout = QVBoxLayout(batch_group)
batch_layout.setContentsMargins(8, 8, 8, 8)
batch_btn_layout = QHBoxLayout()
self.show_all_btn = QPushButton("全部显示")
self.show_all_btn.clicked.connect(self.show_all_fields)
self.hide_all_btn = QPushButton("全部隐藏")
self.hide_all_btn.clicked.connect(self.hide_all_fields)
batch_btn_layout.addWidget(self.show_all_btn)
batch_btn_layout.addWidget(self.hide_all_btn)
batch_btn_layout.addStretch()
batch_layout.addLayout(batch_btn_layout)
right_layout.addWidget(batch_group)
right_layout.addStretch() right_layout.addStretch()
splitter.addWidget(right_widget) splitter.addWidget(right_widget)
@ -292,11 +310,15 @@ class ConfigManagementWindow(QDialog):
self.update_fields_count() self.update_fields_count()
# 加载分组
self.category_combo.clear() self.category_combo.clear()
categories = list(self.rules.get("categories", {}).keys()) categories = list(self.rules.get("categories", {}).keys())
# 确保"未分类"分组始终存在
if "未分类" not in categories:
categories.append("未分类")
if categories:
for category in sorted(categories): for category in sorted(categories):
self.category_combo.addItem(category) self.category_combo.addItem(category)
self.category_combo.addItem("未分类")
def filter_fields(self, search_text): def filter_fields(self, search_text):
"""根据搜索文本过滤配置项列表""" """根据搜索文本过滤配置项列表"""
@ -364,12 +386,14 @@ class ConfigManagementWindow(QDialog):
display_name = self.rules.get("display_names", {}).get(field_name, field_name) display_name = self.rules.get("display_names", {}).get(field_name, field_name)
self.display_name_edit.setText(display_name) self.display_name_edit.setText(display_name)
# 查找配置项所属的分组
category = "未分类" category = "未分类"
for cat, fields in self.rules.get("categories", {}).items(): for cat, fields in self.rules.get("categories", {}).items():
if field_name in fields: if field_name in fields:
category = cat category = cat
break break
# 设置分组
index = self.category_combo.findText(category) index = self.category_combo.findText(category)
if index >= 0: if index >= 0:
self.category_combo.setCurrentIndex(index) self.category_combo.setCurrentIndex(index)
@ -416,12 +440,25 @@ class ConfigManagementWindow(QDialog):
# 更新分组 # 更新分组
category = self.category_combo.currentText().strip() category = self.category_combo.currentText().strip()
if category and category != "未分类": if category == "未分类":
# 从旧分组移除 # 从所有分组中移除该字段
for cat, fields in self.rules.get("categories", {}).items(): for cat, fields in self.rules.setdefault("categories", {}).items():
if cat != "未分类" and field_name in fields:
fields.remove(field_name)
# 确保在"未分类"分组中
if "未分类" not in self.rules["categories"]:
self.rules["categories"]["未分类"] = []
if field_name not in self.rules["categories"]["未分类"]:
self.rules["categories"]["未分类"].append(field_name)
elif category: # 其他分组
# 从所有分组中移除该字段
for cat, fields in self.rules.setdefault("categories", {}).items():
if field_name in fields: if field_name in fields:
fields.remove(field_name) fields.remove(field_name)
break
# 确保"未分类"分组存在
if "未分类" not in self.rules["categories"]:
self.rules["categories"]["未分类"] = []
# 添加到新分组 # 添加到新分组
if category not in self.rules["categories"]: if category not in self.rules["categories"]:
@ -503,11 +540,62 @@ class ConfigManagementWindow(QDialog):
current_group = self.category_combo.currentText() current_group = self.category_combo.currentText()
if current_group and current_group != "未分类": if current_group and current_group != "未分类":
reply = QMessageBox.question(self, "确认删除", reply = QMessageBox.question(self, "确认删除",
f"确定要删除分组 '{current_group}' 吗?") f"确定要删除分组 '{current_group}' 吗?\n该分组中的所有配置项将被移到'未分类'分组。")
if reply == QMessageBox.StandardButton.Yes: if reply == QMessageBox.StandardButton.Yes:
if current_group in self.rules.get("categories", {}): if current_group in self.rules.get("categories", {}):
# 将该分组中的配置项移到"未分类"分组
fields_to_move = self.rules["categories"][current_group]
if "未分类" not in self.rules["categories"]:
self.rules["categories"]["未分类"] = []
for field_name in fields_to_move:
if field_name not in self.rules["categories"]["未分类"]:
self.rules["categories"]["未分类"].append(field_name)
# 删除分组
del self.rules["categories"][current_group] del self.rules["categories"][current_group]
self.category_combo.removeItem(self.category_combo.findText(current_group))
# 从下拉框中移除
index = self.category_combo.findText(current_group)
if index >= 0:
self.category_combo.removeItem(index)
# 设置当前选中的分组为"未分类"
self.category_combo.setCurrentText("未分类")
def show_all_fields(self):
"""批量显示所有配置项(取消所有隐藏)"""
reply = QMessageBox.question(self, "确认",
"确定要取消所有配置项的隐藏状态吗?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
# 清空隐藏列表
self.rules["hidden"] = []
# 更新当前选中字段的隐藏状态
current_item = self.fields_list.currentItem()
if current_item:
self.hidden_checkbox.setChecked(False)
QMessageBox.information(self, "完成", "已取消所有配置项的隐藏状态")
def hide_all_fields(self):
"""批量隐藏所有配置项"""
reply = QMessageBox.question(self, "确认",
"确定要隐藏所有配置项吗?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
# 获取所有配置项的名称
all_fields = list(self.config_fields.keys())
# 将所有配置项添加到隐藏列表
self.rules["hidden"] = all_fields
# 更新当前选中字段的隐藏状态
current_item = self.fields_list.currentItem()
if current_item:
self.hidden_checkbox.setChecked(True)
QMessageBox.information(self, "完成", "已隐藏所有配置项")
def get_updated_rules(self): def get_updated_rules(self):
"""获取更新后的规则""" """获取更新后的规则"""
@ -789,6 +877,12 @@ class ConfigEditor(QMainWindow):
self.toggle_hidden_btn.toggled.connect(self.toggle_hidden_fields) self.toggle_hidden_btn.toggled.connect(self.toggle_hidden_fields)
button_layout.addWidget(self.toggle_hidden_btn) button_layout.addWidget(self.toggle_hidden_btn)
# 新增:一键隐藏所有配置项按钮
self.hide_all_btn = QPushButton("一键隐藏所有项")
self.hide_all_btn.clicked.connect(self.hide_all_fields)
self.hide_all_btn.setStyleSheet("QPushButton { background-color: #ff9800; color: white; }")
button_layout.addWidget(self.hide_all_btn)
main_layout.addLayout(button_layout) main_layout.addLayout(button_layout)
# 更新路径显示 # 更新路径显示
@ -878,6 +972,7 @@ class ConfigEditor(QMainWindow):
self.load_config() self.load_config()
def init_category_tabs(self): def init_category_tabs(self):
"""初始化分类标签页"""
self.category_widgets.clear() self.category_widgets.clear()
categories = list(self.rules.get("categories", {}).keys()) categories = list(self.rules.get("categories", {}).keys())
if not categories: if not categories:
@ -887,6 +982,7 @@ class ConfigEditor(QMainWindow):
self.create_category_tab(category) self.create_category_tab(category)
def create_category_tab(self, category): def create_category_tab(self, category):
"""创建分类标签页"""
tab = QWidget() tab = QWidget()
layout = QVBoxLayout(tab) layout = QVBoxLayout(tab)
layout.setContentsMargins(4, 4, 4, 4) layout.setContentsMargins(4, 4, 4, 4)
@ -908,17 +1004,24 @@ class ConfigEditor(QMainWindow):
self.tab_widget.addTab(tab, category) self.tab_widget.addTab(tab, category)
def load_rules(self): def load_rules(self):
"""加载规则文件"""
try: try:
if os.path.exists(self.rules_file): if os.path.exists(self.rules_file):
with open(self.rules_file, 'r', encoding='utf-8') as f: with open(self.rules_file, 'r', encoding='utf-8') as f:
self.rules = json.load(f) self.rules = json.load(f)
# 确保规则中有"未分类"分组
if "categories" not in self.rules:
self.rules["categories"] = {}
if "未分类" not in self.rules["categories"]:
self.rules["categories"]["未分类"] = []
# 确保规则中有field_decimals字段 # 确保规则中有field_decimals字段
if "field_decimals" not in self.rules: if "field_decimals" not in self.rules:
self.rules["field_decimals"] = {} self.rules["field_decimals"] = {}
else: else:
self.rules = { self.rules = {
"categories": {}, "categories": {"未分类": []}, # 保留"未分类"分组
"display_names": {}, "display_names": {},
"tooltips": {}, "tooltips": {},
"field_types": {}, "field_types": {},
@ -934,7 +1037,7 @@ class ConfigEditor(QMainWindow):
except Exception as e: except Exception as e:
print(f"加载规则文件失败: {e}") print(f"加载规则文件失败: {e}")
self.rules = { self.rules = {
"categories": {}, "categories": {"未分类": []},
"display_names": {}, "display_names": {},
"tooltips": {}, "tooltips": {},
"field_types": {}, "field_types": {},
@ -944,6 +1047,7 @@ class ConfigEditor(QMainWindow):
} }
def save_rules(self): def save_rules(self):
"""保存规则文件"""
try: try:
with open(self.rules_file, 'w', encoding='utf-8') as f: with open(self.rules_file, 'w', encoding='utf-8') as f:
json.dump(self.rules, f, indent=2, ensure_ascii=False) json.dump(self.rules, f, indent=2, ensure_ascii=False)
@ -951,18 +1055,22 @@ class ConfigEditor(QMainWindow):
print(f"保存规则文件失败: {e}") print(f"保存规则文件失败: {e}")
def categorize_field(self, field_name): def categorize_field(self, field_name):
"""为字段分类,如果未分配分组则归到'未分类'"""
for category, fields in self.rules.get("categories", {}).items(): for category, fields in self.rules.get("categories", {}).items():
if field_name in fields: if field_name in fields:
return category return category
return "未分类" return "未分类" # 默认归到"未分类"
def get_display_name(self, field_name): def get_display_name(self, field_name):
"""获取字段的显示名称"""
return self.rules.get("display_names", {}).get(field_name, field_name) return self.rules.get("display_names", {}).get(field_name, field_name)
def get_tooltip(self, field_name): def get_tooltip(self, field_name):
"""获取字段的提示信息"""
return self.rules.get("tooltips", {}).get(field_name, f"配置项: {field_name}") return self.rules.get("tooltips", {}).get(field_name, f"配置项: {field_name}")
def get_field_type(self, field_name, value): def get_field_type(self, field_name, value):
"""获取字段类型"""
if field_name in self.rules.get("field_types", {}): if field_name in self.rules.get("field_types", {}):
return self.rules["field_types"][field_name] return self.rules["field_types"][field_name]
@ -1055,7 +1163,7 @@ class ConfigEditor(QMainWindow):
all_config_fields[var_name] = ConfigField( all_config_fields[var_name] = ConfigField(
name=var_name, name=var_name,
value=var_value, value=var_value,
category=self.categorize_field(var_name), category=self.categorize_field(var_name), # 使用分类方法
display_name=self.get_display_name(var_name), display_name=self.get_display_name(var_name),
field_type=field_type, field_type=field_type,
decimals=decimals, decimals=decimals,
@ -1075,7 +1183,7 @@ class ConfigEditor(QMainWindow):
all_config_fields[var_name] = ConfigField( all_config_fields[var_name] = ConfigField(
name=var_name, name=var_name,
value=value_str, value=value_str,
category=self.categorize_field(var_name), category=self.categorize_field(var_name), # 使用分类方法
display_name=self.get_display_name(var_name), display_name=self.get_display_name(var_name),
field_type="str", field_type="str",
decimals=None, decimals=None,
@ -1091,7 +1199,7 @@ class ConfigEditor(QMainWindow):
all_config_fields[var_name] = ConfigField( all_config_fields[var_name] = ConfigField(
name=var_name, name=var_name,
value="无法解析的值", value="无法解析的值",
category=self.categorize_field(var_name), category=self.categorize_field(var_name), # 使用分类方法
display_name=self.get_display_name(var_name), display_name=self.get_display_name(var_name),
field_type="str", field_type="str",
decimals=None, decimals=None,
@ -1109,6 +1217,7 @@ class ConfigEditor(QMainWindow):
return {}, {}, "" return {}, {}, ""
def create_field_widget(self, config_field): def create_field_widget(self, config_field):
"""创建字段编辑控件"""
field_type = config_field.get_actual_field_type() field_type = config_field.get_actual_field_type()
if field_type == "bool": if field_type == "bool":
@ -1315,7 +1424,7 @@ class ConfigEditor(QMainWindow):
fields.sort(key=lambda x: x.name) fields.sort(key=lambda x: x.name)
# 使用GroupBox更清晰的分组 # 使用GroupBox更清晰的分组
group_box = QGroupBox(f"{category}配置项") group_box = QGroupBox(f"{category}")
group_layout = QVBoxLayout(group_box) group_layout = QVBoxLayout(group_box)
group_layout.setSpacing(6) group_layout.setSpacing(6)
@ -1328,6 +1437,7 @@ class ConfigEditor(QMainWindow):
layout.addWidget(group_box) layout.addWidget(group_box)
def load_config(self): def load_config(self):
"""加载配置文件"""
try: try:
# 检查配置文件是否存在 # 检查配置文件是否存在
if not self.check_config_file(): if not self.check_config_file():
@ -1351,7 +1461,7 @@ class ConfigEditor(QMainWindow):
self.generate_dynamic_ui(show_hidden) self.generate_dynamic_ui(show_hidden)
hidden_count = len(self.all_config_fields) - len(self.config_fields) hidden_count = len(self.all_config_fields) - len(self.config_fields)
self.statusBar().showMessage(f"成功加载 {len(self.config_fields)} 个配置项 ({hidden_count}隐藏)") self.statusBar().showMessage(f"成功加载 {len(self.config_data)} 个配置项 ({len(self.config_fields)} 个显示, {hidden_count}隐藏)")
except Exception as e: except Exception as e:
QMessageBox.critical(self, "错误", f"加载配置文件失败:{str(e)}") QMessageBox.critical(self, "错误", f"加载配置文件失败:{str(e)}")
@ -1370,7 +1480,34 @@ class ConfigEditor(QMainWindow):
self.toggle_hidden_btn.setText("显示隐藏项") self.toggle_hidden_btn.setText("显示隐藏项")
self.statusBar().showMessage("已隐藏标记为隐藏的配置项") self.statusBar().showMessage("已隐藏标记为隐藏的配置项")
def hide_all_fields(self):
"""一键隐藏所有配置项"""
reply = QMessageBox.question(
self, "确认一键隐藏",
"确定要隐藏所有配置项吗?\n隐藏后,页面上将不显示任何配置项。\n如需显示,需要在规则管理中取消隐藏。",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.Yes:
# 获取所有配置项的名称
all_field_names = list(self.all_config_fields.keys())
# 将所有配置项添加到隐藏列表
self.rules["hidden"] = all_field_names
# 保存规则
self.save_rules()
# 重新加载配置
self.load_config()
# 更新状态栏
self.statusBar().showMessage("已隐藏所有配置项,页面已清空")
QMessageBox.information(self, "完成", "已成功隐藏所有配置项。\n如需显示配置项,请在规则管理中取消隐藏。")
def manage_rules(self): def manage_rules(self):
"""管理规则"""
dialog = ConfigManagementWindow(self.rules, self.all_config_fields, self) dialog = ConfigManagementWindow(self.rules, self.all_config_fields, self)
if dialog.exec() == QDialog.DialogCode.Accepted: if dialog.exec() == QDialog.DialogCode.Accepted:
updated_rules = dialog.get_updated_rules() updated_rules = dialog.get_updated_rules()

View File

@ -1,131 +1,11 @@
{ {
"categories": { "categories": {
"数据库配置": [ "未分类": []
"CONNECTION",
"REDIS_ADDRESS",
"REDIS_PORT",
"SYNC_INTERVAL",
"REDIS_FIELD_MAPPING"
],
"PLC控制": [
"PLC_ADDRESS",
"PLC_PORT",
"NH3_LOWER",
"NH3_UPPER",
"IS_AUTO",
"AI_NH3_ADDRESS",
"FLOW_FEEDBACK_ADDRESS",
"NH3_MANUAL"
],
"训练参数": [
"RESAMPLE_SIZE",
"MISSING_VALUE_LENGTH",
"MEAN_MASE",
"INTERVAL_SIZE_V2",
"LAGS",
"PREDICT_FH_V2",
"TRAIN_DAYS_V2",
"THREAD_COUNT",
"GPU_RAM_PART",
"CNF_PREDICT_NUMBER",
"CNF_LAGS",
"CNF_LAGS_PC",
"CNF_OUTPUT_CHUNK_LENGTH",
"CNF_THREAD_COUNT",
"CNF_ALARM_LEVEL_1",
"CNF_ALARM_LEVEL_2",
"CNF_ALARM_LEVEL_3"
],
"计算参数": [
"NH3_LOWER",
"NH3_UPPER",
"SMOKE_VOLUME",
"SMOKE_VOLUME_UPPER",
"SMOKE_VOLUME_LOWER",
"CONC",
"DENSITY",
"IS_SOLUTION",
"DECLINE_LIMIT",
"LOWER_LIMIT_DURATION",
"RAISE_LIMIT",
"UPPER_LIMIT_DURATION",
"PAS_TARGET",
"ACTUAL_PAS_TARGET_DIFF_CEMS",
"ACTUAL_PAS_TARGET_DIFF_PW",
"ACTUAL_PAS_TARGET_CEMS",
"ACTUAL_PAS_TARGET_PW",
"DYNAMIC_TARGET_UPPER",
"DYNAMIC_TARGET_LOWER",
"DYNAMIC_TARGET_START_MINUTE",
"DYNAMIC_TARGET_END_MINUTE",
"NH3_MANUAL"
],
"控制修正": [
"OUT_NH3_TARGET",
"OUT_NH3_TARGET_LOWER",
"OUT_NH3_TARGET_UPPER",
"CORR_PER_LIMIT",
"CORR_SLOPE",
"AVG_PRIMARY_ADJUST_TIME",
"PRIMARY_ADJUST_THRESHOLD",
"PRIMARY_ADJUST_INC_MULT",
"PRIMARY_ADJUST_DEC_MULT",
"CONTROL_METHOD_THRESHOLD",
"AVG_CORR_NOX_THRESHOLD",
"AVG_SMOKE_ADJUST_TIME",
"PRIMARY_ADJUST_SWITCH",
"SECONDARY_ADJUST_SWITCH",
"AVG_PRED_NOX_ADJUST_TIME",
"ADVANCE_TIME",
"BLOWBACK_TIME",
"EFFICIENCY",
"EFFICIENCY_ADJUST_INTERVAL",
"EFFICIENCY_ADJUST_ADVANCE_TIME",
"AVG_EFFICIENCY_ADJUST_TIME",
"EFFICIENCY_ADJUST_THRESHOLD",
"EFFICIENCY_ADJUST_UPPER",
"EFFICIENCY_ADJUST_LOWER",
"CORR_SLOPE_2",
"OUT_NH3_ADJUST_SWITCH",
"OUT_NH3_ADJUST_THRESHOLD",
"OUT_NH3_ADJUST_PCT"
],
"PID控制": [
"PID_VALVE_IS_AUTO",
"PID_VALVE_LOWER",
"PID_VALVE_UPPER",
"PID_VALVE_MANUAL",
"PID_VALVE_AUTO_ADDRESS",
"PID_VALVE_READ_ADDRESS",
"PID_VALVE_MANUAL_ADDRESS",
"PID_VALVE_FEEDBACK_ADDRESS"
],
"MQTT配置": [
"MQTT_HOST",
"MQTT_PORT",
"MQTT_USERNAME",
"MQTT_PASSWORD",
"MQTT_TOPIC",
"MQTT_CLIENT_ID"
],
"其他配置": [
"VALVE_UPPER",
"VALVE_LOWER",
"MODEL_CHANNEL",
"CLEAN_UPPER",
"CLEAN_LOWER",
"ALARM_WEBHOOK",
"ABS_DIFF_THRESHOLD"
],
"未分类": [
"EMERGENCY_ADJUST_INC_MULT",
"USED_RAM_LIMIT"
]
},
"display_names": {
"ABS_DIFF_THRESHOLD": "两个出口NOx绝对值误差阈值"
}, },
"display_names": {},
"tooltips": {}, "tooltips": {},
"field_types": {}, "field_types": {},
"hidden": [] "field_decimals": {},
"hidden": [],
"validations": {}
} }