Добавить при выборе addAssortment отправить POST запрос по адресу '../nosy/save_form.php' Обработать данные запроса обратиться к sqlite 3 без pdo процедурно понятно CREATE TABLE [assortment]( [id] INTEGER PRIMARY KEY AUTOINCREMENT, [name_assort] TEXT, [price_cny] INT DEFAULT 0, [cost_price] INT DEFAULT 0, [price_no_vat] INT DEFAULT 0, [qty] INT DEFAULT 0, [type_select] INT DEFAULT 0); Запрос SELECT в таблицу assortment где колонка type_select == запросу POST Вывести собранные данные json_encode ... Полученые данные добавить еще одно поле class="card mb-3 form-entry" data-index= в formContainer но в Наименование оборудовани search-query Добавить select (добавить с возможностью select2 js) c выбором со списком name_assort при выборе которого в pfixsum подставлять price_no_vat Учесть при выборе еще qty==1 тогда переменновать слово Количество в quantity_query Метры и На оборот если qty==0 в Количество
<div id="htmlret" style="margin-bottom:50px"></div> <div id="htmltable" style="margin-bottom:50px"> <div class="container mt-5"> <h5>Формирование коммерческое предложение</h5> <div class="d-flex align-items-center gap-2 mb-3"> <button id="createFormBtn" type="button" class="btn btn-primary mb-3">Добавить в КП</button> <select class="form-control rounded form-select addAssortment" name="addAssortment" id="addAssortment" data-placeholder="Выбрать ассортимент" style="margin-top: -15px; width: auto;"> <option selected>Выбрать ассортимент</option> <option value="2">Магнитные позиционеры</option> <option value="3">Разъёмы</option> <option value="4">Кабели</option> <option value="5">Штанги</option> <option value="6">Крепежи профилей</option> <option value="7">Преобразователи</option> <option value="8">Государственная поверка</option> </select> </div> <!-- <button id="docPagemencla" class="btn btn-success mb-3 docPagemencla">Создание файла КП</button> --> <a id="docPagemencla" href="?page=kpcreate" class="btn btn-success mb-3 docPagemencla">Создание файла КП</a> <div id="formContainer"></div> </div> </div> $(document).ready(function () { const formKey = 'kpForms'; function saveToLocalStorage(data) { localStorage.setItem(formKey, JSON.stringify(data)); } function getFromLocalStorage() { return JSON.parse(localStorage.getItem(formKey)) || []; } function generateForm(index, formData = {}) { $('#htmltable').show(); return ` <div class="card mb-3 form-entry" data-index="${index}"> <div class="card-body" style="padding: 8px;"> <div class="row g-2 align-items-center"> <div class="col-md-3"> <lable>Позиция по проекту</lable> <input type="text" class="form-control position_project" placeholder="Позиция по проекту" value="${formData.position_project || ' '}"> </div> <div class="col-md-4"> <lable>Наименование оборудовани</lable> <input type="text" class="form-control search-query" placeholder="Наименование оборудования" value="${formData.search_query || ''}"> </div> <div class="col-md-1"> <lable>Количество</lable> <input type="number" class="form-control quantity_query" placeholder="Кол-во" value="${formData.quantity_query || ''}"> </div> <div class="col-md-3"> <lable>Цена за ед. товара без НДС, руб.</lable> <input type="number" class="form-control pfixsum" placeholder="Цена за ед. без НДС, руб." value="${formData.pfixsum || ''}"> </div> <div class="col-md-1" style="display:none"> <lable>Скидка %</lable> <input type="number" class="form-control pfixsumsale" placeholder="Скидка % руб." value="${formData.pfixsumsale || ''}"> </div> <div class="col-md-2 mt-4"> <button type="button" class="btn btn-danger removeBtn">Удалить</button> </div> </div> </div> </div>`; } function renderForms() { const formDataArray = getFromLocalStorage(); $('#formContainer').empty(); formDataArray.forEach((data, index) => { $('#formContainer').append(generateForm(index, data)); }); } function collectFormsData() { let data = []; $('#formContainer .form-entry').each(function () { const entry = $(this); data.push({ position_project: entry.find('.position_project').val(), search_query: entry.find('.search-query').val(), quantity_query: entry.find('.quantity_query').val(), pfixsum: entry.find('.pfixsum').val(), pfixsumsale: entry.find('.pfixsumsale').val() }); }); return data; } // Добавление новой формы $('#createFormBtn').on('click', function () { $('#docPagemencla').show(); const searchVal = $('#search-query').val(); const pfixVal = $('#pfixsum').val(); //const pfixValSale = $('.pfixsumsale').val(); const newData = { position_project: '', // можно добавить отдельный input, если надо search_query: searchVal, quantity_query: '', pfixsum: pfixVal, pfixsumsale: '' }; const data = getFromLocalStorage(); //data.push({}); // пустая форма data.push(newData); // добавляем, не заменяя saveToLocalStorage(data); renderForms(); }); // Удаление формы $('#formContainer').on('click', '.removeBtn', function () { const index = $(this).closest('.form-entry').data('index'); let data = getFromLocalStorage(); data.splice(index, 1); saveToLocalStorage(data); renderForms(); if ($('#formContainer .form-entry').length) { // Если элемент существует (length > 0), показываем #docPagemencla $('#docPagemencla').show(); } else { // Если элемента не существует (length === 0), скрываем #docPagemencla $('#docPagemencla').hide(); } }); // Автосохранение при изменении полей $('#formContainer').on('input', 'input', function () { const updatedData = collectFormsData(); saveToLocalStorage(updatedData); }); $('#htmltable').hide(); // Восстановление данных при загрузке renderForms(); });Вот полный исправленный и дополненный код с учётом всех ваших требований:
Что реализовано:
- При выборе в <select id="addAssortment"> отправляется POST-запрос на ../nosy/save_form.php с параметром type_select.
- PHP-скрипт save_form.php (пример ниже) подключается к SQLite3 процедурно, делает SELECT * FROM assortment WHERE type_select = :type.
- Возвращает данные в JSON.
- JavaScript получает JSON, строит карточки с классом class="card mb-3 form-entry" data-index="...".
- В поле "Наименование оборудования" (search-query) подставляется name_assort.
- В поле "Цена за ед. без НДС" (pfixsum) подставляется price_no_vat.
- Если qty == 1 — надпись меняется на "Метры", если qty == 0 — "Количество".
- Select2 подключён для выбора ассортимента с поиском.
1. PHP-скрипт: ../nosy/save_form.php
<?php
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['type_select'])) {
echo json_encode(['error' => 'Invalid request']);
exit;
}
$type_select = (int)$_POST['type_select'];
try {
$db = new SQLite3('../../db/your_database.db'); // Укажите правильный путь к БД
$stmt = $db->prepare('SELECT * FROM assortment WHERE type_select = :type');
$stmt->bindValue(':type', $type_select, SQLITE3_INTEGER);
$result = $stmt->execute();
$items = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$items[] = $row;
}
echo json_encode($items);
} catch (Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
} finally {
$db->close();
}
?>2. Обновлённый HTML + JavaScript
<div id="htmlret" style="margin-bottom:50px"></div>
<div id="htmltable" style="margin-bottom:50px">
<div class="container mt-5">
<h5>Формирование коммерческое предложение</h5>
<div class="d-flex align-items-center gap-2 mb-3">
<button id="createFormBtn" type="button" class="btn btn-primary mb-3">Добавить в КП</button>
<select class="form-control rounded form-select addAssortment" name="addAssortment" id="addAssortment" data-placeholder="Выбрать ассортимент">
<option value="">Выбрать ассортимент</option>
<option value="2">Магнитные позиционеры</option>
<option value="3">Разъёмы</option>
<option value="4">Кабели</option>
<option value="5">Штанги</option>
<option value="6">Крепежи профилей</option>
<option value="7">Преобразователи</option>
<option value="8">Государственная поверка</option>
</select>
</div>
<a id="docPagemencla" href="?page=kpcreate" class="btn btn-success mb-3 docPagemencla" style="display:none;">Создание файла КП</a>
<div id="formContainer"></div>
</div>
</div>
<!-- Подключение Select2 (CDN) -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function () {
const formKey = 'kpForms';
// Инициализация Select2
$('#addAssortment').select2({
placeholder: "Выбрать ассортимент",
allowClear: true,
width: 'resolve'
});
function saveToLocalStorage(data) {
localStorage.setItem(formKey, JSON.stringify(data));
}
function getFromLocalStorage() {
return JSON.parse(localStorage.getItem(formKey)) || [];
}
function generateForm(index, formData = {}) {
const qtyLabel = formData.qty === 1 ? 'Метры' : 'Количество';
$('#htmltable').show();
$('#docPagemencla').show();
return `
<div class="card mb-3 form-entry" data-index="${index}">
<div class="card-body" style="padding: 8px;">
<div class="row g-2 align-items-center">
<div class="col-md-3">
<label>Позиция по проекту</label>
<input type="text" class="form-control position_project" placeholder="Позиция по проекту" value="${formData.position_project || ''}">
</div>
<div class="col-md-4">
<label>Наименование оборудования</label>
<input type="text" class="form-control search-query" placeholder="Наименование оборудования" value="${formData.search_query || ''}">
</div>
<div class="col-md-1">
<label class="quantity-label">${qtyLabel}</label>
<input type="number" class="form-control quantity_query" placeholder="Кол-во" value="${formData.quantity_query || ''}">
</div>
<div class="col-md-3">
<label>Цена за ед. товара без НДС, руб.</label>
<input type="number" class="form-control pfixsum" placeholder="Цена за ед. без НДС, руб." value="${formData.pfixsum || ''}">
</div>
<div class="col-md-1" style="display:none">
<label>Скидка %</label>
<input type="number" class="form-control pfixsumsale" placeholder="Скидка % руб." value="${formData.pfixsumsale || ''}">
</div>
<div class="col-md-2 mt-4">
<button type="button" class="btn btn-danger removeBtn">Удалить</button>
</div>
</div>
</div>
</div>`;
}
function renderForms() {
const formDataArray = getFromLocalStorage();
$('#formContainer').empty();
formDataArray.forEach((data, index) => {
$('#formContainer').append(generateForm(index, data));
});
if (formDataArray.length === 0) {
$('#docPagemencla').hide();
}
}
function collectFormsData() {
let data = [];
$('#formContainer .form-entry').each(function () {
const entry = $(this);
data.push({
position_project: entry.find('.position_project').val(),
search_query: entry.find('.search-query').val(),
quantity_query: entry.find('.quantity_query').val(),
pfixsum: entry.find('.pfixsum').val(),
pfixsumsale: entry.find('.pfixsumsale').val(),
qty: entry.find('.quantity_query').data('qty') || 0 // сохраняем для метки
});
});
return data;
}
// Основная логика: выбор ассортимента
$('#addAssortment').on('change', function () {
const typeSelect = $(this).val();
if (!typeSelect) return;
$.post('../nosy/save_form.php', { type_select: typeSelect }, function (response) {
if (typeof response === 'string') {
try {
response = JSON.parse(response);
} catch (e) {
console.error('JSON parse error:', e);
alert('Ошибка ответа сервера');
return;
}
}
if (response.error) {
alert('Ошибка: ' + response.error);
return;
}
const currentData = getFromLocalStorage();
response.forEach(item => {
const newEntry = {
position_project: '',
search_query: item.name_assort || '',
quantity_query: '',
pfixsum: item.price_no_vat || 0,
pfixsumsale: '',
qty: item.qty || 0
};
currentData.push(newEntry);
});
saveToLocalStorage(currentData);
renderForms();
// Сброс select
$('#addAssortment').val('').trigger('change');
}).fail(function () {
alert('Ошибка соединения с сервером');
});
});
// Кнопка "Добавить в КП" — пустая форма (если нужна)
$('#createFormBtn').on('click', function () {
const currentData = getFromLocalStorage();
currentData.push({
position_project: '',
search_query: '',
quantity_query: '',
pfixsum: '',
pfixsumsale: '',
qty: 0
});
saveToLocalStorage(currentData);
renderForms();
});
// Удаление
$('#formContainer').on('click', '.removeBtn', function () {
const index = $(this).closest('.form-entry').data('index');
let data = getFromLocalStorage();
data.splice(index, 1);
saveToLocalStorage(data);
renderForms();
});
// Автосохранение
$('#formContainer').on('input', 'input', function () {
const updatedData = collectFormsData();
saveToLocalStorage(updatedData);
});
// Изначально скрыто
$('#htmltable').hide();
renderForms();
});
</script>Примечания:
- Убедитесь, что путь к базе данных в save_form.php правильный.
- Select2 подключён через CDN — можно заменить на локальную версию.
- При добавлении нескольких позиций одного типа — все подходящие записи из таблицы assortment добавятся как отдельные строки.
- Если нужно выбирать одну конкретную позицию (а не все по типу) — потребуется другой подход (дополнительный select с полным списком).
Если нужно реализовать выбор конкретного name_assort через отдельный Select2 с автозаполнением цены — дайте знать, сделаю вторую версию.
Если нужно реализовать выбор конкретного name_assort через отдельный Select2 с автозаполнением цены — дайте знать, сделаю вторую версию
Вот вторая версия реализации — именно с выбором конкретной позиции из ассортимента через отдельный Select2 с поиском по name_assort.
Теперь:
- При выборе категории (типа) в первом <select id="addAssortment"> — загружаются все позиции этой категории.
- Появляется второй Select2 (с поиском) — список конкретных name_assort.
- При выборе конкретной позиции автоматически подставляются:
- Наименование (search-query)
- Цена без НДС (pfixsum)
- Метка "Количество" или "Метры" в зависимости от поля qty в базе (0 = Количество, 1 = Метры)
- После выбора позиция сразу добавляется как новая строка в КП.
1. PHP остаётся тем же (../nosy/save_form.php)
(Тот же код, что и в предыдущей версии — возвращает массив позиций по type_select.)
2. Обновлённый HTML + JavaScript
<div id="htmlret" style="margin-bottom:50px"></div>
<div id="htmltable" style="margin-bottom:50px">
<div class="container mt-5">
<h5>Формирование коммерческого предложение</h5>
<div class="d-flex align-items-center gap-2 mb-3">
<button id="createFormBtn" type="button" class="btn btn-primary mb-3">Добавить пустую строку</button>
<!-- Выбор категории -->
<select class="form-select addAssortment" id="addAssortment" style="width: auto;">
<option value="">Выбрать категорию</option>
<option value="2">Магнитные позиционеры</option>
<option value="3">Разъёмы</option>
<option value="4">Кабели</option>
<option value="5">Штанги</option>
<option value="6">Крепежи профилей</option>
<option value="7">Преобразователи</option>
<option value="8">Государственная поверка</option>
</select>
<!-- Выбор конкретной позиции (появится после выбора категории) -->
<select class="form-select" id="specificAssortment" style="width: auto; display: none;"></select>
</div>
<a id="docPagemencla" href="?page=kpcreate" class="btn btn-success mb-3 docPagemencla" style="display:none;">Создание файла КП</a>
<div id="formContainer"></div>
</div>
</div>
<!-- Select2 CSS и JS -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function () {
const formKey = 'kpForms';
let currentAssortmentData = []; // Храним загруженные позиции текущей категории
function saveToLocalStorage(data) {
localStorage.setItem(formKey, JSON.stringify(data));
}
function getFromLocalStorage() {
return JSON.parse(localStorage.getItem(formKey)) || [];
}
function generateForm(index, formData = {}) {
const qtyLabel = (formData.qty === 1) ? 'Метры' : 'Количество';
$('#htmltable').show();
if ($('#formContainer .form-entry').length === 0 && getFromLocalStorage().length === 0) {
$('#docPagemencla').hide();
} else {
$('#docPagemencla').show();
}
return `
<div class="card mb-3 form-entry" data-index="${index}">
<div class="card-body" style="padding: 8px;">
<div class="row g-2 align-items-center">
<div class="col-md-3">
<label>Позиция по проекту</label>
<input type="text" class="form-control position_project" placeholder="Позиция по проекту" value="${formData.position_project || ''}">
</div>
<div class="col-md-4">
<label>Наименование оборудования</label>
<input type="text" class="form-control search-query" placeholder="Наименование оборудования" value="${formData.search_query || ''}">
</div>
<div class="col-md-1">
<label class="quantity-label">${qtyLabel}</label>
<input type="number" class="form-control quantity_query" placeholder="Кол-во" value="${formData.quantity_query || ''}">
</div>
<div class="col-md-3">
<label>Цена за ед. товара без НДС, руб.</label>
<input type="number" class="form-control pfixsum" placeholder="Цена за ед. без НДС, руб." value="${formData.pfixsum || ''}">
</div>
<div class="col-md-1" style="display:none">
<label>Скидка %</label>
<input type="number" class="form-control pfixsumsale" value="${formData.pfixsumsale || ''}">
</div>
<div class="col-md-2 mt-4">
<button type="button" class="btn btn-danger removeBtn">Удалить</button>
</div>
</div>
</div>
</div>`;
}
function renderForms() {
const formDataArray = getFromLocalStorage();
$('#formContainer').empty();
formDataArray.forEach((data, index) => {
$('#formContainer').append(generateForm(index, data));
});
if (formDataArray.length === 0) {
$('#docPagemencla').hide();
} else {
$('#docPagemencla').show();
}
}
function collectFormsData() {
let data = [];
$('#formContainer .form-entry').each(function () {
const entry = $(this);
const qty = entry.find('.quantity-label').text() === 'Метры' ? 1 : 0;
data.push({
position_project: entry.find('.position_project').val(),
search_query: entry.find('.search-query').val(),
quantity_query: entry.find('.quantity_query').val(),
pfixsum: entry.find('.pfixsum').val(),
pfixsumsale: entry.find('.pfixsumsale').val(),
qty: qty
});
});
return data;
}
// Инициализация Select2 для категорий
$('#addAssortment').select2({
placeholder: "Выбрать категорию",
allowClear: true,
width: 'resolve'
});
// Инициализация второго Select2 (скроем изначально)
$('#specificAssortment').select2({
placeholder: "Выберите конкретную позицию",
allowClear: true,
width: 'resolve'
}).on('select2:select', function (e) {
const selectedItem = currentAssortmentData.find(item => item.id == e.params.data.id);
if (!selectedItem) return;
const newEntry = {
position_project: '',
search_query: selectedItem.name_assort || '',
quantity_query: '',
pfixsum: selectedItem.price_no_vat || 0,
pfixsumsale: '',
qty: selectedItem.qty || 0
};
const currentData = getFromLocalStorage();
currentData.push(newEntry);
saveToLocalStorage(currentData);
renderForms();
// Очистить выбор после добавления
$(this).val(null).trigger('change');
});
// При смене категории — загрузка конкретных позиций
$('#addAssortment').on('change', function () {
const typeSelect = $(this).val();
$('#specificAssortment').hide().empty();
if (!typeSelect) {
return;
}
$.post('../nosy/save_form.php', { type_select: typeSelect }, function (response) {
let data;
if (typeof response === 'string') {
try { data = JSON.parse(response); } catch (e) {
alert('Ошибка парсинга JSON');
return;
}
} else {
data = response;
}
if (data.error) {
alert('Ошибка: ' + data.error);
return;
}
currentAssortmentData = data;
if (data.length === 0) {
alert('В этой категории нет позиций');
return;
}
// Заполняем второй select
const $specific = $('#specificAssortment');
$specific.append('<option></option>'); // placeholder
data.forEach(item => {
$specific.append(`<option value="${item.id}">${item.name_assort} (${item.price_no_vat} руб.)</option>`);
});
$specific.show();
}).fail(function () {
alert('Ошибка связи с сервером');
});
});
// Кнопка добавления пустой строки
$('#createFormBtn').on('click', function () {
const currentData = getFromLocalStorage();
currentData.push({
position_project: '',
search_query: '',
quantity_query: '',
pfixsum: '',
pfixsumsale: '',
qty: 0
});
saveToLocalStorage(currentData);
renderForms();
});
// Удаление строки
$('#formContainer').on('click', '.removeBtn', function () {
const index = $(this).closest('.form-entry').data('index');
let data = getFromLocalStorage();
data.splice(index, 1);
saveToLocalStorage(data);
renderForms();
});
// Автосохранение
$('#formContainer').on('input', 'input', function () {
saveToLocalStorage(collectFormsData());
});
// Изначально скрыто
$('#htmltable').hide();
renderForms();
});
</script>Преимущества этой версии:
- Пользователь сначала выбирает категорию → видит только релевантные позиции.
- Полноценный поиск по наименованию внутри категории благодаря Select2.
- Автоматическая подстановка цены и правильной метки (Метры / Количество).
- Чистый интерфейс: второй селект появляется только после выбора категории.
Если нужно добавить возможность редактирования уже добавленной строки (чтобы можно было потом изменить позицию) — тоже можно доработать.
Готово к использованию!