303 lines
16 KiB
PHP
303 lines
16 KiB
PHP
<?php
|
||
require_once __DIR__ . '/ai/LocalAIApi.php';
|
||
|
||
$ai_response = '';
|
||
$user_prompt = '';
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['user_prompt'])) {
|
||
$user_prompt = htmlspecialchars($_POST['user_prompt']);
|
||
|
||
if (!empty($user_prompt)) {
|
||
$response = LocalAIApi::createResponse([
|
||
'input' => [
|
||
['role' => 'system', 'content' => 'You are a helpful assistant.'],
|
||
['role' => 'user', 'content' => $user_prompt],
|
||
],
|
||
]);
|
||
|
||
if (!empty($response['success'])) {
|
||
$ai_response = LocalAIApi::extractText($response);
|
||
} else {
|
||
$ai_response = 'Ошибка: Не удалось получить ответ от AI.';
|
||
}
|
||
}
|
||
}
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Инструменты - Ваше Имя</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||
<link rel="stylesheet" href="assets/css/custom.css">
|
||
</head>
|
||
<body class="dark-theme">
|
||
|
||
<div id="particles-js"></div>
|
||
|
||
<nav class="navbar navbar-expand-lg navbar-dark fixed-top">
|
||
<div class="container">
|
||
<a class="navbar-brand" href="index.php">Ваше Имя</a>
|
||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||
<span class="navbar-toggler-icon"></span>
|
||
</button>
|
||
<div class="collapse navbar-collapse" id="navbarNav">
|
||
<ul class="navbar-nav ms-auto">
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="index.php#about">Обо мне</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="index.php#portfolio">Портфолио</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="index.php#contact">Контакт</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link active" href="tools.php">Инструменты</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<main class="container mt-5 pt-5">
|
||
<div class="text-center mb-5">
|
||
<h1 class="display-4">Инструменты</h1>
|
||
<p class="lead">Полезные инструменты для автоматизации ваших задач.</p>
|
||
</div>
|
||
|
||
<div class="row g-4">
|
||
<div class="col-12">
|
||
<div class="card tool-card">
|
||
<div class="card-body">
|
||
<h3 class="card-title">AI-чат</h3>
|
||
<p>Задайте любой вопрос и получите ответ от искусственного интеллекта.</p>
|
||
<form action="tools.php" method="post">
|
||
<div class="form-group mb-3">
|
||
<label for="user_prompt">Ваш вопрос:</label>
|
||
<input type="text" id="user_prompt" name="user_prompt" class="form-control" required value="<?php echo $user_prompt; ?>">
|
||
</div>
|
||
<button type="submit" class="btn btn-primary">Отправить</button>
|
||
</form>
|
||
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($user_prompt)): ?>
|
||
<div class="mt-4">
|
||
<div class="user-prompt">
|
||
<strong>Вы:</strong>
|
||
<p><?php echo $user_prompt; ?></p>
|
||
</div>
|
||
<div class="ai-response">
|
||
<strong>AI:</strong>
|
||
<p><?php echo nl2br($ai_response); ?></p>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-12">
|
||
<div class="card tool-card">
|
||
<div class="card-body">
|
||
<h2 class="card-title">Генератор инвойсов</h2>
|
||
<p>Создайте профессиональный инвойс и сохраните его в PDF.</p>
|
||
<form action="invoice.php" method="POST" target="_blank">
|
||
<div class="row mb-4">
|
||
<div class="col-md-6">
|
||
<h5 class="mb-3">От кого</h5>
|
||
<div class="mb-2">
|
||
<input type="text" class="form-control" name="from_name" placeholder="Ваше имя / Название компании" required>
|
||
</div>
|
||
<div class="mb-2">
|
||
<textarea class="form-control" name="from_address" placeholder="Ваш адрес" required></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<h5 class="mb-3">Кому</h5>
|
||
<div class="mb-2">
|
||
<input type="text" class="form-control" name="to_name" placeholder="Имя клиента / Название компании" required>
|
||
</div>
|
||
<div class="mb-2">
|
||
<textarea class="form-control" name="to_address" placeholder="Адрес клиента" required></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row mb-4">
|
||
<div class="col-md-4">
|
||
<label for="invoice_number" class="form-label">Номер инвойса</label>
|
||
<input type="text" class="form-control" id="invoice_number" name="invoice_number" value="INV-001">
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label for="invoice_date" class="form-label">Дата</label>
|
||
<input type="date" class="form-control" id="invoice_date" name="invoice_date">
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label for="invoice_due_date" class="form-label">Срок оплаты</label>
|
||
<input type="date" class="form-control" id="invoice_due_date" name="invoice_due_date">
|
||
</div>
|
||
</div>
|
||
|
||
<table class="table table-bordered" id="invoice-items">
|
||
<thead>
|
||
<tr>
|
||
<th>Описание</th>
|
||
<th>Кол-во</th>
|
||
<th>Цена за ед.</th>
|
||
<th>Сумма</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><input type="text" class="form-control" name="items[0][description]" placeholder="Название услуги или товара" required></td>
|
||
<td><input type="number" class="form-control item-qty" name="items[0][qty]" value="1" min="1" required></td>
|
||
<td><input type="number" class="form-control item-price" name="items[0][price]" value="0.00" step="0.01" min="0" required></td>
|
||
<td><input type="text" class="form-control item-total" readonly></td>
|
||
<td><button type="button" class="btn btn-danger btn-sm remove-item">×</button></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<button type="button" class="btn btn-secondary mb-3" id="add-item">Добавить позицию</button>
|
||
|
||
<div class="row justify-content-end">
|
||
<div class="col-md-5">
|
||
<div class="row mb-2">
|
||
<div class="col">Валюта:</div>
|
||
<div class="col-auto">
|
||
<input type="text" class="form-control" name="currency" value="$">
|
||
</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col">Подытог:</div>
|
||
<div class="col-auto" id="subtotal">0.00</div>
|
||
</div>
|
||
<div class="row mb-2 align-items-center">
|
||
<div class="col">Налог (%):</div>
|
||
<div class="col-auto">
|
||
<input type="number" class="form-control" id="tax-rate" name="tax_rate" value="0" min="0" step="1">
|
||
</div>
|
||
</div>
|
||
<hr>
|
||
<div class="row fw-bold fs-5">
|
||
<div class="col">Итого:</div>
|
||
<div class="col-auto" id="total">0.00</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-4">
|
||
<label for="notes" class="form-label">Примечания</label>
|
||
<textarea class="form-control" id="notes" name="notes" rows="3" placeholder="Например: Спасибо за ваш бизнес!"></textarea>
|
||
</div>
|
||
|
||
<div class="text-center mt-4">
|
||
<button type="submit" class="btn btn-primary btn-lg">Сгенерировать инвойс</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<footer class="text-center py-4">
|
||
<p>© 2025 Ваше Имя. Все права защищены.</p>
|
||
</footer>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
|
||
<script>
|
||
particlesJS.load('particles-js', 'assets/particles.json', function() {
|
||
console.log('callback - particles.js config loaded');
|
||
});
|
||
</script>
|
||
<script src="assets/js/main.js"></script>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
// Set default dates
|
||
const today = new Date().toISOString().split('T')[0];
|
||
const invoiceDate = document.getElementById('invoice_date');
|
||
const dueDate = document.getElementById('invoice_due_date');
|
||
if (invoiceDate) {
|
||
invoiceDate.value = today;
|
||
}
|
||
if (dueDate) {
|
||
// Set due date to 30 days from now
|
||
const thirtyDaysFromNow = new Date();
|
||
thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);
|
||
dueDate.value = thirtyDaysFromNow.toISOString().split('T')[0];
|
||
}
|
||
|
||
const itemsTable = document.getElementById('invoice-items');
|
||
if (!itemsTable) return;
|
||
|
||
let itemIndex = 1;
|
||
|
||
// Function to update totals
|
||
function updateTotals() {
|
||
let subtotal = 0;
|
||
document.querySelectorAll('#invoice-items tbody tr').forEach(row => {
|
||
const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
|
||
const price = parseFloat(row.querySelector('.item-price').value) || 0;
|
||
const total = qty * price;
|
||
row.querySelector('.item-total').value = total.toFixed(2);
|
||
subtotal += total;
|
||
});
|
||
|
||
const taxRate = parseFloat(document.getElementById('tax-rate').value) || 0;
|
||
const taxAmount = subtotal * (taxRate / 100);
|
||
const total = subtotal + taxAmount;
|
||
|
||
const currency = document.querySelector('input[name="currency"]').value || '$';
|
||
|
||
document.getElementById('subtotal').textContent = currency + ' ' + subtotal.toFixed(2);
|
||
document.getElementById('total').textContent = currency + ' ' + total.toFixed(2);
|
||
}
|
||
|
||
// Add new item row
|
||
document.getElementById('add-item').addEventListener('click', function () {
|
||
const newRow = document.createElement('tr');
|
||
newRow.innerHTML = `
|
||
<td><input type="text" class="form-control" name="items[${itemIndex}][description]" placeholder="Название услуги или товара" required></td>
|
||
<td><input type="number" class="form-control item-qty" name="items[${itemIndex}][qty]" value="1" min="1" required></td>
|
||
<td><input type="number" class="form-control item-price" name="items[${itemIndex}][price]" value="0.00" step="0.01" min="0" required></td>
|
||
<td><input type="text" class="form-control item-total" readonly></td>
|
||
<td><button type="button" class="btn btn-danger btn-sm remove-item">×</button></td>
|
||
`;
|
||
itemsTable.querySelector('tbody').appendChild(newRow);
|
||
itemIndex++;
|
||
updateTotals();
|
||
});
|
||
|
||
// Remove item row and update totals on click
|
||
itemsTable.addEventListener('click', function (e) {
|
||
if (e.target.classList.contains('remove-item')) {
|
||
e.target.closest('tr').remove();
|
||
updateTotals();
|
||
}
|
||
});
|
||
|
||
// Update totals on input change
|
||
itemsTable.addEventListener('input', function (e) {
|
||
if (e.target.classList.contains('item-qty') || e.target.classList.contains('item-price')) {
|
||
updateTotals();
|
||
}
|
||
});
|
||
|
||
document.getElementById('tax-rate').addEventListener('input', updateTotals);
|
||
document.querySelector('input[name="currency"]').addEventListener('input', updateTotals);
|
||
|
||
|
||
// Initial calculation
|
||
updateTotals();
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|