#include "databasecontroller.h" #include #include #include // Added for QThread::currentThreadId() #include #include #include #include // Added for QFileInfo // Инициализация статического счетчика int DataBaseController::s_connectionCounter = 0; DataBaseController::DataBaseController(QObject *parent) : QObject(parent) { } DataBaseController::~DataBaseController() { if (m_database.isOpen()) { m_database.close(); } } bool DataBaseController::initializeDatabase(const QString &dbPath, const QString &connectionName) { // Закрываем предыдущее соединение, если оно открыто if (m_database.isOpen()) { m_database.close(); } // Удаляем предыдущее соединение, если оно существует if (!connectionName.isEmpty()) { QSqlDatabase::removeDatabase(connectionName); } // Создаем новое соединение с уникальным именем QString connName = connectionName.isEmpty() ? "default" : connectionName; m_database = QSqlDatabase::addDatabase("QSQLITE", connName); m_database.setDatabaseName(dbPath); if (!m_database.open()) { setLastError("Не удалось открыть базу данных: " + m_database.lastError().text()); return false; } return createTables(); } bool DataBaseController::createTables() { QStringList tables = { "CREATE TABLE IF NOT EXISTS variants (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " name TEXT UNIQUE NOT NULL" ")", "CREATE TABLE IF NOT EXISTS components (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " designator TEXT UNIQUE NOT NULL" ")", "CREATE TABLE IF NOT EXISTS component_properties (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " component_id INTEGER NOT NULL," " property_name TEXT NOT NULL," " property_value TEXT," " FOREIGN KEY(component_id) REFERENCES components(id) ON DELETE CASCADE," " UNIQUE(component_id, property_name)" ")", "CREATE TABLE IF NOT EXISTS component_variants (" " component_id INTEGER NOT NULL," " variant_id INTEGER NOT NULL," " is_fitted BOOLEAN DEFAULT 1," " PRIMARY KEY(component_id, variant_id)," " FOREIGN KEY(component_id) REFERENCES components(id) ON DELETE CASCADE," " FOREIGN KEY(variant_id) REFERENCES variants(id) ON DELETE CASCADE" ")", "CREATE TABLE IF NOT EXISTS variant_properties (" " component_id INTEGER NOT NULL," " variant_id INTEGER NOT NULL," " property_name TEXT NOT NULL," " property_value TEXT," " PRIMARY KEY(component_id, variant_id, property_name)," " FOREIGN KEY(component_id) REFERENCES components(id) ON DELETE CASCADE," " FOREIGN KEY(variant_id) REFERENCES variants(id) ON DELETE CASCADE" ")", "CREATE TABLE IF NOT EXISTS project_params (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " name TEXT UNIQUE NOT NULL," " value TEXT" ")", "CREATE TABLE IF NOT EXISTS project_settings (" " key TEXT PRIMARY KEY," " value TEXT" ")", "CREATE TABLE IF NOT EXISTS designator_mappings (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " designator TEXT UNIQUE NOT NULL," " singular_name TEXT NOT NULL," " plural_name TEXT NOT NULL," " is_custom BOOLEAN DEFAULT 0" ")", "CREATE TABLE IF NOT EXISTS title_inscriptions (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " project_name TEXT NOT NULL," " field_number INTEGER NOT NULL," " field_value TEXT," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP," " UNIQUE(project_name, field_number)" ")", "CREATE TABLE IF NOT EXISTS perechen_rows (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " project_name TEXT NOT NULL," " row_order INTEGER NOT NULL," " position_value TEXT," " designation_value TEXT," " quantity_value TEXT," " note_value TEXT," " is_header BOOLEAN DEFAULT 0," " is_empty BOOLEAN DEFAULT 0," " position_is_auto BOOLEAN DEFAULT 0," " designation_is_auto BOOLEAN DEFAULT 0," " quantity_is_auto BOOLEAN DEFAULT 0," " note_is_auto BOOLEAN DEFAULT 0," " cell_stretches TEXT," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP" ")", "CREATE TABLE IF NOT EXISTS specification_pcb_rows (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " project_name TEXT NOT NULL," " row_order INTEGER NOT NULL," " format_value TEXT," " zone_value TEXT," " position_value TEXT," " designation_value TEXT," " name_value TEXT," " quantity_value TEXT," " note_value TEXT," " is_header BOOLEAN DEFAULT 0," " is_empty BOOLEAN DEFAULT 0," " format_is_auto BOOLEAN DEFAULT 0," " zone_is_auto BOOLEAN DEFAULT 0," " position_is_auto BOOLEAN DEFAULT 0," " designation_is_auto BOOLEAN DEFAULT 0," " name_is_auto BOOLEAN DEFAULT 0," " quantity_is_auto BOOLEAN DEFAULT 0," " note_is_auto BOOLEAN DEFAULT 0," " cell_stretches TEXT," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP" ")", "CREATE TABLE IF NOT EXISTS specification_rows (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " project_name TEXT NOT NULL," " row_order INTEGER NOT NULL," " format_value TEXT," " zone_value TEXT," " position_value TEXT," " designation_value TEXT," " name_value TEXT," " quantity_value TEXT," " note_value TEXT," " is_header BOOLEAN DEFAULT 0," " is_empty BOOLEAN DEFAULT 0," " format_is_auto BOOLEAN DEFAULT 0," " zone_is_auto BOOLEAN DEFAULT 0," " position_is_auto BOOLEAN DEFAULT 0," " designation_is_auto BOOLEAN DEFAULT 0," " name_is_auto BOOLEAN DEFAULT 0," " quantity_is_auto BOOLEAN DEFAULT 0," " note_is_auto BOOLEAN DEFAULT 0," " cell_stretches TEXT," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP" ")", "CREATE TABLE IF NOT EXISTS vedomost_rows (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " project_name TEXT NOT NULL," " row_order INTEGER NOT NULL," " name_value TEXT," " product_code_value TEXT," " document_code_value TEXT," " supplier_value TEXT," " where_used_value TEXT," " quantity_per_item_value TEXT," " quantity_in_set_value TEXT," " quantity_for_reg_value TEXT," " total_quantity_value TEXT," " note_value TEXT," " is_header BOOLEAN DEFAULT 0," " is_empty BOOLEAN DEFAULT 0," " name_is_auto BOOLEAN DEFAULT 0," " product_code_is_auto BOOLEAN DEFAULT 0," " document_code_is_auto BOOLEAN DEFAULT 0," " supplier_is_auto BOOLEAN DEFAULT 0," " where_used_is_auto BOOLEAN DEFAULT 0," " quantity_per_item_is_auto BOOLEAN DEFAULT 0," " quantity_in_set_is_auto BOOLEAN DEFAULT 0," " quantity_for_reg_is_auto BOOLEAN DEFAULT 0," " total_quantity_is_auto BOOLEAN DEFAULT 0," " note_is_auto BOOLEAN DEFAULT 0," " row_number INTEGER DEFAULT 0," " page_number INTEGER DEFAULT 1," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP" ")", "CREATE TABLE IF NOT EXISTS simple_list_rows (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " project_name TEXT NOT NULL," " row_order INTEGER NOT NULL," " designator_value TEXT," " name_value TEXT," " quantity_value TEXT," " is_empty BOOLEAN DEFAULT 0," " designator_is_auto BOOLEAN DEFAULT 0," " name_is_auto BOOLEAN DEFAULT 0," " quantity_is_auto BOOLEAN DEFAULT 0," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP" ")", "CREATE TABLE IF NOT EXISTS pcb_data (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " layer_count INTEGER DEFAULT 0," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP" ")", "CREATE TABLE IF NOT EXISTS diel_materials (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " pcb_id INTEGER NOT NULL," " name TEXT NOT NULL," " value TEXT," " height REAL DEFAULT 0.0," " diel_type INTEGER DEFAULT 0," " layer_number INTEGER NOT NULL," " created_at DATETIME DEFAULT CURRENT_TIMESTAMP," " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP," " FOREIGN KEY(pcb_id) REFERENCES pcb_data(id) ON DELETE CASCADE," " UNIQUE(pcb_id, layer_number)" ")" }; for (const QString &tableQuery : tables) { if (!executeQuery(tableQuery)) { return false; } } // Миграция: добавляем поле cell_stretches в существующие таблицы, если его нет migrateAddCellStretchesColumn(); return true; } void DataBaseController::migrateAddCellStretchesColumn() { qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Проверяем наличие поля cell_stretches"; // Список таблиц, в которые нужно добавить поле cell_stretches QStringList tables = {"perechen_rows", "specification_pcb_rows", "specification_rows", "vedomost_rows"}; for (const QString &tableName : tables) { // Проверяем, существует ли колонка cell_stretches QSqlQuery checkQuery = prepareQuery( QString("PRAGMA table_info(%1)").arg(tableName) ); bool columnExists = false; if (checkQuery.exec()) { while (checkQuery.next()) { QString columnName = checkQuery.value(1).toString(); if (columnName == "cell_stretches") { columnExists = true; break; } } } if (!columnExists) { qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Добавляем поле cell_stretches в таблицу" << tableName; QSqlQuery alterQuery = prepareQuery( QString("ALTER TABLE %1 ADD COLUMN cell_stretches TEXT").arg(tableName) ); if (!alterQuery.exec()) { qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Ошибка добавления колонки в" << tableName << ":" << alterQuery.lastError().text(); } else { qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Поле cell_stretches успешно добавлено в" << tableName; } } else { qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Поле cell_stretches уже существует в" << tableName; } } } int DataBaseController::addVariant(const QString &name) { QSqlQuery query = prepareQuery("INSERT INTO variants (name) VALUES (?)"); query.addBindValue(name); if (!query.exec()) { setLastError("Ошибка добавления варианта: " + query.lastError().text()); return -1; } return query.lastInsertId().toInt(); } bool DataBaseController::removeVariant(int variantId) { QSqlQuery query = prepareQuery("DELETE FROM variants WHERE id = ?"); query.addBindValue(variantId); if (!query.exec()) { setLastError("Ошибка удаления варианта: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QList DataBaseController::getAllVariants() { QList variants; QSqlQuery query = prepareQuery("SELECT id, name FROM variants"); if (query.exec()) { while (query.next()) { VariantData variant; variant.id = query.value(0).toInt(); variant.name = query.value(1).toString(); variants << variant; } } return variants; } int DataBaseController::getVariantId(const QString &name) { QSqlQuery query = prepareQuery("SELECT id FROM variants WHERE name = ?"); query.addBindValue(name); if (query.exec() && query.next()) { return query.value(0).toInt(); } return -1; } int DataBaseController::addComponent(const QString &designator) { QSqlQuery query = prepareQuery("INSERT INTO components (designator) VALUES (?)"); query.addBindValue(designator); if (!query.exec()) { setLastError("Ошибка добавления компонента: " + query.lastError().text()); return -1; } return query.lastInsertId().toInt(); } bool DataBaseController::removeComponent(int componentId) { QSqlQuery query = prepareQuery("DELETE FROM components WHERE id = ?"); query.addBindValue(componentId); if (!query.exec()) { setLastError("Ошибка удаления компонента: " + query.lastError().text()); return false; } emit dataChanged(); return true; } bool DataBaseController::updateComponentDesignator(int componentId, const QString &designator) { QSqlQuery query = prepareQuery("UPDATE components SET designator = ? WHERE id = ?"); query.addBindValue(designator); query.addBindValue(componentId); return query.exec(); } QList DataBaseController::getAllComponents() { QList components; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return components; } QSqlQuery query = prepareQuery("SELECT id, designator FROM components ORDER BY designator"); if (!query.exec()) { setLastError("Ошибка получения компонентов: " + query.lastError().text()); return components; } while (query.next()) { ComponentData component; component.id = query.value(0).toInt(); component.designator = query.value(1).toString(); component.baseProperties = getComponentProperties(component.id); // Получаем варианты для компонента QSqlQuery variantQuery = prepareQuery( "SELECT v.id, v.name, cv.is_fitted FROM variants v " "JOIN component_variants cv ON v.id = cv.variant_id " "WHERE cv.component_id = ?" ); variantQuery.addBindValue(component.id); if (variantQuery.exec()) { while (variantQuery.next()) { int variantId = variantQuery.value(0).toInt(); QString variantName = variantQuery.value(1).toString(); bool fitted = variantQuery.value(2).toBool(); component.variantFitted[variantName] = fitted; // Получаем свойства варианта QSqlQuery propQuery = prepareQuery( "SELECT property_name, property_value FROM variant_properties " "WHERE component_id = ? AND variant_id = ?" ); propQuery.addBindValue(component.id); propQuery.addBindValue(variantId); if (propQuery.exec()) { QMap variantProps; while (propQuery.next()) { QString propName = propQuery.value(0).toString(); QString propValue = propQuery.value(1).toString(); variantProps[propName] = propValue; } component.variantProperties[variantName] = variantProps; } else { } } } else { } components.append(component); } return components; } ComponentData DataBaseController::getComponent(int componentId) { ComponentData component; QSqlQuery query = prepareQuery("SELECT id, designator FROM components WHERE id = ?"); query.addBindValue(componentId); if (!query.exec() || !query.next()) { return component; } component.id = query.value(0).toInt(); component.designator = query.value(1).toString(); component.baseProperties = getComponentProperties(componentId); // Получаем варианты для компонента QSqlQuery variantQuery = prepareQuery( "SELECT v.id, v.name, cv.is_fitted FROM variants v " "JOIN component_variants cv ON v.id = cv.variant_id " "WHERE cv.component_id = ?" ); variantQuery.addBindValue(componentId); if (variantQuery.exec()) { while (variantQuery.next()) { int variantId = variantQuery.value(0).toInt(); QString variantName = variantQuery.value(1).toString(); bool fitted = variantQuery.value(2).toBool(); component.variantFitted[variantName] = fitted; // Получаем свойства варианта QSqlQuery propQuery = prepareQuery( "SELECT property_name, property_value FROM variant_properties " "WHERE component_id = ? AND variant_id = ?" ); propQuery.addBindValue(componentId); propQuery.addBindValue(variantId); if (propQuery.exec()) { QMap variantProps; while (propQuery.next()) { QString propName = propQuery.value(0).toString(); QString propValue = propQuery.value(1).toString(); variantProps[propName] = propValue; } component.variantProperties[variantName] = variantProps; } } } return component; } ComponentData DataBaseController::getComponent(const QString &designator) { ComponentData component; QSqlQuery query = prepareQuery("SELECT id, designator FROM components WHERE designator = ?"); query.addBindValue(designator); if (!query.exec() || !query.next()) { return component; } component.id = query.value(0).toInt(); component.designator = query.value(1).toString(); component.baseProperties = getComponentProperties(component.id); // Получаем варианты для компонента QSqlQuery variantQuery = prepareQuery( "SELECT v.id, v.name, cv.is_fitted FROM variants v " "JOIN component_variants cv ON v.id = cv.variant_id " "WHERE cv.component_id = ?" ); variantQuery.addBindValue(component.id); if (variantQuery.exec()) { while (variantQuery.next()) { int variantId = variantQuery.value(0).toInt(); QString variantName = variantQuery.value(1).toString(); bool fitted = variantQuery.value(2).toBool(); component.variantFitted[variantName] = fitted; // Получаем свойства варианта QSqlQuery propQuery = prepareQuery( "SELECT property_name, property_value FROM variant_properties " "WHERE component_id = ? AND variant_id = ?" ); propQuery.addBindValue(component.id); propQuery.addBindValue(variantId); if (propQuery.exec()) { QMap variantProps; while (propQuery.next()) { QString propName = propQuery.value(0).toString(); QString propValue = propQuery.value(1).toString(); variantProps[propName] = propValue; } component.variantProperties[variantName] = variantProps; } } } return component; } bool DataBaseController::saveComponents(const QList &components) { // Очищаем существующие компоненты if (!executeQuery("DELETE FROM components")) { return false; } // Добавляем новые компоненты for (const auto& component : components) { int componentId = addComponent(component.designator); if (componentId == -1) { return false; } // Сохраняем свойства for (auto it = component.baseProperties.begin(); it != component.baseProperties.end(); ++it) { if (!setComponentProperty(componentId, it.key(), it.value())) { return false; } } // Сохраняем варианты for (auto it = component.variantFitted.begin(); it != component.variantFitted.end(); ++it) { int variantId = getVariantId(it.key()); if (variantId != -1) { setComponentVariantFitted(componentId, variantId, it.value()); } } // Сохраняем свойства вариантов for (auto it = component.variantProperties.begin(); it != component.variantProperties.end(); ++it) { int variantId = getVariantId(it.key()); if (variantId != -1) { for (auto propIt = it.value().begin(); propIt != it.value().end(); ++propIt) { setVariantProperty(componentId, variantId, propIt.key(), propIt.value()); } } } } return true; } QMap DataBaseController::getComponentProperties(int componentId) { QMap properties; QSqlQuery query = prepareQuery( "SELECT property_name, property_value FROM component_properties WHERE component_id = ?" ); query.addBindValue(componentId); if (!query.exec()) { setLastError("Ошибка получения свойств компонента: " + query.lastError().text()); return properties; } while (query.next()) { QString propertyName = query.value(0).toString(); QString propertyValue = query.value(1).toString(); properties[propertyName] = propertyValue; } return properties; } bool DataBaseController::setComponentProperty(int componentId, const QString &propertyName, const QString &propertyValue) { QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO component_properties (component_id, property_name, property_value) VALUES (?, ?, ?)"); query.addBindValue(componentId); query.addBindValue(propertyName); query.addBindValue(propertyValue); return query.exec(); } bool DataBaseController::removeComponentProperty(int componentId, const QString &propertyName) { QSqlQuery query = prepareQuery("DELETE FROM component_properties WHERE component_id = ? AND property_name = ?"); query.addBindValue(componentId); query.addBindValue(propertyName); return query.exec(); } bool DataBaseController::setComponentVariantFitted(int componentId, int variantId, bool fitted) { QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO component_variants (component_id, variant_id, is_fitted) VALUES (?, ?, ?)"); query.addBindValue(componentId); query.addBindValue(variantId); query.addBindValue(fitted); return query.exec(); } bool DataBaseController::setVariantProperty(int componentId, int variantId, const QString &propertyName, const QString &propertyValue) { QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO variant_properties (component_id, variant_id, property_name, property_value) VALUES (?, ?, ?, ?)"); query.addBindValue(componentId); query.addBindValue(variantId); query.addBindValue(propertyName); query.addBindValue(propertyValue); return query.exec(); } bool DataBaseController::removeVariantProperty(int componentId, int variantId, const QString &propertyName) { QSqlQuery query = prepareQuery( "DELETE FROM variant_properties WHERE component_id = ? AND variant_id = ? AND property_name = ?" ); query.addBindValue(componentId); query.addBindValue(variantId); query.addBindValue(propertyName); if (!query.exec()) { setLastError("Ошибка удаления свойства варианта: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QList DataBaseController::getComponentsForVariant(int variantId) { QList components; QSqlQuery query = prepareQuery( "SELECT c.id, c.designator, cv.is_fitted FROM components c " "JOIN component_variants cv ON c.id = cv.component_id " "WHERE cv.variant_id = ? " "ORDER BY c.designator" ); query.addBindValue(variantId); if (!query.exec()) { setLastError("Ошибка получения компонентов для варианта: " + query.lastError().text()); return components; } while (query.next()) { ComponentData component; component.id = query.value(0).toInt(); component.designator = query.value(1).toString(); bool fitted = query.value(2).toBool(); // Получаем базовые свойства component.baseProperties = getComponentProperties(component.id); // Получаем ВСЕ варианты для этого компонента QSqlQuery allVariantsQuery = prepareQuery( "SELECT v.id, v.name, cv.is_fitted FROM variants v " "JOIN component_variants cv ON v.id = cv.variant_id " "WHERE cv.component_id = ?" ); allVariantsQuery.addBindValue(component.id); if (allVariantsQuery.exec()) { while (allVariantsQuery.next()) { int currentVariantId = allVariantsQuery.value(0).toInt(); QString currentVariantName = allVariantsQuery.value(1).toString(); bool currentFitted = allVariantsQuery.value(2).toBool(); component.variantFitted[currentVariantName] = currentFitted; // Получаем свойства для текущего варианта QSqlQuery propQuery = prepareQuery( "SELECT property_name, property_value FROM variant_properties " "WHERE component_id = ? AND variant_id = ?" ); propQuery.addBindValue(component.id); propQuery.addBindValue(currentVariantId); if (propQuery.exec()) { QMap variantProps; while (propQuery.next()) { QString propName = propQuery.value(0).toString(); QString propValue = propQuery.value(1).toString(); variantProps[propName] = propValue; } component.variantProperties[currentVariantName] = variantProps; } } } components.append(component); } return components; } QList DataBaseController::getComponentsForVariant(const QString &variantName) { int variantId = getVariantId(variantName); if (variantId == -1) { setLastError("Вариант не найден: " + variantName); return QList(); } return getComponentsForVariant(variantId); } QStringList DataBaseController::getAllPropertyNames() { QStringList propertyNames; QSqlQuery query = prepareQuery("SELECT DISTINCT property_name FROM component_properties"); if (query.exec()) { while (query.next()) { propertyNames << query.value(0).toString(); } } return propertyNames; } int DataBaseController::addProjectParam(const QString &name, const QString &value) { QSqlQuery query = prepareQuery("INSERT INTO project_params (name, value) VALUES (?, ?)"); query.addBindValue(name); query.addBindValue(value); if (!query.exec()) { setLastError("Ошибка добавления параметра проекта: " + query.lastError().text()); return -1; } emit dataChanged(); return query.lastInsertId().toInt(); } bool DataBaseController::updateProjectParam(int paramId, const QString &name, const QString &value) { QSqlQuery query = prepareQuery("UPDATE project_params SET name = ?, value = ? WHERE id = ?"); query.addBindValue(name); query.addBindValue(value); query.addBindValue(paramId); if (!query.exec()) { setLastError("Ошибка обновления параметра проекта: " + query.lastError().text()); return false; } emit dataChanged(); return true; } bool DataBaseController::removeProjectParam(int paramId) { QSqlQuery query = prepareQuery("DELETE FROM project_params WHERE id = ?"); query.addBindValue(paramId); if (!query.exec()) { setLastError("Ошибка удаления параметра проекта: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QList DataBaseController::getAllProjectParams() { QList params; if (!m_database.isOpen()) { setLastError("База данных не открыта"); qDebug() << "DataBaseController: База данных не открыта для загрузки параметров проекта"; return params; } qDebug() << "DataBaseController: Загружаем параметры проекта из БД"; QSqlQuery query = prepareQuery("SELECT id, name, value FROM project_params ORDER BY name"); if (!query.exec()) { setLastError("Ошибка получения параметров проекта: " + query.lastError().text()); qDebug() << "DataBaseController: Ошибка запроса параметров проекта:" << query.lastError().text(); return params; } while (query.next()) { ProjectParamData param; param.id = query.value(0).toInt(); param.name = query.value(1).toString(); param.value = query.value(2).toString(); params.append(param); qDebug() << "DataBaseController: Загружен параметр проекта:" << param.name << "=" << param.value; } qDebug() << "DataBaseController: Всего загружено параметров проекта:" << params.size(); return params; } ProjectParamData DataBaseController::getProjectParam(int paramId) { ProjectParamData param; QSqlQuery query = prepareQuery("SELECT id, name, value FROM project_params WHERE id = ?"); query.addBindValue(paramId); if (!query.exec() || !query.next()) { return param; } param.id = query.value(0).toInt(); param.name = query.value(1).toString(); param.value = query.value(2).toString(); return param; } bool DataBaseController::setProjectParam(const QString &name, const QString &value) { // Проверяем, существует ли уже параметр с таким именем QSqlQuery checkQuery = prepareQuery("SELECT id FROM project_params WHERE name = ?"); checkQuery.addBindValue(name); if (checkQuery.exec() && checkQuery.next()) { // Обновляем существующий параметр int paramId = checkQuery.value(0).toInt(); return updateProjectParam(paramId, name, value); } else { // Добавляем новый параметр return addProjectParam(name, value) != -1; } } bool DataBaseController::isDatabaseOpen() const { return m_database.isOpen(); } QString DataBaseController::lastError() const { return m_lastError; } QString DataBaseController::getDatabasePath() const { return m_database.databaseName(); } bool DataBaseController::executeQuery(const QString &query, const QVariantMap ¶ms) { QSqlQuery sqlQuery = prepareQuery(query); for (auto it = params.begin(); it != params.end(); ++it) { sqlQuery.addBindValue(it.value()); } if (!sqlQuery.exec()) { setLastError("Ошибка выполнения запроса: " + sqlQuery.lastError().text()); return false; } return true; } QSqlQuery DataBaseController::prepareQuery(const QString &query) { QSqlQuery sqlQuery(m_database); sqlQuery.prepare(query); return sqlQuery; } void DataBaseController::setLastError(const QString &error) { m_lastError = error; emit databaseError(error); } void DataBaseController::clearAllData() { QSqlQuery query(m_database); query.exec("DELETE FROM component_properties"); query.exec("DELETE FROM component_variants"); query.exec("DELETE FROM variant_properties"); query.exec("DELETE FROM project_params"); query.exec("DELETE FROM project_settings"); // Added for project settings query.exec("DELETE FROM diel_materials"); // Added for PCB materials query.exec("DELETE FROM pcb_data"); // Added for PCB data query.exec("DELETE FROM components"); query.exec("DELETE FROM variants"); } // Пакетная вставка компонентов (оптимизация) bool DataBaseController::beginTransaction() { QSqlQuery query(m_database); return query.exec("BEGIN TRANSACTION"); } bool DataBaseController::commitTransaction() { QSqlQuery query(m_database); return query.exec("COMMIT"); } bool DataBaseController::rollbackTransaction() { QSqlQuery query(m_database); return query.exec("ROLLBACK"); } bool DataBaseController::addComponentBatch(const QString &designator, const QMap &properties) { // Добавляем компонент QSqlQuery query(m_database); query.prepare("INSERT INTO components (designator) VALUES (?)"); query.addBindValue(designator); if (!query.exec()) { setLastError("Ошибка добавления компонента: " + query.lastError().text()); return false; } int componentId = query.lastInsertId().toInt(); // Добавляем свойства пакетно if (!properties.isEmpty()) { return addComponentPropertiesBatch(componentId, properties); } return true; } bool DataBaseController::addComponentPropertiesBatch(int componentId, const QMap &properties) { if (properties.isEmpty()) { return true; } // Подготавливаем пакетный INSERT QStringList placeholders; QVariantList values; for (auto it = properties.begin(); it != properties.end(); ++it) { placeholders.append("(?, ?, ?)"); values.append(componentId); values.append(it.key()); values.append(it.value()); } QString queryStr = QString("INSERT INTO component_properties (component_id, property_name, property_value) VALUES %1") .arg(placeholders.join(", ")); QSqlQuery query(m_database); query.prepare(queryStr); for (const QVariant &value : values) { query.addBindValue(value); } if (!query.exec()) { setLastError("Ошибка пакетной вставки свойств: " + query.lastError().text()); return false; } return true; } bool DataBaseController::addComponentVariantsBatch(int componentId, const QStringList &variantNames) { if (variantNames.isEmpty()) { return true; } // Получаем ID вариантов QList variantIds; for (const QString &variantName : variantNames) { int variantId = getVariantId(variantName); if (variantId != -1) { variantIds.append(variantId); } } if (variantIds.isEmpty()) { return true; } // Подготавливаем пакетный INSERT QStringList placeholders; QVariantList values; for (int variantId : variantIds) { placeholders.append("(?, ?, 1)"); values.append(componentId); values.append(variantId); } QString queryStr = QString("INSERT INTO component_variants (component_id, variant_id, is_fitted) VALUES %1") .arg(placeholders.join(", ")); QSqlQuery query(m_database); query.prepare(queryStr); for (const QVariant &value : values) { query.addBindValue(value); } if (!query.exec()) { setLastError("Ошибка пакетной вставки вариантов: " + query.lastError().text()); return false; } return true; } // Методы для работы с настройками проекта bool DataBaseController::setProjectSetting(const QString &key, const QString &value) { QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO project_settings (key, value) VALUES (?, ?)"); query.addBindValue(key); query.addBindValue(value); if (!query.exec()) { setLastError("Ошибка сохранения настройки проекта: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QString DataBaseController::getProjectSetting(const QString &key, const QString &defaultValue) { QSqlQuery query = prepareQuery("SELECT value FROM project_settings WHERE key = ?"); query.addBindValue(key); if (!query.exec()) { setLastError("Ошибка получения настройки проекта: " + query.lastError().text()); return defaultValue; } if (query.next()) { return query.value(0).toString(); } return defaultValue; } bool DataBaseController::setProjectSettingList(const QString &key, const QStringList &value) { // Сохраняем список как JSON строку QJsonArray array; for (const QString &item : value) { array.append(item); } QJsonDocument doc(array); QString jsonString = doc.toJson(QJsonDocument::Compact); return setProjectSetting(key, jsonString); } QStringList DataBaseController::getProjectSettingList(const QString &key, const QStringList &defaultValue) { QString jsonString = getProjectSetting(key, QString()); if (jsonString.isEmpty()) { return defaultValue; } QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8()); if (!doc.isArray()) { return defaultValue; } QStringList result; QJsonArray array = doc.array(); for (const QJsonValue &value : array) { result.append(value.toString()); } return result; } // Методы для работы с маппингами дезигнаторов int DataBaseController::addDesignatorMapping(const QString &designator, const QString &singularName, const QString &pluralName, bool isCustom) { QSqlQuery query = prepareQuery("INSERT INTO designator_mappings (designator, singular_name, plural_name, is_custom) VALUES (?, ?, ?, ?)"); query.addBindValue(designator); query.addBindValue(singularName); query.addBindValue(pluralName); query.addBindValue(isCustom); if (!query.exec()) { setLastError("Ошибка добавления маппинга дезигнатора: " + query.lastError().text()); return -1; } emit dataChanged(); return query.lastInsertId().toInt(); } bool DataBaseController::updateDesignatorMapping(int mappingId, const QString &designator, const QString &singularName, const QString &pluralName, bool isCustom) { QSqlQuery query = prepareQuery("UPDATE designator_mappings SET designator = ?, singular_name = ?, plural_name = ?, is_custom = ? WHERE id = ?"); query.addBindValue(designator); query.addBindValue(singularName); query.addBindValue(pluralName); query.addBindValue(isCustom); query.addBindValue(mappingId); if (!query.exec()) { setLastError("Ошибка обновления маппинга дезигнатора: " + query.lastError().text()); return false; } emit dataChanged(); return true; } bool DataBaseController::removeDesignatorMapping(int mappingId) { QSqlQuery query = prepareQuery("DELETE FROM designator_mappings WHERE id = ?"); query.addBindValue(mappingId); if (!query.exec()) { setLastError("Ошибка удаления маппинга дезигнатора: " + query.lastError().text()); return false; } emit dataChanged(); return true; } bool DataBaseController::removeDesignatorMapping(const QString &designator) { QSqlQuery query = prepareQuery("DELETE FROM designator_mappings WHERE designator = ?"); query.addBindValue(designator); if (!query.exec()) { setLastError("Ошибка удаления маппинга дезигнатора: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QList DataBaseController::getAllDesignatorMappings() { QList mappings; QSqlQuery query = prepareQuery("SELECT id, designator, singular_name, plural_name, is_custom FROM designator_mappings ORDER BY designator"); if (!query.exec()) { setLastError("Ошибка получения маппингов дезигнаторов: " + query.lastError().text()); return mappings; } while (query.next()) { DesignatorMappingData mapping; mapping.id = query.value(0).toInt(); mapping.designator = query.value(1).toString(); mapping.singularName = query.value(2).toString(); mapping.pluralName = query.value(3).toString(); mapping.isCustom = query.value(4).toBool(); mappings.append(mapping); } return mappings; } DesignatorMappingData DataBaseController::getDesignatorMapping(int mappingId) { DesignatorMappingData mapping; mapping.id = -1; QSqlQuery query = prepareQuery("SELECT id, designator, singular_name, plural_name, is_custom FROM designator_mappings WHERE id = ?"); query.addBindValue(mappingId); if (!query.exec()) { setLastError("Ошибка получения маппинга дезигнатора: " + query.lastError().text()); return mapping; } if (query.next()) { mapping.id = query.value(0).toInt(); mapping.designator = query.value(1).toString(); mapping.singularName = query.value(2).toString(); mapping.pluralName = query.value(3).toString(); mapping.isCustom = query.value(4).toBool(); } return mapping; } DesignatorMappingData DataBaseController::getDesignatorMapping(const QString &designator) { DesignatorMappingData mapping; mapping.id = -1; QSqlQuery query = prepareQuery("SELECT id, designator, singular_name, plural_name, is_custom FROM designator_mappings WHERE designator = ?"); query.addBindValue(designator); if (!query.exec()) { setLastError("Ошибка получения маппинга дезигнатора: " + query.lastError().text()); return mapping; } if (query.next()) { mapping.id = query.value(0).toInt(); mapping.designator = query.value(1).toString(); mapping.singularName = query.value(2).toString(); mapping.pluralName = query.value(3).toString(); mapping.isCustom = query.value(4).toBool(); } return mapping; } bool DataBaseController::saveDesignatorMappings(const QList &mappings) { // Начинаем транзакцию if (!beginTransaction()) { return false; } // Очищаем все существующие маппинги QSqlQuery clearQuery = prepareQuery("DELETE FROM designator_mappings"); if (!clearQuery.exec()) { setLastError("Ошибка очистки маппингов дезигнаторов: " + clearQuery.lastError().text()); rollbackTransaction(); return false; } // Добавляем новые маппинги for (const auto &mapping : mappings) { QSqlQuery insertQuery = prepareQuery("INSERT INTO designator_mappings (designator, singular_name, plural_name, is_custom) VALUES (?, ?, ?, ?)"); insertQuery.addBindValue(mapping.designator); insertQuery.addBindValue(mapping.singularName); insertQuery.addBindValue(mapping.pluralName); insertQuery.addBindValue(mapping.isCustom); if (!insertQuery.exec()) { setLastError("Ошибка сохранения маппинга дезигнатора: " + insertQuery.lastError().text()); rollbackTransaction(); return false; } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } emit dataChanged(); return true; } bool DataBaseController::clearCustomDesignatorMappings() { QSqlQuery query = prepareQuery("DELETE FROM designator_mappings WHERE is_custom = 1"); if (!query.exec()) { setLastError("Ошибка очистки пользовательских маппингов: " + query.lastError().text()); return false; } emit dataChanged(); return true; } bool DataBaseController::resetDesignatorMappingsToDefaults() { // Сначала очищаем все маппинги QSqlQuery clearQuery = prepareQuery("DELETE FROM designator_mappings"); if (!clearQuery.exec()) { setLastError("Ошибка очистки маппингов дезигнаторов: " + clearQuery.lastError().text()); return false; } // Добавляем значения по умолчанию QList defaultMappings = { {1, "A", "Устройство (общее обозначение)", "Устройства (общее обозначение)", false}, {2, "B", "Преобразователи неэлектрических величин в электрические", "Преобразователи неэлектрических величин в электрические", false}, {3, "C", "Конденсаторы", "Конденсаторы", false}, {4, "D", "Схемы интегральные, микросборки", "Схемы интегральные, микросборки", false}, {5, "E", "Элементы разные", "Элементы разные", false}, {6, "F", "Защитные аппараты, предохранители, разрядники", "Защитные аппараты, предохранители, разрядники", false}, {7, "G", "Генераторы, источники питания", "Генераторы, источники питания", false}, {8, "H", "Устройства индикаторные и сигнальные", "Устройства индикаторные и сигнальные", false}, {9, "K", "Реле", "Реле", false}, {10, "L", "Катушки индуктивности, дроссели", "Катушки индуктивности, дроссели", false}, {11, "M", "Двигатели", "Двигатели", false}, {12, "P", "Приборы измерительные", "Приборы измерительные", false}, {13, "Q", "Выключатели и разъединители в силовых цепях", "Выключатели и разъединители в силовых цепях", false}, {14, "R", "Резисторы", "Резисторы", false}, {15, "S", "Устройства коммутационные в цепях управления, сигнализации и измерительных", "Устройства коммутационные в цепях управления, сигнализации и измерительных", false}, {16, "T", "Трансформаторы, автотрансформаторы", "Трансформаторы, автотрансформаторы", false}, {17, "U", "Преобразователи электрических величин в электрические", "Преобразователи электрических величин в электрические", false}, {18, "V", "Приборы электровакуумные и полупроводниковые", "Приборы электровакуумные и полупроводниковые", false}, {19, "W", "Линии и элементы сверхвысоких частот", "Линии и элементы сверхвысоких частот", false}, {20, "X", "Соединения контактные", "Соединения контактные", false}, {21, "Y", "Устройства механические с электромагнитным приводом", "Устройства механические с электромагнитным приводом", false}, {22, "Z", "Ограничители, устройства оконечные, фильтры", "Ограничители, устройства оконечные, фильтры", false}, {23, "BA", "Громкоговорители", "Громкоговорители", false}, {24, "BB", "Преобразователи неэлектрических величин в электрические", "Преобразователи неэлектрических величин в электрические", false}, {25, "BZ", "Преобразователи неэлектрических величин в электрические", "Преобразователи неэлектрических величин в электрические", false} }; return saveDesignatorMappings(defaultMappings); } // Работа с надписями титульного листа bool DataBaseController::saveTitleInscriptions(const QMap &inscriptions, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::saveTitleInscriptions: Сохраняем надписи для проекта:" << projectName; qDebug() << "DataBaseController::saveTitleInscriptions: Путь к БД:" << m_database.databaseName(); qDebug() << "DataBaseController::saveTitleInscriptions: Количество полей для сохранения:" << inscriptions.size(); // Начинаем транзакцию if (!beginTransaction()) { return false; } // Удаляем существующие записи для данного проекта QSqlQuery deleteQuery = prepareQuery("DELETE FROM title_inscriptions WHERE project_name = ?"); deleteQuery.addBindValue(projectName); if (!deleteQuery.exec()) { setLastError("Ошибка удаления существующих надписей: " + deleteQuery.lastError().text()); qDebug() << "DataBaseController::saveTitleInscriptions: Ошибка удаления:" << deleteQuery.lastError().text(); rollbackTransaction(); return false; } // Добавляем новые записи int savedCount = 0; for (auto it = inscriptions.begin(); it != inscriptions.end(); ++it) { if (!it.value().isEmpty()) { // Сохраняем только непустые значения QSqlQuery insertQuery = prepareQuery( "INSERT INTO title_inscriptions (project_name, field_number, field_value) VALUES (?, ?, ?)" ); insertQuery.addBindValue(projectName); insertQuery.addBindValue(it.key()); insertQuery.addBindValue(it.value()); if (!insertQuery.exec()) { setLastError("Ошибка сохранения надписи: " + insertQuery.lastError().text()); qDebug() << "DataBaseController::saveTitleInscriptions: Ошибка сохранения поля" << it.key() << ":" << insertQuery.lastError().text(); rollbackTransaction(); return false; } savedCount++; qDebug() << "DataBaseController::saveTitleInscriptions: Сохранено поле" << it.key() << "=" << it.value(); } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } qDebug() << "DataBaseController::saveTitleInscriptions: Всего сохранено полей:" << savedCount; emit dataChanged(); return true; } bool DataBaseController::loadTitleInscriptions(QMap &inscriptions, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } inscriptions.clear(); qDebug() << "DataBaseController::loadTitleInscriptions: Загружаем надписи для проекта:" << projectName; qDebug() << "DataBaseController::loadTitleInscriptions: Путь к БД:" << m_database.databaseName(); QSqlQuery query = prepareQuery( "SELECT field_number, field_value FROM title_inscriptions WHERE project_name = ? ORDER BY field_number" ); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка загрузки надписей: " + query.lastError().text()); qDebug() << "DataBaseController::loadTitleInscriptions: Ошибка выполнения запроса:" << query.lastError().text(); return false; } int count = 0; while (query.next()) { int fieldNumber = query.value(0).toInt(); QString fieldValue = query.value(1).toString(); inscriptions[fieldNumber] = fieldValue; count++; qDebug() << "DataBaseController::loadTitleInscriptions: Загружено поле" << fieldNumber << "=" << fieldValue; } qDebug() << "DataBaseController::loadTitleInscriptions: Всего загружено полей:" << count; return true; } bool DataBaseController::deleteTitleInscriptions(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("DELETE FROM title_inscriptions WHERE project_name = ?"); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка удаления надписей: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QStringList DataBaseController::getAvailableTitleInscriptionProjects() { QStringList projects; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return projects; } QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM title_inscriptions ORDER BY project_name"); if (!query.exec()) { setLastError("Ошибка получения списка проектов: " + query.lastError().text()); return projects; } while (query.next()) { projects << query.value(0).toString(); } return projects; } // Работа с перечнем элементов bool DataBaseController::savePerechenTable(const QByteArray &tableData, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::savePerechenTable: Сохраняем перечень для проекта:" << projectName; // Начинаем транзакцию if (!beginTransaction()) { return false; } // Удаляем существующие записи для данного проекта QSqlQuery deleteQuery = prepareQuery("DELETE FROM perechen_rows WHERE project_name = ?"); deleteQuery.addBindValue(projectName); if (!deleteQuery.exec()) { setLastError("Ошибка удаления существующего перечня: " + deleteQuery.lastError().text()); qDebug() << "DataBaseController::savePerechenTable: Ошибка удаления:" << deleteQuery.lastError().text(); rollbackTransaction(); return false; } // Парсим JSON данные и сохраняем каждую строку отдельно QJsonDocument doc = QJsonDocument::fromJson(tableData); if (!doc.isObject()) { setLastError("Ошибка парсинга JSON данных перечня"); rollbackTransaction(); return false; } QJsonObject root = doc.object(); QJsonArray rowsArray = root["rows"].toArray(); int rowOrder = 0; for (const QJsonValue &value : rowsArray) { QJsonObject rowObj = value.toObject(); // Получаем данные ячеек QJsonObject positionObj = rowObj["position"].toObject(); QJsonObject designationObj = rowObj["designation"].toObject(); QJsonObject quantityObj = rowObj["quantity"].toObject(); QJsonObject noteObj = rowObj["note"].toObject(); // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline) QJsonObject cellSettingsObj; QJsonObject positionCellObj; positionCellObj["stretch"] = positionObj["stretch"].toInt(100); positionCellObj["isHeader"] = positionObj["isHeader"].toBool(false); positionCellObj["isUnderline"] = positionObj["isUnderline"].toBool(false); cellSettingsObj["position"] = positionCellObj; QJsonObject designationCellObj; designationCellObj["stretch"] = designationObj["stretch"].toInt(100); designationCellObj["isHeader"] = designationObj["isHeader"].toBool(false); designationCellObj["isUnderline"] = designationObj["isUnderline"].toBool(false); cellSettingsObj["designation"] = designationCellObj; QJsonObject quantityCellObj; quantityCellObj["stretch"] = quantityObj["stretch"].toInt(100); quantityCellObj["isHeader"] = quantityObj["isHeader"].toBool(false); quantityCellObj["isUnderline"] = quantityObj["isUnderline"].toBool(false); cellSettingsObj["quantity"] = quantityCellObj; QJsonObject noteCellObj; noteCellObj["stretch"] = noteObj["stretch"].toInt(100); noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false); noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false); cellSettingsObj["note"] = noteCellObj; QJsonDocument cellSettingsDoc(cellSettingsObj); QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact); // Добавляем строку в БД QSqlQuery insertQuery = prepareQuery( "INSERT INTO perechen_rows (project_name, row_order, position_value, designation_value, quantity_value, note_value, " "is_header, is_empty, position_is_auto, designation_is_auto, quantity_is_auto, note_is_auto, cell_stretches) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ); insertQuery.addBindValue(projectName); insertQuery.addBindValue(rowOrder++); insertQuery.addBindValue(positionObj["value"].toString()); insertQuery.addBindValue(designationObj["value"].toString()); insertQuery.addBindValue(quantityObj["value"].toString()); insertQuery.addBindValue(noteObj["value"].toString()); insertQuery.addBindValue(rowObj["isHeader"].toBool()); insertQuery.addBindValue(rowObj["isEmpty"].toBool()); insertQuery.addBindValue(positionObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(designationObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(noteObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(cellSettingsJson); if (!insertQuery.exec()) { setLastError("Ошибка сохранения строки перечня: " + insertQuery.lastError().text()); qDebug() << "DataBaseController::savePerechenTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text(); rollbackTransaction(); return false; } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } qDebug() << "DataBaseController::savePerechenTable: Перечень успешно сохранен," << rowsArray.size() << "строк"; emit dataChanged(); return true; } QByteArray DataBaseController::loadPerechenTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QByteArray(); } qDebug() << "DataBaseController::loadPerechenTable: Загружаем перечень для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT row_order, position_value, designation_value, quantity_value, note_value, " "is_header, is_empty, position_is_auto, designation_is_auto, quantity_is_auto, note_is_auto, cell_stretches " "FROM perechen_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка загрузки перечня: " + query.lastError().text()); qDebug() << "DataBaseController::loadPerechenTable: Ошибка выполнения запроса:" << query.lastError().text(); return QByteArray(); } // Создаем JSON структуру для совместимости с PerechenTableModel QJsonObject root; QJsonArray rowsArray; while (query.next()) { QJsonObject rowObj; // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON QJsonObject cellSettingsObj; QString cellSettingsJson = query.value(11).toString(); if (!cellSettingsJson.isEmpty()) { QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8()); if (cellSettingsDoc.isObject()) { cellSettingsObj = cellSettingsDoc.object(); } } // Получаем настройки для каждой ячейки (с fallback на старый формат массива) QJsonObject positionCellObj = cellSettingsObj["position"].toObject(); QJsonObject designationCellObj = cellSettingsObj["designation"].toObject(); QJsonObject quantityCellObj = cellSettingsObj["quantity"].toObject(); QJsonObject noteCellObj = cellSettingsObj["note"].toObject(); // Если старый формат (массив), конвертируем if (positionCellObj.isEmpty() && cellSettingsJson.startsWith("[")) { QJsonDocument oldDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8()); if (oldDoc.isArray()) { QJsonArray stretchesArray = oldDoc.array(); if (stretchesArray.size() > 0) { positionCellObj["stretch"] = stretchesArray[0].toInt(100); positionCellObj["isHeader"] = false; positionCellObj["isUnderline"] = false; } if (stretchesArray.size() > 1) { designationCellObj["stretch"] = stretchesArray[1].toInt(100); designationCellObj["isHeader"] = false; designationCellObj["isUnderline"] = false; } if (stretchesArray.size() > 2) { quantityCellObj["stretch"] = stretchesArray[2].toInt(100); quantityCellObj["isHeader"] = false; quantityCellObj["isUnderline"] = false; } if (stretchesArray.size() > 3) { noteCellObj["stretch"] = stretchesArray[3].toInt(100); noteCellObj["isHeader"] = false; noteCellObj["isUnderline"] = false; } } } // Создаем объекты для каждой ячейки QJsonObject positionObj; positionObj["value"] = query.value(1).toString(); positionObj["rowNumber"] = query.value(0).toInt(); positionObj["pageNumber"] = 1; positionObj["isHeader"] = positionCellObj["isHeader"].toBool(query.value(5).toBool()); positionObj["isAutoGenerated"] = query.value(7).toBool(); positionObj["isEmpty"] = query.value(1).toString().isEmpty(); positionObj["stretch"] = positionCellObj["stretch"].toInt(100); positionObj["isUnderline"] = positionCellObj["isUnderline"].toBool(false); QJsonObject designationObj; designationObj["value"] = query.value(2).toString(); designationObj["rowNumber"] = query.value(0).toInt(); designationObj["pageNumber"] = 1; designationObj["isHeader"] = designationCellObj["isHeader"].toBool(query.value(5).toBool()); designationObj["isAutoGenerated"] = query.value(8).toBool(); designationObj["isEmpty"] = query.value(2).toString().isEmpty(); designationObj["stretch"] = designationCellObj["stretch"].toInt(100); designationObj["isUnderline"] = designationCellObj["isUnderline"].toBool(false); QJsonObject quantityObj; quantityObj["value"] = query.value(3).toString(); quantityObj["rowNumber"] = query.value(0).toInt(); quantityObj["pageNumber"] = 1; quantityObj["isHeader"] = quantityCellObj["isHeader"].toBool(query.value(5).toBool()); quantityObj["isAutoGenerated"] = query.value(9).toBool(); quantityObj["isEmpty"] = query.value(3).toString().isEmpty(); quantityObj["stretch"] = quantityCellObj["stretch"].toInt(100); quantityObj["isUnderline"] = quantityCellObj["isUnderline"].toBool(false); QJsonObject noteObj; noteObj["value"] = query.value(4).toString(); noteObj["rowNumber"] = query.value(0).toInt(); noteObj["pageNumber"] = 1; noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(5).toBool()); noteObj["isAutoGenerated"] = query.value(10).toBool(); noteObj["isEmpty"] = query.value(4).toString().isEmpty(); noteObj["stretch"] = noteCellObj["stretch"].toInt(100); noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false); // Создаем объект строки rowObj["position"] = positionObj; rowObj["designation"] = designationObj; rowObj["quantity"] = quantityObj; rowObj["note"] = noteObj; rowObj["isHeader"] = query.value(5).toBool(); rowObj["isEmpty"] = query.value(6).toBool(); rowObj["rowNumber"] = query.value(0).toInt(); rowObj["pageNumber"] = 1; rowsArray.append(rowObj); } root["rows"] = rowsArray; root["columnMappings"] = QJsonArray::fromStringList(QStringList() << "<Авто>" << "Designator" << "<Пусто>" << "<Пусто>"); root["propertyNames"] = QJsonArray::fromStringList(QStringList() << "Designator"); QJsonDocument doc(root); QByteArray result = doc.toJson(); qDebug() << "DataBaseController::loadPerechenTable: Загружено" << rowsArray.size() << "строк"; return result; } bool DataBaseController::deletePerechenTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("DELETE FROM perechen_rows WHERE project_name = ?"); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка удаления перечня: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QStringList DataBaseController::getAvailablePerechenProjects() { QStringList projects; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return projects; } QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM perechen_rows ORDER BY project_name"); if (!query.exec()) { setLastError("Ошибка получения списка проектов перечня: " + query.lastError().text()); return projects; } while (query.next()) { projects << query.value(0).toString(); } return projects; } QString DataBaseController::getPerechenTableInfo(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QString(); } QString actualProjectName = projectName; if (actualProjectName.isEmpty()) { actualProjectName = QFileInfo(m_database.databaseName()).baseName(); } QSqlQuery query = prepareQuery( "SELECT row_order, position_value, designation_value, quantity_value, note_value, " "is_header, is_empty, position_is_auto, designation_is_auto, quantity_is_auto, note_is_auto " "FROM perechen_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(actualProjectName); if (!query.exec()) { setLastError("Ошибка получения информации о перечне: " + query.lastError().text()); return QString(); } QString info = QString("Информация о перечне для проекта '%1':\n").arg(actualProjectName); info += QString("Всего строк: %1\n\n").arg(query.size()); while (query.next()) { int rowOrder = query.value(0).toInt(); QString position = query.value(1).toString(); QString designation = query.value(2).toString(); QString quantity = query.value(3).toString(); QString note = query.value(4).toString(); bool isHeader = query.value(5).toBool(); bool isEmpty = query.value(6).toBool(); bool posAuto = query.value(7).toBool(); bool desAuto = query.value(8).toBool(); bool qtyAuto = query.value(9).toBool(); bool noteAuto = query.value(10).toBool(); info += QString("Строка %1:\n").arg(rowOrder); info += QString(" Поз.: '%1' (авто: %2)\n").arg(position).arg(posAuto ? "да" : "нет"); info += QString(" Наим.: '%1' (авто: %2)\n").arg(designation).arg(desAuto ? "да" : "нет"); info += QString(" Кол.: '%1' (авто: %2)\n").arg(quantity).arg(qtyAuto ? "да" : "нет"); info += QString(" Прим.: '%1' (авто: %2)\n").arg(note).arg(noteAuto ? "да" : "нет"); info += QString(" Заголовок: %1, Пустая: %2\n\n").arg(isHeader ? "да" : "нет").arg(isEmpty ? "да" : "нет"); } return info; } // Работа со спецификацией платы bool DataBaseController::saveSpecificationPCBTable(const QByteArray &tableData, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::saveSpecificationPCBTable: Сохраняем спецификацию платы для проекта:" << projectName; // Начинаем транзакцию if (!beginTransaction()) { return false; } // Удаляем существующие записи для данного проекта QSqlQuery deleteQuery = prepareQuery("DELETE FROM specification_pcb_rows WHERE project_name = ?"); deleteQuery.addBindValue(projectName); if (!deleteQuery.exec()) { setLastError("Ошибка удаления существующей спецификации платы: " + deleteQuery.lastError().text()); qDebug() << "DataBaseController::saveSpecificationPCBTable: Ошибка удаления:" << deleteQuery.lastError().text(); rollbackTransaction(); return false; } // Парсим JSON данные и сохраняем каждую строку отдельно QJsonDocument doc = QJsonDocument::fromJson(tableData); if (!doc.isObject()) { setLastError("Ошибка парсинга JSON данных спецификации платы"); rollbackTransaction(); return false; } QJsonObject root = doc.object(); QJsonArray rowsArray = root["rows"].toArray(); int rowOrder = 0; for (const QJsonValue &value : rowsArray) { QJsonObject rowObj = value.toObject(); // Получаем данные ячеек для 7 столбцов QJsonObject formatObj = rowObj["format"].toObject(); QJsonObject zoneObj = rowObj["zone"].toObject(); QJsonObject positionObj = rowObj["position"].toObject(); QJsonObject designationObj = rowObj["designation"].toObject(); QJsonObject nameObj = rowObj["name"].toObject(); QJsonObject quantityObj = rowObj["quantity"].toObject(); QJsonObject noteObj = rowObj["note"].toObject(); // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline) QJsonObject cellSettingsObj; QJsonObject formatCellObj; formatCellObj["stretch"] = formatObj["stretch"].toInt(100); formatCellObj["isHeader"] = formatObj["isHeader"].toBool(false); formatCellObj["isUnderline"] = formatObj["isUnderline"].toBool(false); cellSettingsObj["format"] = formatCellObj; QJsonObject zoneCellObj; zoneCellObj["stretch"] = zoneObj["stretch"].toInt(100); zoneCellObj["isHeader"] = zoneObj["isHeader"].toBool(false); zoneCellObj["isUnderline"] = zoneObj["isUnderline"].toBool(false); cellSettingsObj["zone"] = zoneCellObj; QJsonObject positionCellObj; positionCellObj["stretch"] = positionObj["stretch"].toInt(100); positionCellObj["isHeader"] = positionObj["isHeader"].toBool(false); positionCellObj["isUnderline"] = positionObj["isUnderline"].toBool(false); cellSettingsObj["position"] = positionCellObj; QJsonObject designationCellObj; designationCellObj["stretch"] = designationObj["stretch"].toInt(100); designationCellObj["isHeader"] = designationObj["isHeader"].toBool(false); designationCellObj["isUnderline"] = designationObj["isUnderline"].toBool(false); cellSettingsObj["designation"] = designationCellObj; QJsonObject nameCellObj; nameCellObj["stretch"] = nameObj["stretch"].toInt(100); nameCellObj["isHeader"] = nameObj["isHeader"].toBool(false); nameCellObj["isUnderline"] = nameObj["isUnderline"].toBool(false); cellSettingsObj["name"] = nameCellObj; QJsonObject quantityCellObj; quantityCellObj["stretch"] = quantityObj["stretch"].toInt(100); quantityCellObj["isHeader"] = quantityObj["isHeader"].toBool(false); quantityCellObj["isUnderline"] = quantityObj["isUnderline"].toBool(false); cellSettingsObj["quantity"] = quantityCellObj; QJsonObject noteCellObj; noteCellObj["stretch"] = noteObj["stretch"].toInt(100); noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false); noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false); cellSettingsObj["note"] = noteCellObj; QJsonDocument cellSettingsDoc(cellSettingsObj); QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact); // Добавляем строку в БД QSqlQuery insertQuery = prepareQuery( "INSERT INTO specification_pcb_rows (project_name, row_order, format_value, zone_value, position_value, " "designation_value, name_value, quantity_value, note_value, is_header, is_empty, " "format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ); insertQuery.addBindValue(projectName); insertQuery.addBindValue(rowOrder++); insertQuery.addBindValue(formatObj["value"].toString()); insertQuery.addBindValue(zoneObj["value"].toString()); insertQuery.addBindValue(positionObj["value"].toString()); insertQuery.addBindValue(designationObj["value"].toString()); insertQuery.addBindValue(nameObj["value"].toString()); insertQuery.addBindValue(quantityObj["value"].toString()); insertQuery.addBindValue(noteObj["value"].toString()); insertQuery.addBindValue(rowObj["isHeader"].toBool()); insertQuery.addBindValue(rowObj["isEmpty"].toBool()); insertQuery.addBindValue(formatObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(zoneObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(positionObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(designationObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(nameObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(noteObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(cellSettingsJson); if (!insertQuery.exec()) { setLastError("Ошибка сохранения строки спецификации платы: " + insertQuery.lastError().text()); qDebug() << "DataBaseController::saveSpecificationPCBTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text(); rollbackTransaction(); return false; } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } qDebug() << "DataBaseController::saveSpecificationPCBTable: Спецификация платы успешно сохранена," << rowsArray.size() << "строк"; emit dataChanged(); return true; } QByteArray DataBaseController::loadSpecificationPCBTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QByteArray(); } qDebug() << "DataBaseController::loadSpecificationPCBTable: Загружаем спецификацию платы для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT row_order, format_value, zone_value, position_value, designation_value, name_value, quantity_value, note_value, " "is_header, is_empty, format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches " "FROM specification_pcb_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка загрузки спецификации платы: " + query.lastError().text()); qDebug() << "DataBaseController::loadSpecificationPCBTable: Ошибка выполнения запроса:" << query.lastError().text(); return QByteArray(); } // Создаем JSON структуру для совместимости с SpecificationPCBTableModel QJsonObject root; QJsonArray rowsArray; while (query.next()) { QJsonObject rowObj; // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON QJsonObject cellSettingsObj; QString cellSettingsJson = query.value(17).toString(); if (!cellSettingsJson.isEmpty()) { QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8()); if (cellSettingsDoc.isObject()) { cellSettingsObj = cellSettingsDoc.object(); } } // Получаем настройки для каждой ячейки QJsonObject formatCellObj = cellSettingsObj["format"].toObject(); QJsonObject zoneCellObj = cellSettingsObj["zone"].toObject(); QJsonObject positionCellObj = cellSettingsObj["position"].toObject(); QJsonObject designationCellObj = cellSettingsObj["designation"].toObject(); QJsonObject nameCellObj = cellSettingsObj["name"].toObject(); QJsonObject quantityCellObj = cellSettingsObj["quantity"].toObject(); QJsonObject noteCellObj = cellSettingsObj["note"].toObject(); // Создаем объекты для каждой ячейки (7 столбцов) QJsonObject formatObj; formatObj["value"] = query.value(1).toString(); formatObj["rowNumber"] = query.value(0).toInt(); formatObj["pageNumber"] = 1; formatObj["isHeader"] = formatCellObj["isHeader"].toBool(query.value(8).toBool()); formatObj["isAutoGenerated"] = query.value(10).toBool(); formatObj["isEmpty"] = query.value(1).toString().isEmpty(); formatObj["stretch"] = formatCellObj["stretch"].toInt(100); formatObj["isUnderline"] = formatCellObj["isUnderline"].toBool(false); QJsonObject zoneObj; zoneObj["value"] = query.value(2).toString(); zoneObj["rowNumber"] = query.value(0).toInt(); zoneObj["pageNumber"] = 1; zoneObj["isHeader"] = zoneCellObj["isHeader"].toBool(query.value(8).toBool()); zoneObj["isAutoGenerated"] = query.value(11).toBool(); zoneObj["isEmpty"] = query.value(2).toString().isEmpty(); zoneObj["stretch"] = zoneCellObj["stretch"].toInt(100); zoneObj["isUnderline"] = zoneCellObj["isUnderline"].toBool(false); QJsonObject positionObj; positionObj["value"] = query.value(3).toString(); positionObj["rowNumber"] = query.value(0).toInt(); positionObj["pageNumber"] = 1; positionObj["isHeader"] = positionCellObj["isHeader"].toBool(query.value(8).toBool()); positionObj["isAutoGenerated"] = query.value(12).toBool(); positionObj["isEmpty"] = query.value(3).toString().isEmpty(); positionObj["stretch"] = positionCellObj["stretch"].toInt(100); positionObj["isUnderline"] = positionCellObj["isUnderline"].toBool(false); QJsonObject designationObj; designationObj["value"] = query.value(4).toString(); designationObj["rowNumber"] = query.value(0).toInt(); designationObj["pageNumber"] = 1; designationObj["isHeader"] = designationCellObj["isHeader"].toBool(query.value(8).toBool()); designationObj["isAutoGenerated"] = query.value(13).toBool(); designationObj["isEmpty"] = query.value(4).toString().isEmpty(); designationObj["stretch"] = designationCellObj["stretch"].toInt(100); designationObj["isUnderline"] = designationCellObj["isUnderline"].toBool(false); QJsonObject nameObj; nameObj["value"] = query.value(5).toString(); nameObj["rowNumber"] = query.value(0).toInt(); nameObj["pageNumber"] = 1; nameObj["isHeader"] = nameCellObj["isHeader"].toBool(query.value(8).toBool()); nameObj["isAutoGenerated"] = query.value(14).toBool(); nameObj["isEmpty"] = query.value(5).toString().isEmpty(); nameObj["stretch"] = nameCellObj["stretch"].toInt(100); nameObj["isUnderline"] = nameCellObj["isUnderline"].toBool(false); QJsonObject quantityObj; quantityObj["value"] = query.value(6).toString(); quantityObj["rowNumber"] = query.value(0).toInt(); quantityObj["pageNumber"] = 1; quantityObj["isHeader"] = quantityCellObj["isHeader"].toBool(query.value(8).toBool()); quantityObj["isAutoGenerated"] = query.value(15).toBool(); quantityObj["isEmpty"] = query.value(6).toString().isEmpty(); quantityObj["stretch"] = quantityCellObj["stretch"].toInt(100); quantityObj["isUnderline"] = quantityCellObj["isUnderline"].toBool(false); QJsonObject noteObj; noteObj["value"] = query.value(7).toString(); noteObj["rowNumber"] = query.value(0).toInt(); noteObj["pageNumber"] = 1; noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(8).toBool()); noteObj["isAutoGenerated"] = query.value(16).toBool(); noteObj["isEmpty"] = query.value(7).toString().isEmpty(); noteObj["stretch"] = noteCellObj["stretch"].toInt(100); noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false); // Создаем объект строки rowObj["format"] = formatObj; rowObj["zone"] = zoneObj; rowObj["position"] = positionObj; rowObj["designation"] = designationObj; rowObj["name"] = nameObj; rowObj["quantity"] = quantityObj; rowObj["note"] = noteObj; rowObj["isHeader"] = query.value(8).toBool(); rowObj["isEmpty"] = query.value(9).toBool(); rowObj["rowNumber"] = query.value(0).toInt(); rowObj["pageNumber"] = 1; rowsArray.append(rowObj); } root["rows"] = rowsArray; root["columnMappings"] = QJsonArray::fromStringList(QStringList() << "Format" << "Zone" << "Position" << "Designator" << "Name" << "Quantity" << "Note"); root["propertyNames"] = QJsonArray::fromStringList(QStringList() << "Designator" << "Format" << "Zone" << "Position"); QJsonDocument doc(root); QByteArray result = doc.toJson(); qDebug() << "DataBaseController::loadSpecificationPCBTable: Загружено" << rowsArray.size() << "строк"; return result; } bool DataBaseController::deleteSpecificationPCBTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("DELETE FROM specification_pcb_rows WHERE project_name = ?"); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка удаления спецификации платы: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QStringList DataBaseController::getAvailableSpecificationPCBProjects() { QStringList projects; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return projects; } QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM specification_pcb_rows ORDER BY project_name"); if (!query.exec()) { setLastError("Ошибка получения списка проектов спецификации платы: " + query.lastError().text()); return projects; } while (query.next()) { projects << query.value(0).toString(); } return projects; } QString DataBaseController::getSpecificationPCBTableInfo(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QString(); } QString actualProjectName = projectName; if (actualProjectName.isEmpty()) { actualProjectName = QFileInfo(m_database.databaseName()).baseName(); } QSqlQuery query = prepareQuery( "SELECT row_order, format_value, zone_value, position_value, designation_value, name_value, quantity_value, note_value, " "is_header, is_empty, format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto " "FROM specification_pcb_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(actualProjectName); if (!query.exec()) { setLastError("Ошибка получения информации о спецификации платы: " + query.lastError().text()); return QString(); } QString info = QString("Информация о спецификации платы для проекта '%1':\n").arg(actualProjectName); info += QString("Всего строк: %1\n\n").arg(query.size()); while (query.next()) { int rowOrder = query.value(0).toInt(); QString format = query.value(1).toString(); QString zone = query.value(2).toString(); QString position = query.value(3).toString(); QString designation = query.value(4).toString(); QString name = query.value(5).toString(); QString quantity = query.value(6).toString(); QString note = query.value(7).toString(); bool isHeader = query.value(8).toBool(); bool isEmpty = query.value(9).toBool(); bool formatAuto = query.value(10).toBool(); bool zoneAuto = query.value(11).toBool(); bool posAuto = query.value(12).toBool(); bool desAuto = query.value(13).toBool(); bool nameAuto = query.value(14).toBool(); bool qtyAuto = query.value(15).toBool(); bool noteAuto = query.value(16).toBool(); info += QString("Строка %1:\n").arg(rowOrder); info += QString(" Формат: '%1' (авто: %2)\n").arg(format).arg(formatAuto ? "да" : "нет"); info += QString(" Зона: '%1' (авто: %2)\n").arg(zone).arg(zoneAuto ? "да" : "нет"); info += QString(" Поз.: '%1' (авто: %2)\n").arg(position).arg(posAuto ? "да" : "нет"); info += QString(" Обозн.: '%1' (авто: %2)\n").arg(designation).arg(desAuto ? "да" : "нет"); info += QString(" Наим.: '%1' (авто: %2)\n").arg(name).arg(nameAuto ? "да" : "нет"); info += QString(" Кол.: '%1' (авто: %2)\n").arg(quantity).arg(qtyAuto ? "да" : "нет"); info += QString(" Прим.: '%1' (авто: %2)\n").arg(note).arg(noteAuto ? "да" : "нет"); info += QString(" Заголовок: %1, Пустая: %2\n\n").arg(isHeader ? "да" : "нет").arg(isEmpty ? "да" : "нет"); } return info; } // Работа со спецификацией материалов bool DataBaseController::saveSpecificationTable(const QByteArray &tableData, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::saveSpecificationTable: Сохраняем спецификацию для проекта:" << projectName; // Начинаем транзакцию if (!beginTransaction()) { return false; } // Удаляем существующие записи для данного проекта QSqlQuery deleteQuery = prepareQuery("DELETE FROM specification_rows WHERE project_name = ?"); deleteQuery.addBindValue(projectName); if (!deleteQuery.exec()) { setLastError("Ошибка удаления существующей спецификации: " + deleteQuery.lastError().text()); qDebug() << "DataBaseController::saveSpecificationTable: Ошибка удаления:" << deleteQuery.lastError().text(); rollbackTransaction(); return false; } // Парсим JSON данные и сохраняем каждую строку отдельно QJsonDocument doc = QJsonDocument::fromJson(tableData); if (!doc.isObject()) { setLastError("Ошибка парсинга JSON данных спецификации"); rollbackTransaction(); return false; } QJsonObject root = doc.object(); QJsonArray rowsArray = root["rows"].toArray(); int rowOrder = 0; for (const QJsonValue &value : rowsArray) { QJsonObject rowObj = value.toObject(); // Получаем данные ячеек для 7 столбцов QJsonObject formatObj = rowObj["format"].toObject(); QJsonObject zoneObj = rowObj["zone"].toObject(); QJsonObject positionObj = rowObj["position"].toObject(); QJsonObject designationObj = rowObj["designation"].toObject(); QJsonObject nameObj = rowObj["name"].toObject(); QJsonObject quantityObj = rowObj["quantity"].toObject(); QJsonObject noteObj = rowObj["note"].toObject(); // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline) QJsonObject cellSettingsObj; QJsonObject formatCellObj; formatCellObj["stretch"] = formatObj["stretch"].toInt(100); formatCellObj["isHeader"] = formatObj["isHeader"].toBool(false); formatCellObj["isUnderline"] = formatObj["isUnderline"].toBool(false); cellSettingsObj["format"] = formatCellObj; QJsonObject zoneCellObj; zoneCellObj["stretch"] = zoneObj["stretch"].toInt(100); zoneCellObj["isHeader"] = zoneObj["isHeader"].toBool(false); zoneCellObj["isUnderline"] = zoneObj["isUnderline"].toBool(false); cellSettingsObj["zone"] = zoneCellObj; QJsonObject positionCellObj; positionCellObj["stretch"] = positionObj["stretch"].toInt(100); positionCellObj["isHeader"] = positionObj["isHeader"].toBool(false); positionCellObj["isUnderline"] = positionObj["isUnderline"].toBool(false); cellSettingsObj["position"] = positionCellObj; QJsonObject designationCellObj; designationCellObj["stretch"] = designationObj["stretch"].toInt(100); designationCellObj["isHeader"] = designationObj["isHeader"].toBool(false); designationCellObj["isUnderline"] = designationObj["isUnderline"].toBool(false); cellSettingsObj["designation"] = designationCellObj; QJsonObject nameCellObj; nameCellObj["stretch"] = nameObj["stretch"].toInt(100); nameCellObj["isHeader"] = nameObj["isHeader"].toBool(false); nameCellObj["isUnderline"] = nameObj["isUnderline"].toBool(false); cellSettingsObj["name"] = nameCellObj; QJsonObject quantityCellObj; quantityCellObj["stretch"] = quantityObj["stretch"].toInt(100); quantityCellObj["isHeader"] = quantityObj["isHeader"].toBool(false); quantityCellObj["isUnderline"] = quantityObj["isUnderline"].toBool(false); cellSettingsObj["quantity"] = quantityCellObj; QJsonObject noteCellObj; noteCellObj["stretch"] = noteObj["stretch"].toInt(100); noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false); noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false); cellSettingsObj["note"] = noteCellObj; QJsonDocument cellSettingsDoc(cellSettingsObj); QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact); // Добавляем строку в БД QSqlQuery insertQuery = prepareQuery( "INSERT INTO specification_rows (project_name, row_order, format_value, zone_value, position_value, " "designation_value, name_value, quantity_value, note_value, is_header, is_empty, " "format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ); insertQuery.addBindValue(projectName); insertQuery.addBindValue(rowOrder++); insertQuery.addBindValue(formatObj["value"].toString()); insertQuery.addBindValue(zoneObj["value"].toString()); insertQuery.addBindValue(positionObj["value"].toString()); insertQuery.addBindValue(designationObj["value"].toString()); insertQuery.addBindValue(nameObj["value"].toString()); insertQuery.addBindValue(quantityObj["value"].toString()); insertQuery.addBindValue(noteObj["value"].toString()); insertQuery.addBindValue(rowObj["isHeader"].toBool()); insertQuery.addBindValue(rowObj["isEmpty"].toBool()); insertQuery.addBindValue(formatObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(zoneObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(positionObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(designationObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(nameObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(noteObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(cellSettingsJson); if (!insertQuery.exec()) { setLastError("Ошибка сохранения строки спецификации: " + insertQuery.lastError().text()); qDebug() << "DataBaseController::saveSpecificationTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text(); rollbackTransaction(); return false; } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } qDebug() << "DataBaseController::saveSpecificationTable: Спецификация успешно сохранена," << rowsArray.size() << "строк"; emit dataChanged(); return true; } QByteArray DataBaseController::loadSpecificationTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QByteArray(); } qDebug() << "DataBaseController::loadSpecificationTable: Загружаем спецификацию для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT row_order, format_value, zone_value, position_value, designation_value, name_value, quantity_value, note_value, " "is_header, is_empty, format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches " "FROM specification_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка загрузки спецификации: " + query.lastError().text()); qDebug() << "DataBaseController::loadSpecificationTable: Ошибка выполнения запроса:" << query.lastError().text(); return QByteArray(); } // Создаем JSON структуру для совместимости с SpecificationTableModel QJsonObject root; QJsonArray rowsArray; while (query.next()) { QJsonObject rowObj; // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON QJsonObject cellSettingsObj; QString cellSettingsJson = query.value(17).toString(); if (!cellSettingsJson.isEmpty()) { QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8()); if (cellSettingsDoc.isObject()) { cellSettingsObj = cellSettingsDoc.object(); } } // Получаем настройки для каждой ячейки QJsonObject formatCellObj = cellSettingsObj["format"].toObject(); QJsonObject zoneCellObj = cellSettingsObj["zone"].toObject(); QJsonObject positionCellObj = cellSettingsObj["position"].toObject(); QJsonObject designationCellObj = cellSettingsObj["designation"].toObject(); QJsonObject nameCellObj = cellSettingsObj["name"].toObject(); QJsonObject quantityCellObj = cellSettingsObj["quantity"].toObject(); QJsonObject noteCellObj = cellSettingsObj["note"].toObject(); // Создаем объекты для каждой ячейки (7 столбцов) QJsonObject formatObj; formatObj["value"] = query.value(1).toString(); formatObj["rowNumber"] = query.value(0).toInt(); formatObj["pageNumber"] = 1; formatObj["isHeader"] = formatCellObj["isHeader"].toBool(query.value(8).toBool()); formatObj["isAutoGenerated"] = query.value(10).toBool(); formatObj["isEmpty"] = query.value(1).toString().isEmpty(); formatObj["stretch"] = formatCellObj["stretch"].toInt(100); formatObj["isUnderline"] = formatCellObj["isUnderline"].toBool(false); QJsonObject zoneObj; zoneObj["value"] = query.value(2).toString(); zoneObj["rowNumber"] = query.value(0).toInt(); zoneObj["pageNumber"] = 1; zoneObj["isHeader"] = zoneCellObj["isHeader"].toBool(query.value(8).toBool()); zoneObj["isAutoGenerated"] = query.value(11).toBool(); zoneObj["isEmpty"] = query.value(2).toString().isEmpty(); zoneObj["stretch"] = zoneCellObj["stretch"].toInt(100); zoneObj["isUnderline"] = zoneCellObj["isUnderline"].toBool(false); QJsonObject positionObj; positionObj["value"] = query.value(3).toString(); positionObj["rowNumber"] = query.value(0).toInt(); positionObj["pageNumber"] = 1; positionObj["isHeader"] = positionCellObj["isHeader"].toBool(query.value(8).toBool()); positionObj["isAutoGenerated"] = query.value(12).toBool(); positionObj["isEmpty"] = query.value(3).toString().isEmpty(); positionObj["stretch"] = positionCellObj["stretch"].toInt(100); positionObj["isUnderline"] = positionCellObj["isUnderline"].toBool(false); QJsonObject designationObj; designationObj["value"] = query.value(4).toString(); designationObj["rowNumber"] = query.value(0).toInt(); designationObj["pageNumber"] = 1; designationObj["isHeader"] = designationCellObj["isHeader"].toBool(query.value(8).toBool()); designationObj["isAutoGenerated"] = query.value(13).toBool(); designationObj["isEmpty"] = query.value(4).toString().isEmpty(); designationObj["stretch"] = designationCellObj["stretch"].toInt(100); designationObj["isUnderline"] = designationCellObj["isUnderline"].toBool(false); QJsonObject nameObj; nameObj["value"] = query.value(5).toString(); nameObj["rowNumber"] = query.value(0).toInt(); nameObj["pageNumber"] = 1; nameObj["isHeader"] = nameCellObj["isHeader"].toBool(query.value(8).toBool()); nameObj["isAutoGenerated"] = query.value(14).toBool(); nameObj["isEmpty"] = query.value(5).toString().isEmpty(); nameObj["stretch"] = nameCellObj["stretch"].toInt(100); nameObj["isUnderline"] = nameCellObj["isUnderline"].toBool(false); QJsonObject quantityObj; quantityObj["value"] = query.value(6).toString(); quantityObj["rowNumber"] = query.value(0).toInt(); quantityObj["pageNumber"] = 1; quantityObj["isHeader"] = quantityCellObj["isHeader"].toBool(query.value(8).toBool()); quantityObj["isAutoGenerated"] = query.value(15).toBool(); quantityObj["isEmpty"] = query.value(6).toString().isEmpty(); quantityObj["stretch"] = quantityCellObj["stretch"].toInt(100); quantityObj["isUnderline"] = quantityCellObj["isUnderline"].toBool(false); QJsonObject noteObj; noteObj["value"] = query.value(7).toString(); noteObj["rowNumber"] = query.value(0).toInt(); noteObj["pageNumber"] = 1; noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(8).toBool()); noteObj["isAutoGenerated"] = query.value(16).toBool(); noteObj["isEmpty"] = query.value(7).toString().isEmpty(); noteObj["stretch"] = noteCellObj["stretch"].toInt(100); noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false); // Создаем объект строки rowObj["format"] = formatObj; rowObj["zone"] = zoneObj; rowObj["position"] = positionObj; rowObj["designation"] = designationObj; rowObj["name"] = nameObj; rowObj["quantity"] = quantityObj; rowObj["note"] = noteObj; rowObj["isHeader"] = query.value(8).toBool(); rowObj["isEmpty"] = query.value(9).toBool(); rowObj["rowNumber"] = query.value(0).toInt(); rowObj["pageNumber"] = 1; rowsArray.append(rowObj); } root["rows"] = rowsArray; root["columnMappings"] = QJsonArray::fromStringList(QStringList() << "Format" << "Zone" << "Position" << "Designation" << "Name" << "Quantity" << "Note"); root["propertyNames"] = QJsonArray::fromStringList(QStringList() << "Name" << "Value" << "Height" << "DielType" << "LayerNumber"); QJsonDocument doc(root); QByteArray result = doc.toJson(); qDebug() << "DataBaseController::loadSpecificationTable: Загружено" << rowsArray.size() << "строк"; return result; } bool DataBaseController::deleteSpecificationTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("DELETE FROM specification_rows WHERE project_name = ?"); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка удаления спецификации: " + query.lastError().text()); return false; } emit dataChanged(); return true; } QStringList DataBaseController::getAvailableSpecificationProjects() { QStringList projects; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return projects; } QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM specification_rows ORDER BY project_name"); if (!query.exec()) { setLastError("Ошибка получения списка проектов спецификации: " + query.lastError().text()); return projects; } while (query.next()) { projects << query.value(0).toString(); } return projects; } QString DataBaseController::getSpecificationTableInfo(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QString(); } qDebug() << "DataBaseController::getSpecificationTableInfo: Получаем информацию о спецификации материалов для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT COUNT(*) as total_rows, " "SUM(CASE WHEN is_header = 1 THEN 1 ELSE 0 END) as header_rows, " "SUM(CASE WHEN is_empty = 1 THEN 1 ELSE 0 END) as empty_rows, " "MIN(row_order) as min_order, " "MAX(row_order) as max_order " "FROM specification_rows WHERE project_name = ?" ); query.addBindValue(projectName); if (!query.exec() || !query.next()) { setLastError("Ошибка получения информации о спецификации: " + query.lastError().text()); return QString(); } int totalRows = query.value(0).toInt(); int headerRows = query.value(1).toInt(); int emptyRows = query.value(2).toInt(); int minOrder = query.value(3).toInt(); int maxOrder = query.value(4).toInt(); QString info = QString("Спецификация для проекта '%1':\n" "Всего строк: %2\n" "Заголовков: %3\n" "Пустых строк: %4\n" "Диапазон строк: %5-%6") .arg(projectName) .arg(totalRows) .arg(headerRows) .arg(emptyRows) .arg(minOrder) .arg(maxOrder); qDebug() << "DataBaseController::getSpecificationTableInfo: Информация получена:" << info; return info; } // Работа с ведомостью покупных изделий bool DataBaseController::saveVedomostTable(const QByteArray &tableData, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::saveVedomostTable: Сохраняем ведомость покупных изделий для проекта:" << projectName; // Начинаем транзакцию if (!beginTransaction()) { return false; } // Удаляем существующие данные для этого проекта QSqlQuery deleteQuery = prepareQuery("DELETE FROM vedomost_rows WHERE project_name = ?"); deleteQuery.addBindValue(projectName); if (!deleteQuery.exec()) { qDebug() << "DataBaseController::saveVedomostTable: Ошибка удаления:" << deleteQuery.lastError().text(); setLastError("Ошибка удаления существующих данных ведомости: " + deleteQuery.lastError().text()); rollbackTransaction(); return false; } // Парсим JSON данные и сохраняем каждую строку отдельно QJsonDocument doc = QJsonDocument::fromJson(tableData); if (!doc.isObject()) { setLastError("Ошибка парсинга JSON данных ведомости"); rollbackTransaction(); return false; } QJsonObject root = doc.object(); QJsonArray rowsArray = root["rows"].toArray(); int rowOrder = 0; for (const QJsonValue &value : rowsArray) { QJsonObject rowObj = value.toObject(); // Отладочная информация для первых нескольких строк if (rowOrder < 5) { qDebug() << "DataBaseController::saveVedomostTable: Обрабатываем строку" << rowOrder << ":"; if (rowObj.contains("name")) { QJsonObject nameObj = rowObj["name"].toObject(); qDebug() << " name.value:" << nameObj["value"].toString(); } if (rowObj.contains("productCode")) { QJsonObject productCodeObj = rowObj["productCode"].toObject(); qDebug() << " productCode.value:" << productCodeObj["value"].toString(); } qDebug() << " isHeader:" << rowObj["isHeader"].toBool(); qDebug() << " isEmpty:" << rowObj["isEmpty"].toBool(); } // Получаем данные ячеек QJsonObject nameObj = rowObj["name"].toObject(); QJsonObject productCodeObj = rowObj["productCode"].toObject(); QJsonObject documentCodeObj = rowObj["documentCode"].toObject(); QJsonObject supplierObj = rowObj["supplier"].toObject(); QJsonObject whereUsedObj = rowObj["whereUsed"].toObject(); QJsonObject quantityPerItemObj = rowObj["quantityPerItem"].toObject(); QJsonObject quantityInSetObj = rowObj["quantityInSet"].toObject(); QJsonObject quantityForRegObj = rowObj["quantityForReg"].toObject(); QJsonObject totalQuantityObj = rowObj["totalQuantity"].toObject(); QJsonObject noteObj = rowObj["note"].toObject(); // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline) QJsonObject cellSettingsObj; QJsonObject nameCellObj; nameCellObj["stretch"] = nameObj["stretch"].toInt(100); nameCellObj["isHeader"] = nameObj["isHeader"].toBool(false); nameCellObj["isUnderline"] = nameObj["isUnderline"].toBool(false); cellSettingsObj["name"] = nameCellObj; QJsonObject productCodeCellObj; productCodeCellObj["stretch"] = productCodeObj["stretch"].toInt(100); productCodeCellObj["isHeader"] = productCodeObj["isHeader"].toBool(false); productCodeCellObj["isUnderline"] = productCodeObj["isUnderline"].toBool(false); cellSettingsObj["productCode"] = productCodeCellObj; QJsonObject documentCodeCellObj; documentCodeCellObj["stretch"] = documentCodeObj["stretch"].toInt(100); documentCodeCellObj["isHeader"] = documentCodeObj["isHeader"].toBool(false); documentCodeCellObj["isUnderline"] = documentCodeObj["isUnderline"].toBool(false); cellSettingsObj["documentCode"] = documentCodeCellObj; QJsonObject supplierCellObj; supplierCellObj["stretch"] = supplierObj["stretch"].toInt(100); supplierCellObj["isHeader"] = supplierObj["isHeader"].toBool(false); supplierCellObj["isUnderline"] = supplierObj["isUnderline"].toBool(false); cellSettingsObj["supplier"] = supplierCellObj; QJsonObject whereUsedCellObj; whereUsedCellObj["stretch"] = whereUsedObj["stretch"].toInt(100); whereUsedCellObj["isHeader"] = whereUsedObj["isHeader"].toBool(false); whereUsedCellObj["isUnderline"] = whereUsedObj["isUnderline"].toBool(false); cellSettingsObj["whereUsed"] = whereUsedCellObj; QJsonObject quantityPerItemCellObj; quantityPerItemCellObj["stretch"] = quantityPerItemObj["stretch"].toInt(100); quantityPerItemCellObj["isHeader"] = quantityPerItemObj["isHeader"].toBool(false); quantityPerItemCellObj["isUnderline"] = quantityPerItemObj["isUnderline"].toBool(false); cellSettingsObj["quantityPerItem"] = quantityPerItemCellObj; QJsonObject quantityInSetCellObj; quantityInSetCellObj["stretch"] = quantityInSetObj["stretch"].toInt(100); quantityInSetCellObj["isHeader"] = quantityInSetObj["isHeader"].toBool(false); quantityInSetCellObj["isUnderline"] = quantityInSetObj["isUnderline"].toBool(false); cellSettingsObj["quantityInSet"] = quantityInSetCellObj; QJsonObject quantityForRegCellObj; quantityForRegCellObj["stretch"] = quantityForRegObj["stretch"].toInt(100); quantityForRegCellObj["isHeader"] = quantityForRegObj["isHeader"].toBool(false); quantityForRegCellObj["isUnderline"] = quantityForRegObj["isUnderline"].toBool(false); cellSettingsObj["quantityForReg"] = quantityForRegCellObj; QJsonObject totalQuantityCellObj; totalQuantityCellObj["stretch"] = totalQuantityObj["stretch"].toInt(100); totalQuantityCellObj["isHeader"] = totalQuantityObj["isHeader"].toBool(false); totalQuantityCellObj["isUnderline"] = totalQuantityObj["isUnderline"].toBool(false); cellSettingsObj["totalQuantity"] = totalQuantityCellObj; QJsonObject noteCellObj; noteCellObj["stretch"] = noteObj["stretch"].toInt(100); noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false); noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false); cellSettingsObj["note"] = noteCellObj; QJsonDocument cellSettingsDoc(cellSettingsObj); QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact); // Добавляем строку в БД QSqlQuery insertQuery = prepareQuery( "INSERT INTO vedomost_rows (project_name, row_order, name_value, product_code_value, document_code_value, " "supplier_value, where_used_value, quantity_per_item_value, quantity_in_set_value, quantity_for_reg_value, total_quantity_value, " "note_value, is_header, is_empty, row_number, page_number, cell_stretches) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ); insertQuery.addBindValue(projectName); insertQuery.addBindValue(rowOrder++); insertQuery.addBindValue(nameObj["value"].toString()); insertQuery.addBindValue(productCodeObj["value"].toString()); insertQuery.addBindValue(documentCodeObj["value"].toString()); insertQuery.addBindValue(supplierObj["value"].toString()); insertQuery.addBindValue(whereUsedObj["value"].toString()); insertQuery.addBindValue(quantityPerItemObj["value"].toString()); insertQuery.addBindValue(quantityInSetObj["value"].toString()); insertQuery.addBindValue(quantityForRegObj["value"].toString()); insertQuery.addBindValue(totalQuantityObj["value"].toString()); insertQuery.addBindValue(noteObj["value"].toString()); insertQuery.addBindValue(rowObj["isHeader"].toBool()); insertQuery.addBindValue(rowObj["isEmpty"].toBool()); insertQuery.addBindValue(rowObj["rowNumber"].toInt()); insertQuery.addBindValue(rowObj["pageNumber"].toInt()); insertQuery.addBindValue(cellSettingsJson); if (!insertQuery.exec()) { qDebug() << "DataBaseController::saveVedomostTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text(); setLastError("Ошибка сохранения строки ведомости: " + insertQuery.lastError().text()); rollbackTransaction(); return false; } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } qDebug() << "DataBaseController::saveVedomostTable: Ведомость успешно сохранена," << rowsArray.size() << "строк"; emit dataChanged(); return true; } // Работа с бланком заказа bool DataBaseController::saveSimpleListTable(const QByteArray &tableData, const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::saveSimpleListTable: Сохраняем бланк заказа для проекта:" << projectName; // Начинаем транзакцию if (!beginTransaction()) { return false; } // Удаляем существующие данные для этого проекта QSqlQuery deleteQuery = prepareQuery("DELETE FROM simple_list_rows WHERE project_name = ?"); deleteQuery.addBindValue(projectName); if (!deleteQuery.exec()) { qDebug() << "DataBaseController::saveSimpleListTable: Ошибка удаления:" << deleteQuery.lastError().text(); setLastError("Ошибка удаления существующих данных бланка заказа: " + deleteQuery.lastError().text()); rollbackTransaction(); return false; } // Парсим JSON данные и сохраняем каждую строку отдельно QJsonDocument doc = QJsonDocument::fromJson(tableData); if (!doc.isObject()) { setLastError("Ошибка парсинга JSON данных бланка заказа"); rollbackTransaction(); return false; } QJsonObject root = doc.object(); QJsonArray rowsArray = root["rows"].toArray(); int rowOrder = 0; for (const QJsonValue &value : rowsArray) { QJsonObject rowObj = value.toObject(); // Получаем данные ячеек QJsonObject designatorObj = rowObj["designator"].toObject(); QJsonObject nameObj = rowObj["name"].toObject(); QJsonObject quantityObj = rowObj["quantity"].toObject(); // Добавляем строку в БД QSqlQuery insertQuery = prepareQuery( "INSERT INTO simple_list_rows (project_name, row_order, designator_value, name_value, quantity_value, " "is_empty, designator_is_auto, name_is_auto, quantity_is_auto) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" ); insertQuery.addBindValue(projectName); insertQuery.addBindValue(rowOrder++); insertQuery.addBindValue(designatorObj["value"].toString()); insertQuery.addBindValue(nameObj["value"].toString()); insertQuery.addBindValue(quantityObj["value"].toString()); insertQuery.addBindValue(rowObj["isEmpty"].toBool()); insertQuery.addBindValue(designatorObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(nameObj["isAutoGenerated"].toBool()); insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool()); if (!insertQuery.exec()) { qDebug() << "DataBaseController::saveSimpleListTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text(); setLastError("Ошибка сохранения строки бланка заказа: " + insertQuery.lastError().text()); rollbackTransaction(); return false; } } // Подтверждаем транзакцию if (!commitTransaction()) { return false; } qDebug() << "DataBaseController::saveSimpleListTable: Бланк заказа успешно сохранен," << rowsArray.size() << "строк"; emit dataChanged(); return true; } QByteArray DataBaseController::loadSimpleListTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QByteArray(); } qDebug() << "DataBaseController::loadSimpleListTable: Загружаем бланк заказа для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT designator_value, name_value, quantity_value, is_empty, designator_is_auto, name_is_auto, quantity_is_auto " "FROM simple_list_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка загрузки бланка заказа: " + query.lastError().text()); return QByteArray(); } QJsonObject root; QJsonArray rowsArray; while (query.next()) { QJsonObject rowObj; // Получаем данные ячеек QJsonObject designatorObj; designatorObj["value"] = query.value(0).toString(); designatorObj["isAutoGenerated"] = query.value(4).toBool(); designatorObj["isEmpty"] = false; rowObj["designator"] = designatorObj; QJsonObject nameObj; nameObj["value"] = query.value(1).toString(); nameObj["isAutoGenerated"] = query.value(5).toBool(); nameObj["isEmpty"] = false; rowObj["name"] = nameObj; QJsonObject quantityObj; quantityObj["value"] = query.value(2).toString(); quantityObj["isAutoGenerated"] = query.value(6).toBool(); quantityObj["isEmpty"] = false; rowObj["quantity"] = quantityObj; rowObj["isEmpty"] = query.value(3).toBool(); rowsArray.append(rowObj); } root["rows"] = rowsArray; QJsonDocument doc(root); QByteArray result = doc.toJson(); qDebug() << "DataBaseController::loadSimpleListTable: Загружено" << rowsArray.size() << "строк"; return result; } QByteArray DataBaseController::loadVedomostTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QByteArray(); } qDebug() << "DataBaseController::loadVedomostTable: Загружаем ведомость покупных изделий для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT name_value, product_code_value, document_code_value, supplier_value, where_used_value, quantity_per_item_value, " "quantity_in_set_value, quantity_for_reg_value, total_quantity_value, note_value, is_header, is_empty, row_number, page_number, cell_stretches " "FROM vedomost_rows WHERE project_name = ? ORDER BY row_order" ); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка загрузки ведомости покупных изделий: " + query.lastError().text()); return QByteArray(); } QJsonObject root; QJsonArray rowsArray; while (query.next()) { QJsonObject rowObj; // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON QJsonObject cellSettingsObj; QString cellSettingsJson = query.value(14).toString(); if (!cellSettingsJson.isEmpty()) { QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8()); if (cellSettingsDoc.isObject()) { cellSettingsObj = cellSettingsDoc.object(); } } // Получаем настройки для каждой ячейки QJsonObject nameCellObj = cellSettingsObj["name"].toObject(); QJsonObject productCodeCellObj = cellSettingsObj["productCode"].toObject(); QJsonObject documentCodeCellObj = cellSettingsObj["documentCode"].toObject(); QJsonObject supplierCellObj = cellSettingsObj["supplier"].toObject(); QJsonObject whereUsedCellObj = cellSettingsObj["whereUsed"].toObject(); QJsonObject quantityPerItemCellObj = cellSettingsObj["quantityPerItem"].toObject(); QJsonObject quantityInSetCellObj = cellSettingsObj["quantityInSet"].toObject(); QJsonObject quantityForRegCellObj = cellSettingsObj["quantityForReg"].toObject(); QJsonObject totalQuantityCellObj = cellSettingsObj["totalQuantity"].toObject(); QJsonObject noteCellObj = cellSettingsObj["note"].toObject(); // Создаем объекты для каждой ячейки QJsonObject nameObj; nameObj["value"] = query.value(0).toString(); nameObj["rowNumber"] = query.value(12).toInt(); nameObj["pageNumber"] = query.value(13).toInt(); nameObj["isHeader"] = nameCellObj["isHeader"].toBool(query.value(10).toBool()); nameObj["isAutoGenerated"] = false; nameObj["isEmpty"] = query.value(11).toBool(); nameObj["stretch"] = nameCellObj["stretch"].toInt(100); nameObj["isUnderline"] = nameCellObj["isUnderline"].toBool(false); rowObj["name"] = nameObj; QJsonObject productCodeObj; productCodeObj["value"] = query.value(1).toString(); productCodeObj["rowNumber"] = query.value(12).toInt(); productCodeObj["pageNumber"] = query.value(13).toInt(); productCodeObj["isHeader"] = productCodeCellObj["isHeader"].toBool(query.value(10).toBool()); productCodeObj["isAutoGenerated"] = false; productCodeObj["isEmpty"] = query.value(11).toBool(); productCodeObj["stretch"] = productCodeCellObj["stretch"].toInt(100); productCodeObj["isUnderline"] = productCodeCellObj["isUnderline"].toBool(false); rowObj["productCode"] = productCodeObj; QJsonObject documentCodeObj; documentCodeObj["value"] = query.value(2).toString(); documentCodeObj["rowNumber"] = query.value(12).toInt(); documentCodeObj["pageNumber"] = query.value(13).toInt(); documentCodeObj["isHeader"] = documentCodeCellObj["isHeader"].toBool(query.value(10).toBool()); documentCodeObj["isAutoGenerated"] = false; documentCodeObj["isEmpty"] = query.value(11).toBool(); documentCodeObj["stretch"] = documentCodeCellObj["stretch"].toInt(100); documentCodeObj["isUnderline"] = documentCodeCellObj["isUnderline"].toBool(false); rowObj["documentCode"] = documentCodeObj; QJsonObject supplierObj; supplierObj["value"] = query.value(3).toString(); supplierObj["rowNumber"] = query.value(12).toInt(); supplierObj["pageNumber"] = query.value(13).toInt(); supplierObj["isHeader"] = supplierCellObj["isHeader"].toBool(query.value(10).toBool()); supplierObj["isAutoGenerated"] = false; supplierObj["isEmpty"] = query.value(11).toBool(); supplierObj["stretch"] = supplierCellObj["stretch"].toInt(100); supplierObj["isUnderline"] = supplierCellObj["isUnderline"].toBool(false); rowObj["supplier"] = supplierObj; QJsonObject whereUsedObj; whereUsedObj["value"] = query.value(4).toString(); whereUsedObj["rowNumber"] = query.value(12).toInt(); whereUsedObj["pageNumber"] = query.value(13).toInt(); whereUsedObj["isHeader"] = whereUsedCellObj["isHeader"].toBool(query.value(10).toBool()); whereUsedObj["isAutoGenerated"] = false; whereUsedObj["isEmpty"] = query.value(11).toBool(); whereUsedObj["stretch"] = whereUsedCellObj["stretch"].toInt(100); whereUsedObj["isUnderline"] = whereUsedCellObj["isUnderline"].toBool(false); rowObj["whereUsed"] = whereUsedObj; QJsonObject quantityPerItemObj; quantityPerItemObj["value"] = query.value(5).toString(); quantityPerItemObj["rowNumber"] = query.value(12).toInt(); quantityPerItemObj["pageNumber"] = query.value(13).toInt(); quantityPerItemObj["isHeader"] = quantityPerItemCellObj["isHeader"].toBool(query.value(10).toBool()); quantityPerItemObj["isAutoGenerated"] = false; quantityPerItemObj["isEmpty"] = query.value(11).toBool(); quantityPerItemObj["stretch"] = quantityPerItemCellObj["stretch"].toInt(100); quantityPerItemObj["isUnderline"] = quantityPerItemCellObj["isUnderline"].toBool(false); rowObj["quantityPerItem"] = quantityPerItemObj; QJsonObject quantityInSetObj; quantityInSetObj["value"] = query.value(6).toString(); quantityInSetObj["rowNumber"] = query.value(12).toInt(); quantityInSetObj["pageNumber"] = query.value(13).toInt(); quantityInSetObj["isHeader"] = quantityInSetCellObj["isHeader"].toBool(query.value(10).toBool()); quantityInSetObj["isAutoGenerated"] = false; quantityInSetObj["isEmpty"] = query.value(11).toBool(); quantityInSetObj["stretch"] = quantityInSetCellObj["stretch"].toInt(100); quantityInSetObj["isUnderline"] = quantityInSetCellObj["isUnderline"].toBool(false); rowObj["quantityInSet"] = quantityInSetObj; QJsonObject quantityForRegObj; quantityForRegObj["value"] = query.value(7).toString(); quantityForRegObj["rowNumber"] = query.value(12).toInt(); quantityForRegObj["pageNumber"] = query.value(13).toInt(); quantityForRegObj["isHeader"] = quantityForRegCellObj["isHeader"].toBool(query.value(10).toBool()); quantityForRegObj["isAutoGenerated"] = false; quantityForRegObj["isEmpty"] = query.value(11).toBool(); quantityForRegObj["stretch"] = quantityForRegCellObj["stretch"].toInt(100); quantityForRegObj["isUnderline"] = quantityForRegCellObj["isUnderline"].toBool(false); rowObj["quantityForReg"] = quantityForRegObj; QJsonObject totalQuantityObj; totalQuantityObj["value"] = query.value(8).toString(); totalQuantityObj["rowNumber"] = query.value(12).toInt(); totalQuantityObj["pageNumber"] = query.value(13).toInt(); totalQuantityObj["isHeader"] = totalQuantityCellObj["isHeader"].toBool(query.value(10).toBool()); totalQuantityObj["isAutoGenerated"] = false; totalQuantityObj["isEmpty"] = query.value(11).toBool(); totalQuantityObj["stretch"] = totalQuantityCellObj["stretch"].toInt(100); totalQuantityObj["isUnderline"] = totalQuantityCellObj["isUnderline"].toBool(false); rowObj["totalQuantity"] = totalQuantityObj; QJsonObject noteObj; noteObj["value"] = query.value(9).toString(); noteObj["rowNumber"] = query.value(12).toInt(); noteObj["pageNumber"] = query.value(13).toInt(); noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(10).toBool()); noteObj["isAutoGenerated"] = false; noteObj["isEmpty"] = query.value(11).toBool(); noteObj["stretch"] = noteCellObj["stretch"].toInt(100); noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false); rowObj["note"] = noteObj; rowObj["isHeader"] = query.value(10).toBool(); rowObj["isEmpty"] = query.value(11).toBool(); rowObj["rowNumber"] = query.value(12).toInt(); rowObj["pageNumber"] = query.value(13).toInt(); rowsArray.append(rowObj); } root["rows"] = rowsArray; // Добавляем настройки колонок по умолчанию QStringList defaultColumnMappings = {"Name", "ProductCode", "DocumentCode", "Supplier", "WhereUsed", "QuantityPerItem", "QuantityInSet", "QuantityForReg", "TotalQuantity", "Note"}; root["columnMappings"] = QJsonArray::fromStringList(defaultColumnMappings); // Добавляем свойства по умолчанию QStringList defaultPropertyNames = {"Name", "ProductCode", "DocumentCode", "Supplier", "WhereUsed", "QuantityPerItem", "QuantityInSet", "QuantityForReg", "TotalQuantity", "Note"}; root["propertyNames"] = QJsonArray::fromStringList(defaultPropertyNames); QJsonDocument doc(root); QByteArray result = doc.toJson(); qDebug() << "DataBaseController::loadVedomostTable: Загружено" << rowsArray.size() << "строк"; return result; } bool DataBaseController::deleteVedomostTable(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController::deleteVedomostTable: Удаляем ведомость покупных изделий для проекта:" << projectName; QSqlQuery query = prepareQuery("DELETE FROM vedomost_rows WHERE project_name = ?"); query.addBindValue(projectName); if (!query.exec()) { setLastError("Ошибка удаления ведомости покупных изделий: " + query.lastError().text()); return false; } qDebug() << "DataBaseController::deleteVedomostTable: Ведомость успешно удалена"; emit dataChanged(); return true; } QStringList DataBaseController::getAvailableVedomostProjects() { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QStringList(); } qDebug() << "DataBaseController::getAvailableVedomostProjects: Получаем список проектов с ведомостями"; QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM vedomost_rows ORDER BY project_name"); if (!query.exec()) { setLastError("Ошибка получения списка проектов с ведомостями: " + query.lastError().text()); return QStringList(); } QStringList projects; while (query.next()) { projects << query.value(0).toString(); } return projects; } QString DataBaseController::getVedomostTableInfo(const QString &projectName) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return QString(); } qDebug() << "DataBaseController::getVedomostTableInfo: Получаем информацию о ведомости покупных изделий для проекта:" << projectName; QSqlQuery query = prepareQuery( "SELECT COUNT(*) as total_rows, " "SUM(CASE WHEN is_header = 1 THEN 1 ELSE 0 END) as header_rows, " "SUM(CASE WHEN is_empty = 1 THEN 1 ELSE 0 END) as empty_rows, " "MIN(row_order) as min_order, " "MAX(row_order) as max_order " "FROM vedomost_rows WHERE project_name = ?" ); query.addBindValue(projectName); if (!query.exec() || !query.next()) { setLastError("Ошибка получения информации о ведомости покупных изделий: " + query.lastError().text()); return QString(); } int totalRows = query.value(0).toInt(); int headerRows = query.value(1).toInt(); int emptyRows = query.value(2).toInt(); int minOrder = query.value(3).toInt(); int maxOrder = query.value(4).toInt(); QString info = QString("Ведомость покупных изделий для проекта '%1':\n" "Всего строк: %2\n" "Заголовков: %3\n" "Пустых строк: %4\n" "Диапазон строк: %5-%6") .arg(projectName) .arg(totalRows) .arg(headerRows) .arg(emptyRows) .arg(minOrder) .arg(maxOrder); qDebug() << "DataBaseController::getVedomostTableInfo: Информация получена:" << info; return info; } // Работа с данными PCB int DataBaseController::addPCBData(int layerCount) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return -1; } QSqlQuery query = prepareQuery("INSERT INTO pcb_data (layer_count) VALUES (?)"); query.addBindValue(layerCount); if (!query.exec()) { setLastError("Ошибка добавления данных PCB: " + query.lastError().text()); return -1; } return query.lastInsertId().toInt(); } bool DataBaseController::updatePCBLayerCount(int pcbId, int layerCount) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("UPDATE pcb_data SET layer_count = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?"); query.addBindValue(layerCount); query.addBindValue(pcbId); if (!query.exec()) { setLastError("Ошибка обновления количества слоев PCB: " + query.lastError().text()); return false; } emit dataChanged(); return true; } bool DataBaseController::addDielMaterial(int pcbId, const QString &name, const QString &value, double height, int dielType, int layerNumber) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } qDebug() << "DataBaseController: Добавляем диэлектрический материал:"; qDebug() << " pcbId:" << pcbId; qDebug() << " name:" << name; qDebug() << " value:" << value; qDebug() << " height:" << height; qDebug() << " dielType:" << dielType; qDebug() << " layerNumber:" << layerNumber; QSqlQuery query = prepareQuery( "REPLACE INTO diel_materials (pcb_id, name, value, height, diel_type, layer_number) " "VALUES (?, ?, ?, ?, ?, ?)" ); query.addBindValue(pcbId); query.addBindValue(name); query.addBindValue(value); query.addBindValue(height); query.addBindValue(dielType); query.addBindValue(layerNumber); if (!query.exec()) { QString errorText = "Ошибка добавления диэлектрического материала: " + query.lastError().text(); qDebug() << "DataBaseController:" << errorText; setLastError(errorText); return false; } qDebug() << "DataBaseController: Диэлектрический материал успешно добавлен"; emit dataChanged(); return true; } bool DataBaseController::updateDielMaterial(int pcbId, const QString &name, const QString &value, double height, int dielType, int layerNumber) { return addDielMaterial(pcbId, name, value, height, dielType, layerNumber); // REPLACE INTO } bool DataBaseController::removeDielMaterial(int pcbId, int layerNumber) { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("DELETE FROM diel_materials WHERE pcb_id = ? AND layer_number = ?"); query.addBindValue(pcbId); query.addBindValue(layerNumber); if (!query.exec()) { setLastError("Ошибка удаления диэлектрического материала: " + query.lastError().text()); return false; } emit dataChanged(); return true; } PCBData DataBaseController::getPCBData(int pcbId) { PCBData pcbData; pcbData.id = -1; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return pcbData; } QSqlQuery query = prepareQuery("SELECT id, layer_count FROM pcb_data WHERE id = ?"); query.addBindValue(pcbId); if (query.exec() && query.next()) { pcbData.id = query.value(0).toInt(); pcbData.layerCount = query.value(1).toInt(); pcbData.dielMaterials = getDielMaterials(pcbId); } return pcbData; } QList DataBaseController::getDielMaterials(int pcbId) { QList materials; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return materials; } QSqlQuery query = prepareQuery("SELECT name, value, height, diel_type, layer_number FROM diel_materials WHERE pcb_id = ? ORDER BY layer_number"); query.addBindValue(pcbId); if (query.exec()) { while (query.next()) { DielProperty material; material.name = query.value(0).toString(); material.value = query.value(1).toString(); material.height = query.value(2).toDouble(); material.dielType = query.value(3).toInt(); material.layerNumber = query.value(4).toInt(); materials << material; } } return materials; } PCBData DataBaseController::getPCBData() { PCBData pcbData; pcbData.id = -1; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return pcbData; } // Получаем последнюю запись PCB QSqlQuery query = prepareQuery("SELECT id, layer_count FROM pcb_data ORDER BY id DESC LIMIT 1"); if (query.exec() && query.next()) { int pcbId = query.value(0).toInt(); pcbData.id = pcbId; pcbData.layerCount = query.value(1).toInt(); pcbData.dielMaterials = getDielMaterials(pcbId); qDebug() << "DataBaseController: Получены данные PCB - ID:" << pcbData.id << "слоев:" << pcbData.layerCount << "материалов:" << pcbData.dielMaterials.size(); } else { qDebug() << "DataBaseController: Данные PCB не найдены в БД"; } return pcbData; } QList DataBaseController::getDielMaterials() { QList materials; if (!m_database.isOpen()) { setLastError("База данных не открыта"); return materials; } // Получаем материалы для последней записи PCB QSqlQuery pcbQuery = prepareQuery("SELECT id FROM pcb_data ORDER BY id DESC LIMIT 1"); if (pcbQuery.exec() && pcbQuery.next()) { int pcbId = pcbQuery.value(0).toInt(); materials = getDielMaterials(pcbId); qDebug() << "DataBaseController: Получены материалы для PCB ID:" << pcbId << "количество:" << materials.size(); } else { qDebug() << "DataBaseController: Записи PCB не найдены в БД"; } return materials; } bool DataBaseController::savePCBData(const PCBData &pcbData) { qDebug() << "DataBaseController: Начинаем сохранение PCB данных:"; qDebug() << " ID:" << pcbData.id; qDebug() << " LayerCount:" << pcbData.layerCount; qDebug() << " Materials count:" << pcbData.dielMaterials.size(); if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } if (!beginTransaction()) { qDebug() << "DataBaseController: ОШИБКА: Не удалось начать транзакцию"; return false; } int pcbId = pcbData.id; if (pcbId == -1) { // Создаем новую запись PCB qDebug() << "DataBaseController: Создаем новую запись PCB"; pcbId = addPCBData(pcbData.layerCount); if (pcbId == -1) { qDebug() << "DataBaseController: ОШИБКА: Не удалось создать запись PCB"; rollbackTransaction(); return false; } qDebug() << "DataBaseController: Создана запись PCB с ID:" << pcbId; } else { // Обновляем существующую запись qDebug() << "DataBaseController: Обновляем существующую запись PCB с ID:" << pcbId; if (!updatePCBLayerCount(pcbId, pcbData.layerCount)) { qDebug() << "DataBaseController: ОШИБКА: Не удалось обновить запись PCB"; rollbackTransaction(); return false; } } // Сохраняем диэлектрические материалы qDebug() << "DataBaseController: Сохраняем" << pcbData.dielMaterials.size() << "материалов"; for (int i = 0; i < pcbData.dielMaterials.size(); i++) { const DielProperty &material = pcbData.dielMaterials[i]; qDebug() << "DataBaseController: Сохраняем материал" << i << ":" << material.name << "=" << material.value << "слой:" << material.layerNumber; if (!addDielMaterial(pcbId, material.name, material.value, material.height, material.dielType, material.layerNumber)) { qDebug() << "DataBaseController: ОШИБКА: Не удалось сохранить материал" << i; rollbackTransaction(); return false; } } if (!commitTransaction()) { qDebug() << "DataBaseController: ОШИБКА: Не удалось завершить транзакцию"; rollbackTransaction(); return false; } qDebug() << "DataBaseController: PCB данные успешно сохранены"; return true; } bool DataBaseController::clearPCBData() { if (!m_database.isOpen()) { setLastError("База данных не открыта"); return false; } QSqlQuery query = prepareQuery("DELETE FROM pcb_data"); if (!query.exec()) { setLastError("Ошибка очистки данных PCB: " + query.lastError().text()); return false; } emit dataChanged(); return true; }