/
Programist1983xp
/
fdff
Обзор
Документация
Войти
/
Programist1983xp
/
fdff
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
548 строк
18 KB
Programist1983xp
upload files
23 май 2025, 21:27
23 май 2025, 21:27
102b207
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Создание договора</title> <script src="https://cdn.jsdelivr.net/npm/html2pdf.js@0.10.1/dist/html2pdf.bundle.min.js"></script> <style> #pdfPreview iframe { width: 100%; height: 80vh; border: none; } body { background-color: rgb(150, 78, 245); font-family: Arial, sans-serif; margin: 20px; font-size: 14px; } h1 { text-align: center; margin-bottom: 20px; } form { max-width: 600px; margin: 0 auto 20px auto; } label { display: block; margin-top: 10px; } input, select { background-color: rgb(218, 128, 125); width: 100%; padding: 8px; box-sizing: border-box; } button { background-color: rgb(223, 199, 68); margin-top: 15px; padding: 10px 20px; cursor: pointer; } #pdfPreview { margin-top: 20px; } /* Адаптивность таблицы для маленьких экранов */ #itemsTable { width: 100%; border-collapse: collapse; overflow-x: auto; display: block; /* чтобы появился скролл */ } #itemsTable th, #itemsTable td { border: 1px solid #000; padding: 5px; text-align: center; min-width: 50px; } /* Стили для кнопки удаления - крестика */ .deleteBtn { background: none; border: none; color: red; font-size: 20px; line-height: 1; cursor: pointer; padding: 0; margin: 0; } #discountCheckbox { appearance: none; -webkit-appearance: none; width: 25px; height: 25px; border: 2px solid #ccc; border-radius: 3px; background-color: rgb(218, 128, 125); cursor: pointer; position: relative; } #discountCheckbox:checked { background-color: #1974ec; border-color: #4CAF50; } #discountCheckbox:checked::after { content: ''; position: absolute; top: 2px; left: 6px; width: 6px; height: 12px; border: solid rgb(138, 27, 27); border-width: 0 2px 2px 0; transform: rotate(45deg); } </style> </head> <body> <h1>Создать договор</h1> <form id="contractForm"> <label> <p>Наим услуги:</p> <input type="text" id="serviceName" placeholder="Наим" required> </label> <label> <p>Дата:</p> <input type="date" id="date" required> </label> <label> <p>Кол-во:</p> <input type="number" id="quantity" min="0" required> </label> <label> <p>Ед:</p> <select id="unit" required> <option value="т">т</option> <option value="м3">м3</option> </select> </label> <label> <p>Сумма (руб):</p> <input type="number" id="amount" min="0" required> </label> <label> <p>Имя заказчика:</p> <input type="text" id="customer" placeholder="Иванов И И" required> </label> <label> <p>Адрес:</p> <input type="text" id="address" placeholder="Новотрактовая, 13" required> </label> <label> <p>Телефон заказчика:</p> <input type="tel" id="customerPhone" placeholder="8-900-00-00" required> </label> <h3>Добавить позиции товаров/услуг</h3> <button type="button" onclick="showAddItemForm()">Добавить товар/услугу</button> <!-- Форма для добавления товаров --> <div id="additionalItemForm" style="display:none; margin-top:10px; padding:10px; border:1px solid #ccc; font-size:13px;"> <label> <p>Наим:</p> <input type="text" id="extraServiceName" placeholder="Наим" style="width:70%; display:inline-block;"> </label> <label> <p>Кол-во:</p> <input type="number" id="extraQuantity" min="0" style="width:70%; display:inline-block;"> </label> <label> <p>Ед:</p> <select id="extraUnit" style="width:70%; display:inline-block;"> <option value="т">т</option> <option value="м3">м3</option> </select> </label> <label> <p>Сумма:</p> <input type="number" id="extraAmount" min="0" style="width:70%; display:inline-block;"> </label> <button type="button" onclick="addItem()" style="margin-top:5px;">Добавить</button> </div> <div style="overflow-x:auto;"> <table id="itemsTable" style="width:100%; margin-top:10px;"> <thead> <tr> <th>№</th> <th>Наим</th> <th>Кол-во</th> <th>Ед</th> <th>Сумма, руб.</th> <th>удал</th> </tr> </thead> <tbody id="itemsBody"></tbody> </table> </div> <!-- Галочка для скидки --> <label style="margin-top:10px; display:flex; justify-content: space-around;"> <input type="checkbox" id="discountCheckbox" onchange="updatePreview()"> <span style="margin-left:8px;">5% скидка при предоставлении карты №</span> </label> <button type="button" onclick="downloadPdf()">Создать договор</button> <button type="button" onclick="previewPdf()">Предварительный просмотр</button> </form> <div id="pdfPreview"></div> <script> const machineBase64='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAMAAAC7m4fXAAAAclBMVEX///8AAABpaWn39/d/f3/5+fnz8/MdHR2qqqq2trbV1dVsbGxOTk5dXV3o6OghISHFxcXb29vU1NTv7+/n5+e2trbY2Ni8vLzv7+/X19cXFycnJx0dHSWlpYlJSUkJCR/f3/v7+2tra+vr4dHR3JycmZmZkRERA4ODhISEh/f3+YmJggICCKiopiYmIEBAQnJyczMzOJiYkVFRVKSkoTExMgICBLS0s6OjiYmJg4ODhpaWlZWVn4+Ph6enp7e3vKxMRU1PU1NQ8PDwAAAD///8e3iyFAAAAAXRSTlMAQObYZgAAAPpJREFUeAFjYBgFo2AUjIJRMApU0UQjEkiRILUFFBGhIpaCgVBAU8lAENQ0OaCgVBAU8lAENQ0OaCgVBAU8lAENQ0OaCgVBAU8lAENQ0ObAJAaXx7z0XZTAAAAAElFTkSuQmCC'; let items=[]; function showAddItemForm() { document.getElementById('additionalItemForm').style.display='block'; document.getElementById('extraServiceName').value=''; document.getElementById('extraQuantity').value=''; document.getElementById('extraUnit').value='т'; document.getElementById('extraAmount').value=''; } function addItem() { const name = document.getElementById('extraServiceName').value.trim(); const quantity = document.getElementById('extraQuantity').value; const unit = document.getElementById('extraUnit').value; const amount = document.getElementById('extraAmount').value; if(!name || !quantity || !amount){ alert('Пожалуйста, заполните все поля для товара/услуги.'); return; } items.push({ serviceName: name, quantity: quantity, unit: unit, amount: amount }); updateItemsTable(); document.getElementById('additionalItemForm').style.display='none'; updatePreview(); } function updateItemsTable() { const tbody=document.getElementById('itemsBody'); tbody.innerHTML=''; items.forEach( (item, index)=> { const row=document.createElement('tr'); const cellNum=document.createElement('td'); cellNum.textContent= index+1; row.appendChild(cellNum); const cellName=document.createElement('td'); cellName.textContent= item.serviceName; row.appendChild(cellName); const cellQty=document.createElement('td'); cellQty.textContent= item.quantity; row.appendChild(cellQty); const cellUnit=document.createElement('td'); cellUnit.textContent= item.unit; row.appendChild(cellUnit); const cellAmount=document.createElement('td'); cellAmount.textContent= item.amount; row.appendChild(cellAmount); const cellAction=document.createElement('td'); const btnDel=document.createElement('button'); btnDel.innerHTML='×'; btnDel.className='deleteBtn'; btnDel.title='Удалить'; btnDel.onclick= ()=> { items.splice(index,1); updateItemsTable(); updatePreview(); }; cellAction.appendChild(btnDel); row.appendChild(cellAction); tbody.appendChild(row); }); } function getFormData() { const serviceName=document.getElementById('serviceName').value.trim(); const dateInput=document.getElementById('date').value; const quantity=document.getElementById('quantity').value; const unit=document.getElementById('unit').value; const amount=document.getElementById('amount').value; const customer=document.getElementById('customer').value.trim(); const address=document.getElementById('address').value.trim(); const customerPhone=document.getElementById('customerPhone').value.trim(); const dateObj=new Date(dateInput); if(isNaN(dateObj)){ alert('Пожалуйста, выберите правильную дату.'); return null; } const options={ day: 'numeric', month: 'long', year: 'numeric' }; const formattedDate=dateObj.toLocaleDateString('ru-RU', options); const day=dateObj.getDate(); const monthLong=dateObj.toLocaleString('ru-RU',{ month:'long' }); const year=dateObj.getFullYear(); return { serviceName, dateObj, formattedDate, day, monthLong, year, quantity, unit, amount, customer, address, customerPhone }; } function getAllItems() { const mainServiceName=document.getElementById('serviceName').value.trim(); const mainQuantity=document.getElementById('quantity').value; const mainUnit=document.getElementById('unit').value; const mainAmount=document.getElementById('amount').value; const allItems=[]; if(mainServiceName){ allItems.push({ serviceName: mainServiceName, quantity: mainQuantity, unit: mainUnit, amount: mainAmount }); } allItems.push(...items); return allItems; } function buildFullContent(data, items) { const totalAmount= items.reduce((sum, item) => sum + Number(item.amount || 0), 0); const discountPercent=5; const isDiscountApplied=document.getElementById('discountCheckbox').checked; const discountAmount= isDiscountApplied ? (totalAmount*discountPercent)/100 : 0; const totalWithDiscount= totalAmount - discountAmount; const itemsRows= items.map( (item, index)=> ` <tr> <td>${index+1}</td> <td>${item.serviceName}</td> <td>${item.quantity}</td> <td>${item.unit}</td> <td>${item.amount}</td> </tr> `).join(''); const discountTable = isDiscountApplied ? ` <table style="width:100%; border-collapse: collapse; margin-top:10px;" border="1" cellpadding="5" cellspacing="0"> <tbody> <tr> <td style="text-align:center;">Сумма с учетом скидки при карте №</td> <td style="text-align:center;">${discountPercent}%</td> <td style="text-align:center;">${totalWithDiscount.toFixed(2)}</td> </tr> </tbody> </table> ` : ''; const totalSumDisplay = isDiscountApplied ? totalWithDiscount.toFixed(2) : totalAmount.toFixed(2); return ` <div style="padding:30px;"> <div style="width:50%; display:flex; align-items:center;"> <img src="${machineBase64}" alt="Машинка" style="width:150px; height:auto;"> </div> <div> <p style="margin:0;">АКТ № 1 ОТ ${data.day} ${data.monthLong} ${data.year} г.</p> <p style="margin:0;">Исполнитель ИП Михайлов Александр Андреевич<br> ИНН 590613985887 ОГРНИП 305590609000010 тел.271-81-41</p> </div> <!-- Таблица товаров --> <div style="margin-top:10px;"> <table style="width:100%; border-collapse: collapse;" border="1" cellpadding="5" cellspacing="0"> <thead> <tr> <th>№</th> <th>Наим</th> <th>Кол-во</th> <th>Ед</th> <th>Сумма</th> </tr> </thead> <tbody> ${itemsRows} </tbody> ${discountTable} </table> </div> <!-- Итоговые суммы --> <p>Общая сумма без скидки и НДС: <u>${totalAmount.toFixed(2)}</u> руб.</p> <p>ИТОГ: <u>${totalSumDisplay}</u> руб.</p> <p>Вышеперечисленные услуги выполнены полностью и в срок. Заказчик претензий по объему, качеству и срокам оказания услуг не имеет.</p> <!-- Подписи --> <div style="display:flex; justify-content: space-between; margin-top:50px; width:100%; "> <div style="width:45%; text-align:center;"> <div style="border-top:1px solid #000; margin-top:50px;"> </div> <div>ВОДИТЕЛЬ, ИСПОЛНИТЕЛЬ, ЛОГИСТ</div> </div> <div style="width:45%; text-align:center;"> <div style="border-top:1px solid #000; margin-top:50px;"> </div> <div>ЗАКАЗЧИК</div> </div> </div> <!-- Важная часть, которая раньше не отображалась --> <p style="margin-top:10px;">*Просим ответить на вопрос:</p> <p>Откуда узнали о нашей компании?</p> <p>__________________________________________________</p> <p style="margin-top:10px;">Перевод 8- 908-271-81-41 Александр Андреевич М.( Сбербанк)</p> </div> <div style="padding:30px;"> <div style="width:50%; display:flex; align-items:center;"> <img src="${machineBase64}" alt="Машинка" style="width:150px; height:auto;"> </div> <div> <p style="margin:0;">АКТ № 1 ОТ ${data.day} ${data.monthLong} ${data.year} г.</p> <p style="margin:0;">Исполнитель ИП Михайлов Александр Андреевич<br> ИНН 590613985887 ОГРНИП 305590609000010 тел.271-81-41</p> </div> <!-- Таблица товаров --> <div style="margin-top:10px;"> <table style="width:100%; border-collapse: collapse;" border="1" cellpadding="5" cellspacing="0"> <thead> <tr> <th>№</th> <th>Наим</th> <th>Кол-во</th> <th>Ед</th> <th>Сумма</th> </tr> </thead> <tbody> ${itemsRows} </tbody> ${discountTable} </table> </div> <!-- Итоговые суммы --> <p>Общая сумма без скидки и НДС: <u>${totalAmount.toFixed(2)}</u> руб.</p> <p>ИТОГ: <u>${totalSumDisplay}</u> руб.</p> <p>Вышеперечисленные услуги выполнены полностью и в срок. Заказчик претензий по объему, качеству и срокам оказания услуг не имеет.</p> <!-- Подписи --> <div style="display:flex; justify-content: space-between; margin-top:50px; width:100%; "> <div style="width:45%; text-align:center;"> <div style="border-top:1px solid #000; margin-top:50px;"> </div> <div>ВОДИТЕЛЬ, ИСПОЛНИТЕЛЬ, ЛОГИСТ</div> </div> <div style="width:45%; text-align:center;"> <div style="border-top:1px solid #000; margin-top:50px;"> </div> <div>ЗАКАЗЧИК</div> </div> </div> <!-- Важная часть, которая раньше не отображалась --> <p style="margin-top:10px;">*Просим ответить на вопрос:</p> <p>Откуда узнали о нашей компании?</p> <p>__________________________________________________</p> <p style="margin-top:10px;">Перевод 8- 908-271-81-41 Александр Андреевич М.( Сбербанк)</p> </div> `; } // Функции для работы с добавлением товаров function showAddItemForm() { document.getElementById('additionalItemForm').style.display='block'; document.getElementById('extraServiceName').value=''; document.getElementById('extraQuantity').value=''; document.getElementById('extraUnit').value='т'; document.getElementById('extraAmount').value=''; } function addItem() { const name = document.getElementById('extraServiceName').value.trim(); const quantity = document.getElementById('extraQuantity').value; const unit = document.getElementById('extraUnit').value; const amount = document.getElementById('extraAmount').value; if(!name || !quantity || !amount){ alert('Пожалуйста, заполните все поля для товара/услуги.'); return; } items.push({ serviceName: name, quantity: quantity, unit: unit, amount: amount }); updateItemsTable(); document.getElementById('additionalItemForm').style.display='none'; updatePreview(); } // Функция для скачивания PDF с улучшенным качеством function downloadPdf() { const data = getFormData(); if (!data) return; const allItems = getAllItems(); const content = buildFullContent(data, allItems); const el = document.createElement('div'); el.innerHTML = content; html2pdf().set({ html2canvas: { scale: 2, dpi: 300, useCORS: true } }).from(el).save(`Акт_${data.formattedDate}.pdf`); } // Обновление предпросмотра с высоким качеством function updatePreview() { const data = getFormData(); if (!data) return; const allItems = getAllItems(); const content = buildFullContent(data, allItems); const container = document.getElementById('pdfPreview'); container.innerHTML=''; const el = document.createElement('div'); el.innerHTML = content; // Используем одинаковые настройки, как в downloadPdf() const options = { html2canvas: { scale: 1, dpi: 150, useCORS: true } }; // Создаем и отображаем PDF html2pdf().set(options).from(el).outputPdf().then(function(pdfBlob) { const url = URL.createObjectURL(pdfBlob); const iframe = document.createElement('iframe'); iframe.src = url; iframe.style.width='100%'; iframe.style.height='80vh'; iframe.style.border='none'; container.innerHTML=''; container.appendChild(iframe); }).catch(function(error){ console.error('Ошибка при создании PDF:', error); alert('Не удалось подготовить предпросмотр PDF. Попробуйте еще раз.'); }); } </script> </body> </html>