Библиотека окон
/**
* @fileoverview Модуль диалоговых окон.
* Реализует пользовательский интерфейс для выбора файла с возможностью ввода пути и обработки результата.
* Создаётся как часть объекта Common.Dialog.
*/
(function () {
/**
* Класс `Dialog` реализует функционал модального окна для выбора файла или ввода пути к данным.
* @class
*/
class Dialog {
/**
* Инициализирует новый экземпляр класса Dialog.
* @constructor
*/
constructor() {
/**
* Функция обратного вызова (callback), которая будет вызвана после подтверждения диалога.
* @type {?Function}
*/
this.fnc = null;
this.functionFilter = null;
//console.log("Load Dialog");
}
/**
* Открывает модальное окно для ввода пути к файлу.
*
* @param {Function} fnc - Callback-функция, которая будет вызвана при нажатии на "Принять".
* @param {string} [fileName=""] - Значение по умолчанию для поля ввода пути к файлу.
*/
ShowOpenFile(fnc, fileName = "") {
this.fnc = fnc;
const self = this;
let html = `
<div id='openFileWindow' class='asc-window modal advanced-settings-dlg'
style='
display: block;
opacity: 1;
position: absolute;
top: 400px;
left: 50%;
transform: translate(-50%, -50%);
width: 500px;
z-index: 10000;
border: 2px solid #0070C0;
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
'>
<div class='header'style='background-color: #0070C0; color: #FFFFFF;'>
<div class='title'>Обновление данных</div>
</div>
<div class='body' style='font-size:11pt; padding: 20px;'>
<label for='fileInput' style='display:block; margin:10px 0 5px 10px;'>Укажите путь к файлу: "Наример C:/Users/Admin/data.csv"</label>
<div class='footer center' style='display:flex; justify-content:center; gap:20px; margin-top:5px;'>
<input type='text' id='fileInput' class='input-field' placeholder='Введите путь' style='width:460px; margin-left:10px;'>
<button id='btnSelctFile' class='btn normal dlg-btn'>...</button>
</div>
<div class='footer center' style='display:flex; justify-content:center; gap:20px; margin-top:5px;'>
<button id='btn1' class='btn normal dlg-btn'>Принять</button>
<button id='btn2' class='btn normal dlg-btn'>Отклонить</button>
</div>
</div>
</div>
`;
$("#app-title").append(html);
$("#fileInput").val(fileName);
// Обработчик кнопки "..."
$("#btnSelctFile").click(function () {
AscDesktopEditor.OpenFilenameDialog("csv/txt", false, function(fileName) {
// Если файл выбрали
var file = fileName;
if (Array.isArray(file))
file = file[0]; //Если выбрали несколько берем первый
// Проверка на пустое значение
if (!file) {
alert('Файл не выбран');
return;
}
// Замена бэкслешей на слеши
file = file.replace(/\\/g, "/");
// Установка значения в input
$("#fileInput").val(file);
});
});
// Обработчик кнопки "Принять"
$("#btn1").click(function () {
const callback = {};
var fileName = $("#fileInput").val();
// Проверка на пустое значение
if (!fileName) {
alert('Имя файла не должно быть пустым');
return;
}
// Проверка на количество слешей в начале
if (fileName.startsWith('/')) {
if (fileName.startsWith('//')) {
// Если два слеша - очищаем поле
$("#fileInput").val('');
return;
} else {
// Если один слеш - убираем его
fileName = fileName.slice(1);
}
}
callback.fileName = fileName;
self.HideStatusWindow1(callback); // Передаем в callback
});
// Обработчик кнопки "Отклонить"
$("#btn2").click(function () {
self.HideStatusWindow(); // Закрываем окно без сохранения
});
}
/**
* Добавляет строку статуса в диалоговое окно.
*
* @param {string} statusId - Уникальный идентификатор статуса.
* @param {string} statusName - Название отображаемого статуса.
*/
AddStatus(statusId, statusName) {
const html = `
<div id='${statusId}' style='display:block'>
<span>${statusName}</span>
<span style='padding-left:15px; font-weight:bold'></span>
</div>
`;
$("#statusBox").append(html);
}
/**
* Обновляет текстовое значение указанного статуса.
*
* @param {string} statusId - Идентификатор статуса.
* @param {string} statusText - Новое значение статуса.
*/
SetStatus(statusId, statusText) {
$("#" + statusId + " span:last-child").html(statusText);
}
/**
* Удаляет строку статуса из диалогового окна.
*
* @param {string} statusId - Идентификатор статуса.
*/
RemoveStatus(statusId) {
$("#" + statusId).remove();
}
/**
* Закрывает диалоговое окно и вызывает переданный callback.
*
* @param {*} value - Данные, которые будут переданы в callback.
*/
HideStatusWindow1(value) {
if (typeof this.fnc === 'function') {
this.fnc(value); // Вызываем callback с данными
}
$("#openFileWindow").hide(250).remove(); // Удаляем DOM-элемент
}
/**
* Просто закрывает диалоговое окно без вызова callback.
*/
HideStatusWindow() {
$("#openFileWindow").hide(250).remove();
}
/**
* Фильтрует массив данных по заданным критериям.
*
* @param {string|null|undefined} eventType - Тип события для фильтрации. - список возможных + null
* @param {string|null|undefined} productId - ID продукта для фильтрации.
* @param {string|null|undefined} categoryCode - Код категории (по префиксу). - список возможных категорий 1 уровня + null
* @param {string|null|undefined} brand - Бренд для фильтрации. - список доступных + null
* @param {string|Date|null|undefined} minEventTime - Минимальная дата события. - минимальная дата
* @param {string|Date|null|undefined} maxEventTime - Максимальная дата события. - максимальная дата
* @param {number|string|null|undefined} minPrice - Минимальная цена.
* @param {number|string|null|undefined} maxPrice - Максимальная цена.
* @returns {Array<Object>} Отфильтрованный массив объектов.
*/
ShowProductFilter(brands, category1, eventDates, prices, functionFilter) {
this.functionFilter = functionFilter;
const self = this;
let periods=[];
let html = `
<div id='productFilter' class='asc-window modal advanced-settings-dlg'
style='
display:block;
opacity:1;
position:relative;
top:300px;
width:550px;
margin:auto;
z-index:10000;
border: 2px solid #0070C0;'>
<div class='header' style='background-color: #0070C0; font-weight: bold; color: #FFFFFF;'>
<div class='title'>Фильтр товаров</div>
</div>
<div class='body' style='font-size:11pt; padding: 20px;'>
<!-- Бренд
<div style='margin-bottom: 15px;'>
<label for='selectCategoryCode' style='display:block; margin: 0 0 5px 10px;'>Выберите бренд:</label>
<select id='selectBrand' name='Выберете бренд'
style='width: 480px; margin-left:10px; padding: 5px;'></select>
</div> -->
<!-- Категория -->
<div style='margin-bottom: 15px;'>
<label for='selectCategoryCode' style='display:block; margin: 0 0 5px 10px;'>Выберите категорию:</label>
<select id='selectCategoryCode' name='Выберете категорию'
style='width: 480px; margin-left:10px; padding: 5px;'></select>
</div>
<!-- Период -->
<div style='margin-bottom: 15px;'>
<label for='selectPeriod' style='display:block; margin: 0 0 5px 10px;'>Выберите период:</label>
<select id='selectPeriod' name='Выберете период'
style='width: 480px; margin-left:10px; padding: 5px;'></select>
</div>
<!-- Диапазон цен -->
<div style='margin-bottom: 15px; display: flex; gap: 10px;'>
<div style='flex: 1;'>
<label for='minPriceInput' style='display:block; margin: 0 0 5px 10px;'>Минимальная цена:</label>
<input type='text' id='minPriceInput' class='input-field'
placeholder='Минимальная цена'
style='width: 80%; padding: 5px; margin-left: 10px;'>
</div>
<div style='flex: 1;'>
<label for='maxPriceInput' style='display:block; margin: 0 0 5px 10px;'>Максимальная цена:</label>
<input type='text' id='maxPriceInput' class='input-field'
placeholder='Максимальная цена'
style='width: 80%; padding: 5px; margin-left: 10px;'>
</div>
</div>
<!-- Кнопки -->
<div style='display:flex; justify-content:center; gap:20px; margin-top:20px;'>
<button id='buttonOkFilter' class='btn normal dlg-btn'>Принять</button>
<button id='buttonCancelFilter' class='btn normal dlg-btn'>Отклонить</button>
</div>
</div>
</div>
`;
$("#app-title").append(html);
if(prices){
$("#minPriceInput").val(prices.minPrice);
$("#maxPriceInput").val(prices.maxPrice);
}
/**
$('<option>')
.val(null)
.text("")
.appendTo('#selectBrand');
console.log(brands);
if((brands)&&(brands.length>0)){
$.each(this.brands, function(index, row) {
$('<option>')
.val(row)
.text(row !== "" ? row : "noname")
.appendTo('#selectBrand');
});
}*/
if((eventDates.minDate)&&(eventDates.maxDate)){
periods = getMonthsBetween(eventDates.minDate, eventDates.maxDate);
$.each(periods, function(index, row) {
$('<option>')
.val(row)
.text(row ? row : "")
.appendTo('#selectPeriod');
});
}
if((category1)&&(category1.length>0)){
$.each(category1, function(index, row) {
$('<option>')
.val(row)
.text(row !=="" ? row : "no category")
.appendTo('#selectCategoryCode');
});
}
// Обработчик кнопки "Принять"
$("#buttonOkFilter").click(function () {
const callback = {};
//callback.brand = $("#selectBrand").val(); // Получаем значение из поля ввода
callback.categoryCode = $("#selectCategoryCode").val(); // Получаем значение из поля ввода
callback.minDate = new Date($("#selectPeriod").val().split('.')[1],+($("#selectPeriod").val().split('.')[0])-1,1); // Получаем значение из поля ввода
callback.maxDate = new Date($("#selectPeriod").val().split('.')[1],+($("#selectPeriod").val().split('.')[0]),0,23,59,59); // Получаем значение из поля ввода
callback.minPrice = $("#minPriceInput").val(); // Получаем значение из поля ввода
callback.maxPrice = $("#maxPriceInput").val(); // Получаем значение из поля ввода
if (self.clickOkFilter){
self.clickOkFilter(callback); // Передаем в callback
}
});
// Обработчик кнопки "Отклонить"
$("#buttonCancelFilter").click(function () {
self.clickCancelFilter(); // Закрываем окно без сохранения
});
}
/**
* Закрывает диалоговое окно и вызывает переданный callback.
*
* @param {*} value - Данные, которые будут переданы в callback.
*/
clickOkFilter(value) {
if (typeof this.functionFilter === 'function') {
this.functionFilter(value); // Вызываем callback с данными
}
$("#productFilter").hide(250).remove(); // Удаляем DOM-элемент
}
/**
* Просто закрывает диалоговое окно без вызова callback.
*/
clickCancelFilter() {
$("#productFilter").hide(250).remove();
}
}
function getMonthsBetween(startDate, endDate) {
// Создаем копии дат, чтобы не изменять исходные
let start = new Date(startDate);
let end = new Date(endDate);
start.setDate(1);
end.setDate(1);
end.setMonth(end.getMonth() + 1);
end.setDate(0);
// Массив для хранения результатов
let months = [];
// Пока начальная дата меньше или равна конечной
while (start <= end) {
// Формируем строку в формате месяц.год
let month = (start.getMonth() + 1).toString().padStart(2, '0');
let year = start.getFullYear();
months.push(`${month}.${year}`);
// Переходим к следующему месяцу
start.setMonth(start.getMonth() + 1);
// Если перешли границу года, возвращаем к началу месяца
if (start.getMonth() > 11) {
start.setFullYear(start.getFullYear() + 1);
start.setMonth(0);
}
}
return months;
}
/**
* Экземпляр класса Dialog, доступный через глобальный объект `Common`.
* @type {Dialog}
*/
Common.Dialog = new Dialog();
})();
Примеры реализации макросов
-
- Сообщения: 3
- Зарегистрирован: 11 дек 2023, 10:04