diff --git a/data/database.db b/data/database.db index 7da05a0..770824a 100644 Binary files a/data/database.db and b/data/database.db differ diff --git a/database/__pycache__/db_manager.cpython-313.pyc b/database/__pycache__/db_manager.cpython-313.pyc index d41ab2b..e502e4d 100644 Binary files a/database/__pycache__/db_manager.cpython-313.pyc and b/database/__pycache__/db_manager.cpython-313.pyc differ diff --git a/database/__pycache__/models.cpython-313.pyc b/database/__pycache__/models.cpython-313.pyc index 3abf0a6..b3eeef5 100644 Binary files a/database/__pycache__/models.cpython-313.pyc and b/database/__pycache__/models.cpython-313.pyc differ diff --git a/database/database_manager.py b/database/database_manager.py new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/database/database_manager.py @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/database/db_manager.py b/database/db_manager.py index d4ba4cd..1f71d8c 100644 --- a/database/db_manager.py +++ b/database/db_manager.py @@ -2,7 +2,7 @@ import sqlite3 from typing import List, Optional, Tuple from pathlib import Path import os -from .models import FilterData, ParamData, ConfigData +from .models import FilterData, ParamData, ConfigData, ProjectData class DatabaseManager: _instance = None @@ -27,15 +27,50 @@ class DatabaseManager: Path(self.db_path).parent.mkdir(parents=True, exist_ok=True) with sqlite3.connect(self.db_path) as conn: - conn.executescript(""" - CREATE TABLE IF NOT EXISTS configs ( + # 首先创建 projects 表(如果不存在) + conn.execute(""" + CREATE TABLE IF NOT EXISTS projects ( id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - channel_id INTEGER NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(name, channel_id) + name TEXT NOT NULL UNIQUE, + description TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); - + """) + + # 检查 configs 表是否存在 + cursor = conn.execute(""" + SELECT name FROM sqlite_master + WHERE type='table' AND name='configs'; + """) + + if cursor.fetchone() is None: + # 如果表不存在,创建新表 + conn.execute(""" + CREATE TABLE configs ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + channel_id INTEGER NOT NULL, + project_id INTEGER, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(name, channel_id, project_id), + FOREIGN KEY (project_id) REFERENCES projects(id) + ); + """) + else: + # 如果表已存在,检查是否需要添加 project_id 列 + cursor = conn.execute("PRAGMA table_info(configs)") + columns = [row[1] for row in cursor.fetchall()] + + if 'project_id' not in columns: + # 添加 project_id 列 + conn.execute(""" + ALTER TABLE configs + ADD COLUMN project_id INTEGER + REFERENCES projects(id); + """) + + # 其他表的创建保持不变 + conn.executescript(""" CREATE TABLE IF NOT EXISTS params ( id INTEGER PRIMARY KEY, config_id INTEGER, @@ -119,12 +154,14 @@ class DatabaseManager: print(f"load_config filters: {filters}") return params, filters - def save_config(self, name: str, channel_id: int, params: ParamData, filters: List[FilterData]) -> int: + def save_config(self, name: str, channel_id: int, params: ParamData, filters: List[FilterData], project_id: Optional[int] = None) -> int: with self.get_connection() as conn: # 检查是否存在相同的配置 cursor = conn.execute( - "SELECT id FROM configs WHERE name = ? AND channel_id = ?", - (name, channel_id) + """SELECT id FROM configs + WHERE name = ? AND channel_id = ? AND + (project_id = ? OR (project_id IS NULL AND ? IS NULL))""", + (name, channel_id, project_id, project_id) ) existing_config = cursor.fetchone() @@ -154,10 +191,10 @@ class DatabaseManager: return config_id else: - # 创建新配置(原有的插入逻辑) + # 创建新配置 cursor = conn.execute( - "INSERT INTO configs (name, channel_id) VALUES (?, ?)", - (name, channel_id) + "INSERT INTO configs (name, channel_id, project_id) VALUES (?, ?, ?)", + (name, channel_id, project_id) ) config_id = cursor.lastrowid @@ -245,3 +282,43 @@ class DatabaseManager: # 保存默认配置 self.save_config("Default Config", 1, default_params, default_filters) + + def add_project(self, name: str, description: str) -> int: + with self.get_connection() as conn: + cursor = conn.execute( + "INSERT INTO projects (name, description) VALUES (?, ?)", + (name, description) + ) + conn.commit() + return cursor.lastrowid + + def get_all_projects(self) -> List[ProjectData]: + with self.get_connection() as conn: + cursor = conn.execute( + "SELECT id, name, description, created_at FROM projects" + ) + return [ProjectData(*row) for row in cursor.fetchall()] + + def update_project_name(self, project_id: int, new_name: str) -> bool: + """更新项目名称""" + try: + with self.get_connection() as conn: + cursor = conn.execute( + "UPDATE projects SET name = ? WHERE id = ?", + (new_name, project_id) + ) + conn.commit() + return cursor.rowcount > 0 + except sqlite3.IntegrityError: + # 项目名已存在 + return False + + def get_project_configs(self, project_id: int) -> List[ConfigData]: + """获取项目关联的所有配置""" + with self.get_connection() as conn: + cursor = conn.execute( + """SELECT id, name, channel_id, created_at, project_id + FROM configs WHERE project_id = ?""", + (project_id,) + ) + return [ConfigData(*row) for row in cursor.fetchall()] diff --git a/database/models.py b/database/models.py index 8ceb411..cb8e8ab 100644 --- a/database/models.py +++ b/database/models.py @@ -30,3 +30,12 @@ class ConfigData: name: str channel_id: int created_at: str + project_id: Optional[int] = None + +@dataclass +class ProjectData: + id: Optional[int] + name: str + description: str + created_at: str = None + configs: List[ConfigData] = None diff --git a/widget_file_list.zip b/widget_file_list.zip deleted file mode 100644 index 7a252b0..0000000 Binary files a/widget_file_list.zip and /dev/null differ diff --git a/widgets/__pycache__/audio_filter_widget.cpython-313.pyc b/widgets/__pycache__/audio_filter_widget.cpython-313.pyc index 67e1155..fe700b8 100644 Binary files a/widgets/__pycache__/audio_filter_widget.cpython-313.pyc and b/widgets/__pycache__/audio_filter_widget.cpython-313.pyc differ diff --git a/widgets/__pycache__/avas_widget.cpython-313.pyc b/widgets/__pycache__/avas_widget.cpython-313.pyc index 5fe4bb4..a3210e0 100644 Binary files a/widgets/__pycache__/avas_widget.cpython-313.pyc and b/widgets/__pycache__/avas_widget.cpython-313.pyc differ diff --git a/widgets/__pycache__/project_dialog.cpython-313.pyc b/widgets/__pycache__/project_dialog.cpython-313.pyc new file mode 100644 index 0000000..e8d14ba Binary files /dev/null and b/widgets/__pycache__/project_dialog.cpython-313.pyc differ diff --git a/widgets/audio_filter_widget.py b/widgets/audio_filter_widget.py index 0abd8f6..4ce89ff 100644 --- a/widgets/audio_filter_widget.py +++ b/widgets/audio_filter_widget.py @@ -3,12 +3,13 @@ from PySide6.QtCore import Qt from widgets.Ui_widget import Ui_Widget from database.db_manager import DatabaseManager from database.models import FilterData, ParamData, ConfigData -from typing import List +from typing import List, Optional class AudioFilterModel: def __init__(self, db_manager: DatabaseManager): self.db_manager = db_manager self.current_config_id: Optional[int] = None + self.current_project_id: Optional[int] = None # 添加当前项目ID self.current_channel_id: int = 1 # 添加当前通道ID self.filters: List[FilterData] = [] self.params: ParamData = ParamData( @@ -38,7 +39,13 @@ class AudioFilterModel: for filter_data in self.filters: print(f"save_config filter_data.channel_id: {filter_data.channel_id}") filter_data.channel_id = self.current_channel_id - return self.db_manager.save_config(name, self.current_channel_id, self.params, self.filters) + return self.db_manager.save_config( + name, + self.current_channel_id, + self.params, + self.filters, + self.current_project_id # 添加项目ID + ) def update_filter(self, index: int, **kwargs): if 0 <= index < len(self.filters): @@ -60,6 +67,10 @@ class AudioFilterModel: if self.current_config_id: self.db_manager.update_params(self.current_config_id, self.params) + def set_project(self, project_id: Optional[int]): + """设置当前项目""" + self.current_project_id = project_id + class FilterTypeDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) @@ -254,15 +265,7 @@ class AudioFilterWidget(QWidget): self.model = AudioFilterModel(self.db_manager) self.model.current_channel_id = channel_id # 设置当前通道ID - # 加载该通道的所有配置 - configs = self.db_manager.get_all_configs() - if configs: - # 获取当前通道的所有配置 - channel_configs = [config for config in configs if config.channel_id == channel_id] - if channel_configs: - # 可以让用户选择要加载哪个配置 - self.show_config_selection_dialog(channel_configs) - + # 移除配置选择相关代码 self.controller = AudioFilterController(self.model, self) self.update_view() @@ -445,31 +448,3 @@ class AudioFilterWidget(QWidget): except ValueError: print("输入的值无效,请输入数字") - def show_config_selection_dialog(self, configs: List[ConfigData]): - dialog = QDialog(self) - dialog.setWindowTitle("选择配置") - layout = QVBoxLayout() - - combo = QComboBox() - for config in configs: - combo.addItem(f"{config.name} (创建于: {config.created_at})", config.id) - - layout.addWidget(QLabel("请选择要加载的配置:")) - layout.addWidget(combo) - - buttons = QHBoxLayout() - ok_button = QPushButton("确定") - cancel_button = QPushButton("取消") - - ok_button.clicked.connect(dialog.accept) - cancel_button.clicked.connect(dialog.reject) - - buttons.addWidget(ok_button) - buttons.addWidget(cancel_button) - layout.addLayout(buttons) - - dialog.setLayout(layout) - - if dialog.exec() == QDialog.Accepted: - selected_config_id = combo.currentData() - self.model.load_config(selected_config_id) diff --git a/widgets/avas_widget.py b/widgets/avas_widget.py index 223f712..dc74783 100644 --- a/widgets/avas_widget.py +++ b/widgets/avas_widget.py @@ -1,10 +1,13 @@ import sys from PySide6.QtWidgets import (QApplication, QWidget, QPushButton, QGridLayout, QVBoxLayout, QHBoxLayout, QCheckBox, QComboBox, - QLabel, QSlider, QFrame, QGroupBox, QListView) + QLabel, QSlider, QFrame, QGroupBox, QListView, QListWidgetItem, QMessageBox) from PySide6.QtCore import Qt, QSize -from PySide6.QtGui import QIcon +from PySide6.QtGui import QIcon, QStandardItemModel, QStandardItem from widgets.audio_filter_widget import AudioFilterWidget +from widgets.project_dialog import AddProjectDialog +import sqlite3 +from database.db_manager import DatabaseManager # 添加这行导入 class ChannelButton(QWidget): def __init__(self, channel_num): @@ -120,9 +123,13 @@ class ChannelButton(QWidget): class AVAS_WIDGET(QWidget): def __init__(self): super().__init__() + # 初始化数据库管理器 + self.db_manager = DatabaseManager() + self.setWindowTitle("AVAS") self.is_panel_visible = True # 添加状态标记 self.setup_ui() + self.setup_connections() def setup_ui(self): # 创建主水平布局 @@ -241,9 +248,9 @@ class AVAS_WIDGET(QWidget): # 添加工具栏按钮 toolbar = QHBoxLayout() - add_btn = QPushButton("添加") - delete_btn = QPushButton("删除") - refresh_btn = QPushButton("刷新") + self.add_btn = QPushButton("添加") + self.delete_btn = QPushButton("删除") + self.refresh_btn = QPushButton("刷新") # 设置按钮样式 button_style = """ @@ -262,13 +269,13 @@ class AVAS_WIDGET(QWidget): background-color: #303030; } """ - add_btn.setStyleSheet(button_style) - delete_btn.setStyleSheet(button_style) - refresh_btn.setStyleSheet(button_style) + self.add_btn.setStyleSheet(button_style) + self.delete_btn.setStyleSheet(button_style) + self.refresh_btn.setStyleSheet(button_style) - toolbar.addWidget(add_btn) - toolbar.addWidget(delete_btn) - toolbar.addWidget(refresh_btn) + toolbar.addWidget(self.add_btn) + toolbar.addWidget(self.delete_btn) + toolbar.addWidget(self.refresh_btn) # 组装面板 layout.addLayout(toolbar) @@ -339,3 +346,47 @@ class AVAS_WIDGET(QWidget): frame.setLayout(layout) return frame + def setup_connections(self): + # 假设添加按钮的变量名是 add_btn + self.add_btn.clicked.connect(self.add_project) + + def add_project(self): + dialog = AddProjectDialog(self) + if dialog.exec(): + name, description = dialog.get_project_data() + + # 验证输入 + if not name: + QMessageBox.warning(self, "警告", "项目名称不能为空!") + return + + try: + # 保存到数据库 + project_id = self.db_manager.add_project(name, description) + + # 更新项目列表 + self.update_project_list() + + QMessageBox.information(self, "成功", "项目添加成功!") + + except sqlite3.IntegrityError: + QMessageBox.warning(self, "警告", "项目名称已存在!") + except Exception as e: + QMessageBox.critical(self, "错误", f"添加项目失败:{str(e)}") + + def update_project_list(self): + """更新项目列表显示""" + # 创建新的模型 + model = QStandardItemModel() + self.project_list.setModel(model) + + # 获取所有项目 + projects = self.db_manager.get_all_projects() + + # 创建项目列表项 + for project in projects: + item = QStandardItem(project.name) + item.setData(project.id, Qt.UserRole) # 存储项目ID + item.setToolTip(project.description) # 显示项目描述为提示 + model.appendRow(item) + diff --git a/widgets/project_dialog.py b/widgets/project_dialog.py new file mode 100644 index 0000000..51ec510 --- /dev/null +++ b/widgets/project_dialog.py @@ -0,0 +1,46 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit, QPushButton, QMessageBox +from PySide6.QtCore import Qt +from typing import Tuple + +class AddProjectDialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + self.setup_ui() + + def setup_ui(self): + self.setWindowTitle("添加项目") + layout = QVBoxLayout() + + # 项目名称输入 + self.name_label = QLabel("项目名称:") + self.name_edit = QLineEdit() + self.name_edit.setPlaceholderText("请输入项目名称") + + # 项目描述输入 + self.desc_label = QLabel("项目描述:") + self.desc_edit = QTextEdit() + self.desc_edit.setPlaceholderText("请输入项目描述") + + # 按钮 + self.btn_layout = QHBoxLayout() + self.ok_btn = QPushButton("确定") + self.cancel_btn = QPushButton("取消") + + self.btn_layout.addWidget(self.ok_btn) + self.btn_layout.addWidget(self.cancel_btn) + + # 添加到主布局 + layout.addWidget(self.name_label) + layout.addWidget(self.name_edit) + layout.addWidget(self.desc_label) + layout.addWidget(self.desc_edit) + layout.addLayout(self.btn_layout) + + self.setLayout(layout) + + # 连接信号 + self.ok_btn.clicked.connect(self.accept) + self.cancel_btn.clicked.connect(self.reject) + + def get_project_data(self) -> Tuple[str, str]: + return self.name_edit.text().strip(), self.desc_edit.toPlainText().strip() \ No newline at end of file