Spaces:
Running
Промт:
Browse filesЕсть Excel-таблица (2016) "1С" ктороая содержит данные сотрудников выгруженные из 1С, в этом файле есть два листа:
1й лист имеет название "ВСЕ ОП" - в нем таблица с данными на всех действующих, трудоустроенных сотрудников. Таблица имееет Заголоки на первой строке, название столбцов:
2й лист имеет название "увольнение" или "Уволены" или "Уволенные" в зависимости как выгрузят из 1С - в нем таблица с данными на всех Уволенных сотрудников. Таблица имееет Заголоки на первой строке, название столбцов, аналогично как и на первом листе,
Необходимо обьединисть эти два листа в один, создать три уникальных столбца:
столбец - B - ФИО+ДР
столбец - C - ФИО+Дата ТУ
столбец - D - Объединенный номер
проанлизировать таблицу, если я ячейка есть значени "0", то удалить, далее по уникальным столбцам: столбец - B - ФИО+ДР удалить дубликаты, а данные из столбцов:
1С столбец - A - Таб№,
1С столбец - H - Дата приема
1С столбец - I - Дата увольнения, распределить в порядке убывния:
столбец - AG - Дата приема данные последнего (текущего) устройотва на работу
столбец - AH - Дата увольнения данные последнего устройотва на работу или осталять пустым если нет даты
столбец - BO - Таб №7 данные по убыванию из 1С столбец - A - Таб№
столбец - BP - Дата Приема 7 данные по убыванию из 1С столбец - H - Дата приема
столбец - BQ - Дата увольнения 7 данные по убыванию из 1С столбец - I - Дата увольнения
столбец - BR - СтаКоличество отработынных дней 7 ="столбец - BQ - Дата увольнения 7" - "столбец - BP - Дата Приема 7" (формат числовой)
столбец - BK - Таб №6 след данные по убыванию, если есть
столбец - BL - Дата Приема 6 след данные по убыванию, если есть
столбец - BM - Дата увольнения 6 след данные по убыванию, если есть
столбец - BN - Количество отработынных дней 6 ="столбец - BM - Дата увольнения 6" - "столбец - столбец - BL - Дата Приема 6" (формат числовой)
столбец - BG - Таб №5 аналогично предыдушим столбцам
столбец - BH - Дата Приема 5 аналогично предыдушим столбцам
столбец - BI - Дата увольнения 5 аналогично предыдушим столбцам
столбец - BJ - Количество отработынных дней 5 аналогично предыдушим столбцам
столбец - BC - Таб №4 аналогично предыдушим столбцам
столбец - BD - Дата Приема 4 аналогично предыдушим столбцам
столбец - BE - Дата увольнения 4 аналогично предыдушим столбцам
столбец - BF - Количество отработынных дней 4 аналогично предыдушим столбцам
столбец - AY - Таб №3 аналогично предыдушим столбцам
столбец - AZ - Дата Приема 3 аналогично предыдушим столбцам
столбец - BA - Дата увольнения 3 аналогично предыдушим столбцам
столбец - BB - Количество отработынных дней 3 аналогично предыдушим столбцам
столбец - AU - Таб №2 аналогично предыдушим столбцам
столбец - AV - Дата Приема 2 аналогично предыдушим столбцам
столбец - AW - Дата увольнения 2 аналогично предыдушим столбцам
столбец - AX - Количество отработынных дней 2 аналогично предыдушим столбцам
столбец - AQ - Таб №1 аналогично предыдушим столбцам
столбец - AR - Дата Приема 1 аналогично предыдушим столбцам
столбец - AS - Дата увольнения 1 аналогично предыдушим столбцам
столбец - AT - Количество отработынных дней 1 аналогично предыдушим столбцам
1й лист "ВСЕ ОП":
Название СТОЛБЦА // Заголовки // ПРИМЕР Данные сотрудников -
столбец - A // Таб№ // ВМ-0180996
столбец - B // ФИО // Абдазов Омурбек
столбец - C // Должность // Изолировщик на термоизоляции
столбец - D // Разряд // 4 разряд
столбец - E // Территория // 005 (АГПЗ-СК (ВСМ))
столбец - F // Организация // СВОБОДНЫЙ (ВСМ)
столбец - G // Подразделение // Участок по монтажу теплоизоляции (ВСМ)
столбец - H // Дата приема // 24.09.2025
столбец - I // Дата увольнения // 0
столбец - J // Сотрудник.Дата выхода на работу (Сотрудники) // 0
столбец - K // Страна гражданства // КИРГИЗИЯ
столбец - L // Удостоверение.Серия // AC
столбец - M // Удостоверение.Номер // 3082078
столбец - N // Дата рождения // 25.06.1979
столбец - O // Место рождения // особое Кыргызстан
столбец - P // Удостоверение.Кем выдан // SRS
столбец - Q // Удостоверение.Дата выдачи // 02.11.2017
столбец - R // Физическое лицо.Дата регистрации // 0
столбец - S // Удостоверение.Код подразделения // 0
столбец - T // Физическое лицо.Адрес по прописке // РОССИЯ, Амурская область, р-н Свободненский, с Черниговка, зд. 18
столбец - U // СНИЛС // 205-448-691 65
столбец - V // ИНН // 0
столбец - W // Физическое лицо.Адрес за пределами РФ // КИРГИЗИЯ
столбец - X // Физическое лицо.Личный мобильный телефон // +7 (983) 4565809
столбец - Y // Физическое лицо.Мобильный телефон // 0
столбец - Z // Физическое лицо.телефон родственника // +7 (111) 1111111
столбец - AA // Состояние // Работа
столбец - AB // Класс условий труда // Подкласс 3.1 класса условий труда "вредный"
столбец - AC // Класс условий труда дата регистрации // 02.05.2025
столбец - AD // График работы // ВМ 3/1/3 (ВСМ)
столбец - AE // Общий стаж лет // 0
столбец - AF // Общий стаж месяцев // 1
столбец - AG // Общий стаж дней // 8
столбец - AH // Трудовой договор номер // СД-871/2025
столбец - AI // Приказ о приеме.Номер // СД00-000871
столбец - AJ // Приказ о приеме.Разрешение на работу // 0
столбец - AK // Приказ о приеме.Разрешение на проживание // 0
столбец - AL // Тарифная ставка // 140
столбец - AM // Вид // Сведения о трудовой деятельности в электронной форме
Строк в этом листе более 15000
2й лист имеет название "увольнение" или "Уволены" или "Уволенные" в зависимости как выгрузят из 1С - в нем таблица с данными на всех Уволенных сотрудников. Таблица имееет Заголоки на первой строке, название столбцов, аналогично как и на первом листе, только в столбец - I // Дата увольнения // 0
стоит дата увольнеие сотрудника.
Строк во втором листе, более 85000
Так же есть файл Excel в котором на каждом листе содержится инфрмация о Прибытии сотрудника на вахту и Убытии сотрудника с площадки. название листов:
Вылет январь 2025
Прилет январь 2025
Вылет февраль 2025
Прилет февраль 2025
Вылет МАРТ
Прилет МАРТ
Вылет Апрель
Прилет Апре�
- components/database.js +86 -0
- components/excel-viewer.js +50 -0
- index.html +52 -2
- script.js +68 -0
- style.css +128 -19
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class EmployeeDatabase {
|
| 2 |
+
constructor() {
|
| 3 |
+
this.db = JSON.parse(window.localStorage.getItem('employeeDB')) || {
|
| 4 |
+
employees: [],
|
| 5 |
+
lastUpdate: new Date().toISOString()
|
| 6 |
+
};
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
save() {
|
| 10 |
+
window.localStorage.setItem('employeeDB', JSON.stringify(this.db));
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
addEmployee(employeeData) {
|
| 14 |
+
// Process 1C data
|
| 15 |
+
const employee = {
|
| 16 |
+
id: this.generateId(),
|
| 17 |
+
fullName: employeeData.B,
|
| 18 |
+
birthDate: employeeData.N,
|
| 19 |
+
hireDate: employeeData.H,
|
| 20 |
+
terminationDate: employeeData.I,
|
| 21 |
+
tabNumber: employeeData.A,
|
| 22 |
+
position: employeeData.C,
|
| 23 |
+
rank: employeeData.D,
|
| 24 |
+
territory: employeeData.E,
|
| 25 |
+
organization: employeeData.F,
|
| 26 |
+
department: employeeData.G,
|
| 27 |
+
// Add all other fields from the specification
|
| 28 |
+
// ...
|
| 29 |
+
updatedAt: new Date().toISOString()
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
this.db.employees.push(employee);
|
| 33 |
+
this.save();
|
| 34 |
+
return employee;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
updateEmployee(tabNumber, newData) {
|
| 38 |
+
const index = this.db.employees.findIndex(e => e.tabNumber === tabNumber);
|
| 39 |
+
if (index !== -1) {
|
| 40 |
+
this.db.employees[index] = {
|
| 41 |
+
...this.db.employees[index],
|
| 42 |
+
...newData,
|
| 43 |
+
updatedAt: new Date().toISOString()
|
| 44 |
+
};
|
| 45 |
+
this.save();
|
| 46 |
+
return true;
|
| 47 |
+
}
|
| 48 |
+
return false;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
findEmployee(tabNumber) {
|
| 52 |
+
return this.db.employees.find(e => e.tabNumber === tabNumber);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
getAllEmployees() {
|
| 56 |
+
return this.db.employees;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
generateId() {
|
| 60 |
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
| 61 |
+
const r = Math.random() * 16 | 0;
|
| 62 |
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
| 63 |
+
return v.toString(16);
|
| 64 |
+
});
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// Add methods for processing different file types
|
| 68 |
+
process1CData(workbook) {
|
| 69 |
+
// Implementation for processing 1C data
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
processFlightData(workbook) {
|
| 73 |
+
// Implementation for processing flight data
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
processPositionData(workbook) {
|
| 77 |
+
// Implementation for processing position data
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
// Export for use in other files
|
| 82 |
+
if (typeof module !== 'undefined' && module.exports) {
|
| 83 |
+
module.exports = EmployeeDatabase;
|
| 84 |
+
} else {
|
| 85 |
+
window.EmployeeDatabase = EmployeeDatabase;
|
| 86 |
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class ExcelViewer {
|
| 2 |
+
constructor(containerId) {
|
| 3 |
+
this.container = document.getElementById(containerId);
|
| 4 |
+
this.init();
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
init() {
|
| 8 |
+
// Create a table structure that mimics Excel
|
| 9 |
+
this.table = document.createElement('table');
|
| 10 |
+
this.table.className = 'excel-table';
|
| 11 |
+
this.container.appendChild(this.table);
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
loadData(data) {
|
| 15 |
+
// Clear existing data
|
| 16 |
+
this.table.innerHTML = '';
|
| 17 |
+
|
| 18 |
+
// Create header row
|
| 19 |
+
const headerRow = document.createElement('tr');
|
| 20 |
+
Object.keys(data[0]).forEach(key => {
|
| 21 |
+
const th = document.createElement('th');
|
| 22 |
+
th.textContent = key;
|
| 23 |
+
headerRow.appendChild(th);
|
| 24 |
+
});
|
| 25 |
+
this.table.appendChild(headerRow);
|
| 26 |
+
|
| 27 |
+
// Create data rows
|
| 28 |
+
data.forEach(item => {
|
| 29 |
+
const row = document.createElement('tr');
|
| 30 |
+
Object.values(item).forEach(value => {
|
| 31 |
+
const td = document.createElement('td');
|
| 32 |
+
td.textContent = value;
|
| 33 |
+
row.appendChild(td);
|
| 34 |
+
});
|
| 35 |
+
this.table.appendChild(row);
|
| 36 |
+
});
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
exportToExcel() {
|
| 40 |
+
// Implementation for exporting to Excel
|
| 41 |
+
// Would use SheetJS library
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
// Export for use in other files
|
| 46 |
+
if (typeof module !== 'undefined' && module.exports) {
|
| 47 |
+
module.exports = ExcelViewer;
|
| 48 |
+
} else {
|
| 49 |
+
window.ExcelViewer = ExcelViewer;
|
| 50 |
+
}
|
|
@@ -1,3 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
|
| 2 |
-
|
| 3 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="ru">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Employee Database System</title>
|
| 7 |
+
<link rel="stylesheet" href="style.css">
|
| 8 |
+
<link rel="stylesheet" href="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.css">
|
| 9 |
+
<script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"></script>
|
| 10 |
+
</head>
|
| 11 |
+
<body>
|
| 12 |
+
<div class="app-container">
|
| 13 |
+
<div class="splash-screen" id="splashScreen">
|
| 14 |
+
<div class="splash-content">
|
| 15 |
+
<img src="https://sun9-42.userapi.com/impf/c858036/v858036285/1855c/ZwoaHhx7m54.jpg?size=1200x772&quality=96&sign=7c74500dc2086c35adc5a8e1e02cb691&c_uniq_tag=mTRocJUOr2Mi9H-Qr0GjOSa_B8FMskeVeaL5yBnLzAg&type=album"
|
| 16 |
+
alt="Background" class="splash-bg">
|
| 17 |
+
<div class="splash-actions">
|
| 18 |
+
<button id="loadConfig" class="action-btn">Загрузить файл Настройка</button>
|
| 19 |
+
<button id="load1C" class="action-btn">Загрузить данные 1С</button>
|
| 20 |
+
<button id="loadFlight" class="action-btn">Загрузить данные Прилет/Вылет</button>
|
| 21 |
+
<button id="loadPosition" class="action-btn">Загрузить данные факт. должности и участка</button>
|
| 22 |
+
<button id="continueBtn" class="action-btn">ПРОДОЛЖИТЬ</button>
|
| 23 |
+
<button id="exitBtn" class="action-btn">ВЫЙТИ</button>
|
| 24 |
+
</div>
|
| 25 |
+
</div>
|
| 26 |
+
</div>
|
| 27 |
|
| 28 |
+
<div class="main-content" id="mainContent" style="display:none;">
|
| 29 |
+
<div class="toolbar">
|
| 30 |
+
<button id="exportBtn">Экспорт в Excel</button>
|
| 31 |
+
<button id="filterBtn">Фильтры</button>
|
| 32 |
+
<button id="refreshBtn">Обновить данные</button>
|
| 33 |
+
</div>
|
| 34 |
+
<div class="excel-container" id="excelContainer"></div>
|
| 35 |
+
</div>
|
| 36 |
+
|
| 37 |
+
<div class="file-input-modal" id="fileModal" style="display:none;">
|
| 38 |
+
<div class="modal-content">
|
| 39 |
+
<h3 id="modalTitle">Загрузка файла</h3>
|
| 40 |
+
<input type="file" id="fileInput" accept=".xlsx,.xls,.xlsb">
|
| 41 |
+
<div class="modal-actions">
|
| 42 |
+
<button id="cancelBtn">Отмена</button>
|
| 43 |
+
<button id="confirmBtn">OK</button>
|
| 44 |
+
</div>
|
| 45 |
+
</div>
|
| 46 |
+
</div>
|
| 47 |
+
</div>
|
| 48 |
+
|
| 49 |
+
<script src="components/database.js"></script>
|
| 50 |
+
<script src="components/excel-viewer.js"></script>
|
| 51 |
+
<script src="script.js"></script>
|
| 52 |
+
</body>
|
| 53 |
+
</html>
|
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 2 |
+
// UI Elements
|
| 3 |
+
const splashScreen = document.getElementById('splashScreen');
|
| 4 |
+
const mainContent = document.getElementById('mainContent');
|
| 5 |
+
const fileModal = document.getElementById('fileModal');
|
| 6 |
+
const modalTitle = document.getElementById('modalTitle');
|
| 7 |
+
const fileInput = document.getElementById('fileInput');
|
| 8 |
+
const cancelBtn = document.getElementById('cancelBtn');
|
| 9 |
+
const confirmBtn = document.getElementById('confirmBtn');
|
| 10 |
+
|
| 11 |
+
// Button handlers
|
| 12 |
+
document.getElementById('loadConfig').addEventListener('click', () => showFileModal('Настройка'));
|
| 13 |
+
document.getElementById('load1C').addEventListener('click', () => showFileModal('1C Data'));
|
| 14 |
+
document.getElementById('loadFlight').addEventListener('click', () => showFileModal('Flight Data'));
|
| 15 |
+
document.getElementById('loadPosition').addEventListener('click', () => showFileModal('Position Data'));
|
| 16 |
+
document.getElementById('continueBtn').addEventListener('click', continueToMain);
|
| 17 |
+
document.getElementById('exitBtn').addEventListener('click', exitApp);
|
| 18 |
+
|
| 19 |
+
cancelBtn.addEventListener('click', closeFileModal);
|
| 20 |
+
confirmBtn.addEventListener('click', processFile);
|
| 21 |
+
|
| 22 |
+
function showFileModal(title) {
|
| 23 |
+
modalTitle.textContent = `Загрузка файла ${title}`;
|
| 24 |
+
fileInput.value = '';
|
| 25 |
+
fileModal.style.display = 'flex';
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
function closeFileModal() {
|
| 29 |
+
fileModal.style.display = 'none';
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
function processFile() {
|
| 33 |
+
const file = fileInput.files[0];
|
| 34 |
+
if (!file) return;
|
| 35 |
+
|
| 36 |
+
// Here we would process the file based on the modal title
|
| 37 |
+
const reader = new FileReader();
|
| 38 |
+
reader.onload = function(e) {
|
| 39 |
+
const data = new Uint8Array(e.target.result);
|
| 40 |
+
const workbook = XLSX.read(data, { type: 'array' });
|
| 41 |
+
|
| 42 |
+
// Process workbook based on file type
|
| 43 |
+
// TODO: Add specific processing for each file type
|
| 44 |
+
closeFileModal();
|
| 45 |
+
};
|
| 46 |
+
reader.readAsArrayBuffer(file);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
function continueToMain() {
|
| 50 |
+
splashScreen.style.display = 'none';
|
| 51 |
+
mainContent.style.display = 'flex';
|
| 52 |
+
// Load initial data here
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
function exitApp() {
|
| 56 |
+
if (confirm('Вы уверены, что хотите выйти?')) {
|
| 57 |
+
window.close();
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
// Initialize database
|
| 62 |
+
if (!window.localStorage.getItem('employeeDB')) {
|
| 63 |
+
window.localStorage.setItem('employeeDB', JSON.stringify({
|
| 64 |
+
employees: [],
|
| 65 |
+
lastUpdate: new Date().toISOString()
|
| 66 |
+
}));
|
| 67 |
+
}
|
| 68 |
+
});
|
|
@@ -1,28 +1,137 @@
|
|
| 1 |
-
body {
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
| 4 |
}
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
|
| 18 |
-
.
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
border-radius: 16px;
|
| 24 |
}
|
| 25 |
|
| 26 |
-
.
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
| 28 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body, html {
|
| 2 |
+
margin: 0;
|
| 3 |
+
padding: 0;
|
| 4 |
+
height: 100%;
|
| 5 |
+
font-family: Arial, sans-serif;
|
| 6 |
}
|
| 7 |
|
| 8 |
+
.app-container {
|
| 9 |
+
height: 100vh;
|
| 10 |
+
display: flex;
|
| 11 |
+
flex-direction: column;
|
| 12 |
}
|
| 13 |
|
| 14 |
+
.splash-screen {
|
| 15 |
+
position: fixed;
|
| 16 |
+
top: 0;
|
| 17 |
+
left: 0;
|
| 18 |
+
width: 100%;
|
| 19 |
+
height: 100%;
|
| 20 |
+
background-color: rgba(0, 0, 0, 0.8);
|
| 21 |
+
display: flex;
|
| 22 |
+
justify-content: center;
|
| 23 |
+
align-items: center;
|
| 24 |
+
z-index: 1000;
|
| 25 |
}
|
| 26 |
|
| 27 |
+
.splash-content {
|
| 28 |
+
position: relative;
|
| 29 |
+
width: 80%;
|
| 30 |
+
max-width: 1200px;
|
| 31 |
+
height: 80%;
|
|
|
|
| 32 |
}
|
| 33 |
|
| 34 |
+
.splash-bg {
|
| 35 |
+
width: 100%;
|
| 36 |
+
height: 100%;
|
| 37 |
+
object-fit: cover;
|
| 38 |
+
border-radius: 10px;
|
| 39 |
}
|
| 40 |
+
|
| 41 |
+
.splash-actions {
|
| 42 |
+
position: absolute;
|
| 43 |
+
top: 20px;
|
| 44 |
+
left: 20px;
|
| 45 |
+
display: flex;
|
| 46 |
+
flex-direction: column;
|
| 47 |
+
gap: 10px;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.action-btn {
|
| 51 |
+
padding: 12px 20px;
|
| 52 |
+
background-color: #2c3e50;
|
| 53 |
+
color: white;
|
| 54 |
+
border: none;
|
| 55 |
+
border-radius: 5px;
|
| 56 |
+
cursor: pointer;
|
| 57 |
+
font-size: 16px;
|
| 58 |
+
transition: background-color 0.3s;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.action-btn:hover {
|
| 62 |
+
background-color: #1a252f;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
.main-content {
|
| 66 |
+
flex: 1;
|
| 67 |
+
display: flex;
|
| 68 |
+
flex-direction: column;
|
| 69 |
+
padding: 20px;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.toolbar {
|
| 73 |
+
padding: 10px;
|
| 74 |
+
background-color: #f8f9fa;
|
| 75 |
+
display: flex;
|
| 76 |
+
gap: 10px;
|
| 77 |
+
margin-bottom: 10px;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
.toolbar button {
|
| 81 |
+
padding: 8px 16px;
|
| 82 |
+
background-color: #3498db;
|
| 83 |
+
color: white;
|
| 84 |
+
border: none;
|
| 85 |
+
border-radius: 4px;
|
| 86 |
+
cursor: pointer;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
.excel-container {
|
| 90 |
+
flex: 1;
|
| 91 |
+
overflow: auto;
|
| 92 |
+
border: 1px solid #ddd;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
.file-input-modal {
|
| 96 |
+
position: fixed;
|
| 97 |
+
top: 0;
|
| 98 |
+
left: 0;
|
| 99 |
+
width: 100%;
|
| 100 |
+
height: 100%;
|
| 101 |
+
background-color: rgba(0, 0, 0, 0.5);
|
| 102 |
+
display: flex;
|
| 103 |
+
justify-content: center;
|
| 104 |
+
align-items: center;
|
| 105 |
+
z-index: 1001;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
.modal-content {
|
| 109 |
+
background-color: white;
|
| 110 |
+
padding: 20px;
|
| 111 |
+
border-radius: 8px;
|
| 112 |
+
width: 400px;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
.modal-actions {
|
| 116 |
+
display: flex;
|
| 117 |
+
justify-content: flex-end;
|
| 118 |
+
gap: 10px;
|
| 119 |
+
margin-top: 20px;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
.modal-actions button {
|
| 123 |
+
padding: 8px 16px;
|
| 124 |
+
border: none;
|
| 125 |
+
border-radius: 4px;
|
| 126 |
+
cursor: pointer;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
#cancelBtn {
|
| 130 |
+
background-color: #e74c3c;
|
| 131 |
+
color: white;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
#confirmBtn {
|
| 135 |
+
background-color: #2ecc71;
|
| 136 |
+
color: white;
|
| 137 |
+
}
|